@open-mercato/ui 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd

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 (246) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +204 -121
  3. package/dist/backend/AppShell.js +25 -28
  4. package/dist/backend/AppShell.js.map +2 -2
  5. package/dist/backend/ContextHelp.js +1 -1
  6. package/dist/backend/ContextHelp.js.map +1 -1
  7. package/dist/backend/CrudForm.js +12 -15
  8. package/dist/backend/CrudForm.js.map +2 -2
  9. package/dist/backend/DataTable.js +9 -10
  10. package/dist/backend/DataTable.js.map +2 -2
  11. package/dist/backend/FilterBar.js +6 -8
  12. package/dist/backend/FilterBar.js.map +2 -2
  13. package/dist/backend/FilterOverlay.js +10 -10
  14. package/dist/backend/FilterOverlay.js.map +2 -2
  15. package/dist/backend/FlashMessages.js +1 -1
  16. package/dist/backend/FlashMessages.js.map +2 -2
  17. package/dist/backend/JsonBuilder.js +6 -6
  18. package/dist/backend/JsonBuilder.js.map +1 -1
  19. package/dist/backend/NextStepCallout.js +1 -1
  20. package/dist/backend/NextStepCallout.js.map +1 -1
  21. package/dist/backend/PerspectiveSidebar.js +2 -2
  22. package/dist/backend/PerspectiveSidebar.js.map +2 -2
  23. package/dist/backend/ProfileDropdown.js +1 -1
  24. package/dist/backend/ProfileDropdown.js.map +1 -1
  25. package/dist/backend/RowActions.js +1 -1
  26. package/dist/backend/RowActions.js.map +1 -1
  27. package/dist/backend/UserMenu.js +2 -2
  28. package/dist/backend/UserMenu.js.map +1 -1
  29. package/dist/backend/WebhookSetupGuide.js +11 -11
  30. package/dist/backend/WebhookSetupGuide.js.map +2 -2
  31. package/dist/backend/charts/KpiCard.js +3 -3
  32. package/dist/backend/charts/KpiCard.js.map +1 -1
  33. package/dist/backend/columns/ColumnChooserPanel.js +1 -1
  34. package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
  35. package/dist/backend/custom-fields/FieldDefinitionsEditor.js +3 -3
  36. package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +2 -2
  37. package/dist/backend/dashboard/DashboardScreen.js +1 -1
  38. package/dist/backend/dashboard/DashboardScreen.js.map +1 -1
  39. package/dist/backend/date-range/DateRangeSelect.js +1 -1
  40. package/dist/backend/date-range/DateRangeSelect.js.map +1 -1
  41. package/dist/backend/date-range/InlineDateRangeSelect.js +1 -1
  42. package/dist/backend/date-range/InlineDateRangeSelect.js.map +1 -1
  43. package/dist/backend/detail/AccessDeniedMessage.js +1 -1
  44. package/dist/backend/detail/AccessDeniedMessage.js.map +1 -1
  45. package/dist/backend/detail/ActivitiesSection.js +5 -5
  46. package/dist/backend/detail/ActivitiesSection.js.map +1 -1
  47. package/dist/backend/detail/AddressEditor.js +3 -3
  48. package/dist/backend/detail/AddressEditor.js.map +2 -2
  49. package/dist/backend/detail/AddressTiles.js +3 -3
  50. package/dist/backend/detail/AddressTiles.js.map +2 -2
  51. package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
  52. package/dist/backend/detail/AttachmentMetadataDialog.js.map +1 -1
  53. package/dist/backend/detail/CustomDataSection.js +1 -1
  54. package/dist/backend/detail/CustomDataSection.js.map +1 -1
  55. package/dist/backend/detail/InlineEditors.js +5 -5
  56. package/dist/backend/detail/InlineEditors.js.map +1 -1
  57. package/dist/backend/detail/NotesSection.js +6 -6
  58. package/dist/backend/detail/NotesSection.js.map +1 -1
  59. package/dist/backend/detail/TagsSection.js +1 -1
  60. package/dist/backend/detail/TagsSection.js.map +1 -1
  61. package/dist/backend/devtools/UmesDevToolsPanel.js +6 -6
  62. package/dist/backend/devtools/UmesDevToolsPanel.js.map +2 -2
  63. package/dist/backend/devtools/components/ConflictWarnings.js +3 -3
  64. package/dist/backend/devtools/components/ConflictWarnings.js.map +2 -2
  65. package/dist/backend/devtools/components/EnricherTiming.js +2 -2
  66. package/dist/backend/devtools/components/EnricherTiming.js.map +2 -2
  67. package/dist/backend/devtools/components/EventFlow.js +5 -5
  68. package/dist/backend/devtools/components/EventFlow.js.map +2 -2
  69. package/dist/backend/devtools/components/ExtensionPointList.js +3 -3
  70. package/dist/backend/devtools/components/ExtensionPointList.js.map +2 -2
  71. package/dist/backend/devtools/components/InterceptorActivity.js +6 -6
  72. package/dist/backend/devtools/components/InterceptorActivity.js.map +2 -2
  73. package/dist/backend/forms/ActionsDropdown.js +1 -1
  74. package/dist/backend/forms/ActionsDropdown.js.map +1 -1
  75. package/dist/backend/forms/FormActionButtons.js +2 -3
  76. package/dist/backend/forms/FormActionButtons.js.map +2 -2
  77. package/dist/backend/indexes/PartialIndexBanner.js +8 -8
  78. package/dist/backend/indexes/PartialIndexBanner.js.map +2 -2
  79. package/dist/backend/inputs/ComboboxInput.js +1 -1
  80. package/dist/backend/inputs/ComboboxInput.js.map +2 -2
  81. package/dist/backend/inputs/DatePicker.js +3 -3
  82. package/dist/backend/inputs/DatePicker.js.map +1 -1
  83. package/dist/backend/inputs/DateTimePicker.js +3 -3
  84. package/dist/backend/inputs/DateTimePicker.js.map +1 -1
  85. package/dist/backend/inputs/EventSelect.js +1 -1
  86. package/dist/backend/inputs/EventSelect.js.map +2 -2
  87. package/dist/backend/inputs/LookupSelect.js +1 -1
  88. package/dist/backend/inputs/LookupSelect.js.map +1 -1
  89. package/dist/backend/inputs/SwitchableMarkdownInput.js +1 -1
  90. package/dist/backend/inputs/SwitchableMarkdownInput.js.map +1 -1
  91. package/dist/backend/inputs/TagsInput.js +2 -2
  92. package/dist/backend/inputs/TagsInput.js.map +2 -2
  93. package/dist/backend/inputs/TimeInput.js +1 -1
  94. package/dist/backend/inputs/TimeInput.js.map +1 -1
  95. package/dist/backend/inputs/TimePicker.js +3 -3
  96. package/dist/backend/inputs/TimePicker.js.map +1 -1
  97. package/dist/backend/messages/MessageObjectDetail.js +1 -1
  98. package/dist/backend/messages/MessageObjectDetail.js.map +1 -1
  99. package/dist/backend/messages/MessageObjectPreview.js +1 -1
  100. package/dist/backend/messages/MessageObjectPreview.js.map +1 -1
  101. package/dist/backend/messages/message-compose-form-groups.js +3 -3
  102. package/dist/backend/messages/message-compose-form-groups.js.map +1 -1
  103. package/dist/backend/notifications/NotificationCountBadge.js +1 -1
  104. package/dist/backend/notifications/NotificationCountBadge.js.map +2 -2
  105. package/dist/backend/notifications/NotificationPanel.js +3 -3
  106. package/dist/backend/notifications/NotificationPanel.js.map +1 -1
  107. package/dist/backend/progress/ProgressTopBar.js +4 -4
  108. package/dist/backend/progress/ProgressTopBar.js.map +2 -2
  109. package/dist/backend/schedule/ScheduleAgenda.js +1 -1
  110. package/dist/backend/schedule/ScheduleAgenda.js.map +2 -2
  111. package/dist/backend/schedule/ScheduleCalendar.js +1 -1
  112. package/dist/backend/schedule/ScheduleCalendar.js.map +1 -1
  113. package/dist/backend/schedule/ScheduleGrid.js +1 -1
  114. package/dist/backend/schedule/ScheduleGrid.js.map +2 -2
  115. package/dist/backend/version-history/VersionHistoryPanel.js +4 -4
  116. package/dist/backend/version-history/VersionHistoryPanel.js.map +2 -2
  117. package/dist/frontend/AuthFooter.js +1 -1
  118. package/dist/frontend/AuthFooter.js.map +1 -1
  119. package/dist/frontend/LanguageSwitcher.js +1 -1
  120. package/dist/frontend/LanguageSwitcher.js.map +1 -1
  121. package/dist/frontend/Layout.js +2 -2
  122. package/dist/frontend/Layout.js.map +1 -1
  123. package/dist/index.js +5 -0
  124. package/dist/index.js.map +2 -2
  125. package/dist/portal/PortalShell.js +15 -15
  126. package/dist/portal/PortalShell.js.map +2 -2
  127. package/dist/portal/components/PortalCard.js +2 -2
  128. package/dist/portal/components/PortalCard.js.map +2 -2
  129. package/dist/portal/components/PortalNotificationPanel.js +18 -18
  130. package/dist/portal/components/PortalNotificationPanel.js.map +2 -2
  131. package/dist/portal/components/PortalPageHeader.js +1 -1
  132. package/dist/portal/components/PortalPageHeader.js.map +2 -2
  133. package/dist/primitives/avatar.js +11 -1
  134. package/dist/primitives/avatar.js.map +2 -2
  135. package/dist/primitives/badge.js +1 -1
  136. package/dist/primitives/badge.js.map +1 -1
  137. package/dist/primitives/button.js +9 -5
  138. package/dist/primitives/button.js.map +2 -2
  139. package/dist/primitives/calendar.js +1 -1
  140. package/dist/primitives/calendar.js.map +1 -1
  141. package/dist/primitives/checkbox-field.js +63 -0
  142. package/dist/primitives/checkbox-field.js.map +7 -0
  143. package/dist/primitives/checkbox.js +31 -17
  144. package/dist/primitives/checkbox.js.map +2 -2
  145. package/dist/primitives/dialog.js +4 -4
  146. package/dist/primitives/dialog.js.map +1 -1
  147. package/dist/primitives/fancy-button.js +72 -0
  148. package/dist/primitives/fancy-button.js.map +7 -0
  149. package/dist/primitives/icon-button.js +20 -4
  150. package/dist/primitives/icon-button.js.map +2 -2
  151. package/dist/primitives/kbd.js +27 -0
  152. package/dist/primitives/kbd.js.map +7 -0
  153. package/dist/primitives/link-button.js +56 -0
  154. package/dist/primitives/link-button.js.map +7 -0
  155. package/dist/primitives/popover.js +1 -1
  156. package/dist/primitives/popover.js.map +1 -1
  157. package/dist/primitives/social-button.js +61 -0
  158. package/dist/primitives/social-button.js.map +7 -0
  159. package/dist/primitives/tabs.js +1 -1
  160. package/dist/primitives/tabs.js.map +1 -1
  161. package/dist/primitives/tag.js +45 -0
  162. package/dist/primitives/tag.js.map +7 -0
  163. package/dist/primitives/tooltip.js +1 -1
  164. package/dist/primitives/tooltip.js.map +1 -1
  165. package/package.json +3 -3
  166. package/src/backend/AppShell.tsx +25 -28
  167. package/src/backend/ContextHelp.tsx +1 -1
  168. package/src/backend/CrudForm.tsx +12 -15
  169. package/src/backend/DataTable.tsx +9 -10
  170. package/src/backend/FilterBar.tsx +6 -5
  171. package/src/backend/FilterOverlay.tsx +10 -10
  172. package/src/backend/FlashMessages.tsx +1 -1
  173. package/src/backend/JsonBuilder.tsx +6 -6
  174. package/src/backend/NextStepCallout.tsx +1 -1
  175. package/src/backend/PerspectiveSidebar.tsx +2 -2
  176. package/src/backend/ProfileDropdown.tsx +1 -1
  177. package/src/backend/RowActions.tsx +1 -1
  178. package/src/backend/UserMenu.tsx +2 -2
  179. package/src/backend/WebhookSetupGuide.tsx +11 -11
  180. package/src/backend/charts/KpiCard.tsx +3 -3
  181. package/src/backend/columns/ColumnChooserPanel.tsx +1 -1
  182. package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +3 -3
  183. package/src/backend/dashboard/DashboardScreen.tsx +1 -1
  184. package/src/backend/date-range/DateRangeSelect.tsx +1 -1
  185. package/src/backend/date-range/InlineDateRangeSelect.tsx +1 -1
  186. package/src/backend/detail/AccessDeniedMessage.tsx +1 -1
  187. package/src/backend/detail/ActivitiesSection.tsx +5 -5
  188. package/src/backend/detail/AddressEditor.tsx +3 -3
  189. package/src/backend/detail/AddressTiles.tsx +3 -3
  190. package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
  191. package/src/backend/detail/CustomDataSection.tsx +1 -1
  192. package/src/backend/detail/InlineEditors.tsx +5 -5
  193. package/src/backend/detail/NotesSection.tsx +6 -6
  194. package/src/backend/detail/TagsSection.tsx +1 -1
  195. package/src/backend/devtools/UmesDevToolsPanel.tsx +6 -6
  196. package/src/backend/devtools/components/ConflictWarnings.tsx +4 -4
  197. package/src/backend/devtools/components/EnricherTiming.tsx +2 -2
  198. package/src/backend/devtools/components/EventFlow.tsx +5 -5
  199. package/src/backend/devtools/components/ExtensionPointList.tsx +3 -3
  200. package/src/backend/devtools/components/InterceptorActivity.tsx +6 -6
  201. package/src/backend/forms/ActionsDropdown.tsx +1 -1
  202. package/src/backend/forms/FormActionButtons.tsx +4 -5
  203. package/src/backend/indexes/PartialIndexBanner.tsx +8 -8
  204. package/src/backend/inputs/ComboboxInput.tsx +1 -1
  205. package/src/backend/inputs/DatePicker.tsx +3 -3
  206. package/src/backend/inputs/DateTimePicker.tsx +3 -3
  207. package/src/backend/inputs/EventSelect.tsx +1 -1
  208. package/src/backend/inputs/LookupSelect.tsx +1 -1
  209. package/src/backend/inputs/SwitchableMarkdownInput.tsx +1 -1
  210. package/src/backend/inputs/TagsInput.tsx +2 -2
  211. package/src/backend/inputs/TimeInput.tsx +1 -1
  212. package/src/backend/inputs/TimePicker.tsx +3 -3
  213. package/src/backend/messages/MessageObjectDetail.tsx +1 -1
  214. package/src/backend/messages/MessageObjectPreview.tsx +1 -1
  215. package/src/backend/messages/message-compose-form-groups.tsx +3 -3
  216. package/src/backend/notifications/NotificationCountBadge.tsx +1 -1
  217. package/src/backend/notifications/NotificationPanel.tsx +3 -3
  218. package/src/backend/progress/ProgressTopBar.tsx +4 -4
  219. package/src/backend/schedule/ScheduleAgenda.tsx +1 -1
  220. package/src/backend/schedule/ScheduleCalendar.tsx +1 -1
  221. package/src/backend/schedule/ScheduleGrid.tsx +1 -1
  222. package/src/backend/version-history/VersionHistoryPanel.tsx +4 -4
  223. package/src/frontend/AuthFooter.tsx +1 -1
  224. package/src/frontend/LanguageSwitcher.tsx +1 -1
  225. package/src/frontend/Layout.tsx +2 -2
  226. package/src/index.ts +6 -1
  227. package/src/portal/PortalShell.tsx +15 -15
  228. package/src/portal/components/PortalCard.tsx +2 -2
  229. package/src/portal/components/PortalNotificationPanel.tsx +18 -18
  230. package/src/portal/components/PortalPageHeader.tsx +1 -1
  231. package/src/primitives/avatar.tsx +22 -0
  232. package/src/primitives/badge.tsx +1 -1
  233. package/src/primitives/button.tsx +12 -5
  234. package/src/primitives/calendar.tsx +1 -1
  235. package/src/primitives/checkbox-field.tsx +85 -0
  236. package/src/primitives/checkbox.tsx +44 -18
  237. package/src/primitives/dialog.tsx +4 -4
  238. package/src/primitives/fancy-button.tsx +89 -0
  239. package/src/primitives/icon-button.tsx +19 -2
  240. package/src/primitives/kbd.tsx +38 -0
  241. package/src/primitives/link-button.tsx +55 -0
  242. package/src/primitives/popover.tsx +1 -1
  243. package/src/primitives/social-button.tsx +80 -0
  244. package/src/primitives/tabs.tsx +1 -1
  245. package/src/primitives/tag.tsx +66 -0
  246. package/src/primitives/tooltip.tsx +1 -1
@@ -17,7 +17,7 @@ function EnricherTiming({ entries }) {
17
17
  const maxMs = Math.max(...recent.map((e) => e.durationMs), 1);
18
18
  return /* @__PURE__ */ jsx("div", { children: recent.map((entry, idx) => {
19
19
  const classes = getTimingClasses(entry.durationMs);
20
- return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/50 py-1 text-xs", children: [
20
+ return /* @__PURE__ */ jsxs("div", { className: "border-b border-border/70 py-1 text-xs", children: [
21
21
  /* @__PURE__ */ jsxs("div", { className: "mb-0.5 flex justify-between", children: [
22
22
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: entry.enricherId }),
23
23
  /* @__PURE__ */ jsxs("span", { className: `font-mono font-semibold ${classes.text}`, children: [
@@ -32,7 +32,7 @@ function EnricherTiming({ entries }) {
32
32
  style: { width: getTimingBarWidth(entry.durationMs, maxMs) }
33
33
  }
34
34
  ) }),
35
- /* @__PURE__ */ jsxs("div", { className: "mt-px text-[11px] text-muted-foreground", children: [
35
+ /* @__PURE__ */ jsxs("div", { className: "mt-px text-overline text-muted-foreground", children: [
36
36
  entry.targetEntity,
37
37
  " | ",
38
38
  entry.moduleId
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/backend/devtools/components/EnricherTiming.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport type { EnricherTimingEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nfunction getTimingClasses(ms: number): { text: string; bar: string } {\n if (ms >= 500) return { text: 'text-red-500', bar: 'bg-red-500' }\n if (ms >= 100) return { text: 'text-amber-500', bar: 'bg-amber-500' }\n return { text: 'text-emerald-500', bar: 'bg-emerald-500' }\n}\n\nfunction getTimingBarWidth(ms: number, maxMs: number): string {\n if (maxMs === 0) return '0%'\n return `${Math.min(100, (ms / maxMs) * 100)}%`\n}\n\nexport function EnricherTiming({ entries }: { entries: EnricherTimingEntry[] }) {\n if (entries.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No timing data</p>\n }\n\n const recent = entries.slice(-20).reverse()\n const maxMs = Math.max(...recent.map((e) => e.durationMs), 1)\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = getTimingClasses(entry.durationMs)\n return (\n <div key={idx} className=\"border-b border-border/50 py-1 text-xs\">\n <div className=\"mb-0.5 flex justify-between\">\n <span className=\"font-medium\">{entry.enricherId}</span>\n <span className={`font-mono font-semibold ${classes.text}`}>\n {entry.durationMs}ms\n </span>\n </div>\n <div className=\"h-1 overflow-hidden rounded bg-muted\">\n <div\n className={`h-full rounded transition-[width] duration-300 ${classes.bar}`}\n style={{ width: getTimingBarWidth(entry.durationMs, maxMs) }}\n />\n </div>\n <div className=\"mt-px text-[11px] text-muted-foreground\">\n {entry.targetEntity} | {entry.moduleId}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n"],
5
- "mappings": ";AAiBW,cAcG,YAdH;AAbX,SAAS,iBAAiB,IAA2C;AACnE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,gBAAgB,KAAK,aAAa;AAChE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,kBAAkB,KAAK,eAAe;AACpE,SAAO,EAAE,MAAM,oBAAoB,KAAK,iBAAiB;AAC3D;AAEA,SAAS,kBAAkB,IAAY,OAAuB;AAC5D,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,GAAG,KAAK,IAAI,KAAM,KAAK,QAAS,GAAG,CAAC;AAC7C;AAEO,SAAS,eAAe,EAAE,QAAQ,GAAuC;AAC9E,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,oBAAC,OAAE,WAAU,wCAAuC,4BAAc;AAAA,EAC3E;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAC1C,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC;AAE5D,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,iBAAiB,MAAM,UAAU;AACjD,WACE,qBAAC,SAAc,WAAU,0CACvB;AAAA,2BAAC,SAAI,WAAU,+BACb;AAAA,4BAAC,UAAK,WAAU,eAAe,gBAAM,YAAW;AAAA,QAChD,qBAAC,UAAK,WAAW,2BAA2B,QAAQ,IAAI,IACrD;AAAA,gBAAM;AAAA,UAAW;AAAA,WACpB;AAAA,SACF;AAAA,MACA,oBAAC,SAAI,WAAU,wCACb;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,kDAAkD,QAAQ,GAAG;AAAA,UACxE,OAAO,EAAE,OAAO,kBAAkB,MAAM,YAAY,KAAK,EAAE;AAAA;AAAA,MAC7D,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,2CACZ;AAAA,cAAM;AAAA,QAAa;AAAA,QAAI,MAAM;AAAA,SAChC;AAAA,SAfQ,GAgBV;AAAA,EAEJ,CAAC,GACH;AAEJ;",
4
+ "sourcesContent": ["'use client'\n\nimport type { EnricherTimingEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nfunction getTimingClasses(ms: number): { text: string; bar: string } {\n if (ms >= 500) return { text: 'text-red-500', bar: 'bg-red-500' }\n if (ms >= 100) return { text: 'text-amber-500', bar: 'bg-amber-500' }\n return { text: 'text-emerald-500', bar: 'bg-emerald-500' }\n}\n\nfunction getTimingBarWidth(ms: number, maxMs: number): string {\n if (maxMs === 0) return '0%'\n return `${Math.min(100, (ms / maxMs) * 100)}%`\n}\n\nexport function EnricherTiming({ entries }: { entries: EnricherTimingEntry[] }) {\n if (entries.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No timing data</p>\n }\n\n const recent = entries.slice(-20).reverse()\n const maxMs = Math.max(...recent.map((e) => e.durationMs), 1)\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = getTimingClasses(entry.durationMs)\n return (\n <div key={idx} className=\"border-b border-border/70 py-1 text-xs\">\n <div className=\"mb-0.5 flex justify-between\">\n <span className=\"font-medium\">{entry.enricherId}</span>\n <span className={`font-mono font-semibold ${classes.text}`}>\n {entry.durationMs}ms\n </span>\n </div>\n <div className=\"h-1 overflow-hidden rounded bg-muted\">\n <div\n className={`h-full rounded transition-[width] duration-300 ${classes.bar}`}\n style={{ width: getTimingBarWidth(entry.durationMs, maxMs) }}\n />\n </div>\n <div className=\"mt-px text-overline text-muted-foreground\">\n {entry.targetEntity} | {entry.moduleId}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAiBW,cAcG,YAdH;AAbX,SAAS,iBAAiB,IAA2C;AACnE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,gBAAgB,KAAK,aAAa;AAChE,MAAI,MAAM,IAAK,QAAO,EAAE,MAAM,kBAAkB,KAAK,eAAe;AACpE,SAAO,EAAE,MAAM,oBAAoB,KAAK,iBAAiB;AAC3D;AAEA,SAAS,kBAAkB,IAAY,OAAuB;AAC5D,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,GAAG,KAAK,IAAI,KAAM,KAAK,QAAS,GAAG,CAAC;AAC7C;AAEO,SAAS,eAAe,EAAE,QAAQ,GAAuC;AAC9E,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,oBAAC,OAAE,WAAU,wCAAuC,4BAAc;AAAA,EAC3E;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAC1C,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC;AAE5D,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,iBAAiB,MAAM,UAAU;AACjD,WACE,qBAAC,SAAc,WAAU,0CACvB;AAAA,2BAAC,SAAI,WAAU,+BACb;AAAA,4BAAC,UAAK,WAAU,eAAe,gBAAM,YAAW;AAAA,QAChD,qBAAC,UAAK,WAAW,2BAA2B,QAAQ,IAAI,IACrD;AAAA,gBAAM;AAAA,UAAW;AAAA,WACpB;AAAA,SACF;AAAA,MACA,oBAAC,SAAI,WAAU,wCACb;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,kDAAkD,QAAQ,GAAG;AAAA,UACxE,OAAO,EAAE,OAAO,kBAAkB,MAAM,YAAY,KAAK,EAAE;AAAA;AAAA,MAC7D,GACF;AAAA,MACA,qBAAC,SAAI,WAAU,6CACZ;AAAA,cAAM;AAAA,QAAa;AAAA,QAAI,MAAM;AAAA,SAChC;AAAA,SAfQ,GAgBV;AAAA,EAEJ,CAAC,GACH;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  const RESULT_CLASSES = {
4
- allowed: { text: "text-emerald-600 dark:text-emerald-400", bg: "bg-emerald-50 dark:bg-emerald-950/30" },
5
- blocked: { text: "text-red-600 dark:text-red-400", bg: "bg-red-50 dark:bg-red-950/30" },
6
- error: { text: "text-amber-600 dark:text-amber-400", bg: "bg-amber-50 dark:bg-amber-950/30" }
4
+ allowed: { text: "text-status-success-icon", bg: "bg-status-success-bg" },
5
+ blocked: { text: "text-status-error-icon", bg: "bg-status-error-bg" },
6
+ error: { text: "text-status-warning-icon", bg: "bg-status-warning-bg" }
7
7
  };
8
8
  function EventFlow({ entries }) {
9
9
  if (entries.length === 0) {
@@ -19,9 +19,9 @@ function EventFlow({ entries }) {
19
19
  children: [
20
20
  /* @__PURE__ */ jsxs("div", { children: [
21
21
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: entry.eventName }),
22
- /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-[11px] text-muted-foreground", children: entry.widgetId })
22
+ /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-overline text-muted-foreground", children: entry.widgetId })
23
23
  ] }),
24
- /* @__PURE__ */ jsx("span", { className: `text-[11px] font-semibold ${classes.text}`, children: entry.result })
24
+ /* @__PURE__ */ jsx("span", { className: `text-overline font-semibold ${classes.text}`, children: entry.result })
25
25
  ]
26
26
  },
27
27
  idx
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/backend/devtools/components/EventFlow.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport type { EventFlowEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-emerald-600 dark:text-emerald-400', bg: 'bg-emerald-50 dark:bg-emerald-950/30' },\n blocked: { text: 'text-red-600 dark:text-red-400', bg: 'bg-red-50 dark:bg-red-950/30' },\n error: { text: 'text-amber-600 dark:text-amber-400', bg: 'bg-amber-50 dark:bg-amber-950/30' },\n}\n\nexport function EventFlow({ entries }: { entries: EventFlowEntry[] }) {\n if (entries.length === 0) {\n return (\n <p className=\"text-xs italic text-muted-foreground\">\n No event flow data\n </p>\n )\n }\n\n const recent = entries.slice(-15).reverse()\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = RESULT_CLASSES[entry.result] ?? RESULT_CLASSES.allowed\n return (\n <div\n key={idx}\n className={`mb-0.5 flex items-center justify-between rounded p-1 px-2 text-xs ${classes.bg}`}\n >\n <div>\n <span className=\"font-medium\">{entry.eventName}</span>\n <span className=\"ml-1.5 text-[11px] text-muted-foreground\">\n {entry.widgetId}\n </span>\n </div>\n <span className={`text-[11px] font-semibold ${classes.text}`}>\n {entry.result}\n </span>\n </div>\n )\n })}\n </div>\n )\n}\n"],
5
- "mappings": ";AAaM,cAiBM,YAjBN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,0CAA0C,IAAI,uCAAuC;AAAA,EACtG,SAAS,EAAE,MAAM,kCAAkC,IAAI,+BAA+B;AAAA,EACtF,OAAO,EAAE,MAAM,sCAAsC,IAAI,mCAAmC;AAC9F;AAEO,SAAS,UAAU,EAAE,QAAQ,GAAkC;AACpE,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,oBAAC,OAAE,WAAU,wCAAuC,gCAEpD;AAAA,EAEJ;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAE1C,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,eAAe,MAAM,MAAM,KAAK,eAAe;AAC/D,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,qEAAqE,QAAQ,EAAE;AAAA,QAE1F;AAAA,+BAAC,SACC;AAAA,gCAAC,UAAK,WAAU,eAAe,gBAAM,WAAU;AAAA,YAC/C,oBAAC,UAAK,WAAU,4CACb,gBAAM,UACT;AAAA,aACF;AAAA,UACA,oBAAC,UAAK,WAAW,6BAA6B,QAAQ,IAAI,IACvD,gBAAM,QACT;AAAA;AAAA;AAAA,MAXK;AAAA,IAYP;AAAA,EAEJ,CAAC,GACH;AAEJ;",
4
+ "sourcesContent": ["'use client'\n\nimport type { EventFlowEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-status-success-icon', bg: 'bg-status-success-bg' },\n blocked: { text: 'text-status-error-icon', bg: 'bg-status-error-bg' },\n error: { text: 'text-status-warning-icon', bg: 'bg-status-warning-bg' },\n}\n\nexport function EventFlow({ entries }: { entries: EventFlowEntry[] }) {\n if (entries.length === 0) {\n return (\n <p className=\"text-xs italic text-muted-foreground\">\n No event flow data\n </p>\n )\n }\n\n const recent = entries.slice(-15).reverse()\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = RESULT_CLASSES[entry.result] ?? RESULT_CLASSES.allowed\n return (\n <div\n key={idx}\n className={`mb-0.5 flex items-center justify-between rounded p-1 px-2 text-xs ${classes.bg}`}\n >\n <div>\n <span className=\"font-medium\">{entry.eventName}</span>\n <span className=\"ml-1.5 text-overline text-muted-foreground\">\n {entry.widgetId}\n </span>\n </div>\n <span className={`text-overline font-semibold ${classes.text}`}>\n {entry.result}\n </span>\n </div>\n )\n })}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAaM,cAiBM,YAjBN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AAAA,EACxE,SAAS,EAAE,MAAM,0BAA0B,IAAI,qBAAqB;AAAA,EACpE,OAAO,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AACxE;AAEO,SAAS,UAAU,EAAE,QAAQ,GAAkC;AACpE,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,oBAAC,OAAE,WAAU,wCAAuC,gCAEpD;AAAA,EAEJ;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAE1C,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,eAAe,MAAM,MAAM,KAAK,eAAe;AAC/D,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,qEAAqE,QAAQ,EAAE;AAAA,QAE1F;AAAA,+BAAC,SACC;AAAA,gCAAC,UAAK,WAAU,eAAe,gBAAM,WAAU;AAAA,YAC/C,oBAAC,UAAK,WAAU,8CACb,gBAAM,UACT;AAAA,aACF;AAAA,UACA,oBAAC,UAAK,WAAW,+BAA+B,QAAQ,IAAI,IACzD,gBAAM,QACT;AAAA;AAAA;AAAA,MAXK;AAAA,IAYP;AAAA,EAEJ,CAAC,GACH;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -29,7 +29,7 @@ function ExtensionPointList({ extensions }) {
29
29
  /* @__PURE__ */ jsx("div", { className: "pl-3.5", children: items.map((ext, idx) => /* @__PURE__ */ jsxs(
30
30
  "div",
31
31
  {
32
- className: "flex items-center justify-between border-b border-border/50 py-1 text-xs",
32
+ className: "flex items-center justify-between border-b border-border/70 py-1 text-xs",
33
33
  children: [
34
34
  /* @__PURE__ */ jsxs("div", { children: [
35
35
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: ext.id }),
@@ -40,8 +40,8 @@ function ExtensionPointList({ extensions }) {
40
40
  ] })
41
41
  ] }),
42
42
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
43
- /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: ext.target }),
44
- ext.priority !== 0 && /* @__PURE__ */ jsxs("span", { className: "rounded bg-muted px-1.5 py-px text-[10px] font-semibold", children: [
43
+ /* @__PURE__ */ jsx("span", { className: "text-overline text-muted-foreground", children: ext.target }),
44
+ ext.priority !== 0 && /* @__PURE__ */ jsxs("span", { className: "rounded bg-muted px-1.5 py-px text-overline font-semibold", children: [
45
45
  "P",
46
46
  ext.priority
47
47
  ] })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/backend/devtools/components/ExtensionPointList.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport type { UmesExtensionInfo } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst TYPE_COLORS: Record<string, string> = {\n enricher: 'bg-blue-500',\n interceptor: 'bg-amber-500',\n 'component-override': 'bg-violet-500',\n 'injection-widget': 'bg-emerald-500',\n 'injection-data-widget': 'bg-cyan-500',\n}\n\nexport function ExtensionPointList({ extensions }: { extensions: UmesExtensionInfo[] }) {\n if (extensions.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No extensions registered</p>\n }\n\n const grouped = new Map<string, UmesExtensionInfo[]>()\n for (const ext of extensions) {\n const key = ext.type\n const group = grouped.get(key) ?? []\n group.push(ext)\n grouped.set(key, group)\n }\n\n return (\n <div>\n {Array.from(grouped.entries()).map(([type, items]) => (\n <div key={type} className=\"mb-3\">\n <div className=\"mb-1 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide\">\n <span className={`inline-block size-2 rounded-full ${TYPE_COLORS[type] ?? 'bg-muted-foreground'}`} />\n {type} ({items.length})\n </div>\n <div className=\"pl-3.5\">\n {items.map((ext, idx) => (\n <div\n key={`${ext.id}-${idx}`}\n className=\"flex items-center justify-between border-b border-border/50 py-1 text-xs\"\n >\n <div>\n <span className=\"font-medium\">{ext.id}</span>\n <span className=\"ml-1.5 text-muted-foreground\">[{ext.moduleId}]</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[11px] text-muted-foreground\">{ext.target}</span>\n {ext.priority !== 0 && (\n <span className=\"rounded bg-muted px-1.5 py-px text-[10px] font-semibold\">\n P{ext.priority}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],
5
- "mappings": ";AAcW,cAeD,YAfC;AAVX,MAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,yBAAyB;AAC3B;AAEO,SAAS,mBAAmB,EAAE,WAAW,GAAwC;AACtF,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,oBAAC,OAAE,WAAU,wCAAuC,sCAAwB;AAAA,EACrF;AAEA,QAAM,UAAU,oBAAI,IAAiC;AACrD,aAAW,OAAO,YAAY;AAC5B,UAAM,MAAM,IAAI;AAChB,UAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK,CAAC;AACnC,UAAM,KAAK,GAAG;AACd,YAAQ,IAAI,KAAK,KAAK;AAAA,EACxB;AAEA,SACE,oBAAC,SACE,gBAAM,KAAK,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAC9C,qBAAC,SAAe,WAAU,QACxB;AAAA,yBAAC,SAAI,WAAU,gFACb;AAAA,0BAAC,UAAK,WAAW,oCAAoC,YAAY,IAAI,KAAK,qBAAqB,IAAI;AAAA,MAClG;AAAA,MAAK;AAAA,MAAG,MAAM;AAAA,MAAO;AAAA,OACxB;AAAA,IACA,oBAAC,SAAI,WAAU,UACZ,gBAAM,IAAI,CAAC,KAAK,QACf;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,+BAAC,SACC;AAAA,gCAAC,UAAK,WAAU,eAAe,cAAI,IAAG;AAAA,YACtC,qBAAC,UAAK,WAAU,gCAA+B;AAAA;AAAA,cAAE,IAAI;AAAA,cAAS;AAAA,eAAC;AAAA,aACjE;AAAA,UACA,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAK,WAAU,qCAAqC,cAAI,QAAO;AAAA,YAC/D,IAAI,aAAa,KAChB,qBAAC,UAAK,WAAU,2DAA0D;AAAA;AAAA,cACtE,IAAI;AAAA,eACR;AAAA,aAEJ;AAAA;AAAA;AAAA,MAdK,GAAG,IAAI,EAAE,IAAI,GAAG;AAAA,IAevB,CACD,GACH;AAAA,OAzBQ,IA0BV,CACD,GACH;AAEJ;",
4
+ "sourcesContent": ["'use client'\n\nimport type { UmesExtensionInfo } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst TYPE_COLORS: Record<string, string> = {\n enricher: 'bg-blue-500',\n interceptor: 'bg-amber-500',\n 'component-override': 'bg-violet-500',\n 'injection-widget': 'bg-emerald-500',\n 'injection-data-widget': 'bg-cyan-500',\n}\n\nexport function ExtensionPointList({ extensions }: { extensions: UmesExtensionInfo[] }) {\n if (extensions.length === 0) {\n return <p className=\"text-xs italic text-muted-foreground\">No extensions registered</p>\n }\n\n const grouped = new Map<string, UmesExtensionInfo[]>()\n for (const ext of extensions) {\n const key = ext.type\n const group = grouped.get(key) ?? []\n group.push(ext)\n grouped.set(key, group)\n }\n\n return (\n <div>\n {Array.from(grouped.entries()).map(([type, items]) => (\n <div key={type} className=\"mb-3\">\n <div className=\"mb-1 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide\">\n <span className={`inline-block size-2 rounded-full ${TYPE_COLORS[type] ?? 'bg-muted-foreground'}`} />\n {type} ({items.length})\n </div>\n <div className=\"pl-3.5\">\n {items.map((ext, idx) => (\n <div\n key={`${ext.id}-${idx}`}\n className=\"flex items-center justify-between border-b border-border/70 py-1 text-xs\"\n >\n <div>\n <span className=\"font-medium\">{ext.id}</span>\n <span className=\"ml-1.5 text-muted-foreground\">[{ext.moduleId}]</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-overline text-muted-foreground\">{ext.target}</span>\n {ext.priority !== 0 && (\n <span className=\"rounded bg-muted px-1.5 py-px text-overline font-semibold\">\n P{ext.priority}\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAcW,cAeD,YAfC;AAVX,MAAM,cAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,yBAAyB;AAC3B;AAEO,SAAS,mBAAmB,EAAE,WAAW,GAAwC;AACtF,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,oBAAC,OAAE,WAAU,wCAAuC,sCAAwB;AAAA,EACrF;AAEA,QAAM,UAAU,oBAAI,IAAiC;AACrD,aAAW,OAAO,YAAY;AAC5B,UAAM,MAAM,IAAI;AAChB,UAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK,CAAC;AACnC,UAAM,KAAK,GAAG;AACd,YAAQ,IAAI,KAAK,KAAK;AAAA,EACxB;AAEA,SACE,oBAAC,SACE,gBAAM,KAAK,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAC9C,qBAAC,SAAe,WAAU,QACxB;AAAA,yBAAC,SAAI,WAAU,gFACb;AAAA,0BAAC,UAAK,WAAW,oCAAoC,YAAY,IAAI,KAAK,qBAAqB,IAAI;AAAA,MAClG;AAAA,MAAK;AAAA,MAAG,MAAM;AAAA,MAAO;AAAA,OACxB;AAAA,IACA,oBAAC,SAAI,WAAU,UACZ,gBAAM,IAAI,CAAC,KAAK,QACf;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,+BAAC,SACC;AAAA,gCAAC,UAAK,WAAU,eAAe,cAAI,IAAG;AAAA,YACtC,qBAAC,UAAK,WAAU,gCAA+B;AAAA;AAAA,cAAE,IAAI;AAAA,cAAS;AAAA,eAAC;AAAA,aACjE;AAAA,UACA,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAK,WAAU,uCAAuC,cAAI,QAAO;AAAA,YACjE,IAAI,aAAa,KAChB,qBAAC,UAAK,WAAU,6DAA4D;AAAA;AAAA,cACxE,IAAI;AAAA,eACR;AAAA,aAEJ;AAAA;AAAA;AAAA,MAdK,GAAG,IAAI,EAAE,IAAI,GAAG;AAAA,IAevB,CACD,GACH;AAAA,OAzBQ,IA0BV,CACD,GACH;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  const RESULT_CLASSES = {
4
- allowed: { text: "text-emerald-600 dark:text-emerald-400", bg: "bg-emerald-50 dark:bg-emerald-950/30" },
5
- blocked: { text: "text-red-600 dark:text-red-400", bg: "bg-red-50 dark:bg-red-950/30" },
6
- modified: { text: "text-amber-600 dark:text-amber-400", bg: "bg-amber-50 dark:bg-amber-950/30" }
4
+ allowed: { text: "text-status-success-icon", bg: "bg-status-success-bg" },
5
+ blocked: { text: "text-status-error-icon", bg: "bg-status-error-bg" },
6
+ modified: { text: "text-status-warning-icon", bg: "bg-status-warning-bg" }
7
7
  };
8
8
  function InterceptorActivity({ entries }) {
9
9
  if (entries.length === 0) {
@@ -15,9 +15,9 @@ function InterceptorActivity({ entries }) {
15
15
  return /* @__PURE__ */ jsxs("div", { className: `mb-1 rounded p-1.5 px-2 text-xs ${classes.bg}`, children: [
16
16
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
17
17
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: entry.interceptorId }),
18
- /* @__PURE__ */ jsx("span", { className: `text-[11px] font-semibold uppercase ${classes.text}`, children: entry.result })
18
+ /* @__PURE__ */ jsx("span", { className: `text-overline font-semibold uppercase ${classes.text}`, children: entry.result })
19
19
  ] }),
20
- /* @__PURE__ */ jsxs("div", { className: "mt-0.5 text-[11px] text-muted-foreground", children: [
20
+ /* @__PURE__ */ jsxs("div", { className: "mt-0.5 text-overline text-muted-foreground", children: [
21
21
  entry.method,
22
22
  " ",
23
23
  entry.route,
@@ -26,7 +26,7 @@ function InterceptorActivity({ entries }) {
26
26
  "ms",
27
27
  entry.statusCode ? ` | ${entry.statusCode}` : ""
28
28
  ] }),
29
- entry.message && /* @__PURE__ */ jsx("div", { className: "mt-px text-[11px] text-muted-foreground/70", children: entry.message })
29
+ entry.message && /* @__PURE__ */ jsx("div", { className: "mt-px text-overline text-muted-foreground/70", children: entry.message })
30
30
  ] }, idx);
31
31
  }) });
32
32
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/backend/devtools/components/InterceptorActivity.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport type { InterceptorActivityEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-emerald-600 dark:text-emerald-400', bg: 'bg-emerald-50 dark:bg-emerald-950/30' },\n blocked: { text: 'text-red-600 dark:text-red-400', bg: 'bg-red-50 dark:bg-red-950/30' },\n modified: { text: 'text-amber-600 dark:text-amber-400', bg: 'bg-amber-50 dark:bg-amber-950/30' },\n}\n\nexport function InterceptorActivity({ entries }: { entries: InterceptorActivityEntry[] }) {\n if (entries.length === 0) {\n return (\n <p className=\"text-xs italic text-muted-foreground\">\n No interceptor activity\n </p>\n )\n }\n\n const recent = entries.slice(-15).reverse()\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = RESULT_CLASSES[entry.result] ?? RESULT_CLASSES.allowed\n return (\n <div key={idx} className={`mb-1 rounded p-1.5 px-2 text-xs ${classes.bg}`}>\n <div className=\"flex items-center justify-between\">\n <span className=\"font-medium\">{entry.interceptorId}</span>\n <span className={`text-[11px] font-semibold uppercase ${classes.text}`}>\n {entry.result}\n </span>\n </div>\n <div className=\"mt-0.5 text-[11px] text-muted-foreground\">\n {entry.method} {entry.route} | {entry.durationMs}ms\n {entry.statusCode ? ` | ${entry.statusCode}` : ''}\n </div>\n {entry.message && (\n <div className=\"mt-px text-[11px] text-muted-foreground/70\">\n {entry.message}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n"],
5
- "mappings": ";AAaM,cAcM,YAdN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,0CAA0C,IAAI,uCAAuC;AAAA,EACtG,SAAS,EAAE,MAAM,kCAAkC,IAAI,+BAA+B;AAAA,EACtF,UAAU,EAAE,MAAM,sCAAsC,IAAI,mCAAmC;AACjG;AAEO,SAAS,oBAAoB,EAAE,QAAQ,GAA4C;AACxF,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,oBAAC,OAAE,WAAU,wCAAuC,qCAEpD;AAAA,EAEJ;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAE1C,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,eAAe,MAAM,MAAM,KAAK,eAAe;AAC/D,WACE,qBAAC,SAAc,WAAW,mCAAmC,QAAQ,EAAE,IACrE;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,UAAK,WAAU,eAAe,gBAAM,eAAc;AAAA,QACnD,oBAAC,UAAK,WAAW,uCAAuC,QAAQ,IAAI,IACjE,gBAAM,QACT;AAAA,SACF;AAAA,MACA,qBAAC,SAAI,WAAU,4CACZ;AAAA,cAAM;AAAA,QAAO;AAAA,QAAE,MAAM;AAAA,QAAM;AAAA,QAAI,MAAM;AAAA,QAAW;AAAA,QAChD,MAAM,aAAa,MAAM,MAAM,UAAU,KAAK;AAAA,SACjD;AAAA,MACC,MAAM,WACL,oBAAC,SAAI,WAAU,8CACZ,gBAAM,SACT;AAAA,SAdM,GAgBV;AAAA,EAEJ,CAAC,GACH;AAEJ;",
4
+ "sourcesContent": ["'use client'\n\nimport type { InterceptorActivityEntry } from '@open-mercato/shared/lib/umes/devtools-types'\n\nconst RESULT_CLASSES: Record<string, { text: string; bg: string }> = {\n allowed: { text: 'text-status-success-icon', bg: 'bg-status-success-bg' },\n blocked: { text: 'text-status-error-icon', bg: 'bg-status-error-bg' },\n modified: { text: 'text-status-warning-icon', bg: 'bg-status-warning-bg' },\n}\n\nexport function InterceptorActivity({ entries }: { entries: InterceptorActivityEntry[] }) {\n if (entries.length === 0) {\n return (\n <p className=\"text-xs italic text-muted-foreground\">\n No interceptor activity\n </p>\n )\n }\n\n const recent = entries.slice(-15).reverse()\n\n return (\n <div>\n {recent.map((entry, idx) => {\n const classes = RESULT_CLASSES[entry.result] ?? RESULT_CLASSES.allowed\n return (\n <div key={idx} className={`mb-1 rounded p-1.5 px-2 text-xs ${classes.bg}`}>\n <div className=\"flex items-center justify-between\">\n <span className=\"font-medium\">{entry.interceptorId}</span>\n <span className={`text-overline font-semibold uppercase ${classes.text}`}>\n {entry.result}\n </span>\n </div>\n <div className=\"mt-0.5 text-overline text-muted-foreground\">\n {entry.method} {entry.route} | {entry.durationMs}ms\n {entry.statusCode ? ` | ${entry.statusCode}` : ''}\n </div>\n {entry.message && (\n <div className=\"mt-px text-overline text-muted-foreground/70\">\n {entry.message}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAaM,cAcM,YAdN;AATN,MAAM,iBAA+D;AAAA,EACnE,SAAS,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AAAA,EACxE,SAAS,EAAE,MAAM,0BAA0B,IAAI,qBAAqB;AAAA,EACpE,UAAU,EAAE,MAAM,4BAA4B,IAAI,uBAAuB;AAC3E;AAEO,SAAS,oBAAoB,EAAE,QAAQ,GAA4C;AACxF,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,oBAAC,OAAE,WAAU,wCAAuC,qCAEpD;AAAA,EAEJ;AAEA,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAE1C,SACE,oBAAC,SACE,iBAAO,IAAI,CAAC,OAAO,QAAQ;AAC1B,UAAM,UAAU,eAAe,MAAM,MAAM,KAAK,eAAe;AAC/D,WACE,qBAAC,SAAc,WAAW,mCAAmC,QAAQ,EAAE,IACrE;AAAA,2BAAC,SAAI,WAAU,qCACb;AAAA,4BAAC,UAAK,WAAU,eAAe,gBAAM,eAAc;AAAA,QACnD,oBAAC,UAAK,WAAW,yCAAyC,QAAQ,IAAI,IACnE,gBAAM,QACT;AAAA,SACF;AAAA,MACA,qBAAC,SAAI,WAAU,8CACZ;AAAA,cAAM;AAAA,QAAO;AAAA,QAAE,MAAM;AAAA,QAAM;AAAA,QAAI,MAAM;AAAA,QAAW;AAAA,QAChD,MAAM,aAAa,MAAM,MAAM,UAAU,KAAK;AAAA,SACjD;AAAA,MACC,MAAM,WACL,oBAAC,SAAI,WAAU,gDACZ,gBAAM,SACT;AAAA,SAdM,GAgBV;AAAA,EAEJ,CAAC,GACH;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -115,7 +115,7 @@ function ActionsDropdown({
115
115
  {
116
116
  ref: menuRef,
117
117
  role: "menu",
118
- className: "fixed w-52 rounded-md border bg-background p-1 shadow-md focus:outline-none z-[1000]",
118
+ className: "fixed w-52 rounded-md border bg-background p-1 shadow-md focus-visible:outline-none z-dropdown",
119
119
  onMouseEnter: handleMouseEnter,
120
120
  onMouseLeave: handleMouseLeave,
121
121
  style: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/forms/ActionsDropdown.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\nimport { Zap, ChevronDown, Loader2, MoreHorizontal } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type ActionItem = {\n /** Unique key */\n id: string\n /** Display label */\n label: string\n /** Lucide icon component (optional) */\n icon?: React.ComponentType<{ className?: string }>\n /** Click handler */\n onSelect: () => void\n /** Disable the item */\n disabled?: boolean\n /** Show a loading spinner instead of the icon */\n loading?: boolean\n}\n\nexport type ActionsDropdownProps = {\n /** Items to render inside the dropdown */\n items: ActionItem[]\n /** Button label (default: translated 'Actions') */\n label?: string\n /** Trigger style */\n triggerMode?: 'label' | 'icon'\n /** Accessible label for icon trigger */\n ariaLabel?: string\n /** Button size (default: 'sm') */\n size?: 'sm' | 'default'\n}\n\nexport function ActionsDropdown({\n items,\n label,\n triggerMode = 'label',\n ariaLabel,\n size = 'sm',\n}: ActionsDropdownProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const btnRef = React.useRef<HTMLButtonElement>(null)\n const menuRef = React.useRef<HTMLDivElement>(null)\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null)\n const hoverTimeoutRef = React.useRef<NodeJS.Timeout | null>(null)\n const [direction, setDirection] = React.useState<'down' | 'up'>('down')\n\n const resolvedLabel = label ?? t('ui.actions.actions', 'Actions')\n const resolvedAriaLabel = ariaLabel ?? resolvedLabel\n\n const updatePosition = React.useCallback(() => {\n if (!btnRef.current) return\n const rect = btnRef.current.getBoundingClientRect()\n setAnchorRect(rect)\n const spaceBelow = window.innerHeight - rect.bottom\n const spaceAbove = rect.top\n setDirection(spaceBelow < 200 && spaceAbove > spaceBelow ? 'up' : 'down')\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n updatePosition()\n function onDocClick(event: MouseEvent) {\n const target = event.target as Node\n if (\n menuRef.current && !menuRef.current.contains(target) &&\n btnRef.current && !btnRef.current.contains(target)\n ) {\n setOpen(false)\n }\n }\n function onKey(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n setOpen(false)\n btnRef.current?.focus()\n }\n }\n function onScrollOrResize() {\n updatePosition()\n }\n document.addEventListener('mousedown', onDocClick)\n document.addEventListener('keydown', onKey)\n window.addEventListener('scroll', onScrollOrResize, true)\n window.addEventListener('resize', onScrollOrResize)\n return () => {\n document.removeEventListener('mousedown', onDocClick)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, true)\n window.removeEventListener('resize', onScrollOrResize)\n }\n }, [open, updatePosition])\n\n React.useEffect(() => {\n return () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n }\n }, [])\n\n const handleMouseEnter = () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n setOpen(true)\n }\n\n const handleMouseLeave = () => {\n hoverTimeoutRef.current = setTimeout(() => {\n setOpen(false)\n }, 150)\n }\n\n if (!items.length) return null\n\n return (\n <div\n className=\"relative inline-block\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n <Button\n ref={btnRef}\n type=\"button\"\n variant=\"outline\"\n size={size}\n className={triggerMode === 'icon' ? 'px-2' : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label={resolvedAriaLabel}\n onClick={() => {\n setOpen((prev) => !prev)\n requestAnimationFrame(updatePosition)\n }}\n >\n {triggerMode === 'icon' ? (\n <>\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">{resolvedAriaLabel}</span>\n </>\n ) : (\n <>\n {resolvedLabel}\n <Zap className=\"size-4 ml-1\" />\n <ChevronDown className={`size-3.5 transition-transform duration-150 ${open ? 'rotate-180' : ''}`} />\n </>\n )}\n </Button>\n {open && anchorRect && createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n className=\"fixed w-52 rounded-md border bg-background p-1 shadow-md focus:outline-none z-[1000]\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n style={{\n top: direction === 'down' ? anchorRect.bottom + 4 : anchorRect.top - 4,\n left: anchorRect.right,\n transform: `translate(-100%, ${direction === 'down' ? '0' : '-100%'})`,\n }}\n >\n {items.map((item) => {\n const Icon = item.icon\n return (\n <Button\n key={item.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start\"\n role=\"menuitem\"\n disabled={item.disabled}\n onClick={() => {\n setOpen(false)\n item.onSelect()\n }}\n >\n {item.loading ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : Icon ? (\n <Icon className=\"size-4\" />\n ) : (\n <span className=\"size-4\" />\n )}\n {item.label}\n </Button>\n )\n })}\n </div>,\n document.body,\n )}\n </div>\n )\n}\n"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\nimport { Zap, ChevronDown, Loader2, MoreHorizontal } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type ActionItem = {\n /** Unique key */\n id: string\n /** Display label */\n label: string\n /** Lucide icon component (optional) */\n icon?: React.ComponentType<{ className?: string }>\n /** Click handler */\n onSelect: () => void\n /** Disable the item */\n disabled?: boolean\n /** Show a loading spinner instead of the icon */\n loading?: boolean\n}\n\nexport type ActionsDropdownProps = {\n /** Items to render inside the dropdown */\n items: ActionItem[]\n /** Button label (default: translated 'Actions') */\n label?: string\n /** Trigger style */\n triggerMode?: 'label' | 'icon'\n /** Accessible label for icon trigger */\n ariaLabel?: string\n /** Button size (default: 'sm') */\n size?: 'sm' | 'default'\n}\n\nexport function ActionsDropdown({\n items,\n label,\n triggerMode = 'label',\n ariaLabel,\n size = 'sm',\n}: ActionsDropdownProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const btnRef = React.useRef<HTMLButtonElement>(null)\n const menuRef = React.useRef<HTMLDivElement>(null)\n const [anchorRect, setAnchorRect] = React.useState<DOMRect | null>(null)\n const hoverTimeoutRef = React.useRef<NodeJS.Timeout | null>(null)\n const [direction, setDirection] = React.useState<'down' | 'up'>('down')\n\n const resolvedLabel = label ?? t('ui.actions.actions', 'Actions')\n const resolvedAriaLabel = ariaLabel ?? resolvedLabel\n\n const updatePosition = React.useCallback(() => {\n if (!btnRef.current) return\n const rect = btnRef.current.getBoundingClientRect()\n setAnchorRect(rect)\n const spaceBelow = window.innerHeight - rect.bottom\n const spaceAbove = rect.top\n setDirection(spaceBelow < 200 && spaceAbove > spaceBelow ? 'up' : 'down')\n }, [])\n\n React.useEffect(() => {\n if (!open) return\n updatePosition()\n function onDocClick(event: MouseEvent) {\n const target = event.target as Node\n if (\n menuRef.current && !menuRef.current.contains(target) &&\n btnRef.current && !btnRef.current.contains(target)\n ) {\n setOpen(false)\n }\n }\n function onKey(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n setOpen(false)\n btnRef.current?.focus()\n }\n }\n function onScrollOrResize() {\n updatePosition()\n }\n document.addEventListener('mousedown', onDocClick)\n document.addEventListener('keydown', onKey)\n window.addEventListener('scroll', onScrollOrResize, true)\n window.addEventListener('resize', onScrollOrResize)\n return () => {\n document.removeEventListener('mousedown', onDocClick)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, true)\n window.removeEventListener('resize', onScrollOrResize)\n }\n }, [open, updatePosition])\n\n React.useEffect(() => {\n return () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n }\n }, [])\n\n const handleMouseEnter = () => {\n if (hoverTimeoutRef.current) {\n clearTimeout(hoverTimeoutRef.current)\n }\n setOpen(true)\n }\n\n const handleMouseLeave = () => {\n hoverTimeoutRef.current = setTimeout(() => {\n setOpen(false)\n }, 150)\n }\n\n if (!items.length) return null\n\n return (\n <div\n className=\"relative inline-block\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n <Button\n ref={btnRef}\n type=\"button\"\n variant=\"outline\"\n size={size}\n className={triggerMode === 'icon' ? 'px-2' : undefined}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-label={resolvedAriaLabel}\n onClick={() => {\n setOpen((prev) => !prev)\n requestAnimationFrame(updatePosition)\n }}\n >\n {triggerMode === 'icon' ? (\n <>\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">{resolvedAriaLabel}</span>\n </>\n ) : (\n <>\n {resolvedLabel}\n <Zap className=\"size-4 ml-1\" />\n <ChevronDown className={`size-3.5 transition-transform duration-150 ${open ? 'rotate-180' : ''}`} />\n </>\n )}\n </Button>\n {open && anchorRect && createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n className=\"fixed w-52 rounded-md border bg-background p-1 shadow-md focus-visible:outline-none z-dropdown\"\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n style={{\n top: direction === 'down' ? anchorRect.bottom + 4 : anchorRect.top - 4,\n left: anchorRect.right,\n transform: `translate(-100%, ${direction === 'down' ? '0' : '-100%'})`,\n }}\n >\n {items.map((item) => {\n const Icon = item.icon\n return (\n <Button\n key={item.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"w-full justify-start\"\n role=\"menuitem\"\n disabled={item.disabled}\n onClick={() => {\n setOpen(false)\n item.onSelect()\n }}\n >\n {item.loading ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : Icon ? (\n <Icon className=\"size-4\" />\n ) : (\n <span className=\"size-4\" />\n )}\n {item.label}\n </Button>\n )\n })}\n </div>,\n document.body,\n )}\n </div>\n )\n}\n"],
5
5
  "mappings": ";AA4IU,mBACE,KADF;AA1IV,YAAY,WAAW;AACvB,SAAS,oBAAoB;AAC7B,SAAS,KAAK,aAAa,SAAS,sBAAsB;AAC1D,SAAS,cAAc;AACvB,SAAS,YAAY;AA8Bd,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,OAAO;AACT,GAAyB;AACvB,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAC5C,QAAM,SAAS,MAAM,OAA0B,IAAI;AACnD,QAAM,UAAU,MAAM,OAAuB,IAAI;AACjD,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAyB,IAAI;AACvE,QAAM,kBAAkB,MAAM,OAA8B,IAAI;AAChE,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAwB,MAAM;AAEtE,QAAM,gBAAgB,SAAS,EAAE,sBAAsB,SAAS;AAChE,QAAM,oBAAoB,aAAa;AAEvC,QAAM,iBAAiB,MAAM,YAAY,MAAM;AAC7C,QAAI,CAAC,OAAO,QAAS;AACrB,UAAM,OAAO,OAAO,QAAQ,sBAAsB;AAClD,kBAAc,IAAI;AAClB,UAAM,aAAa,OAAO,cAAc,KAAK;AAC7C,UAAM,aAAa,KAAK;AACxB,iBAAa,aAAa,OAAO,aAAa,aAAa,OAAO,MAAM;AAAA,EAC1E,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,KAAM;AACX,mBAAe;AACf,aAAS,WAAW,OAAmB;AACrC,YAAM,SAAS,MAAM;AACrB,UACE,QAAQ,WAAW,CAAC,QAAQ,QAAQ,SAAS,MAAM,KACnD,OAAO,WAAW,CAAC,OAAO,QAAQ,SAAS,MAAM,GACjD;AACA,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AACA,aAAS,MAAM,OAAsB;AACnC,UAAI,MAAM,QAAQ,UAAU;AAC1B,gBAAQ,KAAK;AACb,eAAO,SAAS,MAAM;AAAA,MACxB;AAAA,IACF;AACA,aAAS,mBAAmB;AAC1B,qBAAe;AAAA,IACjB;AACA,aAAS,iBAAiB,aAAa,UAAU;AACjD,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,iBAAiB,UAAU,kBAAkB,IAAI;AACxD,WAAO,iBAAiB,UAAU,gBAAgB;AAClD,WAAO,MAAM;AACX,eAAS,oBAAoB,aAAa,UAAU;AACpD,eAAS,oBAAoB,WAAW,KAAK;AAC7C,aAAO,oBAAoB,UAAU,kBAAkB,IAAI;AAC3D,aAAO,oBAAoB,UAAU,gBAAgB;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,MAAM,cAAc,CAAC;AAEzB,QAAM,UAAU,MAAM;AACpB,WAAO,MAAM;AACX,UAAI,gBAAgB,SAAS;AAC3B,qBAAa,gBAAgB,OAAO;AAAA,MACtC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,MAAM;AAC7B,QAAI,gBAAgB,SAAS;AAC3B,mBAAa,gBAAgB,OAAO;AAAA,IACtC;AACA,YAAQ,IAAI;AAAA,EACd;AAEA,QAAM,mBAAmB,MAAM;AAC7B,oBAAgB,UAAU,WAAW,MAAM;AACzC,cAAQ,KAAK;AAAA,IACf,GAAG,GAAG;AAAA,EACR;AAEA,MAAI,CAAC,MAAM,OAAQ,QAAO;AAE1B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,cAAc;AAAA,MACd,cAAc;AAAA,MAEd;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,MAAK;AAAA,YACL,SAAQ;AAAA,YACR;AAAA,YACA,WAAW,gBAAgB,SAAS,SAAS;AAAA,YAC7C,iBAAc;AAAA,YACd,iBAAe;AAAA,YACf,cAAY;AAAA,YACZ,SAAS,MAAM;AACb,sBAAQ,CAAC,SAAS,CAAC,IAAI;AACvB,oCAAsB,cAAc;AAAA,YACtC;AAAA,YAEC,0BAAgB,SACf,iCACE;AAAA,kCAAC,kBAAe,WAAU,UAAS;AAAA,cACnC,oBAAC,UAAK,WAAU,WAAW,6BAAkB;AAAA,eAC/C,IAEA,iCACG;AAAA;AAAA,cACD,oBAAC,OAAI,WAAU,eAAc;AAAA,cAC7B,oBAAC,eAAY,WAAW,8CAA8C,OAAO,eAAe,EAAE,IAAI;AAAA,eACpG;AAAA;AAAA,QAEJ;AAAA,QACC,QAAQ,cAAc;AAAA,UACrB;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL,WAAU;AAAA,cACV,cAAc;AAAA,cACd,cAAc;AAAA,cACd,OAAO;AAAA,gBACL,KAAK,cAAc,SAAS,WAAW,SAAS,IAAI,WAAW,MAAM;AAAA,gBACrE,MAAM,WAAW;AAAA,gBACjB,WAAW,oBAAoB,cAAc,SAAS,MAAM,OAAO;AAAA,cACrE;AAAA,cAEC,gBAAM,IAAI,CAAC,SAAS;AACnB,sBAAM,OAAO,KAAK;AAClB,uBACE;AAAA,kBAAC;AAAA;AAAA,oBAEC,MAAK;AAAA,oBACL,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,MAAK;AAAA,oBACL,UAAU,KAAK;AAAA,oBACf,SAAS,MAAM;AACb,8BAAQ,KAAK;AACb,2BAAK,SAAS;AAAA,oBAChB;AAAA,oBAEC;AAAA,2BAAK,UACJ,oBAAC,WAAQ,WAAU,uBAAsB,IACvC,OACF,oBAAC,QAAK,WAAU,UAAS,IAEzB,oBAAC,UAAK,WAAU,UAAS;AAAA,sBAE1B,KAAK;AAAA;AAAA;AAAA,kBAnBD,KAAK;AAAA,gBAoBZ;AAAA,cAEJ,CAAC;AAAA;AAAA,UACH;AAAA,UACA,SAAS;AAAA,QACX;AAAA;AAAA;AAAA,EACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -28,17 +28,16 @@ function FormActionButtons({
28
28
  Button,
29
29
  {
30
30
  type: "button",
31
- variant: "outline",
31
+ variant: "destructive-outline",
32
32
  onClick: onDelete,
33
33
  disabled: isDeleting,
34
- className: "text-red-600 border-red-200 hover:bg-red-50 rounded",
35
34
  children: [
36
35
  isDeleting ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 mr-2 animate-spin" }) : /* @__PURE__ */ jsx(Trash2, { className: "size-4 mr-2" }),
37
36
  resolvedDeleteLabel
38
37
  ]
39
38
  }
40
39
  ) : null,
41
- cancelHref ? /* @__PURE__ */ jsx(Link, { href: cancelHref, className: "h-9 inline-flex items-center rounded border px-3 text-sm", children: resolvedCancelLabel }) : null,
40
+ cancelHref ? /* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", children: /* @__PURE__ */ jsx(Link, { href: cancelHref, children: resolvedCancelLabel }) }) : null,
42
41
  submit ? /* @__PURE__ */ jsxs(
43
42
  Button,
44
43
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/forms/FormActionButtons.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Trash2, Save, Loader2 } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type FormActionButtonsProps = {\n /** Extra action buttons rendered before the standard buttons */\n extraActions?: React.ReactNode\n /** Show the delete button */\n showDelete?: boolean\n /** Callback when delete is clicked */\n onDelete?: () => void\n /** Label for the delete button */\n deleteLabel?: string\n /** Whether the delete button shows a loading spinner */\n isDeleting?: boolean\n /** URL for the cancel link */\n cancelHref?: string\n /** Label for the cancel link */\n cancelLabel?: string\n /** Submit button configuration */\n submit?: {\n /** Form ID for the submit button (needed in header to trigger form submit) */\n formId?: string\n /** Whether the form is currently submitting */\n pending?: boolean\n /** Label while idle */\n label?: string\n /** Label while saving */\n pendingLabel?: string\n /** Optional icon for idle submit state */\n icon?: React.ComponentType<{ className?: string }>\n }\n /** When true, hides all buttons */\n hidden?: boolean\n}\n\nexport function FormActionButtons({\n extraActions,\n showDelete,\n onDelete,\n deleteLabel,\n isDeleting,\n cancelHref,\n cancelLabel,\n submit,\n hidden,\n}: FormActionButtonsProps) {\n const t = useT()\n\n if (hidden) return null\n\n const resolvedDeleteLabel = deleteLabel ?? t('ui.forms.actions.delete')\n const resolvedCancelLabel = cancelLabel ?? t('ui.forms.actions.cancel')\n const resolvedSubmitLabel = submit?.label ?? t('ui.forms.actions.save')\n const resolvedPendingLabel = submit?.pendingLabel ?? t('ui.forms.status.saving')\n const SubmitIcon = submit?.icon ?? Save\n\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n {extraActions}\n {showDelete ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onDelete}\n disabled={isDeleting}\n className=\"text-red-600 border-red-200 hover:bg-red-50 rounded\"\n >\n {isDeleting ? (\n <Loader2 className=\"size-4 mr-2 animate-spin\" />\n ) : (\n <Trash2 className=\"size-4 mr-2\" />\n )}\n {resolvedDeleteLabel}\n </Button>\n ) : null}\n {cancelHref ? (\n <Link href={cancelHref} className=\"h-9 inline-flex items-center rounded border px-3 text-sm\">\n {resolvedCancelLabel}\n </Link>\n ) : null}\n {submit ? (\n <Button\n type=\"submit\"\n form={submit.formId}\n disabled={submit.pending}\n >\n {submit.pending ? <Loader2 className=\"size-4 mr-2 animate-spin\" /> : <SubmitIcon className=\"size-4 mr-2\" />}\n {submit.pending ? resolvedPendingLabel : resolvedSubmitLabel}\n </Button>\n ) : null}\n </div>\n )\n}\n"],
5
- "mappings": ";AAiEQ,SAQI,KARJ;AA9DR,OAAO,UAAU;AACjB,SAAS,QAAQ,MAAM,eAAe;AACtC,SAAS,cAAc;AACvB,SAAS,YAAY;AAkCd,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,IAAI,KAAK;AAEf,MAAI,OAAQ,QAAO;AAEnB,QAAM,sBAAsB,eAAe,EAAE,yBAAyB;AACtE,QAAM,sBAAsB,eAAe,EAAE,yBAAyB;AACtE,QAAM,sBAAsB,QAAQ,SAAS,EAAE,uBAAuB;AACtE,QAAM,uBAAuB,QAAQ,gBAAgB,EAAE,wBAAwB;AAC/E,QAAM,aAAa,QAAQ,QAAQ;AAEnC,SACE,qBAAC,SAAI,WAAU,qCACZ;AAAA;AAAA,IACA,aACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAU;AAAA,QAET;AAAA,uBACC,oBAAC,WAAQ,WAAU,4BAA2B,IAE9C,oBAAC,UAAO,WAAU,eAAc;AAAA,UAEjC;AAAA;AAAA;AAAA,IACH,IACE;AAAA,IACH,aACC,oBAAC,QAAK,MAAM,YAAY,WAAU,4DAC/B,+BACH,IACE;AAAA,IACH,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,MAAM,OAAO;AAAA,QACb,UAAU,OAAO;AAAA,QAEhB;AAAA,iBAAO,UAAU,oBAAC,WAAQ,WAAU,4BAA2B,IAAK,oBAAC,cAAW,WAAU,eAAc;AAAA,UACxG,OAAO,UAAU,uBAAuB;AAAA;AAAA;AAAA,IAC3C,IACE;AAAA,KACN;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Trash2, Save, Loader2 } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type FormActionButtonsProps = {\n /** Extra action buttons rendered before the standard buttons */\n extraActions?: React.ReactNode\n /** Show the delete button */\n showDelete?: boolean\n /** Callback when delete is clicked */\n onDelete?: () => void\n /** Label for the delete button */\n deleteLabel?: string\n /** Whether the delete button shows a loading spinner */\n isDeleting?: boolean\n /** URL for the cancel link */\n cancelHref?: string\n /** Label for the cancel link */\n cancelLabel?: string\n /** Submit button configuration */\n submit?: {\n /** Form ID for the submit button (needed in header to trigger form submit) */\n formId?: string\n /** Whether the form is currently submitting */\n pending?: boolean\n /** Label while idle */\n label?: string\n /** Label while saving */\n pendingLabel?: string\n /** Optional icon for idle submit state */\n icon?: React.ComponentType<{ className?: string }>\n }\n /** When true, hides all buttons */\n hidden?: boolean\n}\n\nexport function FormActionButtons({\n extraActions,\n showDelete,\n onDelete,\n deleteLabel,\n isDeleting,\n cancelHref,\n cancelLabel,\n submit,\n hidden,\n}: FormActionButtonsProps) {\n const t = useT()\n\n if (hidden) return null\n\n const resolvedDeleteLabel = deleteLabel ?? t('ui.forms.actions.delete')\n const resolvedCancelLabel = cancelLabel ?? t('ui.forms.actions.cancel')\n const resolvedSubmitLabel = submit?.label ?? t('ui.forms.actions.save')\n const resolvedPendingLabel = submit?.pendingLabel ?? t('ui.forms.status.saving')\n const SubmitIcon = submit?.icon ?? Save\n\n return (\n <div className=\"flex flex-wrap items-center gap-2\">\n {extraActions}\n {showDelete ? (\n <Button\n type=\"button\"\n variant=\"destructive-outline\"\n onClick={onDelete}\n disabled={isDeleting}\n >\n {isDeleting ? (\n <Loader2 className=\"size-4 mr-2 animate-spin\" />\n ) : (\n <Trash2 className=\"size-4 mr-2\" />\n )}\n {resolvedDeleteLabel}\n </Button>\n ) : null}\n {cancelHref ? (\n <Button asChild variant=\"outline\">\n <Link href={cancelHref}>{resolvedCancelLabel}</Link>\n </Button>\n ) : null}\n {submit ? (\n <Button\n type=\"submit\"\n form={submit.formId}\n disabled={submit.pending}\n >\n {submit.pending ? <Loader2 className=\"size-4 mr-2 animate-spin\" /> : <SubmitIcon className=\"size-4 mr-2\" />}\n {submit.pending ? resolvedPendingLabel : resolvedSubmitLabel}\n </Button>\n ) : null}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAiEQ,SAOI,KAPJ;AA9DR,OAAO,UAAU;AACjB,SAAS,QAAQ,MAAM,eAAe;AACtC,SAAS,cAAc;AACvB,SAAS,YAAY;AAkCd,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,IAAI,KAAK;AAEf,MAAI,OAAQ,QAAO;AAEnB,QAAM,sBAAsB,eAAe,EAAE,yBAAyB;AACtE,QAAM,sBAAsB,eAAe,EAAE,yBAAyB;AACtE,QAAM,sBAAsB,QAAQ,SAAS,EAAE,uBAAuB;AACtE,QAAM,uBAAuB,QAAQ,gBAAgB,EAAE,wBAAwB;AAC/E,QAAM,aAAa,QAAQ,QAAQ;AAEnC,SACE,qBAAC,SAAI,WAAU,qCACZ;AAAA;AAAA,IACA,aACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,QAET;AAAA,uBACC,oBAAC,WAAQ,WAAU,4BAA2B,IAE9C,oBAAC,UAAO,WAAU,eAAc;AAAA,UAEjC;AAAA;AAAA;AAAA,IACH,IACE;AAAA,IACH,aACC,oBAAC,UAAO,SAAO,MAAC,SAAQ,WACtB,8BAAC,QAAK,MAAM,YAAa,+BAAoB,GAC/C,IACE;AAAA,IACH,SACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,MAAM,OAAO;AAAA,QACb,UAAU,OAAO;AAAA,QAEhB;AAAA,iBAAO,UAAU,oBAAC,WAAQ,WAAU,4BAA2B,IAAK,oBAAC,cAAW,WAAU,eAAc;AAAA,UACxG,OAAO,UAAU,uBAAuB;AAAA;AAAA;AAAA,IAC3C,IACE;AAAA,KACN;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -28,16 +28,16 @@ function PartialIndexBanner() {
28
28
  const indexed = warning.indexedCount;
29
29
  const hasCounts = typeof base === "number" && typeof indexed === "number";
30
30
  const hasExcessIndexedRows = hasCounts && indexed > base;
31
- return /* @__PURE__ */ jsxs("div", { className: "mb-4 flex flex-col gap-3 rounded-md border border-amber-300 bg-amber-50 px-3 py-3 text-sm text-amber-900 dark:border-amber-600/60 dark:bg-amber-950/40 dark:text-amber-100 md:flex-row md:items-center md:justify-between", children: [
31
+ return /* @__PURE__ */ jsxs("div", { className: "mb-4 flex flex-col gap-3 rounded-md border border-status-warning-border bg-status-warning-bg px-3 py-3 text-sm text-status-warning-text md:flex-row md:items-center md:justify-between", children: [
32
32
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 text-sm", children: [
33
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 font-medium text-amber-950 dark:text-amber-50", children: [
33
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 font-medium text-status-warning-text", children: [
34
34
  /* @__PURE__ */ jsx(AlertTriangle, { className: "size-4", "aria-hidden": "true" }),
35
35
  /* @__PURE__ */ jsx("span", { children: t("query_index.banner.partial_title") })
36
36
  ] }),
37
- /* @__PURE__ */ jsx("p", { className: "text-amber-900 dark:text-amber-100", children: t("query_index.banner.partial_description") }),
38
- /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-900/90 dark:text-amber-100/90", children: t("query_index.banner.partial_entity", { entity: entityLabel }) }),
39
- hasCounts && /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-900/90 dark:text-amber-100/90", children: hasExcessIndexedRows ? t("query_index.banner.partial_counts_excess", { indexed, total: base }) : t("query_index.banner.partial_counts", { indexed, total: base }) }),
40
- warning.scope === "global" && /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-900/80 dark:text-amber-100/75", children: t("query_index.banner.partial_global_note") })
37
+ /* @__PURE__ */ jsx("p", { className: "text-status-warning-text", children: t("query_index.banner.partial_description") }),
38
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text", children: t("query_index.banner.partial_entity", { entity: entityLabel }) }),
39
+ hasCounts && /* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text", children: hasExcessIndexedRows ? t("query_index.banner.partial_counts_excess", { indexed, total: base }) : t("query_index.banner.partial_counts", { indexed, total: base }) }),
40
+ warning.scope === "global" && /* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text", children: t("query_index.banner.partial_global_note") })
41
41
  ] }),
42
42
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
43
43
  /* @__PURE__ */ jsx(
@@ -46,7 +46,7 @@ function PartialIndexBanner() {
46
46
  asChild: true,
47
47
  variant: "outline",
48
48
  size: "sm",
49
- className: "border-amber-300 text-amber-900 hover:bg-amber-100 dark:border-amber-500/60 dark:text-amber-100 dark:hover:bg-amber-900/60",
49
+ className: "border-status-warning-border text-status-warning-text hover:bg-status-warning-bg",
50
50
  children: /* @__PURE__ */ jsx(Link, { href: manageIndexesHref, children: t("query_index.banner.manage_indexes") })
51
51
  }
52
52
  ),
@@ -57,7 +57,7 @@ function PartialIndexBanner() {
57
57
  size: "sm",
58
58
  type: "button",
59
59
  onClick: () => dismissPartialIndexWarning(),
60
- className: "text-amber-900 hover:bg-amber-100 dark:text-amber-100 dark:hover:bg-amber-900/60",
60
+ className: "text-status-warning-text hover:bg-status-warning-bg",
61
61
  "aria-label": t("query_index.banner.dismiss"),
62
62
  children: [
63
63
  /* @__PURE__ */ jsx(X, { className: "mr-1 size-4", "aria-hidden": "true" }),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/indexes/PartialIndexBanner.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { usePathname, useSearchParams } from 'next/navigation'\nimport { AlertTriangle, X } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { buildHrefWithReturnTo } from '@open-mercato/shared/lib/navigation/returnTo'\nimport { dismissPartialIndexWarning, usePartialIndexWarning } from './store'\n\nexport function PartialIndexBanner() {\n const t = useT()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const warning = usePartialIndexWarning()\n\n const returnTo = React.useMemo(() => {\n const query = searchParams?.toString() ?? ''\n if (!pathname) return null\n return query.length ? `${pathname}?${query}` : pathname\n }, [pathname, searchParams])\n const manageIndexesHref = React.useMemo(\n () => buildHrefWithReturnTo('/backend/query-indexes', returnTo),\n [returnTo],\n )\n\n if (!warning) return null\n\n const entityLabel = warning.entityLabel || warning.entity\n const base = warning.baseCount\n const indexed = warning.indexedCount\n const hasCounts = typeof base === 'number' && typeof indexed === 'number'\n const hasExcessIndexedRows = hasCounts && indexed > base\n\n return (\n <div className=\"mb-4 flex flex-col gap-3 rounded-md border border-amber-300 bg-amber-50 px-3 py-3 text-sm text-amber-900 dark:border-amber-600/60 dark:bg-amber-950/40 dark:text-amber-100 md:flex-row md:items-center md:justify-between\">\n <div className=\"flex flex-col gap-2 text-sm\">\n <div className=\"flex items-center gap-2 font-medium text-amber-950 dark:text-amber-50\">\n <AlertTriangle className=\"size-4\" aria-hidden=\"true\" />\n <span>{t('query_index.banner.partial_title')}</span>\n </div>\n <p className=\"text-amber-900 dark:text-amber-100\">\n {t('query_index.banner.partial_description')}\n </p>\n <p className=\"text-xs text-amber-900/90 dark:text-amber-100/90\">\n {t('query_index.banner.partial_entity', { entity: entityLabel })}\n </p>\n {hasCounts && (\n <p className=\"text-xs text-amber-900/90 dark:text-amber-100/90\">\n {hasExcessIndexedRows\n ? t('query_index.banner.partial_counts_excess', { indexed, total: base })\n : t('query_index.banner.partial_counts', { indexed, total: base })}\n </p>\n )}\n {warning.scope === 'global' && (\n <p className=\"text-xs text-amber-900/80 dark:text-amber-100/75\">\n {t('query_index.banner.partial_global_note')}\n </p>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n asChild\n variant=\"outline\"\n size=\"sm\"\n className=\"border-amber-300 text-amber-900 hover:bg-amber-100 dark:border-amber-500/60 dark:text-amber-100 dark:hover:bg-amber-900/60\"\n >\n <Link href={manageIndexesHref}>\n {t('query_index.banner.manage_indexes')}\n </Link>\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n type=\"button\"\n onClick={() => dismissPartialIndexWarning()}\n className=\"text-amber-900 hover:bg-amber-100 dark:text-amber-100 dark:hover:bg-amber-900/60\"\n aria-label={t('query_index.banner.dismiss')}\n >\n <X className=\"mr-1 size-4\" aria-hidden=\"true\" />\n {t('query_index.banner.dismiss')}\n </Button>\n </div>\n </div>\n )\n}\n"],
5
- "mappings": ";AAqCQ,SACE,KADF;AApCR,YAAY,WAAW;AACvB,OAAO,UAAU;AACjB,SAAS,aAAa,uBAAuB;AAC7C,SAAS,eAAe,SAAS;AACjC,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,6BAA6B;AACtC,SAAS,4BAA4B,8BAA8B;AAE5D,SAAS,qBAAqB;AACnC,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,YAAY;AAC7B,QAAM,eAAe,gBAAgB;AACrC,QAAM,UAAU,uBAAuB;AAEvC,QAAM,WAAW,MAAM,QAAQ,MAAM;AACnC,UAAM,QAAQ,cAAc,SAAS,KAAK;AAC1C,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO,MAAM,SAAS,GAAG,QAAQ,IAAI,KAAK,KAAK;AAAA,EACjD,GAAG,CAAC,UAAU,YAAY,CAAC;AAC3B,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAM,sBAAsB,0BAA0B,QAAQ;AAAA,IAC9D,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc,QAAQ,eAAe,QAAQ;AACnD,QAAM,OAAO,QAAQ;AACrB,QAAM,UAAU,QAAQ;AACxB,QAAM,YAAY,OAAO,SAAS,YAAY,OAAO,YAAY;AACjE,QAAM,uBAAuB,aAAa,UAAU;AAEpD,SACE,qBAAC,SAAI,WAAU,6NACb;AAAA,yBAAC,SAAI,WAAU,+BACb;AAAA,2BAAC,SAAI,WAAU,yEACb;AAAA,4BAAC,iBAAc,WAAU,UAAS,eAAY,QAAO;AAAA,QACrD,oBAAC,UAAM,YAAE,kCAAkC,GAAE;AAAA,SAC/C;AAAA,MACA,oBAAC,OAAE,WAAU,sCACV,YAAE,wCAAwC,GAC7C;AAAA,MACA,oBAAC,OAAE,WAAU,oDACV,YAAE,qCAAqC,EAAE,QAAQ,YAAY,CAAC,GACjE;AAAA,MACC,aACC,oBAAC,OAAE,WAAU,oDACV,iCACG,EAAE,4CAA4C,EAAE,SAAS,OAAO,KAAK,CAAC,IACtE,EAAE,qCAAqC,EAAE,SAAS,OAAO,KAAK,CAAC,GACrE;AAAA,MAED,QAAQ,UAAU,YACjB,oBAAC,OAAE,WAAU,oDACV,YAAE,wCAAwC,GAC7C;AAAA,OAEJ;AAAA,IACA,qBAAC,SAAI,WAAU,qCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAO;AAAA,UACP,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,WAAU;AAAA,UAEV,8BAAC,QAAK,MAAM,mBACT,YAAE,mCAAmC,GACxC;AAAA;AAAA,MACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,MAAM,2BAA2B;AAAA,UAC1C,WAAU;AAAA,UACV,cAAY,EAAE,4BAA4B;AAAA,UAE1C;AAAA,gCAAC,KAAE,WAAU,eAAc,eAAY,QAAO;AAAA,YAC7C,EAAE,4BAA4B;AAAA;AAAA;AAAA,MACjC;AAAA,OACF;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { usePathname, useSearchParams } from 'next/navigation'\nimport { AlertTriangle, X } from 'lucide-react'\nimport { Button } from '../../primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { buildHrefWithReturnTo } from '@open-mercato/shared/lib/navigation/returnTo'\nimport { dismissPartialIndexWarning, usePartialIndexWarning } from './store'\n\nexport function PartialIndexBanner() {\n const t = useT()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const warning = usePartialIndexWarning()\n\n const returnTo = React.useMemo(() => {\n const query = searchParams?.toString() ?? ''\n if (!pathname) return null\n return query.length ? `${pathname}?${query}` : pathname\n }, [pathname, searchParams])\n const manageIndexesHref = React.useMemo(\n () => buildHrefWithReturnTo('/backend/query-indexes', returnTo),\n [returnTo],\n )\n\n if (!warning) return null\n\n const entityLabel = warning.entityLabel || warning.entity\n const base = warning.baseCount\n const indexed = warning.indexedCount\n const hasCounts = typeof base === 'number' && typeof indexed === 'number'\n const hasExcessIndexedRows = hasCounts && indexed > base\n\n return (\n <div className=\"mb-4 flex flex-col gap-3 rounded-md border border-status-warning-border bg-status-warning-bg px-3 py-3 text-sm text-status-warning-text md:flex-row md:items-center md:justify-between\">\n <div className=\"flex flex-col gap-2 text-sm\">\n <div className=\"flex items-center gap-2 font-medium text-status-warning-text\">\n <AlertTriangle className=\"size-4\" aria-hidden=\"true\" />\n <span>{t('query_index.banner.partial_title')}</span>\n </div>\n <p className=\"text-status-warning-text\">\n {t('query_index.banner.partial_description')}\n </p>\n <p className=\"text-xs text-status-warning-text\">\n {t('query_index.banner.partial_entity', { entity: entityLabel })}\n </p>\n {hasCounts && (\n <p className=\"text-xs text-status-warning-text\">\n {hasExcessIndexedRows\n ? t('query_index.banner.partial_counts_excess', { indexed, total: base })\n : t('query_index.banner.partial_counts', { indexed, total: base })}\n </p>\n )}\n {warning.scope === 'global' && (\n <p className=\"text-xs text-status-warning-text\">\n {t('query_index.banner.partial_global_note')}\n </p>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n asChild\n variant=\"outline\"\n size=\"sm\"\n className=\"border-status-warning-border text-status-warning-text hover:bg-status-warning-bg\"\n >\n <Link href={manageIndexesHref}>\n {t('query_index.banner.manage_indexes')}\n </Link>\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n type=\"button\"\n onClick={() => dismissPartialIndexWarning()}\n className=\"text-status-warning-text hover:bg-status-warning-bg\"\n aria-label={t('query_index.banner.dismiss')}\n >\n <X className=\"mr-1 size-4\" aria-hidden=\"true\" />\n {t('query_index.banner.dismiss')}\n </Button>\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": ";AAqCQ,SACE,KADF;AApCR,YAAY,WAAW;AACvB,OAAO,UAAU;AACjB,SAAS,aAAa,uBAAuB;AAC7C,SAAS,eAAe,SAAS;AACjC,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,6BAA6B;AACtC,SAAS,4BAA4B,8BAA8B;AAE5D,SAAS,qBAAqB;AACnC,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,YAAY;AAC7B,QAAM,eAAe,gBAAgB;AACrC,QAAM,UAAU,uBAAuB;AAEvC,QAAM,WAAW,MAAM,QAAQ,MAAM;AACnC,UAAM,QAAQ,cAAc,SAAS,KAAK;AAC1C,QAAI,CAAC,SAAU,QAAO;AACtB,WAAO,MAAM,SAAS,GAAG,QAAQ,IAAI,KAAK,KAAK;AAAA,EACjD,GAAG,CAAC,UAAU,YAAY,CAAC;AAC3B,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAM,sBAAsB,0BAA0B,QAAQ;AAAA,IAC9D,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc,QAAQ,eAAe,QAAQ;AACnD,QAAM,OAAO,QAAQ;AACrB,QAAM,UAAU,QAAQ;AACxB,QAAM,YAAY,OAAO,SAAS,YAAY,OAAO,YAAY;AACjE,QAAM,uBAAuB,aAAa,UAAU;AAEpD,SACE,qBAAC,SAAI,WAAU,0LACb;AAAA,yBAAC,SAAI,WAAU,+BACb;AAAA,2BAAC,SAAI,WAAU,gEACb;AAAA,4BAAC,iBAAc,WAAU,UAAS,eAAY,QAAO;AAAA,QACrD,oBAAC,UAAM,YAAE,kCAAkC,GAAE;AAAA,SAC/C;AAAA,MACA,oBAAC,OAAE,WAAU,4BACV,YAAE,wCAAwC,GAC7C;AAAA,MACA,oBAAC,OAAE,WAAU,oCACV,YAAE,qCAAqC,EAAE,QAAQ,YAAY,CAAC,GACjE;AAAA,MACC,aACC,oBAAC,OAAE,WAAU,oCACV,iCACG,EAAE,4CAA4C,EAAE,SAAS,OAAO,KAAK,CAAC,IACtE,EAAE,qCAAqC,EAAE,SAAS,OAAO,KAAK,CAAC,GACrE;AAAA,MAED,QAAQ,UAAU,YACjB,oBAAC,OAAE,WAAU,oCACV,YAAE,wCAAwC,GAC7C;AAAA,OAEJ;AAAA,IACA,qBAAC,SAAI,WAAU,qCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAO;AAAA,UACP,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,WAAU;AAAA,UAEV,8BAAC,QAAK,MAAM,mBACT,YAAE,mCAAmC,GACxC;AAAA;AAAA,MACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,MAAM,2BAA2B;AAAA,UAC1C,WAAU;AAAA,UACV,cAAY,EAAE,4BAA4B;AAAA,UAE1C;AAAA,gCAAC,KAAE,WAAU,eAAc,eAAY,QAAO;AAAA,YAC7C,EAAE,4BAA4B;AAAA;AAAA;AAAA,MACjC;AAAA,OACF;AAAA,KACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -200,7 +200,7 @@ function ComboboxInput({
200
200
  }
201
201
  }
202
202
  ),
203
- showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && /* @__PURE__ */ jsx("div", { className: "absolute z-50 w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto", children: loading && touched ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-muted-foreground", children: "Loading suggestions\u2026" }) : filteredSuggestions.map((option, index) => /* @__PURE__ */ jsxs(
203
+ showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && /* @__PURE__ */ jsx("div", { className: "absolute z-dropdown w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto", children: loading && touched ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-muted-foreground", children: "Loading suggestions\u2026" }) : filteredSuggestions.map((option, index) => /* @__PURE__ */ jsxs(
204
204
  Button,
205
205
  {
206
206
  type: "button",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/inputs/ComboboxInput.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '../../primitives/button'\n\nexport type ComboboxOption = {\n value: string\n label: string\n description?: string | null\n}\n\nexport type ComboboxInputProps = {\n value: string\n onChange: (next: string) => void\n placeholder?: string\n suggestions?: Array<string | ComboboxOption>\n loadSuggestions?: (query?: string) => Promise<Array<string | ComboboxOption>>\n resolveLabel?: (value: string) => string\n resolveDescription?: (value: string) => string | null | undefined\n autoFocus?: boolean\n disabled?: boolean\n allowCustomValues?: boolean\n}\n\nfunction normalizeOptions(input?: Array<string | ComboboxOption>): ComboboxOption[] {\n if (!Array.isArray(input)) return []\n return input\n .map((option) => {\n if (typeof option === 'string') {\n const trimmed = option.trim()\n if (!trimmed) return null\n return { value: trimmed, label: trimmed }\n }\n const value = typeof option.value === 'string' ? option.value.trim() : ''\n if (!value) return null\n return {\n value,\n label: option.label?.trim() || value,\n description: option.description ?? null,\n }\n })\n .filter((option): option is ComboboxOption => !!option)\n}\n\nexport function ComboboxInput({\n value,\n onChange,\n placeholder,\n suggestions,\n loadSuggestions,\n resolveLabel,\n resolveDescription,\n autoFocus,\n disabled = false,\n allowCustomValues = true,\n}: ComboboxInputProps) {\n const [input, setInput] = React.useState('')\n const [asyncOptions, setAsyncOptions] = React.useState<ComboboxOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const [touched, setTouched] = React.useState(false)\n const [showSuggestions, setShowSuggestions] = React.useState(false)\n const [selectedIndex, setSelectedIndex] = React.useState(-1)\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n const staticOptions = React.useMemo(() => normalizeOptions(suggestions), [suggestions])\n\n const optionMap = React.useMemo(() => {\n const map = new Map<string, ComboboxOption>()\n const register = (option: ComboboxOption) => {\n if (!map.has(option.value)) {\n map.set(option.value, option)\n }\n }\n staticOptions.forEach(register)\n asyncOptions.forEach(register)\n if (value) {\n const existing = map.get(value)\n if (!existing) {\n map.set(value, {\n value,\n label: resolveLabel?.(value) ?? value,\n description: resolveDescription?.(value) ?? null,\n })\n }\n }\n return map\n }, [asyncOptions, resolveDescription, resolveLabel, staticOptions, value])\n\n const availableOptions = React.useMemo(() => {\n return Array.from(optionMap.values())\n }, [optionMap])\n\n const filteredSuggestions = React.useMemo(() => {\n const query = input.toLowerCase().trim()\n if (!query) return availableOptions\n return availableOptions.filter((option) => {\n const labelMatch = option.label.toLowerCase().includes(query)\n const descMatch = option.description?.toLowerCase().includes(query)\n return labelMatch || Boolean(descMatch)\n })\n }, [availableOptions, input])\n\n React.useEffect(() => {\n if (!loadSuggestions || !touched || disabled) return\n const query = input.trim()\n let cancelled = false\n const handle = window.setTimeout(async () => {\n setLoading(true)\n try {\n const items = await loadSuggestions(query)\n if (!cancelled) {\n setAsyncOptions(normalizeOptions(items))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n window.clearTimeout(handle)\n }\n }, [disabled, input, loadSuggestions, touched])\n\n // Sync input with value when value changes externally and input is not focused\n React.useEffect(() => {\n if (document.activeElement !== inputRef.current) {\n const option = optionMap.get(value)\n setInput(option?.label ?? value ?? '')\n }\n }, [value, optionMap])\n\n const selectValue = React.useCallback(\n (nextValue: string) => {\n if (disabled) return\n const trimmed = nextValue.trim()\n onChange(trimmed)\n const option = optionMap.get(trimmed)\n setInput(option?.label ?? trimmed)\n setShowSuggestions(false)\n setSelectedIndex(-1)\n },\n [disabled, onChange, optionMap]\n )\n\n const findOptionForInput = React.useCallback(\n (raw: string): ComboboxOption | null => {\n const query = raw.trim().toLowerCase()\n if (!query) return null\n for (const option of optionMap.values()) {\n if (option.value === raw.trim()) return option\n if (option.label.toLowerCase() === query) return option\n }\n return null\n },\n [optionMap]\n )\n\n const confirmSelection = React.useCallback(\n (raw: string) => {\n if (disabled) return\n const option = findOptionForInput(raw)\n if (option) {\n selectValue(option.value)\n return\n }\n if (!allowCustomValues) {\n // Revert to current value if custom values not allowed\n const currentOption = optionMap.get(value)\n setInput(currentOption?.label ?? value ?? '')\n setShowSuggestions(false)\n return\n }\n selectValue(raw)\n },\n [allowCustomValues, disabled, findOptionForInput, optionMap, selectValue, value]\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showSuggestions) {\n setShowSuggestions(true)\n setSelectedIndex(0)\n } else {\n setSelectedIndex((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n setSelectedIndex((prev) => Math.max(prev - 1, -1))\n } else if (event.key === 'Enter') {\n event.preventDefault()\n if (selectedIndex >= 0 && filteredSuggestions[selectedIndex]) {\n selectValue(filteredSuggestions[selectedIndex].value)\n } else {\n confirmSelection(input)\n }\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setShowSuggestions(false)\n setSelectedIndex(-1)\n }\n },\n [confirmSelection, disabled, filteredSuggestions, input, selectValue, selectedIndex, showSuggestions]\n )\n\n return (\n <div className=\"relative w-full\">\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full h-9 rounded border px-2 text-sm disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed\"\n value={input}\n placeholder={placeholder || 'Type to search...'}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n onFocus={() => {\n setTouched(true)\n setShowSuggestions(true)\n }}\n onChange={(event) => {\n setTouched(true)\n setInput(event.target.value)\n setShowSuggestions(true)\n setSelectedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n onBlur={() => {\n // Delay to allow click on suggestions\n setTimeout(() => {\n if (disabled) return\n confirmSelection(input)\n }, 200)\n }}\n />\n\n {showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && (\n <div className=\"absolute z-50 w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto\">\n {loading && touched ? (\n <div className=\"px-3 py-2 text-xs text-muted-foreground\">Loading suggestions\u2026</div>\n ) : (\n filteredSuggestions.map((option, index) => (\n <Button\n key={option.value}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={[\n 'w-full h-auto justify-start font-normal text-left flex flex-col items-start px-3 py-2',\n index === selectedIndex ? 'bg-accent' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectValue(option.value)}\n onMouseEnter={() => setSelectedIndex(index)}\n >\n <span className=\"font-medium\">{option.label}</span>\n {option.description ? (\n <span className=\"text-xs text-muted-foreground\">{option.description}</span>\n ) : null}\n </Button>\n ))\n )}\n </div>\n )}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '../../primitives/button'\n\nexport type ComboboxOption = {\n value: string\n label: string\n description?: string | null\n}\n\nexport type ComboboxInputProps = {\n value: string\n onChange: (next: string) => void\n placeholder?: string\n suggestions?: Array<string | ComboboxOption>\n loadSuggestions?: (query?: string) => Promise<Array<string | ComboboxOption>>\n resolveLabel?: (value: string) => string\n resolveDescription?: (value: string) => string | null | undefined\n autoFocus?: boolean\n disabled?: boolean\n allowCustomValues?: boolean\n}\n\nfunction normalizeOptions(input?: Array<string | ComboboxOption>): ComboboxOption[] {\n if (!Array.isArray(input)) return []\n return input\n .map((option) => {\n if (typeof option === 'string') {\n const trimmed = option.trim()\n if (!trimmed) return null\n return { value: trimmed, label: trimmed }\n }\n const value = typeof option.value === 'string' ? option.value.trim() : ''\n if (!value) return null\n return {\n value,\n label: option.label?.trim() || value,\n description: option.description ?? null,\n }\n })\n .filter((option): option is ComboboxOption => !!option)\n}\n\nexport function ComboboxInput({\n value,\n onChange,\n placeholder,\n suggestions,\n loadSuggestions,\n resolveLabel,\n resolveDescription,\n autoFocus,\n disabled = false,\n allowCustomValues = true,\n}: ComboboxInputProps) {\n const [input, setInput] = React.useState('')\n const [asyncOptions, setAsyncOptions] = React.useState<ComboboxOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const [touched, setTouched] = React.useState(false)\n const [showSuggestions, setShowSuggestions] = React.useState(false)\n const [selectedIndex, setSelectedIndex] = React.useState(-1)\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n const staticOptions = React.useMemo(() => normalizeOptions(suggestions), [suggestions])\n\n const optionMap = React.useMemo(() => {\n const map = new Map<string, ComboboxOption>()\n const register = (option: ComboboxOption) => {\n if (!map.has(option.value)) {\n map.set(option.value, option)\n }\n }\n staticOptions.forEach(register)\n asyncOptions.forEach(register)\n if (value) {\n const existing = map.get(value)\n if (!existing) {\n map.set(value, {\n value,\n label: resolveLabel?.(value) ?? value,\n description: resolveDescription?.(value) ?? null,\n })\n }\n }\n return map\n }, [asyncOptions, resolveDescription, resolveLabel, staticOptions, value])\n\n const availableOptions = React.useMemo(() => {\n return Array.from(optionMap.values())\n }, [optionMap])\n\n const filteredSuggestions = React.useMemo(() => {\n const query = input.toLowerCase().trim()\n if (!query) return availableOptions\n return availableOptions.filter((option) => {\n const labelMatch = option.label.toLowerCase().includes(query)\n const descMatch = option.description?.toLowerCase().includes(query)\n return labelMatch || Boolean(descMatch)\n })\n }, [availableOptions, input])\n\n React.useEffect(() => {\n if (!loadSuggestions || !touched || disabled) return\n const query = input.trim()\n let cancelled = false\n const handle = window.setTimeout(async () => {\n setLoading(true)\n try {\n const items = await loadSuggestions(query)\n if (!cancelled) {\n setAsyncOptions(normalizeOptions(items))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n window.clearTimeout(handle)\n }\n }, [disabled, input, loadSuggestions, touched])\n\n // Sync input with value when value changes externally and input is not focused\n React.useEffect(() => {\n if (document.activeElement !== inputRef.current) {\n const option = optionMap.get(value)\n setInput(option?.label ?? value ?? '')\n }\n }, [value, optionMap])\n\n const selectValue = React.useCallback(\n (nextValue: string) => {\n if (disabled) return\n const trimmed = nextValue.trim()\n onChange(trimmed)\n const option = optionMap.get(trimmed)\n setInput(option?.label ?? trimmed)\n setShowSuggestions(false)\n setSelectedIndex(-1)\n },\n [disabled, onChange, optionMap]\n )\n\n const findOptionForInput = React.useCallback(\n (raw: string): ComboboxOption | null => {\n const query = raw.trim().toLowerCase()\n if (!query) return null\n for (const option of optionMap.values()) {\n if (option.value === raw.trim()) return option\n if (option.label.toLowerCase() === query) return option\n }\n return null\n },\n [optionMap]\n )\n\n const confirmSelection = React.useCallback(\n (raw: string) => {\n if (disabled) return\n const option = findOptionForInput(raw)\n if (option) {\n selectValue(option.value)\n return\n }\n if (!allowCustomValues) {\n // Revert to current value if custom values not allowed\n const currentOption = optionMap.get(value)\n setInput(currentOption?.label ?? value ?? '')\n setShowSuggestions(false)\n return\n }\n selectValue(raw)\n },\n [allowCustomValues, disabled, findOptionForInput, optionMap, selectValue, value]\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showSuggestions) {\n setShowSuggestions(true)\n setSelectedIndex(0)\n } else {\n setSelectedIndex((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n setSelectedIndex((prev) => Math.max(prev - 1, -1))\n } else if (event.key === 'Enter') {\n event.preventDefault()\n if (selectedIndex >= 0 && filteredSuggestions[selectedIndex]) {\n selectValue(filteredSuggestions[selectedIndex].value)\n } else {\n confirmSelection(input)\n }\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setShowSuggestions(false)\n setSelectedIndex(-1)\n }\n },\n [confirmSelection, disabled, filteredSuggestions, input, selectValue, selectedIndex, showSuggestions]\n )\n\n return (\n <div className=\"relative w-full\">\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full h-9 rounded border px-2 text-sm disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed\"\n value={input}\n placeholder={placeholder || 'Type to search...'}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n onFocus={() => {\n setTouched(true)\n setShowSuggestions(true)\n }}\n onChange={(event) => {\n setTouched(true)\n setInput(event.target.value)\n setShowSuggestions(true)\n setSelectedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n onBlur={() => {\n // Delay to allow click on suggestions\n setTimeout(() => {\n if (disabled) return\n confirmSelection(input)\n }, 200)\n }}\n />\n\n {showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && (\n <div className=\"absolute z-dropdown w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto\">\n {loading && touched ? (\n <div className=\"px-3 py-2 text-xs text-muted-foreground\">Loading suggestions\u2026</div>\n ) : (\n filteredSuggestions.map((option, index) => (\n <Button\n key={option.value}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={[\n 'w-full h-auto justify-start font-normal text-left flex flex-col items-start px-3 py-2',\n index === selectedIndex ? 'bg-accent' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectValue(option.value)}\n onMouseEnter={() => setSelectedIndex(index)}\n >\n <span className=\"font-medium\">{option.label}</span>\n {option.description ? (\n <span className=\"text-xs text-muted-foreground\">{option.description}</span>\n ) : null}\n </Button>\n ))\n )}\n </div>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -94,7 +94,7 @@ function DatePicker({
94
94
  className: cn(
95
95
  "w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left",
96
96
  "bg-background transition-colors",
97
- "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1",
97
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
98
98
  "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
99
99
  readOnly && "cursor-default opacity-70",
100
100
  !formattedValue && "text-muted-foreground",
@@ -125,7 +125,7 @@ function DatePicker({
125
125
  {
126
126
  type: "button",
127
127
  onClick: handleToday,
128
- className: "text-sm text-primary hover:underline focus:outline-none",
128
+ className: "text-sm text-primary hover:underline focus-visible:outline-none",
129
129
  children: todayText
130
130
  }
131
131
  ),
@@ -134,7 +134,7 @@ function DatePicker({
134
134
  {
135
135
  type: "button",
136
136
  onClick: handleClear,
137
- className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus:outline-none ml-auto",
137
+ className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto",
138
138
  children: clearText
139
139
  }
140
140
  )
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/inputs/DatePicker.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../primitives/popover'\nimport { Calendar } from '../../primitives/calendar'\n\nexport type DatePickerProps = {\n value?: Date | null\n onChange: (date: Date | null) => void\n placeholder?: string\n disabled?: boolean\n readOnly?: boolean\n className?: string\n locale?: Locale\n displayFormat?: string\n showTodayButton?: boolean\n showClearButton?: boolean\n closeOnSelect?: boolean\n minDate?: Date\n maxDate?: Date\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDisplayFormat(locale?: Locale): string {\n if (!locale) return 'MMM d, yyyy'\n const code = locale.code?.split('-')[0]?.toLowerCase() ?? ''\n return DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n}\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n className,\n locale,\n displayFormat,\n showTodayButton = true,\n showClearButton = true,\n closeOnSelect = true,\n minDate,\n maxDate,\n}: DatePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n\n const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale)\n const placeholderText = placeholder ?? t('ui.datePicker.placeholder', 'Pick a date')\n const todayText = t('ui.datePicker.todayButton', 'Today')\n const clearText = t('ui.datePicker.clearButton', 'Clear')\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n try {\n return format(value, resolvedFormat, locale ? { locale } : undefined)\n } catch {\n return null\n }\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day) return\n const next = new Date(day)\n next.setHours(0, 0, 0, 0)\n onChange(next)\n if (closeOnSelect) setOpen(false)\n },\n [onChange, closeOnSelect]\n )\n\n const handleToday = React.useCallback(() => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n onChange(today)\n setOpen(false)\n }, [onChange])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const isInteractive = !disabled && !readOnly\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-crud-focus-target=\"\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n className={cn(\n 'w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left',\n 'bg-background transition-colors',\n 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1',\n 'disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed',\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className\n )}\n onClick={isInteractive ? undefined : (e) => e.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0 w-auto\">\n <Calendar\n mode=\"single\"\n selected={value ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n {(showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2 border-t px-3 py-2\">\n {showTodayButton && (\n <button\n type=\"button\"\n onClick={handleToday}\n className=\"text-sm text-primary hover:underline focus:outline-none\"\n >\n {todayText}\n </button>\n )}\n {showClearButton && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"text-sm text-muted-foreground hover:text-foreground hover:underline focus:outline-none ml-auto\"\n >\n {clearText}\n </button>\n )}\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../primitives/popover'\nimport { Calendar } from '../../primitives/calendar'\n\nexport type DatePickerProps = {\n value?: Date | null\n onChange: (date: Date | null) => void\n placeholder?: string\n disabled?: boolean\n readOnly?: boolean\n className?: string\n locale?: Locale\n displayFormat?: string\n showTodayButton?: boolean\n showClearButton?: boolean\n closeOnSelect?: boolean\n minDate?: Date\n maxDate?: Date\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDisplayFormat(locale?: Locale): string {\n if (!locale) return 'MMM d, yyyy'\n const code = locale.code?.split('-')[0]?.toLowerCase() ?? ''\n return DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n}\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n className,\n locale,\n displayFormat,\n showTodayButton = true,\n showClearButton = true,\n closeOnSelect = true,\n minDate,\n maxDate,\n}: DatePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n\n const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale)\n const placeholderText = placeholder ?? t('ui.datePicker.placeholder', 'Pick a date')\n const todayText = t('ui.datePicker.todayButton', 'Today')\n const clearText = t('ui.datePicker.clearButton', 'Clear')\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n try {\n return format(value, resolvedFormat, locale ? { locale } : undefined)\n } catch {\n return null\n }\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day) return\n const next = new Date(day)\n next.setHours(0, 0, 0, 0)\n onChange(next)\n if (closeOnSelect) setOpen(false)\n },\n [onChange, closeOnSelect]\n )\n\n const handleToday = React.useCallback(() => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n onChange(today)\n setOpen(false)\n }, [onChange])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const isInteractive = !disabled && !readOnly\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-crud-focus-target=\"\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n className={cn(\n 'w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left',\n 'bg-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed',\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className\n )}\n onClick={isInteractive ? undefined : (e) => e.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0 w-auto\">\n <Calendar\n mode=\"single\"\n selected={value ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n {(showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2 border-t px-3 py-2\">\n {showTodayButton && (\n <button\n type=\"button\"\n onClick={handleToday}\n className=\"text-sm text-primary hover:underline focus-visible:outline-none\"\n >\n {todayText}\n </button>\n )}\n {showClearButton && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto\"\n >\n {clearText}\n </button>\n )}\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
5
  "mappings": ";AAyGQ,SAgBE,KAhBF;AAvGR,YAAY,WAAW;AACvB,SAAS,cAAc;AAEvB,SAAS,oBAAoB;AAC7B,SAAS,UAAU;AACnB,SAAS,YAAY;AACrB,SAAS,SAAS,gBAAgB,sBAAsB;AACxD,SAAS,gBAAgB;AAkBzB,MAAM,yBAAyB,oBAAI,IAAI;AAAA,EACrC;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AACpE,CAAC;AAED,SAAS,oBAAoB,QAAyB;AACpD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY,KAAK;AAC1D,SAAO,uBAAuB,IAAI,IAAI,IAAI,eAAe;AAC3D;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAE5C,QAAM,iBAAiB,iBAAiB,oBAAoB,MAAM;AAClE,QAAM,kBAAkB,eAAe,EAAE,6BAA6B,aAAa;AACnF,QAAM,YAAY,EAAE,6BAA6B,OAAO;AACxD,QAAM,YAAY,EAAE,6BAA6B,OAAO;AAExD,QAAM,iBAAiB,MAAM,QAAQ,MAAM;AACzC,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI;AACF,aAAO,OAAO,OAAO,gBAAgB,SAAS,EAAE,OAAO,IAAI,MAAS;AAAA,IACtE,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,OAAO,gBAAgB,MAAM,CAAC;AAElC,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,QAA0B;AACzB,UAAI,CAAC,IAAK;AACV,YAAM,OAAO,IAAI,KAAK,GAAG;AACzB,WAAK,SAAS,GAAG,GAAG,GAAG,CAAC;AACxB,eAAS,IAAI;AACb,UAAI,cAAe,SAAQ,KAAK;AAAA,IAClC;AAAA,IACA,CAAC,UAAU,aAAa;AAAA,EAC1B;AAEA,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,UAAM,QAAQ,oBAAI,KAAK;AACvB,UAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AACzB,aAAS,KAAK;AACd,YAAQ,KAAK;AAAA,EACf,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,aAAS,IAAI;AACb,YAAQ,KAAK;AAAA,EACf,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,gBAAgB,CAAC,YAAY,CAAC;AAEpC,QAAM,kBAAkB,MAAM,QAAQ,MAAM;AAC1C,QAAI,CAAC,WAAW,CAAC,QAAS,QAAO;AACjC,UAAM,WAAiD,CAAC;AACxD,QAAI,QAAS,UAAS,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAC9C,QAAI,QAAS,UAAS,KAAK,EAAE,OAAO,QAAQ,CAAC;AAC7C,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,OAAO,CAAC;AAErB,SACE,qBAAC,WAAQ,MAAY,cAAc,gBAAgB,UAAU,QAC3D;AAAA,wBAAC,kBAAe,SAAO,MACrB;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,0BAAuB;AAAA,QACvB;AAAA,QACA,iBAAc;AAAA,QACd,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ,CAAC,kBAAkB;AAAA,UACnB;AAAA,QACF;AAAA,QACA,SAAS,gBAAgB,SAAY,CAAC,MAAM,EAAE,eAAe;AAAA,QAE7D;AAAA,8BAAC,gBAAa,WAAU,0CAAyC;AAAA,UACjE,oBAAC,UAAK,WAAU,mBACb,4BAAkB,iBACrB;AAAA;AAAA;AAAA,IACF,GACF;AAAA,IACA,qBAAC,kBAAe,WAAU,cACxB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,SAAS;AAAA,UACnB,UAAU;AAAA,UACV;AAAA,UACA,UAAU;AAAA,UACV,cAAY;AAAA;AAAA,MACd;AAAA,OACE,mBAAmB,oBACnB,qBAAC,SAAI,WAAU,8DACZ;AAAA,2BACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,QAED,mBACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,SAEJ;AAAA,OAEJ;AAAA,KACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -118,7 +118,7 @@ function DateTimePicker({
118
118
  className: cn(
119
119
  "w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left",
120
120
  "bg-background transition-colors",
121
- "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1",
121
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
122
122
  "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
123
123
  readOnly && "cursor-default opacity-70",
124
124
  !formattedValue && "text-muted-foreground",
@@ -164,7 +164,7 @@ function DateTimePicker({
164
164
  {
165
165
  type: "button",
166
166
  onClick: handleToday,
167
- className: "text-sm text-primary hover:underline focus:outline-none",
167
+ className: "text-sm text-primary hover:underline focus-visible:outline-none",
168
168
  children: todayText
169
169
  }
170
170
  ),
@@ -173,7 +173,7 @@ function DateTimePicker({
173
173
  {
174
174
  type: "button",
175
175
  onClick: handleClear,
176
- className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus:outline-none ml-auto",
176
+ className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto",
177
177
  children: clearText
178
178
  }
179
179
  )