@open-mercato/ui 0.6.4-develop.4178.1.aad9ddaa95 → 0.6.4-develop.4210.1.d412061cfe

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 (92) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +14 -0
  3. package/dist/backend/DataTable.js +28 -62
  4. package/dist/backend/DataTable.js.map +2 -2
  5. package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
  6. package/dist/backend/detail/AttachmentMetadataDialog.js.map +2 -2
  7. package/dist/primitives/activity-feed.js +196 -0
  8. package/dist/primitives/activity-feed.js.map +7 -0
  9. package/dist/primitives/avatar.js +140 -14
  10. package/dist/primitives/avatar.js.map +3 -3
  11. package/dist/primitives/badge.js +94 -5
  12. package/dist/primitives/badge.js.map +2 -2
  13. package/dist/primitives/button-group.js +52 -0
  14. package/dist/primitives/button-group.js.map +7 -0
  15. package/dist/primitives/color-picker.js +520 -0
  16. package/dist/primitives/color-picker.js.map +7 -0
  17. package/dist/primitives/command-menu.js +355 -0
  18. package/dist/primitives/command-menu.js.map +7 -0
  19. package/dist/primitives/dialog.js +210 -35
  20. package/dist/primitives/dialog.js.map +2 -2
  21. package/dist/primitives/drawer.js +219 -0
  22. package/dist/primitives/drawer.js.map +7 -0
  23. package/dist/primitives/notification-feed.js +213 -0
  24. package/dist/primitives/notification-feed.js.map +7 -0
  25. package/dist/primitives/notification.js +23 -2
  26. package/dist/primitives/notification.js.map +2 -2
  27. package/dist/primitives/pagination.js +245 -0
  28. package/dist/primitives/pagination.js.map +7 -0
  29. package/dist/primitives/progress.js +178 -5
  30. package/dist/primitives/progress.js.map +2 -2
  31. package/dist/primitives/rating.js +174 -0
  32. package/dist/primitives/rating.js.map +7 -0
  33. package/dist/primitives/scroll-area.js +82 -0
  34. package/dist/primitives/scroll-area.js.map +7 -0
  35. package/dist/primitives/segmented-control.js +101 -0
  36. package/dist/primitives/segmented-control.js.map +7 -0
  37. package/dist/primitives/separator.js +103 -4
  38. package/dist/primitives/separator.js.map +2 -2
  39. package/dist/primitives/slider.js +115 -0
  40. package/dist/primitives/slider.js.map +7 -0
  41. package/dist/primitives/step-indicator.js +187 -0
  42. package/dist/primitives/step-indicator.js.map +7 -0
  43. package/dist/primitives/table.js +102 -10
  44. package/dist/primitives/table.js.map +2 -2
  45. package/dist/primitives/tabs.js +122 -14
  46. package/dist/primitives/tabs.js.map +2 -2
  47. package/dist/primitives/time-picker.js +9 -11
  48. package/dist/primitives/time-picker.js.map +2 -2
  49. package/package.json +8 -4
  50. package/src/backend/DataTable.tsx +43 -60
  51. package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
  52. package/src/primitives/__tests__/activity-feed.test.tsx +216 -0
  53. package/src/primitives/__tests__/avatar.test.tsx +131 -0
  54. package/src/primitives/__tests__/badge.test.tsx +189 -0
  55. package/src/primitives/__tests__/button-group.test.tsx +117 -0
  56. package/src/primitives/__tests__/color-picker.test.tsx +589 -0
  57. package/src/primitives/__tests__/command-menu.test.tsx +231 -0
  58. package/src/primitives/__tests__/dialog.test.tsx +290 -0
  59. package/src/primitives/__tests__/drawer.test.tsx +264 -0
  60. package/src/primitives/__tests__/notification-feed.test.tsx +303 -0
  61. package/src/primitives/__tests__/notification.test.tsx +102 -2
  62. package/src/primitives/__tests__/pagination.test.tsx +268 -0
  63. package/src/primitives/__tests__/progress.test.tsx +222 -0
  64. package/src/primitives/__tests__/rating.test.tsx +164 -0
  65. package/src/primitives/__tests__/scroll-area.test.tsx +109 -0
  66. package/src/primitives/__tests__/segmented-control.test.tsx +129 -0
  67. package/src/primitives/__tests__/separator.test.tsx +143 -0
  68. package/src/primitives/__tests__/slider.test.tsx +86 -0
  69. package/src/primitives/__tests__/step-indicator.test.tsx +205 -0
  70. package/src/primitives/__tests__/table.test.tsx +199 -0
  71. package/src/primitives/__tests__/tabs.test.tsx +139 -0
  72. package/src/primitives/activity-feed.tsx +326 -0
  73. package/src/primitives/avatar.tsx +225 -22
  74. package/src/primitives/badge.tsx +141 -6
  75. package/src/primitives/button-group.tsx +100 -0
  76. package/src/primitives/color-picker.tsx +693 -0
  77. package/src/primitives/command-menu.tsx +503 -0
  78. package/src/primitives/dialog.tsx +315 -51
  79. package/src/primitives/drawer.tsx +338 -0
  80. package/src/primitives/notification-feed.tsx +358 -0
  81. package/src/primitives/notification.tsx +42 -2
  82. package/src/primitives/pagination.tsx +376 -0
  83. package/src/primitives/progress.tsx +267 -6
  84. package/src/primitives/rating.tsx +245 -0
  85. package/src/primitives/scroll-area.tsx +169 -0
  86. package/src/primitives/segmented-control.tsx +162 -0
  87. package/src/primitives/separator.tsx +163 -3
  88. package/src/primitives/slider.tsx +160 -0
  89. package/src/primitives/step-indicator.tsx +287 -0
  90. package/src/primitives/table.tsx +142 -11
  91. package/src/primitives/tabs.tsx +174 -12
  92. package/src/primitives/time-picker.tsx +9 -11
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/primitives/table.tsx"],
4
- "sourcesContent": ["import * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nexport function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) {\n return <table className={cn('w-full text-sm', className)} {...props} />\n}\n\nexport function TableHeader({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <thead className={cn(className)} {...props} />\n}\n\nexport function TableBody(props: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody {...props} />\n}\n\nexport function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) {\n return <tr className={cn('border-b last:border-b-0', className)} {...props} />\n}\n\nexport function TableHead({ className, ref, ...props }: React.ThHTMLAttributes<HTMLTableCellElement> & { ref?: React.Ref<HTMLTableCellElement> }) {\n return <th ref={ref} className={cn('text-left font-medium px-4 py-2 whitespace-nowrap text-muted-foreground', className)} {...props} />\n}\n\nexport function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return <td className={cn('px-4 py-2', className)} {...props} />\n}\n\n"],
5
- "mappings": "AAIS;AAHT,SAAS,UAAU;AAEZ,SAAS,MAAM,EAAE,WAAW,GAAG,MAAM,GAA2C;AACrF,SAAO,oBAAC,WAAM,WAAW,GAAG,kBAAkB,SAAS,GAAI,GAAG,OAAO;AACvE;AAEO,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAkD;AAClG,SAAO,oBAAC,WAAM,WAAW,GAAG,SAAS,GAAI,GAAG,OAAO;AACrD;AAEO,SAAS,UAAU,OAAsD;AAC9E,SAAO,oBAAC,WAAO,GAAG,OAAO;AAC3B;AAEO,SAAS,SAAS,EAAE,WAAW,GAAG,MAAM,GAA8C;AAC3F,SAAO,oBAAC,QAAG,WAAW,GAAG,4BAA4B,SAAS,GAAI,GAAG,OAAO;AAC9E;AAEO,SAAS,UAAU,EAAE,WAAW,KAAK,GAAG,MAAM,GAA6F;AAChJ,SAAO,oBAAC,QAAG,KAAU,WAAW,GAAG,2EAA2E,SAAS,GAAI,GAAG,OAAO;AACvI;AAEO,SAAS,UAAU,EAAE,WAAW,GAAG,MAAM,GAAiD;AAC/F,SAAO,oBAAC,QAAG,WAAW,GAAG,aAAa,SAAS,GAAI,GAAG,OAAO;AAC/D;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\n\n/**\n * Low-level table primitive used by `DataTable` and a handful of\n * direct consumers (`DictionaryEntriesEditor.tsx`). Phase B.6 polish\n * aligns the chrome with Figma `Table` page (`553:14955`):\n *\n * - `Table Header Cell [1.1]` (`587:5793`) \u2014 subtle `bg-muted/40`\n * header strip + sortable chevron slot\n * - `Table Row Cell [1.1]` (`553:22175`) \u2014 comfortable padding,\n * hover affordance\n * - `Sorting Icons [1.1]` (`581:2327`) \u2014 handled by DataTable\n * - Assembled examples in `Blocks` (167144:147461 et al.) confirm\n * the chrome.\n *\n * Backward compatibility: every existing export (`Table`,\n * `TableHeader`, `TableBody`, `TableRow`, `TableHead`, `TableCell`)\n * stays callable verbatim. Header now ships a subtle `bg-muted/40`\n * strip \u2014 visible-but-soft polish per Figma. Row hover ships\n * `hover:bg-muted/30`. Both default to the new look since the spec\n * scope calls for \"row-hover state token\" + \"header cell padding\n * alignment with Figma\".\n *\n * New (additive):\n * - `<Table variant=\"striped\">` \u2014 even-row bg-muted/20 tint per\n * Figma striped block.\n * - `<TableFooter>` \u2014 bordered top footer row group.\n * - `<TableCaption>` \u2014 accessible caption above the table.\n */\n\ntype TableContextValue = {\n variant: 'default' | 'striped'\n}\n\nconst TableContext = React.createContext<TableContextValue>({ variant: 'default' })\n\nexport type TableVariant = 'default' | 'striped'\n\nexport type TableProps = React.HTMLAttributes<HTMLTableElement> & {\n /** `striped` adds even-row `bg-muted/20` tint per Figma. */\n variant?: TableVariant\n}\n\nexport function Table({ className, variant = 'default', ...props }: TableProps) {\n const contextValue = React.useMemo(() => ({ variant }), [variant])\n return (\n <TableContext.Provider value={contextValue}>\n <table\n data-slot=\"table\"\n data-variant={variant}\n className={cn('w-full text-sm', className)}\n {...props}\n />\n </TableContext.Provider>\n )\n}\n\nexport function TableHeader({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n return (\n <thead\n data-slot=\"table-header\"\n className={cn('bg-muted/40 [&_tr]:border-b', className)}\n {...props}\n />\n )\n}\n\nexport function TableBody(props: React.HTMLAttributes<HTMLTableSectionElement>) {\n return <tbody data-slot=\"table-body\" {...props} />\n}\n\nexport function TableFooter({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableSectionElement>) {\n return (\n <tfoot\n data-slot=\"table-footer\"\n className={cn('border-t bg-muted/40 font-medium', className)}\n {...props}\n />\n )\n}\n\nexport type TableRowProps = React.HTMLAttributes<HTMLTableRowElement>\n\nexport function TableRow({ className, ...props }: TableRowProps) {\n const { variant } = React.useContext(TableContext)\n return (\n <tr\n data-slot=\"table-row\"\n className={cn(\n 'border-b last:border-b-0 transition-colors',\n // Row hover affordance \u2014 only applies to body rows (header\n // rows have their own bg-muted/40 strip and shouldn't bounce\n // on hover). Children that are inside <thead> bypass via\n // CSS-attribute selectors at the consumer level if needed.\n '[&:not(thead_*)]:hover:bg-muted/30',\n variant === 'striped' ? '[&:not(thead_*)]:even:bg-muted/20' : '',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport function TableHead({\n className,\n ref,\n ...props\n}: React.ThHTMLAttributes<HTMLTableCellElement> & {\n ref?: React.Ref<HTMLTableCellElement>\n}) {\n return (\n <th\n ref={ref}\n data-slot=\"table-head\"\n className={cn(\n 'text-left font-medium px-4 py-2 whitespace-nowrap text-muted-foreground',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport function TableCell({\n className,\n ...props\n}: React.TdHTMLAttributes<HTMLTableCellElement>) {\n return (\n <td\n data-slot=\"table-cell\"\n className={cn('px-4 py-2', className)}\n {...props}\n />\n )\n}\n\nexport function TableCaption({\n className,\n ...props\n}: React.HTMLAttributes<HTMLTableCaptionElement>) {\n return (\n <caption\n data-slot=\"table-caption\"\n className={cn('mt-2 text-sm text-muted-foreground', className)}\n {...props}\n />\n )\n}\n"],
5
+ "mappings": ";AAmDM;AAjDN,YAAY,WAAW;AAEvB,SAAS,UAAU;AAkCnB,MAAM,eAAe,MAAM,cAAiC,EAAE,SAAS,UAAU,CAAC;AAS3E,SAAS,MAAM,EAAE,WAAW,UAAU,WAAW,GAAG,MAAM,GAAe;AAC9E,QAAM,eAAe,MAAM,QAAQ,OAAO,EAAE,QAAQ,IAAI,CAAC,OAAO,CAAC;AACjE,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,cAC5B;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,WAAW,GAAG,kBAAkB,SAAS;AAAA,MACxC,GAAG;AAAA;AAAA,EACN,GACF;AAEJ;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAAkD;AAChD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,+BAA+B,SAAS;AAAA,MACrD,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,UAAU,OAAsD;AAC9E,SAAO,oBAAC,WAAM,aAAU,cAAc,GAAG,OAAO;AAClD;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAAkD;AAChD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,oCAAoC,SAAS;AAAA,MAC1D,GAAG;AAAA;AAAA,EACN;AAEJ;AAIO,SAAS,SAAS,EAAE,WAAW,GAAG,MAAM,GAAkB;AAC/D,QAAM,EAAE,QAAQ,IAAI,MAAM,WAAW,YAAY;AACjD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA;AAAA,QACA,YAAY,YAAY,sCAAsC;AAAA,QAC9D;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAEG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,aAAa,SAAS;AAAA,MACnC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,GAAG;AACL,GAAkD;AAChD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,sCAAsC,SAAS;AAAA,MAC5D,GAAG;AAAA;AAAA,EACN;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { createContext, useContext } from "react";
5
5
  import { cn } from "@open-mercato/shared/lib/utils";
@@ -16,6 +16,8 @@ function Tabs({
16
16
  value: controlledValue,
17
17
  defaultValue,
18
18
  onValueChange,
19
+ variant = "pill",
20
+ orientation = "horizontal",
19
21
  children,
20
22
  className
21
23
  }) {
@@ -32,28 +34,103 @@ function Tabs({
32
34
  [isControlled, onValueChange]
33
35
  );
34
36
  const contextValue = React.useMemo(
35
- () => ({ value, onValueChange: handleValueChange }),
36
- [value, handleValueChange]
37
+ () => ({ value, onValueChange: handleValueChange, variant, orientation }),
38
+ [value, handleValueChange, variant, orientation]
37
39
  );
38
- return /* @__PURE__ */ jsx(TabsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { className, children }) });
40
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
41
+ "div",
42
+ {
43
+ "data-slot": "tabs",
44
+ "data-variant": variant,
45
+ "data-orientation": orientation,
46
+ className: cn(orientation === "vertical" ? "flex gap-4" : "", className),
47
+ children
48
+ }
49
+ ) });
39
50
  }
40
51
  function TabsList({ children, className }) {
52
+ const { variant, orientation } = useTabsContext();
53
+ const baseClasses = variant === "underline" ? (
54
+ // Underline strip — flat, full-width border-bottom for the rail,
55
+ // selected trigger gets its own border-b-2 accent below.
56
+ orientation === "vertical" ? "inline-flex flex-col items-stretch gap-1 border-r border-input pr-3" : "inline-flex h-10 items-center justify-start gap-4 border-b border-input text-muted-foreground"
57
+ ) : (
58
+ // Pill strip (original) — rounded container, bg-muted shell.
59
+ orientation === "vertical" ? "inline-flex flex-col items-stretch gap-1 rounded-lg bg-muted p-1 text-muted-foreground" : "inline-flex h-9 items-center justify-start gap-1 rounded-lg bg-muted p-1 text-muted-foreground"
60
+ );
41
61
  return /* @__PURE__ */ jsx(
42
62
  "div",
43
63
  {
44
- className: cn(
45
- "inline-flex h-9 items-center justify-start rounded-lg bg-muted p-1 text-muted-foreground",
46
- className
47
- ),
64
+ "data-slot": "tabs-list",
65
+ className: cn(baseClasses, className),
48
66
  role: "tablist",
67
+ "aria-orientation": orientation,
49
68
  children
50
69
  }
51
70
  );
52
71
  }
53
- function TabsTrigger({ value, children, className, disabled }) {
54
- const { value: selectedValue, onValueChange } = useTabsContext();
72
+ function TabsTrigger({
73
+ value,
74
+ children,
75
+ className,
76
+ disabled,
77
+ leading,
78
+ count
79
+ }) {
80
+ const { value: selectedValue, onValueChange, variant, orientation } = useTabsContext();
55
81
  const isSelected = selectedValue === value;
56
- return /* @__PURE__ */ jsx(
82
+ if (variant === "underline") {
83
+ return /* @__PURE__ */ jsxs(
84
+ "button",
85
+ {
86
+ type: "button",
87
+ role: "tab",
88
+ "aria-selected": isSelected,
89
+ disabled,
90
+ onClick: () => onValueChange(value),
91
+ "data-slot": "tabs-trigger",
92
+ "data-state": isSelected ? "active" : "inactive",
93
+ "data-variant": "underline",
94
+ className: cn(
95
+ // Underline trigger — flat, bottom-border accent when active.
96
+ // Negative margin-bottom -1px so the active accent sits on
97
+ // top of the rail's border-bottom (rather than below it).
98
+ orientation === "vertical" ? "group relative inline-flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground outline-none transition-colors" : "group relative -mb-px inline-flex items-center gap-2 border-b-2 border-transparent px-1 py-2 text-sm font-medium text-muted-foreground outline-none transition-colors",
99
+ "hover:text-foreground focus-visible:shadow-focus",
100
+ "disabled:pointer-events-none disabled:opacity-50",
101
+ isSelected ? orientation === "vertical" ? "bg-muted/40 text-foreground" : "border-accent-indigo font-semibold text-foreground" : "",
102
+ className
103
+ ),
104
+ children: [
105
+ leading ? /* @__PURE__ */ jsx(
106
+ "span",
107
+ {
108
+ "data-slot": "tabs-trigger-leading",
109
+ "aria-hidden": "true",
110
+ className: cn(
111
+ "inline-flex shrink-0 items-center justify-center",
112
+ isSelected ? "text-accent-indigo" : "text-muted-foreground"
113
+ ),
114
+ children: leading
115
+ }
116
+ ) : null,
117
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children }),
118
+ count !== void 0 ? /* @__PURE__ */ jsx(
119
+ "span",
120
+ {
121
+ "data-slot": "tabs-trigger-count",
122
+ className: cn(
123
+ "inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 text-xs font-medium",
124
+ isSelected ? "bg-accent-indigo/10 text-accent-indigo" : "bg-muted text-muted-foreground"
125
+ ),
126
+ children: count
127
+ }
128
+ ) : null
129
+ ]
130
+ }
131
+ );
132
+ }
133
+ return /* @__PURE__ */ jsxs(
57
134
  Button,
58
135
  {
59
136
  type: "button",
@@ -63,16 +140,42 @@ function TabsTrigger({ value, children, className, disabled }) {
63
140
  "aria-selected": isSelected,
64
141
  disabled,
65
142
  onClick: () => onValueChange(value),
143
+ "data-slot": "tabs-trigger",
144
+ "data-state": isSelected ? "active" : "inactive",
145
+ "data-variant": "pill",
66
146
  className: cn(
147
+ "gap-2",
67
148
  isSelected ? "bg-background text-foreground shadow" : "hover:bg-background/80 hover:text-foreground",
68
149
  className
69
150
  ),
70
- children
151
+ children: [
152
+ leading ? /* @__PURE__ */ jsx(
153
+ "span",
154
+ {
155
+ "data-slot": "tabs-trigger-leading",
156
+ "aria-hidden": "true",
157
+ className: "inline-flex shrink-0 items-center justify-center",
158
+ children: leading
159
+ }
160
+ ) : null,
161
+ /* @__PURE__ */ jsx("span", { children }),
162
+ count !== void 0 ? /* @__PURE__ */ jsx(
163
+ "span",
164
+ {
165
+ "data-slot": "tabs-trigger-count",
166
+ className: cn(
167
+ "inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 text-xs font-medium",
168
+ isSelected ? "bg-accent-indigo/10 text-accent-indigo" : "bg-background/60 text-muted-foreground"
169
+ ),
170
+ children: count
171
+ }
172
+ ) : null
173
+ ]
71
174
  }
72
175
  );
73
176
  }
74
177
  function TabsContent({ value, children, className }) {
75
- const { value: selectedValue } = useTabsContext();
178
+ const { value: selectedValue, orientation } = useTabsContext();
76
179
  if (selectedValue !== value) {
77
180
  return null;
78
181
  }
@@ -80,7 +183,12 @@ function TabsContent({ value, children, className }) {
80
183
  "div",
81
184
  {
82
185
  role: "tabpanel",
83
- className: cn("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className),
186
+ "data-slot": "tabs-content",
187
+ className: cn(
188
+ orientation === "vertical" ? "flex-1 min-w-0" : "mt-2",
189
+ "ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
190
+ className
191
+ ),
84
192
  children
85
193
  }
86
194
  );
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/primitives/tabs.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { createContext, useContext } from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from './button'\n\ntype TabsContextValue = {\n value: string\n onValueChange: (value: string) => void\n}\n\nexport const TabsContext = createContext<TabsContextValue | undefined>(undefined)\n\nexport function useTabsContext() {\n const context = useContext(TabsContext)\n if (!context) {\n throw new Error('Tabs components must be used within a Tabs provider')\n }\n return context\n}\n\nexport type TabsProps = {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n children: React.ReactNode\n className?: string\n}\n\nexport function Tabs({\n value: controlledValue,\n defaultValue,\n onValueChange,\n children,\n className,\n}: TabsProps) {\n const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? '')\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : uncontrolledValue\n\n const handleValueChange = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setUncontrolledValue(newValue)\n }\n onValueChange?.(newValue)\n },\n [isControlled, onValueChange],\n )\n\n const contextValue = React.useMemo<TabsContextValue>(\n () => ({ value, onValueChange: handleValueChange }),\n [value, handleValueChange],\n )\n\n return (\n <TabsContext.Provider value={contextValue}>\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n )\n}\n\nexport type TabsListProps = {\n children: React.ReactNode\n className?: string\n}\n\nexport function TabsList({ children, className }: TabsListProps) {\n return (\n <div\n className={cn(\n 'inline-flex h-9 items-center justify-start rounded-lg bg-muted p-1 text-muted-foreground',\n className,\n )}\n role=\"tablist\"\n >\n {children}\n </div>\n )\n}\n\nexport type TabsTriggerProps = {\n value: string\n children: React.ReactNode\n className?: string\n disabled?: boolean\n}\n\nexport function TabsTrigger({ value, children, className, disabled }: TabsTriggerProps) {\n const { value: selectedValue, onValueChange } = useTabsContext()\n const isSelected = selectedValue === value\n\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n role=\"tab\"\n aria-selected={isSelected}\n disabled={disabled}\n onClick={() => onValueChange(value)}\n className={cn(\n isSelected\n ? 'bg-background text-foreground shadow'\n : 'hover:bg-background/80 hover:text-foreground',\n className,\n )}\n >\n {children}\n </Button>\n )\n}\n\nexport type TabsContentProps = {\n value: string\n children: React.ReactNode\n className?: string\n}\n\nexport function TabsContent({ value, children, className }: TabsContentProps) {\n const { value: selectedValue } = useTabsContext()\n\n if (selectedValue !== value) {\n return null\n }\n\n return (\n <div\n role=\"tabpanel\"\n className={cn('mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', className)}\n >\n {children}\n </div>\n )\n}\n"],
5
- "mappings": ";AA0DM;AAxDN,YAAY,WAAW;AACvB,SAAS,eAAe,kBAAkB;AAC1C,SAAS,UAAU;AACnB,SAAS,cAAc;AAOhB,MAAM,cAAc,cAA4C,MAAS;AAEzE,SAAS,iBAAiB;AAC/B,QAAM,UAAU,WAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;AAUO,SAAS,KAAK;AAAA,EACnB,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAc;AACZ,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAAS,gBAAgB,EAAE;AACnF,QAAM,eAAe,oBAAoB;AACzC,QAAM,QAAQ,eAAe,kBAAkB;AAE/C,QAAM,oBAAoB,MAAM;AAAA,IAC9B,CAAC,aAAqB;AACpB,UAAI,CAAC,cAAc;AACjB,6BAAqB,QAAQ;AAAA,MAC/B;AACA,sBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA,CAAC,cAAc,aAAa;AAAA,EAC9B;AAEA,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,EAAE,OAAO,eAAe,kBAAkB;AAAA,IACjD,CAAC,OAAO,iBAAiB;AAAA,EAC3B;AAEA,SACE,oBAAC,YAAY,UAAZ,EAAqB,OAAO,cAC3B,8BAAC,SAAI,WAAuB,UAAS,GACvC;AAEJ;AAOO,SAAS,SAAS,EAAE,UAAU,UAAU,GAAkB;AAC/D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAK;AAAA,MAEJ;AAAA;AAAA,EACH;AAEJ;AASO,SAAS,YAAY,EAAE,OAAO,UAAU,WAAW,SAAS,GAAqB;AACtF,QAAM,EAAE,OAAO,eAAe,cAAc,IAAI,eAAe;AAC/D,QAAM,aAAa,kBAAkB;AAErC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,MAAK;AAAA,MACL,iBAAe;AAAA,MACf;AAAA,MACA,SAAS,MAAM,cAAc,KAAK;AAAA,MAClC,WAAW;AAAA,QACT,aACI,yCACA;AAAA,QACJ;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAQO,SAAS,YAAY,EAAE,OAAO,UAAU,UAAU,GAAqB;AAC5E,QAAM,EAAE,OAAO,cAAc,IAAI,eAAe;AAEhD,MAAI,kBAAkB,OAAO;AAC3B,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAW,GAAG,mIAAmI,SAAS;AAAA,MAEzJ;AAAA;AAAA,EACH;AAEJ;",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { createContext, useContext } from 'react'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from './button'\n\n/**\n * Tab navigation primitive \u2014 backward compatible with the original\n * pill-style API. Phase B.5 rewrite adds the Figma underline variant\n * (`Tab Menu Horizontal [1.1]` in `553:734`), the vertical orientation\n * (`Tab Menu Vertical [1.1]`), and per-tab `leading` icon + `count`\n * badge slots.\n *\n * Backward compatibility (6 import sites):\n * integrations/[id]/page.tsx\n * scheduler JobLogsModal.tsx\n * checkout LinkTemplateForm.tsx\n * search VectorSearchSection.tsx + FulltextSearchSection.tsx\n * ai-assistant AiPlaygroundPageClient.tsx\n *\n * All six call `<Tabs>` + `<TabsList>` + `<TabsTrigger>` +\n * `<TabsContent>` with the default pill look. The default `variant`\n * stays `pill` so they keep rendering verbatim.\n */\n\ntype TabsContextValue = {\n value: string\n onValueChange: (value: string) => void\n variant: 'pill' | 'underline'\n orientation: 'horizontal' | 'vertical'\n}\n\nexport const TabsContext = createContext<TabsContextValue | undefined>(undefined)\n\nexport function useTabsContext() {\n const context = useContext(TabsContext)\n if (!context) {\n throw new Error('Tabs components must be used within a Tabs provider')\n }\n return context\n}\n\nexport type TabsVariant = 'pill' | 'underline'\nexport type TabsOrientation = 'horizontal' | 'vertical'\n\nexport type TabsProps = {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n /** Visual style. `pill` is the original look (bg-muted container,\n * bg-background selected pill). `underline` matches Figma `Tab Menu\n * Horizontal [1.1]` \u2014 flat strip with a thin border-bottom and an\n * accent-indigo underline on the active tab. */\n variant?: TabsVariant\n /** Tab strip orientation. `horizontal` lays the strip in a row;\n * `vertical` lays it in a column. The default `pill` variant\n * supports both; the underline variant supports only `horizontal`\n * (per Figma \u2014 vertical underline is not a documented pattern). */\n orientation?: TabsOrientation\n children: React.ReactNode\n className?: string\n}\n\nexport function Tabs({\n value: controlledValue,\n defaultValue,\n onValueChange,\n variant = 'pill',\n orientation = 'horizontal',\n children,\n className,\n}: TabsProps) {\n const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? '')\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : uncontrolledValue\n\n const handleValueChange = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setUncontrolledValue(newValue)\n }\n onValueChange?.(newValue)\n },\n [isControlled, onValueChange],\n )\n\n const contextValue = React.useMemo<TabsContextValue>(\n () => ({ value, onValueChange: handleValueChange, variant, orientation }),\n [value, handleValueChange, variant, orientation],\n )\n\n return (\n <TabsContext.Provider value={contextValue}>\n <div\n data-slot=\"tabs\"\n data-variant={variant}\n data-orientation={orientation}\n className={cn(orientation === 'vertical' ? 'flex gap-4' : '', className)}\n >\n {children}\n </div>\n </TabsContext.Provider>\n )\n}\n\nexport type TabsListProps = {\n children: React.ReactNode\n className?: string\n}\n\nexport function TabsList({ children, className }: TabsListProps) {\n const { variant, orientation } = useTabsContext()\n\n const baseClasses =\n variant === 'underline'\n ? // Underline strip \u2014 flat, full-width border-bottom for the rail,\n // selected trigger gets its own border-b-2 accent below.\n orientation === 'vertical'\n ? 'inline-flex flex-col items-stretch gap-1 border-r border-input pr-3'\n : 'inline-flex h-10 items-center justify-start gap-4 border-b border-input text-muted-foreground'\n : // Pill strip (original) \u2014 rounded container, bg-muted shell.\n orientation === 'vertical'\n ? 'inline-flex flex-col items-stretch gap-1 rounded-lg bg-muted p-1 text-muted-foreground'\n : 'inline-flex h-9 items-center justify-start gap-1 rounded-lg bg-muted p-1 text-muted-foreground'\n\n return (\n <div\n data-slot=\"tabs-list\"\n className={cn(baseClasses, className)}\n role=\"tablist\"\n aria-orientation={orientation}\n >\n {children}\n </div>\n )\n}\n\nexport type TabsTriggerProps = {\n value: string\n children: React.ReactNode\n className?: string\n disabled?: boolean\n /** Optional leading icon slot \u2014 typically a lucide-react icon at\n * `size-4`. Per Figma `Tab Menu Horizontal Items [1.1]`. */\n leading?: React.ReactNode\n /** Optional trailing count badge \u2014 typically a numeric count or\n * \"New\". Rendered as a muted pill that highlights to indigo when\n * the tab is selected. */\n count?: React.ReactNode\n}\n\nexport function TabsTrigger({\n value,\n children,\n className,\n disabled,\n leading,\n count,\n}: TabsTriggerProps) {\n const { value: selectedValue, onValueChange, variant, orientation } = useTabsContext()\n const isSelected = selectedValue === value\n\n if (variant === 'underline') {\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={isSelected}\n disabled={disabled}\n onClick={() => onValueChange(value)}\n data-slot=\"tabs-trigger\"\n data-state={isSelected ? 'active' : 'inactive'}\n data-variant=\"underline\"\n className={cn(\n // Underline trigger \u2014 flat, bottom-border accent when active.\n // Negative margin-bottom -1px so the active accent sits on\n // top of the rail's border-bottom (rather than below it).\n orientation === 'vertical'\n ? 'group relative inline-flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium text-muted-foreground outline-none transition-colors'\n : 'group relative -mb-px inline-flex items-center gap-2 border-b-2 border-transparent px-1 py-2 text-sm font-medium text-muted-foreground outline-none transition-colors',\n 'hover:text-foreground focus-visible:shadow-focus',\n 'disabled:pointer-events-none disabled:opacity-50',\n isSelected\n ? orientation === 'vertical'\n ? 'bg-muted/40 text-foreground'\n : 'border-accent-indigo font-semibold text-foreground'\n : '',\n className,\n )}\n >\n {leading ? (\n <span\n data-slot=\"tabs-trigger-leading\"\n aria-hidden=\"true\"\n className={cn(\n 'inline-flex shrink-0 items-center justify-center',\n isSelected ? 'text-accent-indigo' : 'text-muted-foreground',\n )}\n >\n {leading}\n </span>\n ) : null}\n <span className=\"min-w-0 truncate\">{children}</span>\n {count !== undefined ? (\n <span\n data-slot=\"tabs-trigger-count\"\n className={cn(\n 'inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 text-xs font-medium',\n isSelected\n ? 'bg-accent-indigo/10 text-accent-indigo'\n : 'bg-muted text-muted-foreground',\n )}\n >\n {count}\n </span>\n ) : null}\n </button>\n )\n }\n\n // Pill variant (original look) \u2014 `<Button variant=\"ghost\" size=\"sm\">`\n // with state classes. Backward compatible.\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n role=\"tab\"\n aria-selected={isSelected}\n disabled={disabled}\n onClick={() => onValueChange(value)}\n data-slot=\"tabs-trigger\"\n data-state={isSelected ? 'active' : 'inactive'}\n data-variant=\"pill\"\n className={cn(\n 'gap-2',\n isSelected\n ? 'bg-background text-foreground shadow'\n : 'hover:bg-background/80 hover:text-foreground',\n className,\n )}\n >\n {leading ? (\n <span\n data-slot=\"tabs-trigger-leading\"\n aria-hidden=\"true\"\n className=\"inline-flex shrink-0 items-center justify-center\"\n >\n {leading}\n </span>\n ) : null}\n <span>{children}</span>\n {count !== undefined ? (\n <span\n data-slot=\"tabs-trigger-count\"\n className={cn(\n 'inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 text-xs font-medium',\n isSelected\n ? 'bg-accent-indigo/10 text-accent-indigo'\n : 'bg-background/60 text-muted-foreground',\n )}\n >\n {count}\n </span>\n ) : null}\n </Button>\n )\n}\n\nexport type TabsContentProps = {\n value: string\n children: React.ReactNode\n className?: string\n}\n\nexport function TabsContent({ value, children, className }: TabsContentProps) {\n const { value: selectedValue, orientation } = useTabsContext()\n\n if (selectedValue !== value) {\n return null\n }\n\n return (\n <div\n role=\"tabpanel\"\n data-slot=\"tabs-content\"\n className={cn(\n orientation === 'vertical' ? 'flex-1 min-w-0' : 'mt-2',\n 'ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n className,\n )}\n >\n {children}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -106,7 +106,7 @@ const slotVariants = cva(
106
106
  state: {
107
107
  default: "bg-background hover:bg-muted/50 text-muted-foreground cursor-pointer",
108
108
  hover: "bg-muted/50 text-muted-foreground cursor-pointer",
109
- active: "bg-brand-violet/10 text-brand-violet cursor-pointer",
109
+ active: "bg-primary/10 text-primary cursor-pointer",
110
110
  disabled: "bg-background text-muted-foreground/40 cursor-not-allowed"
111
111
  }
112
112
  },
@@ -145,13 +145,13 @@ const TimePickerSlot = React.forwardRef(
145
145
  children: [
146
146
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-1", children: [
147
147
  /* @__PURE__ */ jsx("span", { children: display.main }),
148
- display.suffix ? /* @__PURE__ */ jsx("span", { className: effectiveState === "active" ? "text-brand-violet/60" : "text-muted-foreground/60", children: display.suffix }) : null
148
+ display.suffix ? /* @__PURE__ */ jsx("span", { className: effectiveState === "active" ? "text-primary/60" : "text-muted-foreground/60", children: display.suffix }) : null
149
149
  ] }),
150
150
  right ? /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center justify-end gap-1", children: [
151
151
  /* @__PURE__ */ jsx("span", { children: right.main }),
152
- right.suffix ? /* @__PURE__ */ jsx("span", { className: effectiveState === "active" ? "text-brand-violet/60" : "text-muted-foreground/60", children: right.suffix }) : null
152
+ right.suffix ? /* @__PURE__ */ jsx("span", { className: effectiveState === "active" ? "text-primary/60" : "text-muted-foreground/60", children: right.suffix }) : null
153
153
  ] }) : null,
154
- effectiveState === "active" ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 shrink-0 text-brand-violet", "aria-hidden": "true" }) : null
154
+ effectiveState === "active" ? /* @__PURE__ */ jsx(Check, { className: "size-3.5 shrink-0 text-primary", "aria-hidden": "true" }) : null
155
155
  ]
156
156
  }
157
157
  );
@@ -165,7 +165,7 @@ const durationChipVariants = cva(
165
165
  state: {
166
166
  default: "bg-background border border-border shadow-xs text-muted-foreground hover:bg-muted/40 cursor-pointer",
167
167
  hover: "bg-muted/40 border border-border text-muted-foreground cursor-pointer",
168
- active: "bg-brand-violet/10 text-brand-violet cursor-pointer",
168
+ active: "bg-primary/10 text-primary cursor-pointer",
169
169
  disabled: "bg-background border border-border text-muted-foreground/40 cursor-not-allowed shadow-xs"
170
170
  }
171
171
  },
@@ -297,8 +297,7 @@ function HorizontalScrollRow({
297
297
  {
298
298
  ref: scrollRef,
299
299
  className: cn(
300
- "flex items-center gap-2 overflow-x-auto py-3.5",
301
- "[scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden",
300
+ "scrollbar-hide flex items-center gap-2 overflow-x-auto py-3.5",
302
301
  contentClassName
303
302
  ),
304
303
  role: "group",
@@ -443,8 +442,7 @@ function TimePickerCard({
443
442
  "div",
444
443
  {
445
444
  className: cn(
446
- "flex w-[348px] flex-col overflow-hidden rounded-[20px] border border-border bg-background",
447
- "shadow-[0px_1px_2px_0px_rgba(10,13,20,0.03),0px_24px_24px_-12px_rgba(51,51,51,0.04),0px_12px_12px_-6px_rgba(51,51,51,0.04)]",
445
+ "flex w-80 flex-col overflow-hidden rounded-xl border border-border bg-background shadow-xl",
448
446
  className
449
447
  ),
450
448
  role: "dialog",
@@ -536,12 +534,12 @@ function TimePickerCard({
536
534
  type: "button",
537
535
  onClick: action.onClick,
538
536
  disabled,
539
- className: "flex h-9 w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium text-brand-violet transition-colors hover:bg-brand-violet/10 cursor-pointer disabled:pointer-events-none disabled:opacity-60",
537
+ className: "flex h-9 w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium text-primary transition-colors hover:bg-primary/10 cursor-pointer disabled:pointer-events-none disabled:opacity-60",
540
538
  "data-slot": "time-picker-pinned-action",
541
539
  children: [
542
540
  action.icon ? /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center [&_svg]:size-4", "aria-hidden": "true", children: action.icon }) : null,
543
541
  /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: action.label }),
544
- action.rightText ? /* @__PURE__ */ jsx("span", { className: "text-brand-violet/60", children: action.rightText }) : null
542
+ action.rightText ? /* @__PURE__ */ jsx("span", { className: "text-primary/60", children: action.rightText }) : null
545
543
  ]
546
544
  },
547
545
  action.label
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/primitives/time-picker.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Check, ChevronLeft, ChevronRight, Clock, X } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from './button'\nimport { Popover, PopoverContent, PopoverTrigger } from './popover'\n\nexport type TimePickerValue = string | null\n\nexport type TimePickerStatusVariant = 'available' | 'busy' | 'in-meeting' | 'offline'\n\ntype SlotInteractiveState = 'default' | 'hover' | 'active' | 'disabled'\ntype DurationInteractiveState = SlotInteractiveState\ntype StatusInteractiveState = 'default' | 'hover' | 'selected' | 'disabled'\n\ntype TimeFormat = '12h' | '24h'\n\ntype LegacyFooterAction = {\n label: string\n onClick: () => void\n variant?: 'link' | 'muted'\n}\n\ntype PinnedTopAction = {\n label: string\n onClick: () => void\n icon?: React.ReactNode\n /** Optional secondary text rendered right-aligned (e.g. the current time next to `Now`). */\n rightText?: string\n}\n\ntype DurationOption = {\n value: number\n label?: string\n disabled?: boolean\n}\n\ntype StatusOption = {\n variant: TimePickerStatusVariant\n label?: string\n disabled?: boolean\n}\n\nfunction padTwo(input: number): string {\n return String(input).padStart(2, '0')\n}\n\nfunction parseTime(value: string | null | undefined): { hour: number; minute: number } | null {\n if (!value) return null\n const parts = value.split(':')\n if (parts.length < 2) return null\n const hour = parseInt(parts[0] ?? '0', 10)\n const minute = parseInt(parts[1] ?? '0', 10)\n if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null\n return {\n hour: Math.max(0, Math.min(23, hour)),\n minute: Math.max(0, Math.min(59, minute)),\n }\n}\n\nfunction formatSlotDisplay(value: string, format: TimeFormat): { main: string; suffix: string | null } {\n const parsed = parseTime(value)\n if (!parsed) return { main: value, suffix: null }\n if (format === '24h') {\n return { main: `${padTwo(parsed.hour)}:${padTwo(parsed.minute)}`, suffix: null }\n }\n const hour12 = parsed.hour === 0 ? 12 : parsed.hour > 12 ? parsed.hour - 12 : parsed.hour\n const suffix = parsed.hour < 12 ? 'AM' : 'PM'\n return { main: `${padTwo(hour12)}:${padTwo(parsed.minute)}`, suffix }\n}\n\nfunction generateSlots(startTime: string, endTime: string, intervalMinutes: number): string[] {\n const start = parseTime(startTime)\n const end = parseTime(endTime)\n if (!start || !end) return []\n const step = intervalMinutes > 0 ? intervalMinutes : 30\n const out: string[] = []\n const startTotal = start.hour * 60 + start.minute\n const endTotal = end.hour * 60 + end.minute\n if (endTotal < startTotal) return []\n for (let m = startTotal; m <= endTotal; m += step) {\n const h = Math.floor(m / 60)\n const min = m % 60\n out.push(`${padTwo(h)}:${padTwo(min)}`)\n }\n return out\n}\n\n/**\n * Format an HH:MM 24h string for display, splitting into the main digits and an\n * optional AM/PM suffix. Exported so consumers (e.g. the legacy `backend/inputs/TimePicker`\n * shim) can render their trigger label in the same format as the slot list.\n */\nexport function formatTimePickerDisplay(\n value: string,\n format: '12h' | '24h' = '12h',\n): { main: string; suffix: string | null } {\n return formatSlotDisplay(value, format)\n}\n\nexport function formatDuration(minutes: number, options?: { short?: boolean }): string {\n const short = options?.short ?? true\n if (!Number.isFinite(minutes) || minutes <= 0) return short ? '0 min' : '0 minutes'\n if (minutes < 60) return short ? `${minutes} min` : `${minutes} minutes`\n if (minutes % (24 * 60) === 0) {\n const days = minutes / (24 * 60)\n return short ? (days === 1 ? '1 day' : `${days} days`) : days === 1 ? '1 day' : `${days} days`\n }\n if (minutes % 60 === 0) {\n const hours = minutes / 60\n return short ? (hours === 1 ? '1 hour' : `${hours} hours`) : hours === 1 ? '1 hour' : `${hours} hours`\n }\n const hours = Math.floor(minutes / 60)\n const rest = minutes - hours * 60\n return short\n ? `${hours}h ${rest}m`\n : `${hours} hour${hours === 1 ? '' : 's'} ${rest} minute${rest === 1 ? '' : 's'}`\n}\n\nconst defaultStatusLabels: Record<TimePickerStatusVariant, string> = {\n available: 'Available',\n busy: 'Busy',\n 'in-meeting': 'In meeting',\n offline: 'Offline',\n}\n\nconst statusColorMap: Record<\n TimePickerStatusVariant,\n { dot: string; bgSoft: string; border: string; text: string }\n> = {\n available: {\n dot: 'bg-status-success-icon',\n bgSoft: 'bg-status-success-bg',\n border: 'border-status-success-border',\n text: 'text-status-success-text',\n },\n busy: {\n dot: 'bg-status-error-icon',\n bgSoft: 'bg-status-error-bg',\n border: 'border-status-error-border',\n text: 'text-status-error-text',\n },\n 'in-meeting': {\n dot: 'bg-status-warning-icon',\n bgSoft: 'bg-status-warning-bg',\n border: 'border-status-warning-border',\n text: 'text-status-warning-text',\n },\n offline: {\n dot: 'bg-muted-foreground',\n bgSoft: 'bg-muted',\n border: 'border-border',\n text: 'text-muted-foreground',\n },\n}\n\nconst slotVariants = cva(\n 'flex h-9 w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium transition-colors text-left',\n {\n variants: {\n state: {\n default: 'bg-background hover:bg-muted/50 text-muted-foreground cursor-pointer',\n hover: 'bg-muted/50 text-muted-foreground cursor-pointer',\n active: 'bg-brand-violet/10 text-brand-violet cursor-pointer',\n disabled: 'bg-background text-muted-foreground/40 cursor-not-allowed',\n },\n },\n defaultVariants: { state: 'default' },\n },\n)\n\nexport type TimePickerSlotProps = {\n value: string\n label?: string\n rightText?: string\n state?: SlotInteractiveState\n selected?: boolean\n disabled?: boolean\n format?: TimeFormat\n onSelect?: (value: string) => void\n className?: string\n 'aria-label'?: string\n}\n\nexport const TimePickerSlot = React.forwardRef<HTMLButtonElement, TimePickerSlotProps>(\n (\n {\n value,\n label,\n rightText,\n state,\n selected,\n disabled,\n format = '12h',\n onSelect,\n className,\n 'aria-label': ariaLabel,\n },\n ref,\n ) => {\n const effectiveState: SlotInteractiveState = disabled\n ? 'disabled'\n : selected\n ? 'active'\n : (state ?? 'default')\n const display = label != null ? { main: label, suffix: null as string | null } : formatSlotDisplay(value, format)\n const right = rightText ? formatSlotDisplay(rightText, format) : null\n const isInteractive = effectiveState !== 'disabled'\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(slotVariants({ state: effectiveState }), className)}\n onClick={isInteractive ? () => onSelect?.(value) : undefined}\n disabled={!isInteractive}\n aria-label={ariaLabel ?? value}\n aria-pressed={effectiveState === 'active'}\n data-slot=\"time-picker-slot\"\n data-state={effectiveState}\n >\n <span className=\"flex min-w-0 flex-1 items-center gap-1\">\n <span>{display.main}</span>\n {display.suffix ? (\n <span className={effectiveState === 'active' ? 'text-brand-violet/60' : 'text-muted-foreground/60'}>\n {display.suffix}\n </span>\n ) : null}\n </span>\n {right ? (\n <span className=\"flex min-w-0 items-center justify-end gap-1\">\n <span>{right.main}</span>\n {right.suffix ? (\n <span className={effectiveState === 'active' ? 'text-brand-violet/60' : 'text-muted-foreground/60'}>\n {right.suffix}\n </span>\n ) : null}\n </span>\n ) : null}\n {effectiveState === 'active' ? (\n <Check className=\"size-3.5 shrink-0 text-brand-violet\" aria-hidden=\"true\" />\n ) : null}\n </button>\n )\n },\n)\nTimePickerSlot.displayName = 'TimePickerSlot'\n\nconst durationChipVariants = cva(\n 'inline-flex h-7 items-center justify-center gap-1.5 rounded-lg px-2.5 text-sm font-medium transition-colors whitespace-nowrap',\n {\n variants: {\n state: {\n default:\n 'bg-background border border-border shadow-xs text-muted-foreground hover:bg-muted/40 cursor-pointer',\n hover: 'bg-muted/40 border border-border text-muted-foreground cursor-pointer',\n active: 'bg-brand-violet/10 text-brand-violet cursor-pointer',\n disabled:\n 'bg-background border border-border text-muted-foreground/40 cursor-not-allowed shadow-xs',\n },\n },\n defaultVariants: { state: 'default' },\n },\n)\n\nexport type TimePickerDurationChipProps = {\n value: number\n label?: string\n state?: DurationInteractiveState\n selected?: boolean\n disabled?: boolean\n onSelect?: (value: number) => void\n className?: string\n}\n\nexport const TimePickerDurationChip = React.forwardRef<HTMLButtonElement, TimePickerDurationChipProps>(\n (\n { value, label, state, selected, disabled, onSelect, className },\n ref,\n ) => {\n const effectiveState: DurationInteractiveState = disabled\n ? 'disabled'\n : selected\n ? 'active'\n : (state ?? 'default')\n const isInteractive = effectiveState !== 'disabled'\n const displayLabel = label ?? formatDuration(value)\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(durationChipVariants({ state: effectiveState }), className)}\n onClick={isInteractive ? () => onSelect?.(value) : undefined}\n disabled={!isInteractive}\n aria-pressed={effectiveState === 'active'}\n data-slot=\"time-picker-duration-chip\"\n data-state={effectiveState}\n >\n {effectiveState === 'active' ? (\n <Check className=\"size-3 shrink-0\" aria-hidden=\"true\" />\n ) : null}\n <span>{displayLabel}</span>\n </button>\n )\n },\n)\nTimePickerDurationChip.displayName = 'TimePickerDurationChip'\n\nconst statusChipBaseVariants = cva(\n 'inline-flex h-7 items-center justify-center gap-1.5 rounded-lg px-2.5 text-sm font-medium transition-colors whitespace-nowrap border',\n {\n variants: {\n state: {\n default: '',\n hover: '',\n selected: '',\n disabled: 'cursor-not-allowed opacity-60',\n },\n },\n defaultVariants: { state: 'default' },\n },\n)\n\nexport type TimePickerStatusChipProps = {\n variant: TimePickerStatusVariant\n label?: string\n state?: StatusInteractiveState\n selected?: boolean\n disabled?: boolean\n icon?: React.ReactNode\n onSelect?: (variant: TimePickerStatusVariant) => void\n className?: string\n}\n\nexport const TimePickerStatusChip = React.forwardRef<HTMLButtonElement, TimePickerStatusChipProps>(\n (\n { variant, label, state, selected, disabled, icon, onSelect, className },\n ref,\n ) => {\n const effectiveState: StatusInteractiveState = disabled\n ? 'disabled'\n : selected\n ? 'selected'\n : (state ?? 'default')\n const colors = statusColorMap[variant]\n const isInteractive = effectiveState !== 'disabled'\n const displayLabel = label ?? defaultStatusLabels[variant]\n\n const stateClasses =\n effectiveState === 'selected'\n ? cn(colors.bgSoft, colors.border, colors.text)\n : effectiveState === 'hover'\n ? cn('bg-muted/30 border-border', colors.text, 'cursor-pointer')\n : effectiveState === 'disabled'\n ? cn('bg-background border-border', colors.text)\n : cn('bg-background border-border text-muted-foreground hover:bg-muted/30 cursor-pointer')\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(statusChipBaseVariants({ state: effectiveState }), stateClasses, className)}\n onClick={isInteractive ? () => onSelect?.(variant) : undefined}\n disabled={!isInteractive}\n aria-pressed={effectiveState === 'selected'}\n data-slot=\"time-picker-status-chip\"\n data-state={effectiveState}\n data-variant={variant}\n >\n {icon ?? (\n <span\n className={cn('inline-block size-1.5 shrink-0 rounded-full', colors.dot)}\n aria-hidden=\"true\"\n />\n )}\n <span>{displayLabel}</span>\n </button>\n )\n },\n)\nTimePickerStatusChip.displayName = 'TimePickerStatusChip'\n\n/**\n * Wraps a horizontally-scrollable row with prev/next arrow buttons that appear\n * only when overflow is present. Hides the native scrollbar and reserves padding\n * on each side proportional to the visible arrow so chips never sit underneath\n * the arrow button. Exported for consumers that need the same UX (e.g. inline\n * duration chip row inside a meeting/activity form).\n */\nexport function HorizontalScrollRow({\n className,\n contentClassName,\n children,\n ariaLabel,\n arrowSize = 'default',\n scrollLeftAriaLabel = 'Scroll left',\n scrollRightAriaLabel = 'Scroll right',\n}: {\n className?: string\n /** Override classes for the inner scroll container (e.g. tighter padding when inlined into a form row). */\n contentClassName?: string\n children: React.ReactNode\n ariaLabel?: string\n /** Arrow button size. `default` = 28px circle, `sm` = 24px (denser rows). */\n arrowSize?: 'default' | 'sm'\n /** Override the left arrow's aria-label. Default is English 'Scroll left'. */\n scrollLeftAriaLabel?: string\n /** Override the right arrow's aria-label. Default is English 'Scroll right'. */\n scrollRightAriaLabel?: string\n}) {\n const scrollRef = React.useRef<HTMLDivElement>(null)\n const [canScrollLeft, setCanScrollLeft] = React.useState(false)\n const [canScrollRight, setCanScrollRight] = React.useState(false)\n\n const refreshScrollState = React.useCallback(() => {\n const el = scrollRef.current\n if (!el) return\n const { scrollLeft, scrollWidth, clientWidth } = el\n setCanScrollLeft(scrollLeft > 1)\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1)\n }, [])\n\n React.useEffect(() => {\n refreshScrollState()\n const el = scrollRef.current\n if (!el) return\n el.addEventListener('scroll', refreshScrollState, { passive: true })\n const ro = new ResizeObserver(refreshScrollState)\n ro.observe(el)\n return () => {\n el.removeEventListener('scroll', refreshScrollState)\n ro.disconnect()\n }\n }, [refreshScrollState])\n\n const scrollBy = React.useCallback((direction: 'left' | 'right') => {\n const el = scrollRef.current\n if (!el) return\n const amount = Math.max(80, Math.floor(el.clientWidth * 0.6))\n el.scrollBy({ left: direction === 'left' ? -amount : amount, behavior: 'smooth' })\n }, [])\n\n const arrowButtonClass =\n arrowSize === 'sm' ? 'size-6 [&_svg]:size-3.5' : 'size-7 [&_svg]:size-4'\n\n return (\n <div className={cn('relative', className)} data-slot=\"time-picker-scroll-row\">\n {/* Outer gutter \u2014 reserves room for the absolute-positioned chevron buttons.\n The scroll viewport lives INSIDE this gutter so chips can never slide\n underneath the arrows \u2014 moving scroll offsets only shift content inside\n the viewport, not the chevron clearance. */}\n <div\n className={cn(\n 'transition-[padding]',\n canScrollLeft ? 'pl-9' : 'pl-4',\n canScrollRight ? 'pr-9' : 'pr-4',\n )}\n >\n <div\n ref={scrollRef}\n className={cn(\n 'flex items-center gap-2 overflow-x-auto py-3.5',\n '[scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden',\n contentClassName,\n )}\n role=\"group\"\n aria-label={ariaLabel}\n >\n {children}\n </div>\n </div>\n {/* Edge fades \u2014 soft gradient at the boundary between the gutter and the\n scroll viewport, so chips sliding into the viewport dissolve cleanly\n before reaching the arrow's edge. */}\n {canScrollLeft ? (\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-9 w-6 bg-gradient-to-r from-background to-transparent\"\n />\n ) : null}\n {canScrollRight ? (\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 right-9 w-6 bg-gradient-to-l from-background to-transparent\"\n />\n ) : null}\n {canScrollLeft ? (\n <button\n type=\"button\"\n onClick={() => scrollBy('left')}\n aria-label={scrollLeftAriaLabel}\n className={cn(\n 'absolute left-1 top-1/2 z-10 flex -translate-y-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-xs transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40',\n arrowButtonClass,\n )}\n data-slot=\"time-picker-scroll-left\"\n >\n <ChevronLeft aria-hidden=\"true\" />\n </button>\n ) : null}\n {canScrollRight ? (\n <button\n type=\"button\"\n onClick={() => scrollBy('right')}\n aria-label={scrollRightAriaLabel}\n className={cn(\n 'absolute right-1 top-1/2 z-10 flex -translate-y-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-xs transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40',\n arrowButtonClass,\n )}\n data-slot=\"time-picker-scroll-right\"\n >\n <ChevronRight aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n )\n}\n\nfunction useControllable<T>(controlled: T | undefined, defaultValue: T, onChange?: (next: T) => void) {\n const [internal, setInternal] = React.useState<T>(defaultValue)\n const isControlled = controlled !== undefined\n const value = isControlled ? (controlled as T) : internal\n const setValue = React.useCallback(\n (next: T) => {\n if (!isControlled) setInternal(next)\n onChange?.(next)\n },\n [isControlled, onChange],\n )\n return [value, setValue] as const\n}\n\nexport type TimePickerProps = {\n value?: TimePickerValue\n defaultValue?: TimePickerValue\n onChange?: (value: TimePickerValue) => void\n\n showHeader?: boolean\n headerIcon?: React.ReactNode\n headerTitle?: string\n headerPlaceholder?: string\n onClose?: () => void\n\n durations?: DurationOption[]\n activeDuration?: number\n defaultActiveDuration?: number\n onDurationChange?: (value: number) => void\n\n statuses?: StatusOption[]\n activeStatus?: TimePickerStatusVariant\n defaultActiveStatus?: TimePickerStatusVariant\n onStatusChange?: (variant: TimePickerStatusVariant) => void\n statusLabel?: string\n\n slots?: string[]\n startTime?: string\n endTime?: string\n intervalMinutes?: number\n format?: TimeFormat\n slotRightText?: (slot: string) => string | undefined\n slotLabel?: string\n maxHeight?: number\n\n showFooter?: boolean\n cancelLabel?: string\n applyLabel?: string\n onCancel?: () => void\n onApply?: (value: TimePickerValue) => void\n legacyFooterActions?: LegacyFooterAction[]\n /**\n * Quick-action rows rendered above the scrollable slot list \u2014 used for\n * \"Now\"-style shortcuts that stay visible regardless of scroll position.\n * Styled like slots but with primary-tinted foreground.\n */\n pinnedTopActions?: PinnedTopAction[]\n\n trigger?: React.ReactNode\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n popoverAlign?: 'start' | 'center' | 'end'\n popoverSide?: 'top' | 'right' | 'bottom' | 'left'\n\n className?: string\n disabled?: boolean\n 'aria-label'?: string\n}\n\nfunction TimePickerCard({\n value,\n setValue,\n showHeader,\n headerIcon,\n headerTitle,\n headerPlaceholder,\n onClose,\n closeAriaLabel,\n format,\n durationOptions,\n activeDuration,\n setActiveDuration,\n onDurationChange,\n durationsAriaLabel,\n scrollLeftAriaLabel,\n scrollRightAriaLabel,\n statusOptions,\n activeStatus,\n setActiveStatus,\n onStatusChange,\n statusLabel,\n slotList,\n slotLabel,\n slotRightText,\n maxHeight,\n showFooter,\n cancelLabel,\n applyLabel,\n handleCancel,\n handleApply,\n legacyFooterActions,\n pinnedTopActions,\n disabled,\n className,\n ariaLabel,\n slotListRef,\n}: {\n value: TimePickerValue\n setValue: (next: TimePickerValue) => void\n showHeader: boolean\n headerIcon: React.ReactNode\n headerTitle: string | undefined\n headerPlaceholder: string\n onClose: (() => void) | undefined\n closeAriaLabel: string\n format: TimeFormat\n durationOptions: DurationOption[] | undefined\n activeDuration: number | undefined\n setActiveDuration: (next: number) => void\n onDurationChange: ((value: number) => void) | undefined\n durationsAriaLabel: string\n scrollLeftAriaLabel: string\n scrollRightAriaLabel: string\n statusOptions: StatusOption[] | undefined\n activeStatus: TimePickerStatusVariant | undefined\n setActiveStatus: (next: TimePickerStatusVariant) => void\n onStatusChange: ((variant: TimePickerStatusVariant) => void) | undefined\n statusLabel: string\n slotList: string[]\n slotLabel: string | undefined\n slotRightText: ((slot: string) => string | undefined) | undefined\n maxHeight: number\n showFooter: boolean\n cancelLabel: string\n applyLabel: string\n handleCancel: () => void\n handleApply: () => void\n legacyFooterActions: LegacyFooterAction[] | undefined\n pinnedTopActions: PinnedTopAction[] | undefined\n disabled: boolean\n className: string | undefined\n ariaLabel: string\n slotListRef: React.RefObject<HTMLDivElement | null>\n}) {\n const headerDisplay = React.useMemo(() => {\n if (headerTitle != null) return { main: headerTitle, suffix: null as string | null }\n if (value) return formatSlotDisplay(value, format)\n return { main: headerPlaceholder, suffix: null as string | null }\n }, [headerTitle, value, format, headerPlaceholder])\n\n const handleSlotKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n const target = event.target as HTMLElement\n const slotButton = target.closest<HTMLButtonElement>('[data-slot=\"time-picker-slot\"]')\n if (!slotButton) return\n const container = slotListRef.current\n if (!container) return\n const all = Array.from(\n container.querySelectorAll<HTMLButtonElement>('[data-slot=\"time-picker-slot\"]:not(:disabled)'),\n )\n const currentIndex = all.indexOf(slotButton)\n if (currentIndex === -1) return\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n const next = all[Math.min(all.length - 1, currentIndex + 1)]\n next?.focus()\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n const prev = all[Math.max(0, currentIndex - 1)]\n prev?.focus()\n } else if (event.key === 'Home') {\n event.preventDefault()\n all[0]?.focus()\n } else if (event.key === 'End') {\n event.preventDefault()\n all[all.length - 1]?.focus()\n }\n },\n [disabled, slotListRef],\n )\n\n return (\n <div\n className={cn(\n 'flex w-[348px] flex-col overflow-hidden rounded-[20px] border border-border bg-background',\n 'shadow-[0px_1px_2px_0px_rgba(10,13,20,0.03),0px_24px_24px_-12px_rgba(51,51,51,0.04),0px_12px_12px_-6px_rgba(51,51,51,0.04)]',\n className,\n )}\n role=\"dialog\"\n aria-label={ariaLabel}\n aria-disabled={disabled || undefined}\n data-slot=\"time-picker\"\n >\n {showHeader ? (\n <div\n className=\"flex items-center gap-2 border-b border-border px-4 py-3.5\"\n data-slot=\"time-picker-header\"\n >\n <span className=\"flex shrink-0 items-center text-muted-foreground\" aria-hidden=\"true\">\n {headerIcon ?? <Clock className=\"size-5\" aria-hidden=\"true\" />}\n </span>\n <p className=\"flex-1 min-w-0 truncate text-base font-medium text-muted-foreground\">\n <span>{headerDisplay.main}</span>\n {headerDisplay.suffix ? <span className=\"ml-1 text-muted-foreground/60\">{headerDisplay.suffix}</span> : null}\n </p>\n {onClose ? (\n <button\n type=\"button\"\n onClick={onClose}\n disabled={disabled}\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring/40 disabled:pointer-events-none disabled:opacity-60\"\n aria-label={closeAriaLabel}\n data-slot=\"time-picker-close\"\n >\n <X className=\"size-4\" aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n ) : null}\n\n {durationOptions && durationOptions.length > 0 ? (\n <HorizontalScrollRow\n className=\"border-b border-border\"\n ariaLabel={durationsAriaLabel}\n scrollLeftAriaLabel={scrollLeftAriaLabel}\n scrollRightAriaLabel={scrollRightAriaLabel}\n >\n {durationOptions.map((option) => (\n <TimePickerDurationChip\n key={option.value}\n value={option.value}\n label={option.label}\n disabled={disabled || option.disabled}\n selected={activeDuration === option.value}\n onSelect={(next) => {\n setActiveDuration(next)\n onDurationChange?.(next)\n }}\n />\n ))}\n </HorizontalScrollRow>\n ) : null}\n\n {statusOptions && statusOptions.length > 0 ? (\n <div\n className=\"flex flex-col gap-2 border-b border-border px-4 py-3.5\"\n data-slot=\"time-picker-status-row\"\n >\n <p className=\"text-sm font-medium text-muted-foreground\">{statusLabel}</p>\n <div className=\"flex flex-wrap items-center gap-2\">\n {statusOptions.map((option) => (\n <TimePickerStatusChip\n key={option.variant}\n variant={option.variant}\n label={option.label}\n disabled={disabled || option.disabled}\n selected={activeStatus === option.variant}\n onSelect={(next) => {\n setActiveStatus(next)\n onStatusChange?.(next)\n }}\n />\n ))}\n </div>\n </div>\n ) : null}\n\n {pinnedTopActions && pinnedTopActions.length > 0 ? (\n <div\n className=\"flex flex-col gap-0.5 border-b border-border p-2\"\n data-slot=\"time-picker-pinned-top\"\n >\n {pinnedTopActions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={action.onClick}\n disabled={disabled}\n className=\"flex h-9 w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium text-brand-violet transition-colors hover:bg-brand-violet/10 cursor-pointer disabled:pointer-events-none disabled:opacity-60\"\n data-slot=\"time-picker-pinned-action\"\n >\n {action.icon ? (\n <span className=\"flex shrink-0 items-center [&_svg]:size-4\" aria-hidden=\"true\">\n {action.icon}\n </span>\n ) : null}\n <span className=\"flex-1 text-left\">{action.label}</span>\n {action.rightText ? (\n <span className=\"text-brand-violet/60\">{action.rightText}</span>\n ) : null}\n </button>\n ))}\n </div>\n ) : null}\n\n <div\n className=\"flex flex-col gap-0.5 overflow-y-auto p-2\"\n style={{ maxHeight }}\n ref={slotListRef}\n onKeyDown={handleSlotKeyDown}\n data-slot=\"time-picker-slots\"\n >\n {slotLabel ? (\n <p className=\"px-3 pt-1 pb-2 text-sm font-medium text-muted-foreground\">{slotLabel}</p>\n ) : null}\n {slotList.length === 0 ? (\n <p className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No time slots available.</p>\n ) : (\n slotList.map((slot) => (\n <TimePickerSlot\n key={slot}\n value={slot}\n format={format}\n rightText={slotRightText?.(slot)}\n selected={value === slot}\n disabled={disabled}\n onSelect={(next) => setValue(next)}\n />\n ))\n )}\n </div>\n\n {showFooter ? (\n <div\n className=\"flex flex-wrap items-center justify-end gap-2 border-t border-border px-4 py-3\"\n data-slot=\"time-picker-footer\"\n >\n {legacyFooterActions && legacyFooterActions.length > 0 ? (\n <div className=\"mr-auto flex items-center gap-1\">\n {legacyFooterActions.map((action) => (\n <Button\n key={action.label}\n type=\"button\"\n variant={action.variant === 'muted' ? 'muted' : 'ghost'}\n size=\"sm\"\n onClick={action.onClick}\n disabled={disabled}\n data-slot=\"time-picker-legacy-action\"\n >\n {action.label}\n </Button>\n ))}\n <span aria-hidden=\"true\" className=\"ml-2 mr-1 h-5 w-px bg-border\" />\n </div>\n ) : null}\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCancel}\n disabled={disabled}\n data-slot=\"time-picker-cancel\"\n >\n {cancelLabel}\n </Button>\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={handleApply}\n disabled={disabled}\n data-slot=\"time-picker-apply\"\n >\n {applyLabel}\n </Button>\n </div>\n ) : null}\n </div>\n )\n}\n\nexport function TimePicker({\n value: valueProp,\n defaultValue = null,\n onChange,\n showHeader = true,\n headerIcon,\n headerTitle,\n headerPlaceholder,\n onClose,\n durations,\n activeDuration: activeDurationProp,\n defaultActiveDuration,\n onDurationChange,\n statuses,\n activeStatus: activeStatusProp,\n defaultActiveStatus,\n onStatusChange,\n statusLabel,\n slots: slotsProp,\n startTime = '00:00',\n endTime = '23:30',\n intervalMinutes = 30,\n format = '12h',\n slotRightText,\n slotLabel,\n maxHeight = 280,\n showFooter = true,\n cancelLabel,\n applyLabel,\n onCancel,\n onApply,\n legacyFooterActions,\n pinnedTopActions,\n trigger,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n popoverAlign = 'start',\n popoverSide = 'bottom',\n className,\n disabled = false,\n 'aria-label': ariaLabel,\n}: TimePickerProps) {\n const t = useT()\n const resolvedHeaderPlaceholder = headerPlaceholder ?? t('ui.timePicker.placeholder', 'Pick a time')\n const resolvedStatusLabel = statusLabel ?? t('ui.timePicker.statusLabel', 'Select status')\n const resolvedCancelLabel = cancelLabel ?? t('ui.timePicker.cancelButton', 'Cancel')\n const resolvedApplyLabel = applyLabel ?? t('ui.timePicker.applyButton', 'Apply')\n const resolvedAriaLabel = ariaLabel ?? t('ui.timePicker.label', 'Time picker')\n const resolvedCloseAriaLabel = t('ui.timePicker.closeButton', 'Close')\n const resolvedDurationsAriaLabel = t('ui.timePicker.durationsRowLabel', 'Quick duration')\n const resolvedScrollLeftAriaLabel = t('ui.timePicker.scrollLeft', 'Scroll left')\n const resolvedScrollRightAriaLabel = t('ui.timePicker.scrollRight', 'Scroll right')\n const [value, setValue] = useControllable<TimePickerValue>(valueProp, defaultValue, onChange)\n const [activeDuration, setActiveDuration] = useControllable<number | undefined>(\n activeDurationProp,\n defaultActiveDuration,\n )\n const [activeStatus, setActiveStatus] = useControllable<TimePickerStatusVariant | undefined>(\n activeStatusProp,\n defaultActiveStatus,\n )\n const [open, setOpen] = useControllable<boolean>(openProp, defaultOpen, onOpenChange)\n\n const openSnapshotRef = React.useRef<TimePickerValue>(value)\n const slotListRef = React.useRef<HTMLDivElement | null>(null)\n\n const slotList = React.useMemo(() => {\n if (slotsProp && slotsProp.length > 0) return slotsProp\n return generateSlots(startTime, endTime, intervalMinutes)\n }, [slotsProp, startTime, endTime, intervalMinutes])\n\n const setOpenWithSnapshot = React.useCallback(\n (next: boolean) => {\n if (next && !open) {\n openSnapshotRef.current = value\n }\n setOpen(next)\n },\n [open, setOpen, value],\n )\n\n const handleApply = React.useCallback(() => {\n onApply?.(value)\n if (trigger) setOpenWithSnapshot(false)\n }, [onApply, setOpenWithSnapshot, trigger, value])\n\n const handleCancel = React.useCallback(() => {\n onCancel?.()\n if (trigger) {\n setValue(openSnapshotRef.current)\n setOpenWithSnapshot(false)\n }\n }, [onCancel, setOpenWithSnapshot, setValue, trigger])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n handleCancel()\n } else if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleApply()\n }\n },\n [handleApply, handleCancel],\n )\n\n const card = (\n <div onKeyDown={handleKeyDown}>\n <TimePickerCard\n value={value}\n setValue={setValue}\n showHeader={showHeader}\n headerIcon={headerIcon}\n headerTitle={headerTitle}\n headerPlaceholder={resolvedHeaderPlaceholder}\n onClose={onClose}\n closeAriaLabel={resolvedCloseAriaLabel}\n format={format}\n durationOptions={durations}\n activeDuration={activeDuration}\n setActiveDuration={setActiveDuration}\n onDurationChange={onDurationChange}\n durationsAriaLabel={resolvedDurationsAriaLabel}\n scrollLeftAriaLabel={resolvedScrollLeftAriaLabel}\n scrollRightAriaLabel={resolvedScrollRightAriaLabel}\n statusOptions={statuses}\n activeStatus={activeStatus}\n setActiveStatus={setActiveStatus}\n onStatusChange={onStatusChange}\n statusLabel={resolvedStatusLabel}\n slotList={slotList}\n slotLabel={slotLabel}\n slotRightText={slotRightText}\n maxHeight={maxHeight}\n showFooter={showFooter}\n cancelLabel={resolvedCancelLabel}\n applyLabel={resolvedApplyLabel}\n handleCancel={handleCancel}\n handleApply={handleApply}\n legacyFooterActions={legacyFooterActions}\n pinnedTopActions={pinnedTopActions}\n disabled={disabled}\n className={className}\n ariaLabel={resolvedAriaLabel}\n slotListRef={slotListRef}\n />\n </div>\n )\n\n if (!trigger) return card\n\n return (\n <Popover open={open} onOpenChange={setOpenWithSnapshot}>\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\n <PopoverContent\n align={popoverAlign}\n side={popoverSide}\n className=\"w-auto border-none bg-transparent p-0 shadow-none\"\n >\n {card}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Check, ChevronLeft, ChevronRight, Clock, X } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from './button'\nimport { Popover, PopoverContent, PopoverTrigger } from './popover'\n\nexport type TimePickerValue = string | null\n\nexport type TimePickerStatusVariant = 'available' | 'busy' | 'in-meeting' | 'offline'\n\ntype SlotInteractiveState = 'default' | 'hover' | 'active' | 'disabled'\ntype DurationInteractiveState = SlotInteractiveState\ntype StatusInteractiveState = 'default' | 'hover' | 'selected' | 'disabled'\n\ntype TimeFormat = '12h' | '24h'\n\ntype LegacyFooterAction = {\n label: string\n onClick: () => void\n variant?: 'link' | 'muted'\n}\n\ntype PinnedTopAction = {\n label: string\n onClick: () => void\n icon?: React.ReactNode\n /** Optional secondary text rendered right-aligned (e.g. the current time next to `Now`). */\n rightText?: string\n}\n\ntype DurationOption = {\n value: number\n label?: string\n disabled?: boolean\n}\n\ntype StatusOption = {\n variant: TimePickerStatusVariant\n label?: string\n disabled?: boolean\n}\n\nfunction padTwo(input: number): string {\n return String(input).padStart(2, '0')\n}\n\nfunction parseTime(value: string | null | undefined): { hour: number; minute: number } | null {\n if (!value) return null\n const parts = value.split(':')\n if (parts.length < 2) return null\n const hour = parseInt(parts[0] ?? '0', 10)\n const minute = parseInt(parts[1] ?? '0', 10)\n if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null\n return {\n hour: Math.max(0, Math.min(23, hour)),\n minute: Math.max(0, Math.min(59, minute)),\n }\n}\n\nfunction formatSlotDisplay(value: string, format: TimeFormat): { main: string; suffix: string | null } {\n const parsed = parseTime(value)\n if (!parsed) return { main: value, suffix: null }\n if (format === '24h') {\n return { main: `${padTwo(parsed.hour)}:${padTwo(parsed.minute)}`, suffix: null }\n }\n const hour12 = parsed.hour === 0 ? 12 : parsed.hour > 12 ? parsed.hour - 12 : parsed.hour\n const suffix = parsed.hour < 12 ? 'AM' : 'PM'\n return { main: `${padTwo(hour12)}:${padTwo(parsed.minute)}`, suffix }\n}\n\nfunction generateSlots(startTime: string, endTime: string, intervalMinutes: number): string[] {\n const start = parseTime(startTime)\n const end = parseTime(endTime)\n if (!start || !end) return []\n const step = intervalMinutes > 0 ? intervalMinutes : 30\n const out: string[] = []\n const startTotal = start.hour * 60 + start.minute\n const endTotal = end.hour * 60 + end.minute\n if (endTotal < startTotal) return []\n for (let m = startTotal; m <= endTotal; m += step) {\n const h = Math.floor(m / 60)\n const min = m % 60\n out.push(`${padTwo(h)}:${padTwo(min)}`)\n }\n return out\n}\n\n/**\n * Format an HH:MM 24h string for display, splitting into the main digits and an\n * optional AM/PM suffix. Exported so consumers (e.g. the legacy `backend/inputs/TimePicker`\n * shim) can render their trigger label in the same format as the slot list.\n */\nexport function formatTimePickerDisplay(\n value: string,\n format: '12h' | '24h' = '12h',\n): { main: string; suffix: string | null } {\n return formatSlotDisplay(value, format)\n}\n\nexport function formatDuration(minutes: number, options?: { short?: boolean }): string {\n const short = options?.short ?? true\n if (!Number.isFinite(minutes) || minutes <= 0) return short ? '0 min' : '0 minutes'\n if (minutes < 60) return short ? `${minutes} min` : `${minutes} minutes`\n if (minutes % (24 * 60) === 0) {\n const days = minutes / (24 * 60)\n return short ? (days === 1 ? '1 day' : `${days} days`) : days === 1 ? '1 day' : `${days} days`\n }\n if (minutes % 60 === 0) {\n const hours = minutes / 60\n return short ? (hours === 1 ? '1 hour' : `${hours} hours`) : hours === 1 ? '1 hour' : `${hours} hours`\n }\n const hours = Math.floor(minutes / 60)\n const rest = minutes - hours * 60\n return short\n ? `${hours}h ${rest}m`\n : `${hours} hour${hours === 1 ? '' : 's'} ${rest} minute${rest === 1 ? '' : 's'}`\n}\n\nconst defaultStatusLabels: Record<TimePickerStatusVariant, string> = {\n available: 'Available',\n busy: 'Busy',\n 'in-meeting': 'In meeting',\n offline: 'Offline',\n}\n\nconst statusColorMap: Record<\n TimePickerStatusVariant,\n { dot: string; bgSoft: string; border: string; text: string }\n> = {\n available: {\n dot: 'bg-status-success-icon',\n bgSoft: 'bg-status-success-bg',\n border: 'border-status-success-border',\n text: 'text-status-success-text',\n },\n busy: {\n dot: 'bg-status-error-icon',\n bgSoft: 'bg-status-error-bg',\n border: 'border-status-error-border',\n text: 'text-status-error-text',\n },\n 'in-meeting': {\n dot: 'bg-status-warning-icon',\n bgSoft: 'bg-status-warning-bg',\n border: 'border-status-warning-border',\n text: 'text-status-warning-text',\n },\n offline: {\n dot: 'bg-muted-foreground',\n bgSoft: 'bg-muted',\n border: 'border-border',\n text: 'text-muted-foreground',\n },\n}\n\nconst slotVariants = cva(\n 'flex h-9 w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium transition-colors text-left',\n {\n variants: {\n state: {\n default: 'bg-background hover:bg-muted/50 text-muted-foreground cursor-pointer',\n hover: 'bg-muted/50 text-muted-foreground cursor-pointer',\n active: 'bg-primary/10 text-primary cursor-pointer',\n disabled: 'bg-background text-muted-foreground/40 cursor-not-allowed',\n },\n },\n defaultVariants: { state: 'default' },\n },\n)\n\nexport type TimePickerSlotProps = {\n value: string\n label?: string\n rightText?: string\n state?: SlotInteractiveState\n selected?: boolean\n disabled?: boolean\n format?: TimeFormat\n onSelect?: (value: string) => void\n className?: string\n 'aria-label'?: string\n}\n\nexport const TimePickerSlot = React.forwardRef<HTMLButtonElement, TimePickerSlotProps>(\n (\n {\n value,\n label,\n rightText,\n state,\n selected,\n disabled,\n format = '12h',\n onSelect,\n className,\n 'aria-label': ariaLabel,\n },\n ref,\n ) => {\n const effectiveState: SlotInteractiveState = disabled\n ? 'disabled'\n : selected\n ? 'active'\n : (state ?? 'default')\n const display = label != null ? { main: label, suffix: null as string | null } : formatSlotDisplay(value, format)\n const right = rightText ? formatSlotDisplay(rightText, format) : null\n const isInteractive = effectiveState !== 'disabled'\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(slotVariants({ state: effectiveState }), className)}\n onClick={isInteractive ? () => onSelect?.(value) : undefined}\n disabled={!isInteractive}\n aria-label={ariaLabel ?? value}\n aria-pressed={effectiveState === 'active'}\n data-slot=\"time-picker-slot\"\n data-state={effectiveState}\n >\n <span className=\"flex min-w-0 flex-1 items-center gap-1\">\n <span>{display.main}</span>\n {display.suffix ? (\n <span className={effectiveState === 'active' ? 'text-primary/60' : 'text-muted-foreground/60'}>\n {display.suffix}\n </span>\n ) : null}\n </span>\n {right ? (\n <span className=\"flex min-w-0 items-center justify-end gap-1\">\n <span>{right.main}</span>\n {right.suffix ? (\n <span className={effectiveState === 'active' ? 'text-primary/60' : 'text-muted-foreground/60'}>\n {right.suffix}\n </span>\n ) : null}\n </span>\n ) : null}\n {effectiveState === 'active' ? (\n <Check className=\"size-3.5 shrink-0 text-primary\" aria-hidden=\"true\" />\n ) : null}\n </button>\n )\n },\n)\nTimePickerSlot.displayName = 'TimePickerSlot'\n\nconst durationChipVariants = cva(\n 'inline-flex h-7 items-center justify-center gap-1.5 rounded-lg px-2.5 text-sm font-medium transition-colors whitespace-nowrap',\n {\n variants: {\n state: {\n default:\n 'bg-background border border-border shadow-xs text-muted-foreground hover:bg-muted/40 cursor-pointer',\n hover: 'bg-muted/40 border border-border text-muted-foreground cursor-pointer',\n active: 'bg-primary/10 text-primary cursor-pointer',\n disabled:\n 'bg-background border border-border text-muted-foreground/40 cursor-not-allowed shadow-xs',\n },\n },\n defaultVariants: { state: 'default' },\n },\n)\n\nexport type TimePickerDurationChipProps = {\n value: number\n label?: string\n state?: DurationInteractiveState\n selected?: boolean\n disabled?: boolean\n onSelect?: (value: number) => void\n className?: string\n}\n\nexport const TimePickerDurationChip = React.forwardRef<HTMLButtonElement, TimePickerDurationChipProps>(\n (\n { value, label, state, selected, disabled, onSelect, className },\n ref,\n ) => {\n const effectiveState: DurationInteractiveState = disabled\n ? 'disabled'\n : selected\n ? 'active'\n : (state ?? 'default')\n const isInteractive = effectiveState !== 'disabled'\n const displayLabel = label ?? formatDuration(value)\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(durationChipVariants({ state: effectiveState }), className)}\n onClick={isInteractive ? () => onSelect?.(value) : undefined}\n disabled={!isInteractive}\n aria-pressed={effectiveState === 'active'}\n data-slot=\"time-picker-duration-chip\"\n data-state={effectiveState}\n >\n {effectiveState === 'active' ? (\n <Check className=\"size-3 shrink-0\" aria-hidden=\"true\" />\n ) : null}\n <span>{displayLabel}</span>\n </button>\n )\n },\n)\nTimePickerDurationChip.displayName = 'TimePickerDurationChip'\n\nconst statusChipBaseVariants = cva(\n 'inline-flex h-7 items-center justify-center gap-1.5 rounded-lg px-2.5 text-sm font-medium transition-colors whitespace-nowrap border',\n {\n variants: {\n state: {\n default: '',\n hover: '',\n selected: '',\n disabled: 'cursor-not-allowed opacity-60',\n },\n },\n defaultVariants: { state: 'default' },\n },\n)\n\nexport type TimePickerStatusChipProps = {\n variant: TimePickerStatusVariant\n label?: string\n state?: StatusInteractiveState\n selected?: boolean\n disabled?: boolean\n icon?: React.ReactNode\n onSelect?: (variant: TimePickerStatusVariant) => void\n className?: string\n}\n\nexport const TimePickerStatusChip = React.forwardRef<HTMLButtonElement, TimePickerStatusChipProps>(\n (\n { variant, label, state, selected, disabled, icon, onSelect, className },\n ref,\n ) => {\n const effectiveState: StatusInteractiveState = disabled\n ? 'disabled'\n : selected\n ? 'selected'\n : (state ?? 'default')\n const colors = statusColorMap[variant]\n const isInteractive = effectiveState !== 'disabled'\n const displayLabel = label ?? defaultStatusLabels[variant]\n\n const stateClasses =\n effectiveState === 'selected'\n ? cn(colors.bgSoft, colors.border, colors.text)\n : effectiveState === 'hover'\n ? cn('bg-muted/30 border-border', colors.text, 'cursor-pointer')\n : effectiveState === 'disabled'\n ? cn('bg-background border-border', colors.text)\n : cn('bg-background border-border text-muted-foreground hover:bg-muted/30 cursor-pointer')\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cn(statusChipBaseVariants({ state: effectiveState }), stateClasses, className)}\n onClick={isInteractive ? () => onSelect?.(variant) : undefined}\n disabled={!isInteractive}\n aria-pressed={effectiveState === 'selected'}\n data-slot=\"time-picker-status-chip\"\n data-state={effectiveState}\n data-variant={variant}\n >\n {icon ?? (\n <span\n className={cn('inline-block size-1.5 shrink-0 rounded-full', colors.dot)}\n aria-hidden=\"true\"\n />\n )}\n <span>{displayLabel}</span>\n </button>\n )\n },\n)\nTimePickerStatusChip.displayName = 'TimePickerStatusChip'\n\n/**\n * Wraps a horizontally-scrollable row with prev/next arrow buttons that appear\n * only when overflow is present. Hides the native scrollbar and reserves padding\n * on each side proportional to the visible arrow so chips never sit underneath\n * the arrow button. Exported for consumers that need the same UX (e.g. inline\n * duration chip row inside a meeting/activity form).\n */\nexport function HorizontalScrollRow({\n className,\n contentClassName,\n children,\n ariaLabel,\n arrowSize = 'default',\n scrollLeftAriaLabel = 'Scroll left',\n scrollRightAriaLabel = 'Scroll right',\n}: {\n className?: string\n /** Override classes for the inner scroll container (e.g. tighter padding when inlined into a form row). */\n contentClassName?: string\n children: React.ReactNode\n ariaLabel?: string\n /** Arrow button size. `default` = 28px circle, `sm` = 24px (denser rows). */\n arrowSize?: 'default' | 'sm'\n /** Override the left arrow's aria-label. Default is English 'Scroll left'. */\n scrollLeftAriaLabel?: string\n /** Override the right arrow's aria-label. Default is English 'Scroll right'. */\n scrollRightAriaLabel?: string\n}) {\n const scrollRef = React.useRef<HTMLDivElement>(null)\n const [canScrollLeft, setCanScrollLeft] = React.useState(false)\n const [canScrollRight, setCanScrollRight] = React.useState(false)\n\n const refreshScrollState = React.useCallback(() => {\n const el = scrollRef.current\n if (!el) return\n const { scrollLeft, scrollWidth, clientWidth } = el\n setCanScrollLeft(scrollLeft > 1)\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1)\n }, [])\n\n React.useEffect(() => {\n refreshScrollState()\n const el = scrollRef.current\n if (!el) return\n el.addEventListener('scroll', refreshScrollState, { passive: true })\n const ro = new ResizeObserver(refreshScrollState)\n ro.observe(el)\n return () => {\n el.removeEventListener('scroll', refreshScrollState)\n ro.disconnect()\n }\n }, [refreshScrollState])\n\n const scrollBy = React.useCallback((direction: 'left' | 'right') => {\n const el = scrollRef.current\n if (!el) return\n const amount = Math.max(80, Math.floor(el.clientWidth * 0.6))\n el.scrollBy({ left: direction === 'left' ? -amount : amount, behavior: 'smooth' })\n }, [])\n\n const arrowButtonClass =\n arrowSize === 'sm' ? 'size-6 [&_svg]:size-3.5' : 'size-7 [&_svg]:size-4'\n\n return (\n <div className={cn('relative', className)} data-slot=\"time-picker-scroll-row\">\n {/* Outer gutter \u2014 reserves room for the absolute-positioned chevron buttons.\n The scroll viewport lives INSIDE this gutter so chips can never slide\n underneath the arrows \u2014 moving scroll offsets only shift content inside\n the viewport, not the chevron clearance. */}\n <div\n className={cn(\n 'transition-[padding]',\n canScrollLeft ? 'pl-9' : 'pl-4',\n canScrollRight ? 'pr-9' : 'pr-4',\n )}\n >\n <div\n ref={scrollRef}\n className={cn(\n 'scrollbar-hide flex items-center gap-2 overflow-x-auto py-3.5',\n contentClassName,\n )}\n role=\"group\"\n aria-label={ariaLabel}\n >\n {children}\n </div>\n </div>\n {/* Edge fades \u2014 soft gradient at the boundary between the gutter and the\n scroll viewport, so chips sliding into the viewport dissolve cleanly\n before reaching the arrow's edge. */}\n {canScrollLeft ? (\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-9 w-6 bg-gradient-to-r from-background to-transparent\"\n />\n ) : null}\n {canScrollRight ? (\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 right-9 w-6 bg-gradient-to-l from-background to-transparent\"\n />\n ) : null}\n {canScrollLeft ? (\n <button\n type=\"button\"\n onClick={() => scrollBy('left')}\n aria-label={scrollLeftAriaLabel}\n className={cn(\n 'absolute left-1 top-1/2 z-10 flex -translate-y-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-xs transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40',\n arrowButtonClass,\n )}\n data-slot=\"time-picker-scroll-left\"\n >\n <ChevronLeft aria-hidden=\"true\" />\n </button>\n ) : null}\n {canScrollRight ? (\n <button\n type=\"button\"\n onClick={() => scrollBy('right')}\n aria-label={scrollRightAriaLabel}\n className={cn(\n 'absolute right-1 top-1/2 z-10 flex -translate-y-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-xs transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40',\n arrowButtonClass,\n )}\n data-slot=\"time-picker-scroll-right\"\n >\n <ChevronRight aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n )\n}\n\nfunction useControllable<T>(controlled: T | undefined, defaultValue: T, onChange?: (next: T) => void) {\n const [internal, setInternal] = React.useState<T>(defaultValue)\n const isControlled = controlled !== undefined\n const value = isControlled ? (controlled as T) : internal\n const setValue = React.useCallback(\n (next: T) => {\n if (!isControlled) setInternal(next)\n onChange?.(next)\n },\n [isControlled, onChange],\n )\n return [value, setValue] as const\n}\n\nexport type TimePickerProps = {\n value?: TimePickerValue\n defaultValue?: TimePickerValue\n onChange?: (value: TimePickerValue) => void\n\n showHeader?: boolean\n headerIcon?: React.ReactNode\n headerTitle?: string\n headerPlaceholder?: string\n onClose?: () => void\n\n durations?: DurationOption[]\n activeDuration?: number\n defaultActiveDuration?: number\n onDurationChange?: (value: number) => void\n\n statuses?: StatusOption[]\n activeStatus?: TimePickerStatusVariant\n defaultActiveStatus?: TimePickerStatusVariant\n onStatusChange?: (variant: TimePickerStatusVariant) => void\n statusLabel?: string\n\n slots?: string[]\n startTime?: string\n endTime?: string\n intervalMinutes?: number\n format?: TimeFormat\n slotRightText?: (slot: string) => string | undefined\n slotLabel?: string\n maxHeight?: number\n\n showFooter?: boolean\n cancelLabel?: string\n applyLabel?: string\n onCancel?: () => void\n onApply?: (value: TimePickerValue) => void\n legacyFooterActions?: LegacyFooterAction[]\n /**\n * Quick-action rows rendered above the scrollable slot list \u2014 used for\n * \"Now\"-style shortcuts that stay visible regardless of scroll position.\n * Styled like slots but with primary-tinted foreground.\n */\n pinnedTopActions?: PinnedTopAction[]\n\n trigger?: React.ReactNode\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n popoverAlign?: 'start' | 'center' | 'end'\n popoverSide?: 'top' | 'right' | 'bottom' | 'left'\n\n className?: string\n disabled?: boolean\n 'aria-label'?: string\n}\n\nfunction TimePickerCard({\n value,\n setValue,\n showHeader,\n headerIcon,\n headerTitle,\n headerPlaceholder,\n onClose,\n closeAriaLabel,\n format,\n durationOptions,\n activeDuration,\n setActiveDuration,\n onDurationChange,\n durationsAriaLabel,\n scrollLeftAriaLabel,\n scrollRightAriaLabel,\n statusOptions,\n activeStatus,\n setActiveStatus,\n onStatusChange,\n statusLabel,\n slotList,\n slotLabel,\n slotRightText,\n maxHeight,\n showFooter,\n cancelLabel,\n applyLabel,\n handleCancel,\n handleApply,\n legacyFooterActions,\n pinnedTopActions,\n disabled,\n className,\n ariaLabel,\n slotListRef,\n}: {\n value: TimePickerValue\n setValue: (next: TimePickerValue) => void\n showHeader: boolean\n headerIcon: React.ReactNode\n headerTitle: string | undefined\n headerPlaceholder: string\n onClose: (() => void) | undefined\n closeAriaLabel: string\n format: TimeFormat\n durationOptions: DurationOption[] | undefined\n activeDuration: number | undefined\n setActiveDuration: (next: number) => void\n onDurationChange: ((value: number) => void) | undefined\n durationsAriaLabel: string\n scrollLeftAriaLabel: string\n scrollRightAriaLabel: string\n statusOptions: StatusOption[] | undefined\n activeStatus: TimePickerStatusVariant | undefined\n setActiveStatus: (next: TimePickerStatusVariant) => void\n onStatusChange: ((variant: TimePickerStatusVariant) => void) | undefined\n statusLabel: string\n slotList: string[]\n slotLabel: string | undefined\n slotRightText: ((slot: string) => string | undefined) | undefined\n maxHeight: number\n showFooter: boolean\n cancelLabel: string\n applyLabel: string\n handleCancel: () => void\n handleApply: () => void\n legacyFooterActions: LegacyFooterAction[] | undefined\n pinnedTopActions: PinnedTopAction[] | undefined\n disabled: boolean\n className: string | undefined\n ariaLabel: string\n slotListRef: React.RefObject<HTMLDivElement | null>\n}) {\n const headerDisplay = React.useMemo(() => {\n if (headerTitle != null) return { main: headerTitle, suffix: null as string | null }\n if (value) return formatSlotDisplay(value, format)\n return { main: headerPlaceholder, suffix: null as string | null }\n }, [headerTitle, value, format, headerPlaceholder])\n\n const handleSlotKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n const target = event.target as HTMLElement\n const slotButton = target.closest<HTMLButtonElement>('[data-slot=\"time-picker-slot\"]')\n if (!slotButton) return\n const container = slotListRef.current\n if (!container) return\n const all = Array.from(\n container.querySelectorAll<HTMLButtonElement>('[data-slot=\"time-picker-slot\"]:not(:disabled)'),\n )\n const currentIndex = all.indexOf(slotButton)\n if (currentIndex === -1) return\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n const next = all[Math.min(all.length - 1, currentIndex + 1)]\n next?.focus()\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n const prev = all[Math.max(0, currentIndex - 1)]\n prev?.focus()\n } else if (event.key === 'Home') {\n event.preventDefault()\n all[0]?.focus()\n } else if (event.key === 'End') {\n event.preventDefault()\n all[all.length - 1]?.focus()\n }\n },\n [disabled, slotListRef],\n )\n\n return (\n <div\n className={cn(\n 'flex w-80 flex-col overflow-hidden rounded-xl border border-border bg-background shadow-xl',\n className,\n )}\n role=\"dialog\"\n aria-label={ariaLabel}\n aria-disabled={disabled || undefined}\n data-slot=\"time-picker\"\n >\n {showHeader ? (\n <div\n className=\"flex items-center gap-2 border-b border-border px-4 py-3.5\"\n data-slot=\"time-picker-header\"\n >\n <span className=\"flex shrink-0 items-center text-muted-foreground\" aria-hidden=\"true\">\n {headerIcon ?? <Clock className=\"size-5\" aria-hidden=\"true\" />}\n </span>\n <p className=\"flex-1 min-w-0 truncate text-base font-medium text-muted-foreground\">\n <span>{headerDisplay.main}</span>\n {headerDisplay.suffix ? <span className=\"ml-1 text-muted-foreground/60\">{headerDisplay.suffix}</span> : null}\n </p>\n {onClose ? (\n <button\n type=\"button\"\n onClick={onClose}\n disabled={disabled}\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring/40 disabled:pointer-events-none disabled:opacity-60\"\n aria-label={closeAriaLabel}\n data-slot=\"time-picker-close\"\n >\n <X className=\"size-4\" aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n ) : null}\n\n {durationOptions && durationOptions.length > 0 ? (\n <HorizontalScrollRow\n className=\"border-b border-border\"\n ariaLabel={durationsAriaLabel}\n scrollLeftAriaLabel={scrollLeftAriaLabel}\n scrollRightAriaLabel={scrollRightAriaLabel}\n >\n {durationOptions.map((option) => (\n <TimePickerDurationChip\n key={option.value}\n value={option.value}\n label={option.label}\n disabled={disabled || option.disabled}\n selected={activeDuration === option.value}\n onSelect={(next) => {\n setActiveDuration(next)\n onDurationChange?.(next)\n }}\n />\n ))}\n </HorizontalScrollRow>\n ) : null}\n\n {statusOptions && statusOptions.length > 0 ? (\n <div\n className=\"flex flex-col gap-2 border-b border-border px-4 py-3.5\"\n data-slot=\"time-picker-status-row\"\n >\n <p className=\"text-sm font-medium text-muted-foreground\">{statusLabel}</p>\n <div className=\"flex flex-wrap items-center gap-2\">\n {statusOptions.map((option) => (\n <TimePickerStatusChip\n key={option.variant}\n variant={option.variant}\n label={option.label}\n disabled={disabled || option.disabled}\n selected={activeStatus === option.variant}\n onSelect={(next) => {\n setActiveStatus(next)\n onStatusChange?.(next)\n }}\n />\n ))}\n </div>\n </div>\n ) : null}\n\n {pinnedTopActions && pinnedTopActions.length > 0 ? (\n <div\n className=\"flex flex-col gap-0.5 border-b border-border p-2\"\n data-slot=\"time-picker-pinned-top\"\n >\n {pinnedTopActions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={action.onClick}\n disabled={disabled}\n className=\"flex h-9 w-full items-center gap-2.5 rounded-md px-3 py-2 text-sm font-medium text-primary transition-colors hover:bg-primary/10 cursor-pointer disabled:pointer-events-none disabled:opacity-60\"\n data-slot=\"time-picker-pinned-action\"\n >\n {action.icon ? (\n <span className=\"flex shrink-0 items-center [&_svg]:size-4\" aria-hidden=\"true\">\n {action.icon}\n </span>\n ) : null}\n <span className=\"flex-1 text-left\">{action.label}</span>\n {action.rightText ? (\n <span className=\"text-primary/60\">{action.rightText}</span>\n ) : null}\n </button>\n ))}\n </div>\n ) : null}\n\n <div\n className=\"flex flex-col gap-0.5 overflow-y-auto p-2\"\n style={{ maxHeight }}\n ref={slotListRef}\n onKeyDown={handleSlotKeyDown}\n data-slot=\"time-picker-slots\"\n >\n {slotLabel ? (\n <p className=\"px-3 pt-1 pb-2 text-sm font-medium text-muted-foreground\">{slotLabel}</p>\n ) : null}\n {slotList.length === 0 ? (\n <p className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No time slots available.</p>\n ) : (\n slotList.map((slot) => (\n <TimePickerSlot\n key={slot}\n value={slot}\n format={format}\n rightText={slotRightText?.(slot)}\n selected={value === slot}\n disabled={disabled}\n onSelect={(next) => setValue(next)}\n />\n ))\n )}\n </div>\n\n {showFooter ? (\n <div\n className=\"flex flex-wrap items-center justify-end gap-2 border-t border-border px-4 py-3\"\n data-slot=\"time-picker-footer\"\n >\n {legacyFooterActions && legacyFooterActions.length > 0 ? (\n <div className=\"mr-auto flex items-center gap-1\">\n {legacyFooterActions.map((action) => (\n <Button\n key={action.label}\n type=\"button\"\n variant={action.variant === 'muted' ? 'muted' : 'ghost'}\n size=\"sm\"\n onClick={action.onClick}\n disabled={disabled}\n data-slot=\"time-picker-legacy-action\"\n >\n {action.label}\n </Button>\n ))}\n <span aria-hidden=\"true\" className=\"ml-2 mr-1 h-5 w-px bg-border\" />\n </div>\n ) : null}\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCancel}\n disabled={disabled}\n data-slot=\"time-picker-cancel\"\n >\n {cancelLabel}\n </Button>\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={handleApply}\n disabled={disabled}\n data-slot=\"time-picker-apply\"\n >\n {applyLabel}\n </Button>\n </div>\n ) : null}\n </div>\n )\n}\n\nexport function TimePicker({\n value: valueProp,\n defaultValue = null,\n onChange,\n showHeader = true,\n headerIcon,\n headerTitle,\n headerPlaceholder,\n onClose,\n durations,\n activeDuration: activeDurationProp,\n defaultActiveDuration,\n onDurationChange,\n statuses,\n activeStatus: activeStatusProp,\n defaultActiveStatus,\n onStatusChange,\n statusLabel,\n slots: slotsProp,\n startTime = '00:00',\n endTime = '23:30',\n intervalMinutes = 30,\n format = '12h',\n slotRightText,\n slotLabel,\n maxHeight = 280,\n showFooter = true,\n cancelLabel,\n applyLabel,\n onCancel,\n onApply,\n legacyFooterActions,\n pinnedTopActions,\n trigger,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n popoverAlign = 'start',\n popoverSide = 'bottom',\n className,\n disabled = false,\n 'aria-label': ariaLabel,\n}: TimePickerProps) {\n const t = useT()\n const resolvedHeaderPlaceholder = headerPlaceholder ?? t('ui.timePicker.placeholder', 'Pick a time')\n const resolvedStatusLabel = statusLabel ?? t('ui.timePicker.statusLabel', 'Select status')\n const resolvedCancelLabel = cancelLabel ?? t('ui.timePicker.cancelButton', 'Cancel')\n const resolvedApplyLabel = applyLabel ?? t('ui.timePicker.applyButton', 'Apply')\n const resolvedAriaLabel = ariaLabel ?? t('ui.timePicker.label', 'Time picker')\n const resolvedCloseAriaLabel = t('ui.timePicker.closeButton', 'Close')\n const resolvedDurationsAriaLabel = t('ui.timePicker.durationsRowLabel', 'Quick duration')\n const resolvedScrollLeftAriaLabel = t('ui.timePicker.scrollLeft', 'Scroll left')\n const resolvedScrollRightAriaLabel = t('ui.timePicker.scrollRight', 'Scroll right')\n const [value, setValue] = useControllable<TimePickerValue>(valueProp, defaultValue, onChange)\n const [activeDuration, setActiveDuration] = useControllable<number | undefined>(\n activeDurationProp,\n defaultActiveDuration,\n )\n const [activeStatus, setActiveStatus] = useControllable<TimePickerStatusVariant | undefined>(\n activeStatusProp,\n defaultActiveStatus,\n )\n const [open, setOpen] = useControllable<boolean>(openProp, defaultOpen, onOpenChange)\n\n const openSnapshotRef = React.useRef<TimePickerValue>(value)\n const slotListRef = React.useRef<HTMLDivElement | null>(null)\n\n const slotList = React.useMemo(() => {\n if (slotsProp && slotsProp.length > 0) return slotsProp\n return generateSlots(startTime, endTime, intervalMinutes)\n }, [slotsProp, startTime, endTime, intervalMinutes])\n\n const setOpenWithSnapshot = React.useCallback(\n (next: boolean) => {\n if (next && !open) {\n openSnapshotRef.current = value\n }\n setOpen(next)\n },\n [open, setOpen, value],\n )\n\n const handleApply = React.useCallback(() => {\n onApply?.(value)\n if (trigger) setOpenWithSnapshot(false)\n }, [onApply, setOpenWithSnapshot, trigger, value])\n\n const handleCancel = React.useCallback(() => {\n onCancel?.()\n if (trigger) {\n setValue(openSnapshotRef.current)\n setOpenWithSnapshot(false)\n }\n }, [onCancel, setOpenWithSnapshot, setValue, trigger])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n handleCancel()\n } else if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleApply()\n }\n },\n [handleApply, handleCancel],\n )\n\n const card = (\n <div onKeyDown={handleKeyDown}>\n <TimePickerCard\n value={value}\n setValue={setValue}\n showHeader={showHeader}\n headerIcon={headerIcon}\n headerTitle={headerTitle}\n headerPlaceholder={resolvedHeaderPlaceholder}\n onClose={onClose}\n closeAriaLabel={resolvedCloseAriaLabel}\n format={format}\n durationOptions={durations}\n activeDuration={activeDuration}\n setActiveDuration={setActiveDuration}\n onDurationChange={onDurationChange}\n durationsAriaLabel={resolvedDurationsAriaLabel}\n scrollLeftAriaLabel={resolvedScrollLeftAriaLabel}\n scrollRightAriaLabel={resolvedScrollRightAriaLabel}\n statusOptions={statuses}\n activeStatus={activeStatus}\n setActiveStatus={setActiveStatus}\n onStatusChange={onStatusChange}\n statusLabel={resolvedStatusLabel}\n slotList={slotList}\n slotLabel={slotLabel}\n slotRightText={slotRightText}\n maxHeight={maxHeight}\n showFooter={showFooter}\n cancelLabel={resolvedCancelLabel}\n applyLabel={resolvedApplyLabel}\n handleCancel={handleCancel}\n handleApply={handleApply}\n legacyFooterActions={legacyFooterActions}\n pinnedTopActions={pinnedTopActions}\n disabled={disabled}\n className={className}\n ariaLabel={resolvedAriaLabel}\n slotListRef={slotListRef}\n />\n </div>\n )\n\n if (!trigger) return card\n\n return (\n <Popover open={open} onOpenChange={setOpenWithSnapshot}>\n <PopoverTrigger asChild>{trigger}</PopoverTrigger>\n <PopoverContent\n align={popoverAlign}\n side={popoverSide}\n className=\"w-auto border-none bg-transparent p-0 shadow-none\"\n >\n {card}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["hours"]
7
7
  }