@caratlogic/design-system 0.1.31 → 0.1.33

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 (217) hide show
  1. package/dist/components/atoms/ActionButtonWithTooltip/ActionButtonWithTooltip.d.ts.map +1 -1
  2. package/dist/components/atoms/NumberInput/NumberInput.d.ts.map +1 -1
  3. package/dist/components/atoms/NumberInput/NumberInput.types.d.ts +4 -0
  4. package/dist/components/atoms/NumberInput/NumberInput.types.d.ts.map +1 -1
  5. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.d.ts.map +1 -1
  6. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.parts.d.ts +1 -0
  7. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.parts.d.ts.map +1 -1
  8. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.types.d.ts +5 -11
  9. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.types.d.ts.map +1 -1
  10. package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts +1 -1
  11. package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts.map +1 -1
  12. package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts +16 -0
  13. package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts.map +1 -1
  14. package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts +8 -1
  15. package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts.map +1 -1
  16. package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts +20 -0
  17. package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts.map +1 -1
  18. package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts +7 -1
  19. package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts.map +1 -1
  20. package/dist/components/molecules/DocumentDeleteDialog/DocumentDeleteDialog.d.ts +1 -1
  21. package/dist/components/molecules/DocumentDeleteDialog/DocumentDeleteDialog.d.ts.map +1 -1
  22. package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts +8 -3
  23. package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts.map +1 -1
  24. package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts +9 -0
  25. package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts.map +1 -1
  26. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts +3 -0
  27. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts.map +1 -0
  28. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts +6 -0
  29. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts.map +1 -0
  30. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts +16 -0
  31. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts.map +1 -0
  32. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts +7 -0
  33. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts.map +1 -0
  34. package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts +3 -0
  35. package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts.map +1 -0
  36. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts +2 -0
  37. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts.map +1 -0
  38. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts +6 -0
  39. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts.map +1 -0
  40. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts +9 -0
  41. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts.map +1 -0
  42. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts +11 -0
  43. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts.map +1 -0
  44. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts +3 -0
  45. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts.map +1 -0
  46. package/dist/components/molecules/Filters/ContainsFilter/index.d.ts +3 -0
  47. package/dist/components/molecules/Filters/ContainsFilter/index.d.ts.map +1 -0
  48. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts +3 -0
  49. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts.map +1 -0
  50. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts +6 -0
  51. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts.map +1 -0
  52. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts +11 -0
  53. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts.map +1 -0
  54. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts +10 -0
  55. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts.map +1 -0
  56. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts +11 -0
  57. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts.map +1 -0
  58. package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts +3 -0
  59. package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts.map +1 -0
  60. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts +3 -0
  61. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts.map +1 -0
  62. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts +6 -0
  63. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts.map +1 -0
  64. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts +24 -0
  65. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts.map +1 -0
  66. package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts +3 -0
  67. package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts.map +1 -0
  68. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts +6 -0
  69. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts.map +1 -0
  70. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts +14 -0
  71. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts.map +1 -0
  72. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts +5 -0
  73. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts.map +1 -0
  74. package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts +3 -0
  75. package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts.map +1 -0
  76. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts +6 -0
  77. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts.map +1 -0
  78. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts +28 -0
  79. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts.map +1 -0
  80. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts +4 -0
  81. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts.map +1 -0
  82. package/dist/components/molecules/Filters/FilterPanel/index.d.ts +3 -0
  83. package/dist/components/molecules/Filters/FilterPanel/index.d.ts.map +1 -0
  84. package/dist/components/molecules/Filters/Filters.hooks.d.ts +20 -0
  85. package/dist/components/molecules/Filters/Filters.hooks.d.ts.map +1 -0
  86. package/dist/components/molecules/Filters/Filters.types.d.ts +66 -0
  87. package/dist/components/molecules/Filters/Filters.types.d.ts.map +1 -0
  88. package/dist/components/molecules/Filters/Filters.utils.d.ts +53 -0
  89. package/dist/components/molecules/Filters/Filters.utils.d.ts.map +1 -0
  90. package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts +2 -0
  91. package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts.map +1 -0
  92. package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts +6 -0
  93. package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts.map +1 -0
  94. package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts +10 -0
  95. package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts.map +1 -0
  96. package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts +10 -0
  97. package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts.map +1 -0
  98. package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts +4 -0
  99. package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts.map +1 -0
  100. package/dist/components/molecules/Filters/IdListInput/index.d.ts +3 -0
  101. package/dist/components/molecules/Filters/IdListInput/index.d.ts.map +1 -0
  102. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts +5 -0
  103. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts.map +1 -0
  104. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts +6 -0
  105. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts.map +1 -0
  106. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts +16 -0
  107. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts.map +1 -0
  108. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts +14 -0
  109. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts.map +1 -0
  110. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts +8 -0
  111. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts.map +1 -0
  112. package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts +3 -0
  113. package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts.map +1 -0
  114. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts +3 -0
  115. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts.map +1 -0
  116. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts +6 -0
  117. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts.map +1 -0
  118. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts +15 -0
  119. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts.map +1 -0
  120. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts +17 -0
  121. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts.map +1 -0
  122. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts +12 -0
  123. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts.map +1 -0
  124. package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts +3 -0
  125. package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts.map +1 -0
  126. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts +2 -0
  127. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts.map +1 -0
  128. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts +6 -0
  129. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts.map +1 -0
  130. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts +3 -0
  131. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts.map +1 -0
  132. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts +32 -0
  133. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts.map +1 -0
  134. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts +19 -0
  135. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts.map +1 -0
  136. package/dist/components/molecules/Filters/PickListFilter/index.d.ts +3 -0
  137. package/dist/components/molecules/Filters/PickListFilter/index.d.ts.map +1 -0
  138. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts +6 -0
  139. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts.map +1 -0
  140. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts +4 -0
  141. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts.map +1 -0
  142. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts +22 -0
  143. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts.map +1 -0
  144. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts +7 -0
  145. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts.map +1 -0
  146. package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts +3 -0
  147. package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts.map +1 -0
  148. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts +6 -0
  149. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts.map +1 -0
  150. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts +7 -0
  151. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts.map +1 -0
  152. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts +15 -0
  153. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts.map +1 -0
  154. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts +4 -0
  155. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts.map +1 -0
  156. package/dist/components/molecules/Filters/ScrollFade/index.d.ts +3 -0
  157. package/dist/components/molecules/Filters/ScrollFade/index.d.ts.map +1 -0
  158. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts +6 -0
  159. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts.map +1 -0
  160. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts +6 -0
  161. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts.map +1 -0
  162. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts +7 -0
  163. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts.map +1 -0
  164. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts +3 -0
  165. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts.map +1 -0
  166. package/dist/components/molecules/Filters/TriStateFilter/index.d.ts +3 -0
  167. package/dist/components/molecules/Filters/TriStateFilter/index.d.ts.map +1 -0
  168. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts +6 -0
  169. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts.map +1 -0
  170. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts +5 -0
  171. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts.map +1 -0
  172. package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts +3 -0
  173. package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts.map +1 -0
  174. package/dist/components/molecules/Filters/index.d.ts +17 -0
  175. package/dist/components/molecules/Filters/index.d.ts.map +1 -0
  176. package/dist/components/molecules/InventoryFilterSelects.d.ts.map +1 -1
  177. package/dist/components/molecules/Modal/Modal.d.ts +1 -1
  178. package/dist/components/molecules/Modal/Modal.d.ts.map +1 -1
  179. package/dist/components/molecules/Modal/Modal.types.d.ts +9 -3
  180. package/dist/components/molecules/Modal/Modal.types.d.ts.map +1 -1
  181. package/dist/components/organisms/FileUploader/ImageCropModal.d.ts.map +1 -1
  182. package/dist/components/organisms/Filters/FilterField/FilterField.d.ts +11 -0
  183. package/dist/components/organisms/Filters/FilterField/FilterField.d.ts.map +1 -0
  184. package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts +66 -0
  185. package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts.map +1 -0
  186. package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts +38 -0
  187. package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts.map +1 -0
  188. package/dist/components/organisms/Filters/FilterField/index.d.ts +4 -0
  189. package/dist/components/organisms/Filters/FilterField/index.d.ts.map +1 -0
  190. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts +4 -0
  191. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts.map +1 -0
  192. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts +9 -0
  193. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts.map +1 -0
  194. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts +6 -0
  195. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts.map +1 -0
  196. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts +26 -0
  197. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts.map +1 -0
  198. package/dist/components/organisms/Filters/FilterSurface/index.d.ts +3 -0
  199. package/dist/components/organisms/Filters/FilterSurface/index.d.ts.map +1 -0
  200. package/dist/components/organisms/Filters/index.d.ts +3 -0
  201. package/dist/components/organisms/Filters/index.d.ts.map +1 -0
  202. package/dist/components/ui/button.d.ts.map +1 -1
  203. package/dist/components/ui/dialog.d.ts +23 -2
  204. package/dist/components/ui/dialog.d.ts.map +1 -1
  205. package/dist/index.cjs.js +1617 -353
  206. package/dist/index.cjs.js.map +1 -1
  207. package/dist/index.d.ts +2 -0
  208. package/dist/index.d.ts.map +1 -1
  209. package/dist/index.esm.js +1578 -355
  210. package/dist/index.esm.js.map +1 -1
  211. package/dist/ui.cjs.js +60 -14
  212. package/dist/ui.cjs.js.map +1 -1
  213. package/dist/ui.esm.js +59 -15
  214. package/dist/ui.esm.js.map +1 -1
  215. package/package.json +1 -1
  216. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.hooks.d.ts +0 -3
  217. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.hooks.d.ts.map +0 -1
package/dist/index.cjs.js CHANGED
@@ -2698,12 +2698,12 @@ const createLucideIcon = (iconName, iconNode) => {
2698
2698
  */
2699
2699
 
2700
2700
 
2701
- const __iconNode$1s = [
2701
+ const __iconNode$1v = [
2702
2702
  ["path", { d: "M15 12H3", key: "6jk70r" }],
2703
2703
  ["path", { d: "M17 18H3", key: "1amg6g" }],
2704
2704
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
2705
2705
  ];
2706
- const AlignLeft = createLucideIcon("align-left", __iconNode$1s);
2706
+ const AlignLeft = createLucideIcon("align-left", __iconNode$1v);
2707
2707
 
2708
2708
  /**
2709
2709
  * @license lucide-react v0.539.0 - ISC
@@ -2713,12 +2713,12 @@ const AlignLeft = createLucideIcon("align-left", __iconNode$1s);
2713
2713
  */
2714
2714
 
2715
2715
 
2716
- const __iconNode$1r = [
2716
+ const __iconNode$1u = [
2717
2717
  ["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
2718
2718
  ["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
2719
2719
  ["path", { d: "M10 12h4", key: "a56b0p" }]
2720
2720
  ];
2721
- const Archive = createLucideIcon("archive", __iconNode$1r);
2721
+ const Archive = createLucideIcon("archive", __iconNode$1u);
2722
2722
 
2723
2723
  /**
2724
2724
  * @license lucide-react v0.539.0 - ISC
@@ -2728,11 +2728,11 @@ const Archive = createLucideIcon("archive", __iconNode$1r);
2728
2728
  */
2729
2729
 
2730
2730
 
2731
- const __iconNode$1q = [
2731
+ const __iconNode$1t = [
2732
2732
  ["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
2733
2733
  ["path", { d: "M19 12H5", key: "x3x0zl" }]
2734
2734
  ];
2735
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1q);
2735
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1t);
2736
2736
 
2737
2737
  /**
2738
2738
  * @license lucide-react v0.539.0 - ISC
@@ -2742,11 +2742,11 @@ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1q);
2742
2742
  */
2743
2743
 
2744
2744
 
2745
- const __iconNode$1p = [
2745
+ const __iconNode$1s = [
2746
2746
  ["path", { d: "M5 12h14", key: "1ays0h" }],
2747
2747
  ["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
2748
2748
  ];
2749
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$1p);
2749
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$1s);
2750
2750
 
2751
2751
  /**
2752
2752
  * @license lucide-react v0.539.0 - ISC
@@ -2756,11 +2756,11 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$1p);
2756
2756
  */
2757
2757
 
2758
2758
 
2759
- const __iconNode$1o = [
2759
+ const __iconNode$1r = [
2760
2760
  ["path", { d: "M4.929 4.929 19.07 19.071", key: "196cmz" }],
2761
2761
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
2762
2762
  ];
2763
- const Ban = createLucideIcon("ban", __iconNode$1o);
2763
+ const Ban = createLucideIcon("ban", __iconNode$1r);
2764
2764
 
2765
2765
  /**
2766
2766
  * @license lucide-react v0.539.0 - ISC
@@ -2770,7 +2770,7 @@ const Ban = createLucideIcon("ban", __iconNode$1o);
2770
2770
  */
2771
2771
 
2772
2772
 
2773
- const __iconNode$1n = [
2773
+ const __iconNode$1q = [
2774
2774
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
2775
2775
  [
2776
2776
  "path",
@@ -2781,7 +2781,7 @@ const __iconNode$1n = [
2781
2781
  ],
2782
2782
  ["circle", { cx: "18", cy: "8", r: "3", key: "1g0gzu" }]
2783
2783
  ];
2784
- const BellDot = createLucideIcon("bell-dot", __iconNode$1n);
2784
+ const BellDot = createLucideIcon("bell-dot", __iconNode$1q);
2785
2785
 
2786
2786
  /**
2787
2787
  * @license lucide-react v0.539.0 - ISC
@@ -2791,7 +2791,7 @@ const BellDot = createLucideIcon("bell-dot", __iconNode$1n);
2791
2791
  */
2792
2792
 
2793
2793
 
2794
- const __iconNode$1m = [
2794
+ const __iconNode$1p = [
2795
2795
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
2796
2796
  ["path", { d: "M22 8c0-2.3-.8-4.3-2-6", key: "5bb3ad" }],
2797
2797
  [
@@ -2803,7 +2803,7 @@ const __iconNode$1m = [
2803
2803
  ],
2804
2804
  ["path", { d: "M4 2C2.8 3.7 2 5.7 2 8", key: "tap9e0" }]
2805
2805
  ];
2806
- const BellRing = createLucideIcon("bell-ring", __iconNode$1m);
2806
+ const BellRing = createLucideIcon("bell-ring", __iconNode$1p);
2807
2807
 
2808
2808
  /**
2809
2809
  * @license lucide-react v0.539.0 - ISC
@@ -2813,7 +2813,7 @@ const BellRing = createLucideIcon("bell-ring", __iconNode$1m);
2813
2813
  */
2814
2814
 
2815
2815
 
2816
- const __iconNode$1l = [
2816
+ const __iconNode$1o = [
2817
2817
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
2818
2818
  [
2819
2819
  "path",
@@ -2823,7 +2823,7 @@ const __iconNode$1l = [
2823
2823
  }
2824
2824
  ]
2825
2825
  ];
2826
- const Bell = createLucideIcon("bell", __iconNode$1l);
2826
+ const Bell = createLucideIcon("bell", __iconNode$1o);
2827
2827
 
2828
2828
  /**
2829
2829
  * @license lucide-react v0.539.0 - ISC
@@ -2833,13 +2833,13 @@ const Bell = createLucideIcon("bell", __iconNode$1l);
2833
2833
  */
2834
2834
 
2835
2835
 
2836
- const __iconNode$1k = [
2836
+ const __iconNode$1n = [
2837
2837
  [
2838
2838
  "path",
2839
2839
  { d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8", key: "mg9rjx" }
2840
2840
  ]
2841
2841
  ];
2842
- const Bold$1 = createLucideIcon("bold", __iconNode$1k);
2842
+ const Bold$1 = createLucideIcon("bold", __iconNode$1n);
2843
2843
 
2844
2844
  /**
2845
2845
  * @license lucide-react v0.539.0 - ISC
@@ -2849,7 +2849,7 @@ const Bold$1 = createLucideIcon("bold", __iconNode$1k);
2849
2849
  */
2850
2850
 
2851
2851
 
2852
- const __iconNode$1j = [
2852
+ const __iconNode$1m = [
2853
2853
  [
2854
2854
  "path",
2855
2855
  {
@@ -2860,7 +2860,7 @@ const __iconNode$1j = [
2860
2860
  ["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
2861
2861
  ["path", { d: "M12 22V12", key: "d0xqtd" }]
2862
2862
  ];
2863
- const Box = createLucideIcon("box", __iconNode$1j);
2863
+ const Box = createLucideIcon("box", __iconNode$1m);
2864
2864
 
2865
2865
  /**
2866
2866
  * @license lucide-react v0.539.0 - ISC
@@ -2870,7 +2870,7 @@ const Box = createLucideIcon("box", __iconNode$1j);
2870
2870
  */
2871
2871
 
2872
2872
 
2873
- const __iconNode$1i = [
2873
+ const __iconNode$1l = [
2874
2874
  ["path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z", key: "1b4qmf" }],
2875
2875
  ["path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2", key: "i71pzd" }],
2876
2876
  ["path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2", key: "10jefs" }],
@@ -2879,7 +2879,7 @@ const __iconNode$1i = [
2879
2879
  ["path", { d: "M10 14h4", key: "kelpxr" }],
2880
2880
  ["path", { d: "M10 18h4", key: "1ulq68" }]
2881
2881
  ];
2882
- const Building2 = createLucideIcon("building-2", __iconNode$1i);
2882
+ const Building2 = createLucideIcon("building-2", __iconNode$1l);
2883
2883
 
2884
2884
  /**
2885
2885
  * @license lucide-react v0.539.0 - ISC
@@ -2889,7 +2889,7 @@ const Building2 = createLucideIcon("building-2", __iconNode$1i);
2889
2889
  */
2890
2890
 
2891
2891
 
2892
- const __iconNode$1h = [
2892
+ const __iconNode$1k = [
2893
2893
  ["path", { d: "M8 2v4", key: "1cmpym" }],
2894
2894
  ["path", { d: "M16 2v4", key: "4m81vk" }],
2895
2895
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
@@ -2901,7 +2901,7 @@ const __iconNode$1h = [
2901
2901
  ["path", { d: "M12 18h.01", key: "mhygvu" }],
2902
2902
  ["path", { d: "M16 18h.01", key: "kzsmim" }]
2903
2903
  ];
2904
- const CalendarDays = createLucideIcon("calendar-days", __iconNode$1h);
2904
+ const CalendarDays = createLucideIcon("calendar-days", __iconNode$1k);
2905
2905
 
2906
2906
  /**
2907
2907
  * @license lucide-react v0.539.0 - ISC
@@ -2911,13 +2911,13 @@ const CalendarDays = createLucideIcon("calendar-days", __iconNode$1h);
2911
2911
  */
2912
2912
 
2913
2913
 
2914
- const __iconNode$1g = [
2914
+ const __iconNode$1j = [
2915
2915
  ["path", { d: "M8 2v4", key: "1cmpym" }],
2916
2916
  ["path", { d: "M16 2v4", key: "4m81vk" }],
2917
2917
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
2918
2918
  ["path", { d: "M3 10h18", key: "8toen8" }]
2919
2919
  ];
2920
- const Calendar$1 = createLucideIcon("calendar", __iconNode$1g);
2920
+ const Calendar$1 = createLucideIcon("calendar", __iconNode$1j);
2921
2921
 
2922
2922
  /**
2923
2923
  * @license lucide-react v0.539.0 - ISC
@@ -2927,11 +2927,11 @@ const Calendar$1 = createLucideIcon("calendar", __iconNode$1g);
2927
2927
  */
2928
2928
 
2929
2929
 
2930
- const __iconNode$1f = [
2930
+ const __iconNode$1i = [
2931
2931
  ["path", { d: "M18 6 7 17l-5-5", key: "116fxf" }],
2932
2932
  ["path", { d: "m22 10-7.5 7.5L13 16", key: "ke71qq" }]
2933
2933
  ];
2934
- const CheckCheck = createLucideIcon("check-check", __iconNode$1f);
2934
+ const CheckCheck = createLucideIcon("check-check", __iconNode$1i);
2935
2935
 
2936
2936
  /**
2937
2937
  * @license lucide-react v0.539.0 - ISC
@@ -2941,8 +2941,8 @@ const CheckCheck = createLucideIcon("check-check", __iconNode$1f);
2941
2941
  */
2942
2942
 
2943
2943
 
2944
- const __iconNode$1e = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
2945
- const Check = createLucideIcon("check", __iconNode$1e);
2944
+ const __iconNode$1h = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
2945
+ const Check = createLucideIcon("check", __iconNode$1h);
2946
2946
 
2947
2947
  /**
2948
2948
  * @license lucide-react v0.539.0 - ISC
@@ -2952,8 +2952,8 @@ const Check = createLucideIcon("check", __iconNode$1e);
2952
2952
  */
2953
2953
 
2954
2954
 
2955
- const __iconNode$1d = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
2956
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$1d);
2955
+ const __iconNode$1g = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
2956
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1g);
2957
2957
 
2958
2958
  /**
2959
2959
  * @license lucide-react v0.539.0 - ISC
@@ -2963,8 +2963,8 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1d);
2963
2963
  */
2964
2964
 
2965
2965
 
2966
- const __iconNode$1c = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
2967
- const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1c);
2966
+ const __iconNode$1f = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
2967
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1f);
2968
2968
 
2969
2969
  /**
2970
2970
  * @license lucide-react v0.539.0 - ISC
@@ -2974,8 +2974,8 @@ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1c);
2974
2974
  */
2975
2975
 
2976
2976
 
2977
- const __iconNode$1b = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
2978
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$1b);
2977
+ const __iconNode$1e = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
2978
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1e);
2979
2979
 
2980
2980
  /**
2981
2981
  * @license lucide-react v0.539.0 - ISC
@@ -2985,8 +2985,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1b);
2985
2985
  */
2986
2986
 
2987
2987
 
2988
- const __iconNode$1a = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
2989
- const ChevronUp = createLucideIcon("chevron-up", __iconNode$1a);
2988
+ const __iconNode$1d = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
2989
+ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1d);
2990
2990
 
2991
2991
  /**
2992
2992
  * @license lucide-react v0.539.0 - ISC
@@ -2996,11 +2996,11 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1a);
2996
2996
  */
2997
2997
 
2998
2998
 
2999
- const __iconNode$19 = [
2999
+ const __iconNode$1c = [
3000
3000
  ["path", { d: "m11 17-5-5 5-5", key: "13zhaf" }],
3001
3001
  ["path", { d: "m18 17-5-5 5-5", key: "h8a8et" }]
3002
3002
  ];
3003
- const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$19);
3003
+ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1c);
3004
3004
 
3005
3005
  /**
3006
3006
  * @license lucide-react v0.539.0 - ISC
@@ -3010,11 +3010,11 @@ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$19);
3010
3010
  */
3011
3011
 
3012
3012
 
3013
- const __iconNode$18 = [
3013
+ const __iconNode$1b = [
3014
3014
  ["path", { d: "m6 17 5-5-5-5", key: "xnjwq" }],
3015
3015
  ["path", { d: "m13 17 5-5-5-5", key: "17xmmf" }]
3016
3016
  ];
3017
- const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$18);
3017
+ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$1b);
3018
3018
 
3019
3019
  /**
3020
3020
  * @license lucide-react v0.539.0 - ISC
@@ -3024,12 +3024,12 @@ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$18);
3024
3024
  */
3025
3025
 
3026
3026
 
3027
- const __iconNode$17 = [
3027
+ const __iconNode$1a = [
3028
3028
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3029
3029
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
3030
3030
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
3031
3031
  ];
3032
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$17);
3032
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$1a);
3033
3033
 
3034
3034
  /**
3035
3035
  * @license lucide-react v0.539.0 - ISC
@@ -3039,11 +3039,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$17);
3039
3039
  */
3040
3040
 
3041
3041
 
3042
- const __iconNode$16 = [
3042
+ const __iconNode$19 = [
3043
3043
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
3044
3044
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
3045
3045
  ];
3046
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$16);
3046
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$19);
3047
3047
 
3048
3048
  /**
3049
3049
  * @license lucide-react v0.539.0 - ISC
@@ -3053,11 +3053,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$16);
3053
3053
  */
3054
3054
 
3055
3055
 
3056
- const __iconNode$15 = [
3056
+ const __iconNode$18 = [
3057
3057
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3058
3058
  ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
3059
3059
  ];
3060
- const CircleCheck = createLucideIcon("circle-check", __iconNode$15);
3060
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$18);
3061
3061
 
3062
3062
  /**
3063
3063
  * @license lucide-react v0.539.0 - ISC
@@ -3067,11 +3067,11 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$15);
3067
3067
  */
3068
3068
 
3069
3069
 
3070
- const __iconNode$14 = [
3070
+ const __iconNode$17 = [
3071
3071
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3072
3072
  ["path", { d: "m16 10-4 4-4-4", key: "894hmk" }]
3073
3073
  ];
3074
- const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$14);
3074
+ const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$17);
3075
3075
 
3076
3076
  /**
3077
3077
  * @license lucide-react v0.539.0 - ISC
@@ -3081,11 +3081,11 @@ const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$14)
3081
3081
  */
3082
3082
 
3083
3083
 
3084
- const __iconNode$13 = [
3084
+ const __iconNode$16 = [
3085
3085
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3086
3086
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }]
3087
3087
  ];
3088
- const CircleDot = createLucideIcon("circle-dot", __iconNode$13);
3088
+ const CircleDot = createLucideIcon("circle-dot", __iconNode$16);
3089
3089
 
3090
3090
  /**
3091
3091
  * @license lucide-react v0.539.0 - ISC
@@ -3095,12 +3095,12 @@ const CircleDot = createLucideIcon("circle-dot", __iconNode$13);
3095
3095
  */
3096
3096
 
3097
3097
 
3098
- const __iconNode$12 = [
3098
+ const __iconNode$15 = [
3099
3099
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3100
3100
  ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
3101
3101
  ["path", { d: "m9 9 6 6", key: "z0biqf" }]
3102
3102
  ];
3103
- const CircleX = createLucideIcon("circle-x", __iconNode$12);
3103
+ const CircleX = createLucideIcon("circle-x", __iconNode$15);
3104
3104
 
3105
3105
  /**
3106
3106
  * @license lucide-react v0.539.0 - ISC
@@ -3110,8 +3110,8 @@ const CircleX = createLucideIcon("circle-x", __iconNode$12);
3110
3110
  */
3111
3111
 
3112
3112
 
3113
- const __iconNode$11 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
3114
- const Circle = createLucideIcon("circle", __iconNode$11);
3113
+ const __iconNode$14 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
3114
+ const Circle = createLucideIcon("circle", __iconNode$14);
3115
3115
 
3116
3116
  /**
3117
3117
  * @license lucide-react v0.539.0 - ISC
@@ -3121,11 +3121,11 @@ const Circle = createLucideIcon("circle", __iconNode$11);
3121
3121
  */
3122
3122
 
3123
3123
 
3124
- const __iconNode$10 = [
3124
+ const __iconNode$13 = [
3125
3125
  ["path", { d: "M12 6v6l4 2", key: "mmk7yg" }],
3126
3126
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
3127
3127
  ];
3128
- const Clock = createLucideIcon("clock", __iconNode$10);
3128
+ const Clock = createLucideIcon("clock", __iconNode$13);
3129
3129
 
3130
3130
  /**
3131
3131
  * @license lucide-react v0.539.0 - ISC
@@ -3135,11 +3135,11 @@ const Clock = createLucideIcon("clock", __iconNode$10);
3135
3135
  */
3136
3136
 
3137
3137
 
3138
- const __iconNode$$ = [
3138
+ const __iconNode$12 = [
3139
3139
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
3140
3140
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
3141
3141
  ];
3142
- const Copy = createLucideIcon("copy", __iconNode$$);
3142
+ const Copy = createLucideIcon("copy", __iconNode$12);
3143
3143
 
3144
3144
  /**
3145
3145
  * @license lucide-react v0.539.0 - ISC
@@ -3149,11 +3149,11 @@ const Copy = createLucideIcon("copy", __iconNode$$);
3149
3149
  */
3150
3150
 
3151
3151
 
3152
- const __iconNode$_ = [
3152
+ const __iconNode$11 = [
3153
3153
  ["path", { d: "M6 2v14a2 2 0 0 0 2 2h14", key: "ron5a4" }],
3154
3154
  ["path", { d: "M18 22V8a2 2 0 0 0-2-2H2", key: "7s9ehn" }]
3155
3155
  ];
3156
- const Crop = createLucideIcon("crop", __iconNode$_);
3156
+ const Crop = createLucideIcon("crop", __iconNode$11);
3157
3157
 
3158
3158
  /**
3159
3159
  * @license lucide-react v0.539.0 - ISC
@@ -3163,12 +3163,12 @@ const Crop = createLucideIcon("crop", __iconNode$_);
3163
3163
  */
3164
3164
 
3165
3165
 
3166
- const __iconNode$Z = [
3166
+ const __iconNode$10 = [
3167
3167
  ["path", { d: "M12 15V3", key: "m9g1x1" }],
3168
3168
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
3169
3169
  ["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
3170
3170
  ];
3171
- const Download = createLucideIcon("download", __iconNode$Z);
3171
+ const Download = createLucideIcon("download", __iconNode$10);
3172
3172
 
3173
3173
  /**
3174
3174
  * @license lucide-react v0.539.0 - ISC
@@ -3178,12 +3178,12 @@ const Download = createLucideIcon("download", __iconNode$Z);
3178
3178
  */
3179
3179
 
3180
3180
 
3181
- const __iconNode$Y = [
3181
+ const __iconNode$$ = [
3182
3182
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3183
3183
  ["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
3184
3184
  ["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
3185
3185
  ];
3186
- const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$Y);
3186
+ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$$);
3187
3187
 
3188
3188
  /**
3189
3189
  * @license lucide-react v0.539.0 - ISC
@@ -3193,12 +3193,12 @@ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$Y);
3193
3193
  */
3194
3194
 
3195
3195
 
3196
- const __iconNode$X = [
3196
+ const __iconNode$_ = [
3197
3197
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3198
3198
  ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
3199
3199
  ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
3200
3200
  ];
3201
- const Ellipsis = createLucideIcon("ellipsis", __iconNode$X);
3201
+ const Ellipsis = createLucideIcon("ellipsis", __iconNode$_);
3202
3202
 
3203
3203
  /**
3204
3204
  * @license lucide-react v0.539.0 - ISC
@@ -3208,12 +3208,12 @@ const Ellipsis = createLucideIcon("ellipsis", __iconNode$X);
3208
3208
  */
3209
3209
 
3210
3210
 
3211
- const __iconNode$W = [
3211
+ const __iconNode$Z = [
3212
3212
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3213
3213
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
3214
3214
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
3215
3215
  ];
3216
- const ExternalLink = createLucideIcon("external-link", __iconNode$W);
3216
+ const ExternalLink = createLucideIcon("external-link", __iconNode$Z);
3217
3217
 
3218
3218
  /**
3219
3219
  * @license lucide-react v0.539.0 - ISC
@@ -3223,7 +3223,7 @@ const ExternalLink = createLucideIcon("external-link", __iconNode$W);
3223
3223
  */
3224
3224
 
3225
3225
 
3226
- const __iconNode$V = [
3226
+ const __iconNode$Y = [
3227
3227
  [
3228
3228
  "path",
3229
3229
  {
@@ -3233,7 +3233,7 @@ const __iconNode$V = [
3233
3233
  ],
3234
3234
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
3235
3235
  ];
3236
- const Eye = createLucideIcon("eye", __iconNode$V);
3236
+ const Eye = createLucideIcon("eye", __iconNode$Y);
3237
3237
 
3238
3238
  /**
3239
3239
  * @license lucide-react v0.539.0 - ISC
@@ -3243,13 +3243,13 @@ const Eye = createLucideIcon("eye", __iconNode$V);
3243
3243
  */
3244
3244
 
3245
3245
 
3246
- const __iconNode$U = [
3246
+ const __iconNode$X = [
3247
3247
  [
3248
3248
  "path",
3249
3249
  { d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z", key: "1jg4f8" }
3250
3250
  ]
3251
3251
  ];
3252
- const Facebook = createLucideIcon("facebook", __iconNode$U);
3252
+ const Facebook = createLucideIcon("facebook", __iconNode$X);
3253
3253
 
3254
3254
  /**
3255
3255
  * @license lucide-react v0.539.0 - ISC
@@ -3259,7 +3259,7 @@ const Facebook = createLucideIcon("facebook", __iconNode$U);
3259
3259
  */
3260
3260
 
3261
3261
 
3262
- const __iconNode$T = [
3262
+ const __iconNode$W = [
3263
3263
  ["path", { d: "M12 22h6a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3.072", key: "n6s66f" }],
3264
3264
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3265
3265
  [
@@ -3271,7 +3271,7 @@ const __iconNode$T = [
3271
3271
  ],
3272
3272
  ["circle", { cx: "5", cy: "14", r: "3", key: "ufru5t" }]
3273
3273
  ];
3274
- const FileBadge = createLucideIcon("file-badge", __iconNode$T);
3274
+ const FileBadge = createLucideIcon("file-badge", __iconNode$W);
3275
3275
 
3276
3276
  /**
3277
3277
  * @license lucide-react v0.539.0 - ISC
@@ -3281,12 +3281,12 @@ const FileBadge = createLucideIcon("file-badge", __iconNode$T);
3281
3281
  */
3282
3282
 
3283
3283
 
3284
- const __iconNode$S = [
3284
+ const __iconNode$V = [
3285
3285
  ["path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4", key: "1pf5j1" }],
3286
3286
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3287
3287
  ["path", { d: "m3 15 2 2 4-4", key: "1lhrkk" }]
3288
3288
  ];
3289
- const FileCheck2 = createLucideIcon("file-check-2", __iconNode$S);
3289
+ const FileCheck2 = createLucideIcon("file-check-2", __iconNode$V);
3290
3290
 
3291
3291
  /**
3292
3292
  * @license lucide-react v0.539.0 - ISC
@@ -3296,14 +3296,14 @@ const FileCheck2 = createLucideIcon("file-check-2", __iconNode$S);
3296
3296
  */
3297
3297
 
3298
3298
 
3299
- const __iconNode$R = [
3299
+ const __iconNode$U = [
3300
3300
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
3301
3301
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3302
3302
  ["path", { d: "M10 9H8", key: "b1mrlr" }],
3303
3303
  ["path", { d: "M16 13H8", key: "t4e002" }],
3304
3304
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
3305
3305
  ];
3306
- const FileText = createLucideIcon("file-text", __iconNode$R);
3306
+ const FileText = createLucideIcon("file-text", __iconNode$U);
3307
3307
 
3308
3308
  /**
3309
3309
  * @license lucide-react v0.539.0 - ISC
@@ -3313,7 +3313,28 @@ const FileText = createLucideIcon("file-text", __iconNode$R);
3313
3313
  */
3314
3314
 
3315
3315
 
3316
- const __iconNode$Q = [
3316
+ const __iconNode$T = [
3317
+ [
3318
+ "path",
3319
+ {
3320
+ d: "M12.531 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14v6a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341l.427-.473",
3321
+ key: "ol2ft2"
3322
+ }
3323
+ ],
3324
+ ["path", { d: "m16.5 3.5 5 5", key: "15e6fa" }],
3325
+ ["path", { d: "m21.5 3.5-5 5", key: "m0lwru" }]
3326
+ ];
3327
+ const FunnelX = createLucideIcon("funnel-x", __iconNode$T);
3328
+
3329
+ /**
3330
+ * @license lucide-react v0.539.0 - ISC
3331
+ *
3332
+ * This source code is licensed under the ISC license.
3333
+ * See the LICENSE file in the root directory of this source tree.
3334
+ */
3335
+
3336
+
3337
+ const __iconNode$S = [
3317
3338
  [
3318
3339
  "path",
3319
3340
  {
@@ -3322,7 +3343,7 @@ const __iconNode$Q = [
3322
3343
  }
3323
3344
  ]
3324
3345
  ];
3325
- const Funnel = createLucideIcon("funnel", __iconNode$Q);
3346
+ const Funnel = createLucideIcon("funnel", __iconNode$S);
3326
3347
 
3327
3348
  /**
3328
3349
  * @license lucide-react v0.539.0 - ISC
@@ -3332,7 +3353,7 @@ const Funnel = createLucideIcon("funnel", __iconNode$Q);
3332
3353
  */
3333
3354
 
3334
3355
 
3335
- const __iconNode$P = [
3356
+ const __iconNode$R = [
3336
3357
  ["path", { d: "M10.5 3 8 9l4 13 4-13-2.5-6", key: "b3dvk1" }],
3337
3358
  [
3338
3359
  "path",
@@ -3343,7 +3364,7 @@ const __iconNode$P = [
3343
3364
  ],
3344
3365
  ["path", { d: "M2 9h20", key: "16fsjt" }]
3345
3366
  ];
3346
- const Gem = createLucideIcon("gem", __iconNode$P);
3367
+ const Gem = createLucideIcon("gem", __iconNode$R);
3347
3368
 
3348
3369
  /**
3349
3370
  * @license lucide-react v0.539.0 - ISC
@@ -3353,7 +3374,7 @@ const Gem = createLucideIcon("gem", __iconNode$P);
3353
3374
  */
3354
3375
 
3355
3376
 
3356
- const __iconNode$O = [
3377
+ const __iconNode$Q = [
3357
3378
  ["circle", { cx: "12", cy: "9", r: "1", key: "124mty" }],
3358
3379
  ["circle", { cx: "19", cy: "9", r: "1", key: "1ruzo2" }],
3359
3380
  ["circle", { cx: "5", cy: "9", r: "1", key: "1a8b28" }],
@@ -3361,7 +3382,7 @@ const __iconNode$O = [
3361
3382
  ["circle", { cx: "19", cy: "15", r: "1", key: "1a92ep" }],
3362
3383
  ["circle", { cx: "5", cy: "15", r: "1", key: "5r1jwy" }]
3363
3384
  ];
3364
- const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$O);
3385
+ const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$Q);
3365
3386
 
3366
3387
  /**
3367
3388
  * @license lucide-react v0.539.0 - ISC
@@ -3371,7 +3392,7 @@ const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$O);
3371
3392
  */
3372
3393
 
3373
3394
 
3374
- const __iconNode$N = [
3395
+ const __iconNode$P = [
3375
3396
  ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
3376
3397
  ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
3377
3398
  ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
@@ -3379,7 +3400,7 @@ const __iconNode$N = [
3379
3400
  ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
3380
3401
  ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
3381
3402
  ];
3382
- const GripVertical = createLucideIcon("grip-vertical", __iconNode$N);
3403
+ const GripVertical = createLucideIcon("grip-vertical", __iconNode$P);
3383
3404
 
3384
3405
  /**
3385
3406
  * @license lucide-react v0.539.0 - ISC
@@ -3389,13 +3410,13 @@ const GripVertical = createLucideIcon("grip-vertical", __iconNode$N);
3389
3410
  */
3390
3411
 
3391
3412
 
3392
- const __iconNode$M = [
3413
+ const __iconNode$O = [
3393
3414
  ["line", { x1: "4", x2: "20", y1: "9", y2: "9", key: "4lhtct" }],
3394
3415
  ["line", { x1: "4", x2: "20", y1: "15", y2: "15", key: "vyu0kd" }],
3395
3416
  ["line", { x1: "10", x2: "8", y1: "3", y2: "21", key: "1ggp8o" }],
3396
3417
  ["line", { x1: "16", x2: "14", y1: "3", y2: "21", key: "weycgp" }]
3397
3418
  ];
3398
- const Hash = createLucideIcon("hash", __iconNode$M);
3419
+ const Hash = createLucideIcon("hash", __iconNode$O);
3399
3420
 
3400
3421
  /**
3401
3422
  * @license lucide-react v0.539.0 - ISC
@@ -3405,13 +3426,13 @@ const Hash = createLucideIcon("hash", __iconNode$M);
3405
3426
  */
3406
3427
 
3407
3428
 
3408
- const __iconNode$L = [
3429
+ const __iconNode$N = [
3409
3430
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3410
3431
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3411
3432
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3412
3433
  ["path", { d: "m17 12 3-2v8", key: "1hhhft" }]
3413
3434
  ];
3414
- const Heading1 = createLucideIcon("heading-1", __iconNode$L);
3435
+ const Heading1 = createLucideIcon("heading-1", __iconNode$N);
3415
3436
 
3416
3437
  /**
3417
3438
  * @license lucide-react v0.539.0 - ISC
@@ -3421,13 +3442,13 @@ const Heading1 = createLucideIcon("heading-1", __iconNode$L);
3421
3442
  */
3422
3443
 
3423
3444
 
3424
- const __iconNode$K = [
3445
+ const __iconNode$M = [
3425
3446
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3426
3447
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3427
3448
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3428
3449
  ["path", { d: "M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1", key: "9jr5yi" }]
3429
3450
  ];
3430
- const Heading2 = createLucideIcon("heading-2", __iconNode$K);
3451
+ const Heading2 = createLucideIcon("heading-2", __iconNode$M);
3431
3452
 
3432
3453
  /**
3433
3454
  * @license lucide-react v0.539.0 - ISC
@@ -3437,14 +3458,14 @@ const Heading2 = createLucideIcon("heading-2", __iconNode$K);
3437
3458
  */
3438
3459
 
3439
3460
 
3440
- const __iconNode$J = [
3461
+ const __iconNode$L = [
3441
3462
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3442
3463
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3443
3464
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3444
3465
  ["path", { d: "M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2", key: "68ncm8" }],
3445
3466
  ["path", { d: "M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2", key: "1ejuhz" }]
3446
3467
  ];
3447
- const Heading3 = createLucideIcon("heading-3", __iconNode$J);
3468
+ const Heading3 = createLucideIcon("heading-3", __iconNode$L);
3448
3469
 
3449
3470
  /**
3450
3471
  * @license lucide-react v0.539.0 - ISC
@@ -3454,12 +3475,12 @@ const Heading3 = createLucideIcon("heading-3", __iconNode$J);
3454
3475
  */
3455
3476
 
3456
3477
 
3457
- const __iconNode$I = [
3478
+ const __iconNode$K = [
3458
3479
  ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
3459
3480
  ["path", { d: "M3 3v5h5", key: "1xhq8a" }],
3460
3481
  ["path", { d: "M12 7v5l4 2", key: "1fdv2h" }]
3461
3482
  ];
3462
- const History = createLucideIcon("history", __iconNode$I);
3483
+ const History = createLucideIcon("history", __iconNode$K);
3463
3484
 
3464
3485
  /**
3465
3486
  * @license lucide-react v0.539.0 - ISC
@@ -3469,12 +3490,12 @@ const History = createLucideIcon("history", __iconNode$I);
3469
3490
  */
3470
3491
 
3471
3492
 
3472
- const __iconNode$H = [
3493
+ const __iconNode$J = [
3473
3494
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
3474
3495
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
3475
3496
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
3476
3497
  ];
3477
- const Image$1 = createLucideIcon("image", __iconNode$H);
3498
+ const Image$1 = createLucideIcon("image", __iconNode$J);
3478
3499
 
3479
3500
  /**
3480
3501
  * @license lucide-react v0.539.0 - ISC
@@ -3484,12 +3505,12 @@ const Image$1 = createLucideIcon("image", __iconNode$H);
3484
3505
  */
3485
3506
 
3486
3507
 
3487
- const __iconNode$G = [
3508
+ const __iconNode$I = [
3488
3509
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3489
3510
  ["path", { d: "M12 16v-4", key: "1dtifu" }],
3490
3511
  ["path", { d: "M12 8h.01", key: "e9boi3" }]
3491
3512
  ];
3492
- const Info = createLucideIcon("info", __iconNode$G);
3513
+ const Info = createLucideIcon("info", __iconNode$I);
3493
3514
 
3494
3515
  /**
3495
3516
  * @license lucide-react v0.539.0 - ISC
@@ -3499,12 +3520,12 @@ const Info = createLucideIcon("info", __iconNode$G);
3499
3520
  */
3500
3521
 
3501
3522
 
3502
- const __iconNode$F = [
3523
+ const __iconNode$H = [
3503
3524
  ["line", { x1: "19", x2: "10", y1: "4", y2: "4", key: "15jd3p" }],
3504
3525
  ["line", { x1: "14", x2: "5", y1: "20", y2: "20", key: "bu0au3" }],
3505
3526
  ["line", { x1: "15", x2: "9", y1: "4", y2: "20", key: "uljnxc" }]
3506
3527
  ];
3507
- const Italic$1 = createLucideIcon("italic", __iconNode$F);
3528
+ const Italic$1 = createLucideIcon("italic", __iconNode$H);
3508
3529
 
3509
3530
  /**
3510
3531
  * @license lucide-react v0.539.0 - ISC
@@ -3514,7 +3535,7 @@ const Italic$1 = createLucideIcon("italic", __iconNode$F);
3514
3535
  */
3515
3536
 
3516
3537
 
3517
- const __iconNode$E = [
3538
+ const __iconNode$G = [
3518
3539
  [
3519
3540
  "path",
3520
3541
  {
@@ -3524,7 +3545,7 @@ const __iconNode$E = [
3524
3545
  ],
3525
3546
  ["circle", { cx: "16.5", cy: "7.5", r: ".5", fill: "currentColor", key: "w0ekpg" }]
3526
3547
  ];
3527
- const KeyRound = createLucideIcon("key-round", __iconNode$E);
3548
+ const KeyRound = createLucideIcon("key-round", __iconNode$G);
3528
3549
 
3529
3550
  /**
3530
3551
  * @license lucide-react v0.539.0 - ISC
@@ -3534,12 +3555,12 @@ const KeyRound = createLucideIcon("key-round", __iconNode$E);
3534
3555
  */
3535
3556
 
3536
3557
 
3537
- const __iconNode$D = [
3558
+ const __iconNode$F = [
3538
3559
  ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
3539
3560
  ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
3540
3561
  ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
3541
3562
  ];
3542
- const Link2 = createLucideIcon("link-2", __iconNode$D);
3563
+ const Link2 = createLucideIcon("link-2", __iconNode$F);
3543
3564
 
3544
3565
  /**
3545
3566
  * @license lucide-react v0.539.0 - ISC
@@ -3549,14 +3570,14 @@ const Link2 = createLucideIcon("link-2", __iconNode$D);
3549
3570
  */
3550
3571
 
3551
3572
 
3552
- const __iconNode$C = [
3573
+ const __iconNode$E = [
3553
3574
  ["path", { d: "m3 17 2 2 4-4", key: "1jhpwq" }],
3554
3575
  ["path", { d: "m3 7 2 2 4-4", key: "1obspn" }],
3555
3576
  ["path", { d: "M13 6h8", key: "15sg57" }],
3556
3577
  ["path", { d: "M13 12h8", key: "h98zly" }],
3557
3578
  ["path", { d: "M13 18h8", key: "oe0vm4" }]
3558
3579
  ];
3559
- const ListChecks = createLucideIcon("list-checks", __iconNode$C);
3580
+ const ListChecks = createLucideIcon("list-checks", __iconNode$E);
3560
3581
 
3561
3582
  /**
3562
3583
  * @license lucide-react v0.539.0 - ISC
@@ -3566,7 +3587,7 @@ const ListChecks = createLucideIcon("list-checks", __iconNode$C);
3566
3587
  */
3567
3588
 
3568
3589
 
3569
- const __iconNode$B = [
3590
+ const __iconNode$D = [
3570
3591
  ["path", { d: "M10 12h11", key: "6m4ad9" }],
3571
3592
  ["path", { d: "M10 18h11", key: "11hvi2" }],
3572
3593
  ["path", { d: "M10 6h11", key: "c7qv1k" }],
@@ -3574,7 +3595,7 @@ const __iconNode$B = [
3574
3595
  ["path", { d: "M4 6h1v4", key: "cnovpq" }],
3575
3596
  ["path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1", key: "m9a95d" }]
3576
3597
  ];
3577
- const ListOrdered = createLucideIcon("list-ordered", __iconNode$B);
3598
+ const ListOrdered = createLucideIcon("list-ordered", __iconNode$D);
3578
3599
 
3579
3600
  /**
3580
3601
  * @license lucide-react v0.539.0 - ISC
@@ -3584,7 +3605,7 @@ const ListOrdered = createLucideIcon("list-ordered", __iconNode$B);
3584
3605
  */
3585
3606
 
3586
3607
 
3587
- const __iconNode$A = [
3608
+ const __iconNode$C = [
3588
3609
  ["path", { d: "M3 12h.01", key: "nlz23k" }],
3589
3610
  ["path", { d: "M3 18h.01", key: "1tta3j" }],
3590
3611
  ["path", { d: "M3 6h.01", key: "1rqtza" }],
@@ -3592,7 +3613,7 @@ const __iconNode$A = [
3592
3613
  ["path", { d: "M8 18h13", key: "1lx6n3" }],
3593
3614
  ["path", { d: "M8 6h13", key: "ik3vkj" }]
3594
3615
  ];
3595
- const List = createLucideIcon("list", __iconNode$A);
3616
+ const List = createLucideIcon("list", __iconNode$C);
3596
3617
 
3597
3618
  /**
3598
3619
  * @license lucide-react v0.539.0 - ISC
@@ -3602,8 +3623,8 @@ const List = createLucideIcon("list", __iconNode$A);
3602
3623
  */
3603
3624
 
3604
3625
 
3605
- const __iconNode$z = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3606
- const LoaderCircle = createLucideIcon("loader-circle", __iconNode$z);
3626
+ const __iconNode$B = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3627
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$B);
3607
3628
 
3608
3629
  /**
3609
3630
  * @license lucide-react v0.539.0 - ISC
@@ -3613,7 +3634,7 @@ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$z);
3613
3634
  */
3614
3635
 
3615
3636
 
3616
- const __iconNode$y = [
3637
+ const __iconNode$A = [
3617
3638
  ["path", { d: "M12 2v4", key: "3427ic" }],
3618
3639
  ["path", { d: "m16.2 7.8 2.9-2.9", key: "r700ao" }],
3619
3640
  ["path", { d: "M18 12h4", key: "wj9ykh" }],
@@ -3623,7 +3644,7 @@ const __iconNode$y = [
3623
3644
  ["path", { d: "M2 12h4", key: "j09sii" }],
3624
3645
  ["path", { d: "m4.9 4.9 2.9 2.9", key: "giyufr" }]
3625
3646
  ];
3626
- const Loader = createLucideIcon("loader", __iconNode$y);
3647
+ const Loader = createLucideIcon("loader", __iconNode$A);
3627
3648
 
3628
3649
  /**
3629
3650
  * @license lucide-react v0.539.0 - ISC
@@ -3633,12 +3654,12 @@ const Loader = createLucideIcon("loader", __iconNode$y);
3633
3654
  */
3634
3655
 
3635
3656
 
3636
- const __iconNode$x = [
3657
+ const __iconNode$z = [
3637
3658
  ["path", { d: "m16 17 5-5-5-5", key: "1bji2h" }],
3638
3659
  ["path", { d: "M21 12H9", key: "dn1m92" }],
3639
3660
  ["path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4", key: "1uf3rs" }]
3640
3661
  ];
3641
- const LogOut = createLucideIcon("log-out", __iconNode$x);
3662
+ const LogOut = createLucideIcon("log-out", __iconNode$z);
3642
3663
 
3643
3664
  /**
3644
3665
  * @license lucide-react v0.539.0 - ISC
@@ -3648,11 +3669,11 @@ const LogOut = createLucideIcon("log-out", __iconNode$x);
3648
3669
  */
3649
3670
 
3650
3671
 
3651
- const __iconNode$w = [
3672
+ const __iconNode$y = [
3652
3673
  ["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
3653
3674
  ["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
3654
3675
  ];
3655
- const Mail = createLucideIcon("mail", __iconNode$w);
3676
+ const Mail = createLucideIcon("mail", __iconNode$y);
3656
3677
 
3657
3678
  /**
3658
3679
  * @license lucide-react v0.539.0 - ISC
@@ -3662,12 +3683,12 @@ const Mail = createLucideIcon("mail", __iconNode$w);
3662
3683
  */
3663
3684
 
3664
3685
 
3665
- const __iconNode$v = [
3686
+ const __iconNode$x = [
3666
3687
  ["path", { d: "M4 12h16", key: "1lakjw" }],
3667
3688
  ["path", { d: "M4 18h16", key: "19g7jn" }],
3668
3689
  ["path", { d: "M4 6h16", key: "1o0s65" }]
3669
3690
  ];
3670
- const Menu = createLucideIcon("menu", __iconNode$v);
3691
+ const Menu = createLucideIcon("menu", __iconNode$x);
3671
3692
 
3672
3693
  /**
3673
3694
  * @license lucide-react v0.539.0 - ISC
@@ -3677,7 +3698,18 @@ const Menu = createLucideIcon("menu", __iconNode$v);
3677
3698
  */
3678
3699
 
3679
3700
 
3680
- const __iconNode$u = [
3701
+ const __iconNode$w = [["path", { d: "M5 12h14", key: "1ays0h" }]];
3702
+ const Minus = createLucideIcon("minus", __iconNode$w);
3703
+
3704
+ /**
3705
+ * @license lucide-react v0.539.0 - ISC
3706
+ *
3707
+ * This source code is licensed under the ISC license.
3708
+ * See the LICENSE file in the root directory of this source tree.
3709
+ */
3710
+
3711
+
3712
+ const __iconNode$v = [
3681
3713
  [
3682
3714
  "path",
3683
3715
  {
@@ -3686,7 +3718,7 @@ const __iconNode$u = [
3686
3718
  }
3687
3719
  ]
3688
3720
  ];
3689
- const Moon = createLucideIcon("moon", __iconNode$u);
3721
+ const Moon = createLucideIcon("moon", __iconNode$v);
3690
3722
 
3691
3723
  /**
3692
3724
  * @license lucide-react v0.539.0 - ISC
@@ -3696,7 +3728,7 @@ const Moon = createLucideIcon("moon", __iconNode$u);
3696
3728
  */
3697
3729
 
3698
3730
 
3699
- const __iconNode$t = [
3731
+ const __iconNode$u = [
3700
3732
  [
3701
3733
  "path",
3702
3734
  {
@@ -3709,7 +3741,7 @@ const __iconNode$t = [
3709
3741
  ["circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor", key: "qy21gx" }],
3710
3742
  ["circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor", key: "fotxhn" }]
3711
3743
  ];
3712
- const Palette = createLucideIcon("palette", __iconNode$t);
3744
+ const Palette = createLucideIcon("palette", __iconNode$u);
3713
3745
 
3714
3746
  /**
3715
3747
  * @license lucide-react v0.539.0 - ISC
@@ -3719,12 +3751,12 @@ const Palette = createLucideIcon("palette", __iconNode$t);
3719
3751
  */
3720
3752
 
3721
3753
 
3722
- const __iconNode$s = [
3754
+ const __iconNode$t = [
3723
3755
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
3724
3756
  ["path", { d: "M9 3v18", key: "fh3hqa" }],
3725
3757
  ["path", { d: "m16 15-3-3 3-3", key: "14y99z" }]
3726
3758
  ];
3727
- const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$s);
3759
+ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$t);
3728
3760
 
3729
3761
  /**
3730
3762
  * @license lucide-react v0.539.0 - ISC
@@ -3734,7 +3766,7 @@ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$s);
3734
3766
  */
3735
3767
 
3736
3768
 
3737
- const __iconNode$r = [
3769
+ const __iconNode$s = [
3738
3770
  [
3739
3771
  "path",
3740
3772
  {
@@ -3743,7 +3775,7 @@ const __iconNode$r = [
3743
3775
  }
3744
3776
  ]
3745
3777
  ];
3746
- const Paperclip = createLucideIcon("paperclip", __iconNode$r);
3778
+ const Paperclip = createLucideIcon("paperclip", __iconNode$s);
3747
3779
 
3748
3780
  /**
3749
3781
  * @license lucide-react v0.539.0 - ISC
@@ -3753,7 +3785,7 @@ const Paperclip = createLucideIcon("paperclip", __iconNode$r);
3753
3785
  */
3754
3786
 
3755
3787
 
3756
- const __iconNode$q = [
3788
+ const __iconNode$r = [
3757
3789
  [
3758
3790
  "path",
3759
3791
  {
@@ -3763,7 +3795,7 @@ const __iconNode$q = [
3763
3795
  ],
3764
3796
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
3765
3797
  ];
3766
- const Pencil = createLucideIcon("pencil", __iconNode$q);
3798
+ const Pencil = createLucideIcon("pencil", __iconNode$r);
3767
3799
 
3768
3800
  /**
3769
3801
  * @license lucide-react v0.539.0 - ISC
@@ -3773,7 +3805,7 @@ const Pencil = createLucideIcon("pencil", __iconNode$q);
3773
3805
  */
3774
3806
 
3775
3807
 
3776
- const __iconNode$p = [
3808
+ const __iconNode$q = [
3777
3809
  [
3778
3810
  "path",
3779
3811
  {
@@ -3782,7 +3814,7 @@ const __iconNode$p = [
3782
3814
  }
3783
3815
  ]
3784
3816
  ];
3785
- const Phone = createLucideIcon("phone", __iconNode$p);
3817
+ const Phone = createLucideIcon("phone", __iconNode$q);
3786
3818
 
3787
3819
  /**
3788
3820
  * @license lucide-react v0.539.0 - ISC
@@ -3792,7 +3824,7 @@ const Phone = createLucideIcon("phone", __iconNode$p);
3792
3824
  */
3793
3825
 
3794
3826
 
3795
- const __iconNode$o = [
3827
+ const __iconNode$p = [
3796
3828
  [
3797
3829
  "path",
3798
3830
  {
@@ -3801,7 +3833,7 @@ const __iconNode$o = [
3801
3833
  }
3802
3834
  ]
3803
3835
  ];
3804
- const Play = createLucideIcon("play", __iconNode$o);
3836
+ const Play = createLucideIcon("play", __iconNode$p);
3805
3837
 
3806
3838
  /**
3807
3839
  * @license lucide-react v0.539.0 - ISC
@@ -3811,11 +3843,11 @@ const Play = createLucideIcon("play", __iconNode$o);
3811
3843
  */
3812
3844
 
3813
3845
 
3814
- const __iconNode$n = [
3846
+ const __iconNode$o = [
3815
3847
  ["path", { d: "M5 12h14", key: "1ays0h" }],
3816
3848
  ["path", { d: "M12 5v14", key: "s699le" }]
3817
3849
  ];
3818
- const Plus = createLucideIcon("plus", __iconNode$n);
3850
+ const Plus = createLucideIcon("plus", __iconNode$o);
3819
3851
 
3820
3852
  /**
3821
3853
  * @license lucide-react v0.539.0 - ISC
@@ -3825,10 +3857,10 @@ const Plus = createLucideIcon("plus", __iconNode$n);
3825
3857
  */
3826
3858
 
3827
3859
 
3828
- const __iconNode$m = [
3860
+ const __iconNode$n = [
3829
3861
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
3830
3862
  ];
3831
- const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$m);
3863
+ const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$n);
3832
3864
 
3833
3865
  /**
3834
3866
  * @license lucide-react v0.539.0 - ISC
@@ -3838,11 +3870,11 @@ const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$
3838
3870
  */
3839
3871
 
3840
3872
 
3841
- const __iconNode$l = [
3873
+ const __iconNode$m = [
3842
3874
  ["path", { d: "M21 7v6h-6", key: "3ptur4" }],
3843
3875
  ["path", { d: "M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3l3 2.7", key: "1kgawr" }]
3844
3876
  ];
3845
- const Redo = createLucideIcon("redo", __iconNode$l);
3877
+ const Redo = createLucideIcon("redo", __iconNode$m);
3846
3878
 
3847
3879
  /**
3848
3880
  * @license lucide-react v0.539.0 - ISC
@@ -3852,13 +3884,13 @@ const Redo = createLucideIcon("redo", __iconNode$l);
3852
3884
  */
3853
3885
 
3854
3886
 
3855
- const __iconNode$k = [
3887
+ const __iconNode$l = [
3856
3888
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
3857
3889
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
3858
3890
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
3859
3891
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
3860
3892
  ];
3861
- const RefreshCw = createLucideIcon("refresh-cw", __iconNode$k);
3893
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$l);
3862
3894
 
3863
3895
  /**
3864
3896
  * @license lucide-react v0.539.0 - ISC
@@ -3868,14 +3900,28 @@ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$k);
3868
3900
  */
3869
3901
 
3870
3902
 
3871
- const __iconNode$j = [
3903
+ const __iconNode$k = [
3872
3904
  ["path", { d: "M4 7V4h16v3", key: "9msm58" }],
3873
3905
  ["path", { d: "M5 20h6", key: "1h6pxn" }],
3874
3906
  ["path", { d: "M13 4 8 20", key: "kqq6aj" }],
3875
3907
  ["path", { d: "m15 15 5 5", key: "me55sn" }],
3876
3908
  ["path", { d: "m20 15-5 5", key: "11p7ol" }]
3877
3909
  ];
3878
- const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$j);
3910
+ const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$k);
3911
+
3912
+ /**
3913
+ * @license lucide-react v0.539.0 - ISC
3914
+ *
3915
+ * This source code is licensed under the ISC license.
3916
+ * See the LICENSE file in the root directory of this source tree.
3917
+ */
3918
+
3919
+
3920
+ const __iconNode$j = [
3921
+ ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
3922
+ ["path", { d: "M3 3v5h5", key: "1xhq8a" }]
3923
+ ];
3924
+ const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$j);
3879
3925
 
3880
3926
  /**
3881
3927
  * @license lucide-react v0.539.0 - ISC
@@ -4684,7 +4730,7 @@ const buttonVariants$1 = cva("inline-flex items-center justify-center gap-2 whit
4684
4730
  });
4685
4731
  function Button$1({ className, variant, size, asChild = false, ...props }) {
4686
4732
  const Comp = asChild ? reactSlot.Slot : 'button';
4687
- return (jsxRuntime.jsx(Comp, { "data-slot": "button", className: cn(buttonVariants$1({ variant, size, className })), ...props }));
4733
+ return (jsxRuntime.jsx(Comp, { "data-slot": "button", "data-variant": variant ?? 'default', className: cn(buttonVariants$1({ variant, size, className })), ...props }));
4688
4734
  }
4689
4735
 
4690
4736
  const VARIANT_BY_KIND = {
@@ -13478,7 +13524,7 @@ collisionPadding = 8, ...props }, ref) {
13478
13524
  });
13479
13525
 
13480
13526
  const ActionButtonWithTooltip = ({ icon, tooltip, onClick, disabled = false, colorClass = 'h-5 w-5 p-0 bg-muted text-muted-foreground hover:bg-muted/80 transition-colors rounded-md', }) => {
13481
- return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("span", { className: disabled ? 'cursor-not-allowed inline-flex' : 'inline-flex', children: jsxRuntime.jsx(Button$1, { size: "sm", variant: "ghost", className: colorClass, onClick: (e) => {
13527
+ return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("span", { className: disabled ? 'cursor-not-allowed inline-flex' : 'inline-flex', children: jsxRuntime.jsx(Button$1, { size: "sm", variant: "ghost", className: colorClass, "aria-label": tooltip, onClick: (e) => {
13482
13528
  e.stopPropagation();
13483
13529
  onClick?.(e);
13484
13530
  }, disabled: disabled, children: icon }) }) }), jsxRuntime.jsx(TooltipContent, { children: tooltip })] }) }));
@@ -14342,7 +14388,7 @@ function useNumberInput({ value, onChange, precision, min, max, emptyFallback, e
14342
14388
  return { raw, handleChange, handleFocus, handleBlur };
14343
14389
  }
14344
14390
 
14345
- const NumberInput = React__namespace.forwardRef(({ value, onChange, precision, min, max, step, className, emptyFallback = 0, emitUndefinedOnEmpty = false, trimTrailingZeros = false, ...rest }, ref) => {
14391
+ const NumberInput = React__namespace.forwardRef(({ value, onChange, precision, min, max, step, className, emptyFallback = 0, emitUndefinedOnEmpty = false, trimTrailingZeros = false, suffix, stepper = false, ...rest }, ref) => {
14346
14392
  const { onFocus: onFocusProp, onBlur: onBlurProp, ...inputRest } = rest;
14347
14393
  const { raw, handleChange, handleFocus, handleBlur } = useNumberInput({
14348
14394
  value,
@@ -14356,7 +14402,22 @@ const NumberInput = React__namespace.forwardRef(({ value, onChange, precision, m
14356
14402
  onFocusProp,
14357
14403
  onBlurProp,
14358
14404
  });
14359
- return (jsxRuntime.jsx(Input, { ref: ref, type: "text", inputMode: "decimal", className: className, value: raw, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, step: step, ...inputRest }));
14405
+ const input = (jsxRuntime.jsx(Input, { ref: ref, type: "text", inputMode: "decimal", className: cn(className, suffix != null && !stepper && 'pr-10', stepper && 'h-full border-0 bg-transparent px-1 text-center shadow-none focus-visible:ring-0'), value: raw, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, step: step, ...inputRest }));
14406
+ if (stepper) {
14407
+ const current = Number(value);
14408
+ const delta = step ?? 1;
14409
+ const at = Number.isFinite(current) ? current : (min ?? 0);
14410
+ const nudge = (direction) => {
14411
+ const next = at + direction * delta;
14412
+ onChange?.(Math.min(max ?? next, Math.max(min ?? next, next)));
14413
+ };
14414
+ const stepButton = 'flex size-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors hover:bg-muted/70 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40';
14415
+ return (jsxRuntime.jsxs("div", { "aria-invalid": inputRest['aria-invalid'], className: cn('flex h-10 w-full items-center gap-1 rounded-md border border-input-border px-1.5 dark:bg-input/30', 'focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50', 'aria-invalid:border-destructive aria-invalid:ring-destructive/20'), children: [jsxRuntime.jsx("button", { type: "button", "aria-label": "Decrease", className: stepButton, disabled: inputRest.disabled || (min !== undefined && at <= min), onClick: () => nudge(-1), children: jsxRuntime.jsx(Minus, { className: "size-3.5" }) }), input, jsxRuntime.jsx("button", { type: "button", "aria-label": "Increase", className: stepButton, disabled: inputRest.disabled || (max !== undefined && at >= max), onClick: () => nudge(1), children: jsxRuntime.jsx(Plus, { className: "size-3.5" }) })] }));
14416
+ }
14417
+ if (suffix != null) {
14418
+ return (jsxRuntime.jsxs("div", { className: "relative w-full", children: [input, jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-sm text-muted-foreground", children: suffix })] }));
14419
+ }
14420
+ return input;
14360
14421
  });
14361
14422
  NumberInput.displayName = 'NumberInput';
14362
14423
 
@@ -14898,30 +14959,74 @@ const DialogOverlay = React__namespace.forwardRef(({ className, ...props }, ref)
14898
14959
  'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 ' +
14899
14960
  'fixed inset-0 z-50 bg-black/50', className), ...props })));
14900
14961
  DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
14901
- const DialogContent = React__namespace.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [jsxRuntime.jsx(DialogOverlay, {}), jsxRuntime.jsxs(DialogPrimitive__namespace.Content, { ref: ref, "data-slot": "dialog-content", className: cn('bg-background fixed top-[50%] left-[50%] z-50 grid ' +
14902
- 'w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] ' +
14903
- 'gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg ' +
14962
+ const DIALOG_WIDTH = {
14963
+ default: '32rem',
14964
+ wide: '50rem',
14965
+ };
14966
+ /** Every dialog stops growing here; taller content scrolls inside it. */
14967
+ const DIALOG_MAX_HEIGHT = 'min(85vh, 45rem)';
14968
+ const DialogContent = React__namespace.forwardRef(({ className, children, hideCloseButton, size = 'default', style, ...props }, ref) => (jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [jsxRuntime.jsx(DialogOverlay, {}), jsxRuntime.jsxs(DialogPrimitive__namespace.Content, { ref: ref, "data-slot": "dialog-content", className: cn('bg-card fixed top-[50%] left-[50%] z-50 grid ' +
14969
+ 'translate-x-[-50%] translate-y-[-50%] ' +
14970
+ 'gap-4 overflow-y-auto overscroll-contain rounded-2xl border border-border p-6 shadow-xl duration-200 ' +
14971
+ // A footer closes the panel itself; sticky can't sit in the padding a negative margin would bleed into.
14972
+ 'has-[[data-slot=dialog-footer]]:pb-0 ' +
14904
14973
  'data-[state=open]:animate-in data-[state=closed]:animate-out ' +
14905
14974
  'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 ' +
14906
- 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', className), ...props, children: [children, !hideCloseButton && (jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: cn('absolute top-4 right-4 rounded-xs opacity-70 transition-opacity ' +
14907
- 'hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring ' +
14908
- 'focus:ring-offset-2 ring-offset-background disabled:pointer-events-none ' +
14909
- '[&_svg]:pointer-events-none [&_svg]:shrink-0 ' +
14975
+ 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', className), style: {
14976
+ ...style,
14977
+ width: 'calc(100vw - 2rem)',
14978
+ maxWidth: DIALOG_WIDTH[size],
14979
+ maxHeight: DIALOG_MAX_HEIGHT,
14980
+ }, ...props, children: [children, !hideCloseButton && (jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: cn('absolute top-5 right-5 inline-flex size-7 items-center justify-center rounded-md ' +
14981
+ 'text-muted-foreground transition-colors hover:bg-muted hover:text-foreground ' +
14982
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ' +
14983
+ 'disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 ' +
14910
14984
  "[&_svg:not([class*='size-'])]:size-4"), children: [jsxRuntime.jsx(X$2, {}), jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })] }))] })] })));
14911
14985
  DialogContent.displayName = DialogPrimitive__namespace.Content.displayName;
14912
- // Header
14913
- function DialogHeader({ className, ...props }) {
14914
- return (jsxRuntime.jsx("div", { "data-slot": "dialog-header", className: cn('flex flex-col gap-2 text-center sm:text-left', className), ...props }));
14986
+ const DIALOG_ICON_TONE = {
14987
+ primary: 'bg-primary/10 text-primary dark:bg-primary/20',
14988
+ neutral: 'bg-muted text-muted-foreground',
14989
+ warning: 'bg-badge-amber-bg text-badge-amber-text',
14990
+ destructive: 'bg-badge-destructive-bg text-destructive',
14991
+ };
14992
+ /** The tinted tile that names a dialog's action; shared by every dialog header. */
14993
+ function DialogIcon({ tone = 'primary', className, children, }) {
14994
+ return (jsxRuntime.jsx("span", { "aria-hidden": true, className: cn(
14995
+ // 44px = the title's 24px line + the subtitle's 20px line, so the tile spans both.
14996
+ 'flex size-11 shrink-0 items-center justify-center rounded-lg [&_svg]:size-5', DIALOG_ICON_TONE[tone], className), children: children }));
14997
+ }
14998
+ function DialogHeader({ className, icon, iconTone, children, ...props }) {
14999
+ if (icon) {
15000
+ return (jsxRuntime.jsxs("div", { "data-slot": "dialog-header",
15001
+ // A lone title centres on the icon; with a subtitle the pair starts at the icon's top.
15002
+ className: cn('flex flex-row items-center gap-3.5 pr-8 text-left has-[[data-slot=dialog-description]]:items-start', className), ...props, children: [jsxRuntime.jsx(DialogIcon, { tone: iconTone, children: icon }), jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: children })] }));
15003
+ }
15004
+ return (jsxRuntime.jsx("div", { "data-slot": "dialog-header", className: cn('flex flex-col pr-8 text-left', className), ...props, children: children }));
14915
15005
  }
14916
15006
  // Footer
15007
+ /** Neutral footer buttons get the card surface so they stand out from the tinted footer band. */
15008
+ const DIALOG_FOOTER_BUTTONS = '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:border ' +
15009
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:border-border ' +
15010
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:bg-card ' +
15011
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:shadow-xs ' +
15012
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:hover:bg-muted ' +
15013
+ // The outline variant forces its own dark fill; keep every footer secondary button on the same card surface.
15014
+ 'dark:[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:!bg-card ' +
15015
+ 'dark:[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:!border-border ' +
15016
+ 'dark:[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:hover:!bg-muted';
14917
15017
  function DialogFooter({ className, ...props }) {
14918
- return (jsxRuntime.jsx("div", { "data-slot": "dialog-footer", className: cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className), ...props }));
15018
+ return (jsxRuntime.jsx("div", { "data-slot": "dialog-footer",
15019
+ // Bleeds to the dialog's side edges as a tinted band; dialogs that drop the default p-6 reset the margins.
15020
+ className: cn(
15021
+ // Sticky so the actions stay in view while a long body scrolls.
15022
+ 'sticky bottom-0 z-10 -mx-6 mt-1 flex shrink-0 flex-col-reverse gap-2 border-t border-border bg-[color-mix(in_srgb,var(--muted)_40%,var(--card))] px-6 py-4 ' +
15023
+ 'sm:flex-row sm:items-center sm:justify-end', DIALOG_FOOTER_BUTTONS, className), ...props }));
14919
15024
  }
14920
15025
  // Title
14921
- const DialogTitle = React__namespace.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx(DialogPrimitive__namespace.Title, { ref: ref, "data-slot": "dialog-title", className: cn('text-lg font-semibold leading-none', className), ...props })));
15026
+ const DialogTitle = React__namespace.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx(DialogPrimitive__namespace.Title, { ref: ref, "data-slot": "dialog-title", className: cn('text-lg font-semibold leading-6 text-foreground', className), ...props })));
14922
15027
  DialogTitle.displayName = DialogPrimitive__namespace.Title.displayName;
14923
15028
  // Description
14924
- const DialogDescription = React__namespace.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx(DialogPrimitive__namespace.Description, { ref: ref, "data-slot": "dialog-description", className: cn('text-sm text-muted-foreground', className), ...props })));
15029
+ const DialogDescription = React__namespace.forwardRef(({ className, ...props }, ref) => (jsxRuntime.jsx(DialogPrimitive__namespace.Description, { ref: ref, "data-slot": "dialog-description", className: cn('text-sm leading-5 text-muted-foreground', className), ...props })));
14925
15030
  DialogDescription.displayName = DialogPrimitive__namespace.Description.displayName;
14926
15031
 
14927
15032
  // ---------- Command Wrapper ----------
@@ -15341,36 +15446,467 @@ function ApiComboBox({ contactType, selectedItem, onSelect, fetchBusinessContact
15341
15446
  : '', fetchPage: fetchPage, resolveById: resolveById, preSelectedId: customerCode, searchPlaceholder: searchPlaceholder, emptyMessage: "No business contacts found.", disabled: disabled, className: className, align: align, debounceMs: 300, hideTriggerSearchIcon: hideTriggerSearchIcon }));
15342
15447
  }
15343
15448
 
15449
+ const NUMBER = String.raw `(\d+(?:\.\d+)?|\.\d+)`;
15450
+ const COMPARISON_RE = new RegExp(`^(>=|<=|>|<)${NUMBER}$`);
15451
+ const BETWEEN_RE = new RegExp(`^${NUMBER}-${NUMBER}$`);
15452
+ const EXACT_RE = new RegExp(`^${NUMBER}$`);
15453
+ const NUMBER_EXPRESSION_HELP = [
15454
+ { rule: '>1', meaning: 'More than 1' },
15455
+ { rule: '<3', meaning: 'Less than 3' },
15456
+ { rule: '>=1.5', meaning: '1.5 or more' },
15457
+ { rule: '<=3', meaning: '3 or less' },
15458
+ { rule: '1–3', meaning: 'Between 1 and 3, inclusive' },
15459
+ { rule: '1.52', meaning: 'Exactly 1.52' },
15460
+ ];
15461
+ /** Parses the typed rules in `NUMBER_EXPRESSION_HELP`. Accepts `-`, `–` or `—` for ranges and ignores spaces and thousands commas. */
15462
+ function parseNumberExpression(text) {
15463
+ const normalized = text.replace(/[\s,]/g, '').replace(/[–—]/g, '-');
15464
+ if (!normalized)
15465
+ return { ok: true, range: undefined };
15466
+ const comparison = COMPARISON_RE.exec(normalized);
15467
+ if (comparison) {
15468
+ const [, operator, raw] = comparison;
15469
+ const value = Number(raw);
15470
+ if (operator.startsWith('>')) {
15471
+ return {
15472
+ ok: true,
15473
+ range: { min: value, minExclusive: operator === '>' },
15474
+ };
15475
+ }
15476
+ return { ok: true, range: { max: value, maxExclusive: operator === '<' } };
15477
+ }
15478
+ const between = BETWEEN_RE.exec(normalized);
15479
+ if (between) {
15480
+ const min = Number(between[1]);
15481
+ const max = Number(between[2]);
15482
+ return min <= max ? { ok: true, range: { min, max } } : { ok: false };
15483
+ }
15484
+ const exact = EXACT_RE.exec(normalized);
15485
+ if (exact) {
15486
+ const value = Number(exact[1]);
15487
+ return { ok: true, range: { min: value, max: value } };
15488
+ }
15489
+ return { ok: false };
15490
+ }
15491
+ function formatNumberRange(range) {
15492
+ if (!range)
15493
+ return '';
15494
+ const { min, max, minExclusive, maxExclusive } = range;
15495
+ if (min !== undefined && max !== undefined) {
15496
+ return min === max ? String(min) : `${min}–${max}`;
15497
+ }
15498
+ if (min !== undefined)
15499
+ return `${minExclusive ? '>' : '>='}${min}`;
15500
+ if (max !== undefined)
15501
+ return `${maxExclusive ? '<' : '<='}${max}`;
15502
+ return '';
15503
+ }
15504
+ /** Splits a pasted list — commas, semicolons, spaces and new lines all separate IDs. Keeps first-seen order, drops duplicates. */
15505
+ function splitIdList(text) {
15506
+ return Array.from(new Set(text
15507
+ .split(/[\s,;]+/)
15508
+ .map((id) => id.trim())
15509
+ .filter(Boolean)));
15510
+ }
15511
+ function getOptionLabel(options, value) {
15512
+ return options.find((option) => option.value === value)?.label ?? value;
15513
+ }
15514
+ /** Trigger summary for a multi-select: the first selected option (in option order) plus how many more, e.g. `Red +1`. */
15515
+ function summarizeSelection(values, options) {
15516
+ if (values.length === 0)
15517
+ return '';
15518
+ const first = options.find((option) => values.includes(option.value))?.label ?? values[0];
15519
+ return values.length > 1 ? `${first} +${values.length - 1}` : first;
15520
+ }
15521
+ function formatSelectedCount(selected, total) {
15522
+ return `${selected} of ${total} selected`;
15523
+ }
15524
+ function toggleValue(values, value) {
15525
+ return values.includes(value)
15526
+ ? values.filter((v) => v !== value)
15527
+ : [...values, value];
15528
+ }
15529
+ /** Every option between the two ends of the range, inclusive, in scale order. */
15530
+ function expandScaleRange(options, range) {
15531
+ const fromIndex = options.findIndex((option) => option.value === range.from);
15532
+ const toIndex = options.findIndex((option) => option.value === range.to);
15533
+ if (fromIndex < 0 || toIndex < 0)
15534
+ return [];
15535
+ const [start, end] = fromIndex <= toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
15536
+ return options.slice(start, end + 1).map((option) => option.value);
15537
+ }
15538
+ /** `Very Good` → `VG`, `Fair` → `F`. */
15539
+ function toInitials(label) {
15540
+ return label
15541
+ .split(/[\s-]+/)
15542
+ .filter(Boolean)
15543
+ .map((word) => word[0].toUpperCase())
15544
+ .join('');
15545
+ }
15546
+ function formatScaleRange(options, range, short = false) {
15547
+ const values = expandScaleRange(options, range);
15548
+ if (values.length === 0)
15549
+ return '';
15550
+ const labelOf = (value) => {
15551
+ const label = getOptionLabel(options, value);
15552
+ return short ? toInitials(label) : label;
15553
+ };
15554
+ const first = labelOf(values[0]);
15555
+ return values.length === 1
15556
+ ? first
15557
+ : `${first} – ${labelOf(values[values.length - 1])}`;
15558
+ }
15559
+ const DATE_PRESET_OPTIONS = [
15560
+ { value: 'today', label: 'Today' },
15561
+ { value: 'last7Days', label: 'Last 7 days' },
15562
+ { value: 'last30Days', label: 'Last 30 days' },
15563
+ { value: 'thisMonth', label: 'This month' },
15564
+ { value: 'thisFiscalYear', label: 'This fiscal year' },
15565
+ ];
15566
+ function toIsoDate(date) {
15567
+ const month = String(date.getMonth() + 1).padStart(2, '0');
15568
+ const day = String(date.getDate()).padStart(2, '0');
15569
+ return `${date.getFullYear()}-${month}-${day}`;
15570
+ }
15571
+ /** `YYYY-MM-DD` → local date (no timezone shift); empty → undefined. */
15572
+ function fromIsoDate(iso) {
15573
+ if (!iso)
15574
+ return undefined;
15575
+ const [year, month, day] = iso.split('-').map(Number);
15576
+ return new Date(year, month - 1, day);
15577
+ }
15578
+ function daysBefore(today, days) {
15579
+ return new Date(today.getFullYear(), today.getMonth(), today.getDate() - days);
15580
+ }
15581
+ /** `fiscalYearStartMonth` is 1–12 (1 = January, 4 = April). */
15582
+ function resolveDatePreset(preset, today, fiscalYearStartMonth = 1) {
15583
+ const to = toIsoDate(today);
15584
+ switch (preset) {
15585
+ case 'today':
15586
+ return { from: to, to };
15587
+ case 'last7Days':
15588
+ return { from: toIsoDate(daysBefore(today, 6)), to };
15589
+ case 'last30Days':
15590
+ return { from: toIsoDate(daysBefore(today, 29)), to };
15591
+ case 'thisMonth':
15592
+ return {
15593
+ from: toIsoDate(new Date(today.getFullYear(), today.getMonth(), 1)),
15594
+ to,
15595
+ };
15596
+ case 'thisFiscalYear': {
15597
+ const startMonthIndex = fiscalYearStartMonth - 1;
15598
+ const startYear = today.getMonth() >= startMonthIndex
15599
+ ? today.getFullYear()
15600
+ : today.getFullYear() - 1;
15601
+ return { from: toIsoDate(new Date(startYear, startMonthIndex, 1)), to };
15602
+ }
15603
+ }
15604
+ }
15605
+ function resolveDateRange(range, today, fiscalYearStartMonth = 1) {
15606
+ if (range.preset)
15607
+ return resolveDatePreset(range.preset, today, fiscalYearStartMonth);
15608
+ return { from: range.from, to: range.to };
15609
+ }
15610
+ function formatIsoDate(iso) {
15611
+ const [year, month, day] = iso.split('-').map(Number);
15612
+ return new Date(year, month - 1, day).toLocaleDateString('en-GB', {
15613
+ day: 'numeric',
15614
+ month: 'short',
15615
+ year: 'numeric',
15616
+ });
15617
+ }
15618
+ function formatDateRange(range) {
15619
+ if (range.preset)
15620
+ return (DATE_PRESET_OPTIONS.find((option) => option.value === range.preset)
15621
+ ?.label ?? '');
15622
+ if (range.from && range.to)
15623
+ return `${formatIsoDate(range.from)} – ${formatIsoDate(range.to)}`;
15624
+ if (range.from)
15625
+ return `From ${formatIsoDate(range.from)}`;
15626
+ if (range.to)
15627
+ return `Until ${formatIsoDate(range.to)}`;
15628
+ return '';
15629
+ }
15630
+ const TRI_STATE_OPTIONS = [
15631
+ { value: 'any', label: 'Any' },
15632
+ { value: 'yes', label: 'Yes' },
15633
+ { value: 'no', label: 'No' },
15634
+ ];
15635
+ function isFilterValueActive(value) {
15636
+ if (!value)
15637
+ return false;
15638
+ switch (value.type) {
15639
+ case 'list':
15640
+ return value.values.length > 0;
15641
+ case 'ids':
15642
+ return value.ids.length > 0;
15643
+ case 'contains':
15644
+ return value.text.trim().length > 0;
15645
+ case 'number':
15646
+ return value.range.min !== undefined || value.range.max !== undefined;
15647
+ case 'date':
15648
+ return Boolean(value.range.preset || value.range.from || value.range.to);
15649
+ case 'scale':
15650
+ case 'bool':
15651
+ return true;
15652
+ }
15653
+ }
15654
+ const FILTER_FOCUS_RING = 'outline-none focus-visible:ring-2 focus-visible:ring-primary/30';
15655
+ /** Text-link actions such as Clear and "Show all". */
15656
+ const FILTER_LINK_CLASS_NAME = cn('cursor-pointer rounded-sm text-xs font-medium text-primary hover:underline', FILTER_FOCUS_RING);
15657
+ /** A fixed column count, or (when omitted) as many columns as fit at `minWidth` each. */
15658
+ function getGridColumnsStyle(columns, minWidth = '7rem') {
15659
+ return {
15660
+ gridTemplateColumns: columns
15661
+ ? `repeat(${columns}, minmax(0, 1fr))`
15662
+ : `repeat(auto-fill, minmax(${minWidth}, 1fr))`,
15663
+ };
15664
+ }
15665
+ /** Selectable option: a pill chip or a tile, primary-tinted when selected. Unselected ones sit a shade darker than the card so they read against it. */
15666
+ function getSelectableOptionClassName(selected, className) {
15667
+ return cn('cursor-pointer border text-xs transition-colors', FILTER_FOCUS_RING, selected
15668
+ ? 'border-primary bg-primary/5 font-medium text-primary'
15669
+ : 'border-border bg-background text-foreground hover:bg-secondary dark:bg-muted/60 dark:hover:bg-muted', className);
15670
+ }
15671
+ /** Shared look of every filter-row control (trigger buttons and inline inputs). */
15672
+ function getFilterFieldClassName(state, className) {
15673
+ return cn('flex h-7 w-full min-w-0 items-center gap-1 rounded-sm border px-2 text-xs transition-colors outline-none', 'focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-primary/30', state === 'empty' &&
15674
+ 'border-input bg-card text-foreground placeholder:text-placeholder', state === 'applied' &&
15675
+ 'border-primary bg-primary/5 font-medium text-primary', state === 'invalid' && 'border-destructive bg-card text-destructive', state === 'disabled' &&
15676
+ 'pointer-events-none border-dashed border-border bg-transparent', className);
15677
+ }
15678
+
15679
+ function getPanelClassName(variant, active, className) {
15680
+ return cn('flex min-w-0 flex-col gap-3', variant === 'card' && 'rounded-xl border bg-card p-4', variant === 'card' && (active ? 'border-primary' : 'border-border'), variant === 'popover' && 'p-3', className);
15681
+ }
15682
+ function getTitleClassName(variant) {
15683
+ return cn('flex items-center gap-2 text-foreground', variant === 'section'
15684
+ ? 'text-xs font-medium text-label'
15685
+ : 'text-sm font-semibold');
15686
+ }
15687
+
15688
+ /** Shell for one filter: title, selected badge, applied summary, Clear and a hint. Same content in popovers and on full-page surfaces. */
15689
+ function FilterPanel({ title, status, selectedCount, summary, action, onClear, hint, active = false, variant = 'card', className, children, }) {
15690
+ const hasHeader = Boolean(title || status || summary || action || onClear);
15691
+ return (jsxRuntime.jsxs("section", { className: getPanelClassName(variant, active, className), children: [hasHeader && (jsxRuntime.jsxs("header", { className: "flex min-h-5 items-center justify-between gap-3", children: [title ? (jsxRuntime.jsxs("h3", { className: getTitleClassName(variant), children: [title, selectedCount ? (jsxRuntime.jsx("span", { className: "inline-flex size-5 items-center justify-center rounded-full bg-primary text-xs font-semibold text-primary-foreground", children: selectedCount })) : null] })) : (jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: status })), jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-xs", children: [summary && (jsxRuntime.jsx("span", { className: "font-medium text-primary", children: summary })), action, onClear && (jsxRuntime.jsx("button", { type: "button", onClick: onClear, className: FILTER_LINK_CLASS_NAME, children: "Clear" }))] })] })), children, hint && jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: hint })] }));
15692
+ }
15693
+
15344
15694
  function Checkbox({ className, ...props }) {
15345
15695
  return (jsxRuntime.jsx(CheckboxPrimitive__namespace.Root, { "data-slot": "checkbox", className: cn('peer bg-[var(--muted)] border-[var(--muted)] dark:bg-input/30 dark:border-transparent data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 cursor-pointer rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', className), ...props, children: jsxRuntime.jsx(CheckboxPrimitive__namespace.Indicator, { "data-slot": "checkbox-indicator", className: "flex items-center justify-center text-current transition-none", children: jsxRuntime.jsx(Check, { className: "size-3.5" }) }) }));
15346
15696
  }
15347
15697
 
15698
+ // Sub-pixel rounding leaves scrollTop a hair short of the end.
15699
+ const EDGE_TOLERANCE_PX = 1;
15700
+ function getScrollFadeState(el) {
15701
+ const { scrollTop, scrollHeight, clientHeight } = el;
15702
+ return {
15703
+ top: scrollTop > EDGE_TOLERANCE_PX,
15704
+ bottom: scrollTop + clientHeight < scrollHeight - EDGE_TOLERANCE_PX,
15705
+ };
15706
+ }
15707
+ const FADE_BASE_CLASS_NAME = 'pointer-events-none absolute inset-x-0 h-8 from-card to-transparent';
15708
+
15709
+ function useScrollFade() {
15710
+ const ref = React.useRef(null);
15711
+ const [state, setState] = React.useState({
15712
+ top: false,
15713
+ bottom: false,
15714
+ });
15715
+ const update = React.useCallback(() => {
15716
+ if (!ref.current)
15717
+ return;
15718
+ const next = getScrollFadeState(ref.current);
15719
+ // Skip no-op updates (observers fire often).
15720
+ setState((current) => current.top === next.top && current.bottom === next.bottom
15721
+ ? current
15722
+ : next);
15723
+ }, []);
15724
+ React.useEffect(() => {
15725
+ const el = ref.current;
15726
+ if (!el)
15727
+ return;
15728
+ update();
15729
+ const resizeObserver = new ResizeObserver(update);
15730
+ resizeObserver.observe(el);
15731
+ const mutationObserver = new MutationObserver(update);
15732
+ mutationObserver.observe(el, { childList: true, subtree: true });
15733
+ return () => {
15734
+ resizeObserver.disconnect();
15735
+ mutationObserver.disconnect();
15736
+ };
15737
+ }, [update]);
15738
+ return { ref, update, ...state };
15739
+ }
15740
+
15741
+ /** Scroll container that fades its top / bottom edge while more content is hidden there, so it reads as scrollable. */
15742
+ function ScrollFade({ className, wrapperClassName, children, ...props }) {
15743
+ const { ref, update, top, bottom } = useScrollFade();
15744
+ return (jsxRuntime.jsxs("div", { className: cn('relative', wrapperClassName), children: [jsxRuntime.jsx("div", { ...props, ref: ref, onScroll: update, className: className, children: children }), top && (jsxRuntime.jsx("div", { "aria-hidden": "true", className: cn(FADE_BASE_CLASS_NAME, 'top-0 bg-gradient-to-b') })), bottom && (jsxRuntime.jsx("div", { "aria-hidden": "true", className: cn(FADE_BASE_CLASS_NAME, 'bottom-0 bg-gradient-to-t') }))] }));
15745
+ }
15746
+
15747
+ // Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
15748
+ // labels that are not actually clipped.
15749
+ const OVERFLOW_TOLERANCE_PX = 1;
15750
+ function findClippedLabel(root) {
15751
+ const spans = root.querySelectorAll(':scope > span');
15752
+ for (const span of Array.from(spans)) {
15753
+ if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX) {
15754
+ return span;
15755
+ }
15756
+ }
15757
+ return null;
15758
+ }
15759
+ /**
15760
+ * Returns the full text of the first direct-child `<span>` of `ref` that is
15761
+ * clipped by its container (i.e. showing an ellipsis), else `null` — so callers
15762
+ * can surface a tooltip only when the label is actually unreadable.
15763
+ *
15764
+ * Re-measures on element resize (sidebar expand/collapse, window resize) and on
15765
+ * label text changes.
15766
+ */
15767
+ function useTruncatedText(ref) {
15768
+ const [text, setText] = React.useState(null);
15769
+ React.useEffect(() => {
15770
+ const el = ref.current;
15771
+ if (!el)
15772
+ return;
15773
+ let frame = 0;
15774
+ const measure = () => {
15775
+ const label = findClippedLabel(el);
15776
+ setText(label?.textContent?.trim() || null);
15777
+ };
15778
+ const schedule = () => {
15779
+ cancelAnimationFrame(frame);
15780
+ frame = requestAnimationFrame(measure);
15781
+ };
15782
+ schedule();
15783
+ const resizeObserver = new ResizeObserver(schedule);
15784
+ resizeObserver.observe(el);
15785
+ const mutationObserver = new MutationObserver(schedule);
15786
+ mutationObserver.observe(el, {
15787
+ characterData: true,
15788
+ childList: true,
15789
+ subtree: true,
15790
+ });
15791
+ return () => {
15792
+ cancelAnimationFrame(frame);
15793
+ resizeObserver.disconnect();
15794
+ mutationObserver.disconnect();
15795
+ };
15796
+ }, [ref]);
15797
+ return text;
15798
+ }
15799
+
15800
+ /** Single-line label that shows its full text in a tooltip, only while it is cut off. */
15801
+ function TruncatedLabel({ text, className, }) {
15802
+ const ref = React.useRef(null);
15803
+ const clipped = useTruncatedText(ref);
15804
+ return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntime.jsxs(Tooltip, { open: clipped ? undefined : false, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("span", { ref: ref, className: "block w-full min-w-0", children: jsxRuntime.jsx("span", { className: cn('block truncate', className), children: text }) }) }), jsxRuntime.jsx(TooltipContent, { children: text })] }) }));
15805
+ }
15806
+
15807
+ function filterOptionsByQuery(options, query) {
15808
+ const needle = query.trim().toLowerCase();
15809
+ if (!needle)
15810
+ return [...options];
15811
+ return options.filter((option) => option.label.toLowerCase().includes(needle));
15812
+ }
15813
+ function getChipClassName(selected) {
15814
+ return getSelectableOptionClassName(selected, 'inline-flex h-8 items-center gap-1.5 rounded-full px-3');
15815
+ }
15816
+ function getTileClassName(selected) {
15817
+ return getSelectableOptionClassName(selected, 'flex min-h-11 min-w-0 flex-col items-center justify-center gap-0.5 rounded-md px-2 py-1.5 text-center');
15818
+ }
15819
+ /** The list's search box only appears once there are enough options to need it. */
15820
+ const SEARCH_MIN_OPTIONS = 9;
15821
+ /** Long option sets scroll inside the card or popover instead of growing it. */
15822
+ const OPTIONS_SCROLL_CLASS_NAME = 'max-h-48 overflow-y-auto';
15823
+ /** Fills a stretched card: at least the usual height, growing into any space the row gives it (never driving the row height). */
15824
+ const OPTIONS_FILL_CLASS_NAME = 'min-h-48 flex-1 basis-0 overflow-y-auto';
15825
+ const FILL_WRAPPER_CLASS_NAME = 'flex min-h-0 flex-1 flex-col';
15826
+ /** Card lists flow into as many columns as fit; popover lists stay one column. */
15827
+ const LIST_COLUMN_MIN_WIDTH = '10rem';
15828
+ const getOptionsScrollClassName = (fill) => fill ? OPTIONS_FILL_CLASS_NAME : OPTIONS_SCROLL_CLASS_NAME;
15829
+ const LIST_ROW_CLASS_NAME = 'flex w-full cursor-pointer items-center gap-3 rounded-md px-2 py-2 text-sm text-foreground hover:bg-muted/50';
15830
+ /** Outlined (not filled) box until checked; the border is dark enough to read on white. */
15831
+ const LIST_CHECKBOX_CLASS_NAME = 'size-4.5 border-muted-foreground/50 bg-card dark:border-muted-foreground/60 dark:bg-transparent';
15832
+ const SEARCH_BOX_CLASS_NAME = 'flex h-9 items-center gap-2 rounded-lg border border-input bg-card px-3 focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/30';
15833
+
15834
+ function usePickListFilter({ options, value, layout, }) {
15835
+ const [query, setQuery] = React.useState('');
15836
+ const visibleOptions = React.useMemo(() => (layout === 'list' ? filterOptionsByQuery(options, query) : options), [layout, options, query]);
15837
+ const selectedCount = React.useMemo(() => options.filter((option) => value.includes(option.value)).length, [options, value]);
15838
+ return { query, setQuery, visibleOptions, selectedCount };
15839
+ }
15840
+
15841
+ const getSearchInputLabel = (ariaLabel) => `Search ${ariaLabel}`;
15842
+
15843
+ function OptionSwatch({ color, round, }) {
15844
+ if (!color)
15845
+ return null;
15846
+ return (jsxRuntime.jsx("span", { "aria-hidden": "true", className: cn('shrink-0 border border-border', round ? 'size-2.5 rounded-full' : 'size-4 rounded-sm'), style: { backgroundColor: color } }));
15847
+ }
15848
+ /** Multi-select filter: a searchable checkbox list, or pill / tile toggles. Long sets scroll within a max height. */
15849
+ function PickListFilter({ options, value, onChange, ariaLabel, layout = 'list', searchPlaceholder, alwaysSearchable = false, columns = 5, fill = false, listClassName, }) {
15850
+ const { query, setQuery, visibleOptions, selectedCount } = usePickListFilter({
15851
+ options,
15852
+ value,
15853
+ layout,
15854
+ });
15855
+ const scrollClassName = getOptionsScrollClassName(fill);
15856
+ // Rows with a right-hand hint read best in one column.
15857
+ const multiColumn = fill && !options.some((option) => option.hint);
15858
+ const wrapperClassName = fill ? FILL_WRAPPER_CLASS_NAME : undefined;
15859
+ const toggle = (option) => onChange(toggleValue(value, option.value));
15860
+ if (options.length === 0) {
15861
+ return (jsxRuntime.jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No options available" }));
15862
+ }
15863
+ if (layout === 'list') {
15864
+ return (jsxRuntime.jsxs("div", { className: cn('flex flex-col gap-2', fill && FILL_WRAPPER_CLASS_NAME), "aria-label": ariaLabel, role: "group", children: [searchPlaceholder !== undefined &&
15865
+ (alwaysSearchable || options.length >= SEARCH_MIN_OPTIONS) && (jsxRuntime.jsxs("label", { className: SEARCH_BOX_CLASS_NAME, children: [jsxRuntime.jsx(Search, { "aria-hidden": "true", className: "size-4 shrink-0 text-muted-foreground" }), jsxRuntime.jsx("input", { value: query, onChange: (event) => setQuery(event.target.value), placeholder: searchPlaceholder, "aria-label": getSearchInputLabel(ariaLabel), className: "min-w-0 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-placeholder" })] })), jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-1 text-xs text-muted-foreground", children: [jsxRuntime.jsx("span", { children: formatSelectedCount(selectedCount, options.length) }), selectedCount > 0 && (jsxRuntime.jsx("button", { type: "button", onClick: () => onChange([]), className: FILTER_LINK_CLASS_NAME, children: "Clear" }))] }), jsxRuntime.jsx(ScrollFade, { className: cn(multiColumn && 'grid content-start gap-x-3', scrollClassName, listClassName), style: multiColumn
15866
+ ? getGridColumnsStyle(undefined, LIST_COLUMN_MIN_WIDTH)
15867
+ : undefined, wrapperClassName: wrapperClassName, children: visibleOptions.map((option) => (jsxRuntime.jsxs("label", { className: LIST_ROW_CLASS_NAME, children: [jsxRuntime.jsx(Checkbox, { className: LIST_CHECKBOX_CLASS_NAME, checked: value.includes(option.value), onCheckedChange: () => toggle(option) }), jsxRuntime.jsx(OptionSwatch, { color: option.swatch }), option.content ? (jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: option.content })) : (jsxRuntime.jsx(TruncatedLabel, { text: option.label, className: "flex-1" })), (option.count ?? option.hint) !== undefined && (jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground tabular-nums", children: option.count ?? option.hint }))] }, option.value))) })] }));
15868
+ }
15869
+ if (layout === 'tiles') {
15870
+ return (jsxRuntime.jsx(ScrollFade, { role: "group", "aria-label": ariaLabel, wrapperClassName: wrapperClassName, className: cn('grid content-start gap-1.5', scrollClassName), style: getGridColumnsStyle(columns), children: visibleOptions.map((option) => (jsxRuntime.jsxs("button", { type: "button", "aria-pressed": value.includes(option.value), onClick: () => toggle(option), className: getTileClassName(value.includes(option.value)), children: [jsxRuntime.jsx(TruncatedLabel, { text: option.label }), option.count !== undefined && (jsxRuntime.jsx("span", { className: "text-xs font-normal text-muted-foreground", children: option.count }))] }, option.value))) }));
15871
+ }
15872
+ return (jsxRuntime.jsx(ScrollFade, { role: "group", "aria-label": ariaLabel, wrapperClassName: wrapperClassName, className: cn('flex flex-wrap content-start gap-1.5', scrollClassName), children: visibleOptions.map((option) => (jsxRuntime.jsxs("button", { type: "button", "aria-pressed": value.includes(option.value), onClick: () => toggle(option), className: getChipClassName(value.includes(option.value)), children: [jsxRuntime.jsx(OptionSwatch, { color: option.swatch, round: true }), jsxRuntime.jsx("span", { children: option.label }), option.count !== undefined && (jsxRuntime.jsx("span", { className: "font-normal text-muted-foreground", children: option.count }))] }, option.value))) }));
15873
+ }
15874
+
15348
15875
  const TRIGGER_BASE = 'h-9 !w-fit shadow-[0_1px_2px_0_rgba(0,0,0,0.05)] gap-2 text-foreground bg-card hover:bg-muted/40 border border-border rounded-lg text-sm font-medium px-3';
15349
15876
  const TRIGGER_ACTIVE = '!border-primary text-primary shadow-[0_0_0_3px_rgba(49,122,81,0.10)]';
15350
15877
  const CONTENT_BASE = 'min-w-[8rem]';
15351
15878
  const isFilterActive = (value, resetValue) => !!value && value !== resetValue;
15879
+ function collectText(node) {
15880
+ if (typeof node === 'string' || typeof node === 'number')
15881
+ return String(node);
15882
+ if (Array.isArray(node))
15883
+ return node.map(collectText).join(' ');
15884
+ if (React.isValidElement(node))
15885
+ return React.Children.toArray(node.props.children).map(collectText).join(' ');
15886
+ return '';
15887
+ }
15888
+ /** The visible text inside a label, e.g. a JSX name + description becomes "Name Description". */
15889
+ const getNodeText = (node) => collectText(node).replace(/\s+/g, ' ').trim();
15890
+ /** A JSX label keeps its look as the row's `content`; its text (or the value) is what search and screen readers use. */
15891
+ const toPickListOptions = (options) => options.map((option) => typeof option.label === 'string'
15892
+ ? { value: option.value, label: option.label }
15893
+ : {
15894
+ value: option.value,
15895
+ label: getNodeText(option.label) || option.value,
15896
+ content: option.label,
15897
+ });
15352
15898
 
15353
15899
  /**
15354
- * Multi-select filter dropdown — Popover + checkbox list, matching the
15355
- * `FilterSelect` trigger look (filter icon + count badge when active).
15356
- * Selecting items keeps the popover open; the trigger shows the count.
15900
+ * Multi-select filter dropdown with the `FilterSelect` trigger look (filter icon + count badge when active).
15901
+ * Opens a pick list: a searchable checkbox list with "x of y selected · Clear", or chips/tiles under a
15902
+ * title, count and Clear. Selecting keeps the popover open.
15357
15903
  */
15358
- const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, }) => {
15904
+ const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, pickListLayout = 'list', searchPlaceholder, }) => {
15359
15905
  const active = value.length > 0;
15360
- const toggle = (optValue) => {
15361
- if (value.includes(optValue)) {
15362
- onChange(value.filter((v) => v !== optValue));
15363
- }
15364
- else {
15365
- onChange([...value, optValue]);
15366
- }
15367
- };
15368
- return (jsxRuntime.jsxs(Popover, { modal: modal, children: [jsxRuntime.jsx(PopoverTrigger, { className: cn(TRIGGER_BASE, 'inline-flex items-center justify-between', active && TRIGGER_ACTIVE, triggerClassName), children: jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), label, active && (jsxRuntime.jsx("span", { className: "ml-1 inline-flex h-4 min-w-4 items-center justify-center rounded bg-primary/10 px-1 text-[10px] font-semibold leading-none text-primary", children: value.length }))] }) }), jsxRuntime.jsx(PopoverContent, { align: "start", className: cn('w-56 p-1', contentClassName), children: jsxRuntime.jsx("div", { className: cn('max-h-[18rem] overflow-y-auto', listClassName), children: options.map((opt) => {
15369
- const checked = value.includes(opt.value);
15370
- return (jsxRuntime.jsxs("button", { type: "button", onClick: () => toggle(opt.value), className: "flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-foreground hover:bg-muted/60", children: [jsxRuntime.jsx(Checkbox, { checked: checked, onCheckedChange: () => toggle(opt.value),
15371
- // Stop the inner checkbox click from double-toggling via the button.
15372
- onClick: (e) => e.stopPropagation() }), jsxRuntime.jsx("span", { className: "flex-1 truncate", children: opt.label })] }, opt.value));
15373
- }) }) })] }));
15906
+ const isList = pickListLayout === 'list';
15907
+ return (jsxRuntime.jsxs(Popover, { modal: modal, children: [jsxRuntime.jsx(PopoverTrigger, { className: cn(TRIGGER_BASE, 'inline-flex items-center justify-between', active && TRIGGER_ACTIVE, triggerClassName), children: jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), label, active && (jsxRuntime.jsx("span", { className: "ml-1 inline-flex h-4 min-w-4 items-center justify-center rounded bg-primary/10 px-1 text-[10px] font-semibold leading-none text-primary", children: value.length }))] }) }), jsxRuntime.jsx(PopoverContent, { align: "start", sideOffset: 4, className: cn('w-64 p-0', contentClassName), children: jsxRuntime.jsx(FilterPanel, { variant: "popover",
15908
+ // A searchable list has its own "x of y selected · Clear" row.
15909
+ title: isList ? undefined : label, selectedCount: isList ? undefined : value.length, onClear: !isList && active ? () => onChange([]) : undefined, children: jsxRuntime.jsx(PickListFilter, { ariaLabel: label, layout: pickListLayout, options: toPickListOptions(options), value: value, onChange: onChange, searchPlaceholder: isList ? (searchPlaceholder ?? 'Search') : undefined, alwaysSearchable: true, listClassName: listClassName }) }) })] }));
15374
15910
  };
15375
15911
 
15376
15912
  const KYC_STATUS = {
@@ -21241,37 +21777,30 @@ const formatDate$3 = (iso) => {
21241
21777
  }
21242
21778
  };
21243
21779
 
21244
- const InfoCard = ({ info, title, refundToWallet, onRefundChange, }) => {
21780
+ /** The document the dialog acts on: number, customer, total and date, plus paid / outstanding when known. */
21781
+ const InfoCard = ({ info }) => {
21245
21782
  if (!info)
21246
21783
  return null;
21247
21784
  if (React.isValidElement(info))
21248
- return jsxRuntime.jsx("div", { className: "mt-3", children: info });
21785
+ return jsxRuntime.jsx("div", { children: info });
21249
21786
  const i = info;
21250
- return (jsxRuntime.jsx("div", { className: "mt-1 rounded-lg border bg-muted p-3 shadow-sm", children: jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [jsxRuntime.jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Date" }), jsxRuntime.jsx("div", { children: formatDate$3(i.invoiceDate) })] }), jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [jsxRuntime.jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Total" }), jsxRuntime.jsx("div", { className: "font-medium text-foreground", children: formatCurrencyWithTenantSymbol(i.totalAmount) })] }), i.paidAmount !== undefined && (jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [jsxRuntime.jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Paid" }), jsxRuntime.jsx("div", { className: "font-medium text-primary", children: formatCurrencyWithTenantSymbol(i.paidAmount) })] })), i.outstandingAmount !== undefined && (jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [jsxRuntime.jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Outstanding" }), jsxRuntime.jsx("div", { className: "font-medium text-muted-foreground", children: formatCurrencyWithTenantSymbol(i.outstandingAmount) })] })), title === 'Cancel Invoice' &&
21251
- !React.isValidElement(info) &&
21252
- (i?.paidAmount ?? 0) > 0 && (jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [jsxRuntime.jsx("div", { className: "w-36 whitespace-nowrap text-sm text-muted-foreground", children: "Refund to Wallet" }), jsxRuntime.jsx(Checkbox, { checked: !!refundToWallet, onCheckedChange: (v) => onRefundChange?.(Boolean(v)), className: "bg-card" })] })), (i.customerName || i.email) && (jsxRuntime.jsxs("div", { className: "mt-1 rounded bg-card p-2", children: [i.customerName && (jsxRuntime.jsx("div", { className: "text-sm font-medium", children: i.customerName })), i.email && (jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", children: i.email }))] }))] }) }));
21787
+ const party = [i.customerName, i.email].filter(Boolean).join(' · ');
21788
+ const hasBalance = i.paidAmount !== undefined || i.outstandingAmount !== undefined;
21789
+ return (jsxRuntime.jsxs("div", { className: "rounded-xl border border-border bg-muted/30 p-3.5", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("span", { "aria-hidden": true, className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground", children: jsxRuntime.jsx(FileText, { className: "size-4" }) }), jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [i.invoiceNumber && (jsxRuntime.jsx("p", { className: "m-0 truncate text-sm font-semibold text-foreground", children: i.invoiceNumber })), party && jsxRuntime.jsx("p", { className: "m-0 truncate text-xs text-muted-foreground", children: party })] }), jsxRuntime.jsxs("div", { className: "shrink-0 text-right", children: [i.totalAmount !== undefined && (jsxRuntime.jsx("p", { className: "m-0 text-sm font-semibold tabular-nums text-foreground", children: formatCurrencyWithTenantSymbol(i.totalAmount) })), i.invoiceDate && jsxRuntime.jsx("p", { className: "m-0 text-xs text-muted-foreground", children: formatDate$3(i.invoiceDate) })] })] }), hasBalance && (jsxRuntime.jsxs("dl", { className: "m-0 mt-3 grid gap-1.5 border-t border-border pt-3 text-sm", children: [i.paidAmount !== undefined && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground", children: "Paid" }), jsxRuntime.jsx("dd", { className: "m-0 font-medium tabular-nums text-amount-paid", children: formatCurrencyWithTenantSymbol(i.paidAmount) })] })), i.outstandingAmount !== undefined && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground", children: "Outstanding" }), jsxRuntime.jsx("dd", { className: "m-0 font-medium tabular-nums text-foreground", children: formatCurrencyWithTenantSymbol(i.outstandingAmount) })] }))] }))] }));
21253
21790
  };
21254
21791
 
21255
- function useRefundToWallet(open) {
21256
- const [refundToWallet, setRefundToWallet] = React.useState(true);
21257
- React.useEffect(() => {
21258
- if (open)
21259
- setRefundToWallet(true);
21260
- }, [open]);
21261
- return { refundToWallet, setRefundToWallet };
21262
- }
21263
-
21264
- const ConfirmDialog = ({ open, onOpenChange, title, description, info, confirmLabel = 'Yes', cancelLabel = 'Cancel', confirmVariant = 'default', icon: Icon = Trash2, disabled = false, onConfirm, onCancel, }) => {
21265
- const { refundToWallet, setRefundToWallet } = useRefundToWallet(open);
21792
+ const ConfirmDialog = ({ open, onOpenChange, title, description, info, confirmLabel = 'Yes', cancelLabel = 'Cancel', confirmVariant = 'default', icon, disabled = false, onConfirm, onCancel, children, }) => {
21266
21793
  // Opened from a modal menu row, two dismissable layers overlap and Radix
21267
21794
  // restores `pointer-events: none` to <body> on close, freezing the page.
21268
21795
  useOverlayBodyLockRelease(open);
21269
- return (jsxRuntime.jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxRuntime.jsxs(DialogContent, { className: "gap-3 p-5", children: [jsxRuntime.jsxs(DialogHeader, { className: "gap-1.5", children: [jsxRuntime.jsxs(DialogTitle, { className: "flex items-center gap-2", children: [confirmVariant === 'destructive' && (jsxRuntime.jsx("span", { className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-destructive/10", children: jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5 text-destructive" }) })), jsxRuntime.jsx("span", { children: title })] }), description && jsxRuntime.jsx(DialogDescription, { children: description }), info && (jsxRuntime.jsx(InfoCard, { info: info, title: title, refundToWallet: refundToWallet, onRefundChange: setRefundToWallet }))] }), jsxRuntime.jsxs(DialogFooter, { className: "mt-1", children: [jsxRuntime.jsx(Button$1, { variant: "outline", onClick: () => {
21796
+ const destructive = confirmVariant === 'destructive';
21797
+ const Icon = icon ?? (destructive ? Trash2 : undefined);
21798
+ return (jsxRuntime.jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxRuntime.jsxs(DialogContent, { children: [jsxRuntime.jsxs(DialogHeader, { icon: Icon ? jsxRuntime.jsx(Icon, {}) : undefined, iconTone: destructive ? 'destructive' : 'primary', children: [jsxRuntime.jsx(DialogTitle, { children: title }), description && jsxRuntime.jsx(DialogDescription, { children: description })] }), info && jsxRuntime.jsx(InfoCard, { info: info }), children, jsxRuntime.jsxs(DialogFooter, { children: [jsxRuntime.jsx(Button$1, { variant: "outline", onClick: () => {
21270
21799
  onCancel?.();
21271
21800
  onOpenChange(false);
21272
- }, disabled: disabled, children: cancelLabel }), jsxRuntime.jsxs(Button$1, { variant: confirmVariant, onClick: async () => {
21273
- await onConfirm(title === 'Cancel Invoice' ? refundToWallet : undefined);
21274
- }, disabled: disabled, children: [confirmVariant === 'destructive' && (jsxRuntime.jsx(Icon, { className: "h-4 w-4", "aria-hidden": true })), disabled ? 'Please wait...' : confirmLabel] })] })] }) }));
21801
+ }, disabled: disabled, children: cancelLabel }), jsxRuntime.jsx(Button$1, { variant: confirmVariant, onClick: async () => {
21802
+ await onConfirm();
21803
+ }, disabled: disabled, children: disabled ? 'Please wait...' : confirmLabel })] })] }) }));
21275
21804
  };
21276
21805
 
21277
21806
  function matchesSearch(haystack, search) {
@@ -21636,6 +22165,34 @@ function useRowEditing({ saving, onEditChange, onSaveRow, }) {
21636
22165
  handleEditIconClick,
21637
22166
  };
21638
22167
  }
22168
+ /**
22169
+ * Measures the rows area so a loading skeleton can cover exactly the rows it replaces —
22170
+ * the rows stay in the layout (hidden), so column widths and table height never jump.
22171
+ */
22172
+ function useLoadingOverlay(scrollRef, headRef, bodyRef, loading) {
22173
+ const [box, setBox] = React.useState(null);
22174
+ React.useLayoutEffect(() => {
22175
+ const scroll = scrollRef.current;
22176
+ const head = headRef.current;
22177
+ const body = bodyRef.current;
22178
+ if (!loading || !scroll || !head || !body) {
22179
+ setBox(null);
22180
+ return;
22181
+ }
22182
+ const measure = () => setBox({
22183
+ top: head.offsetHeight,
22184
+ width: scroll.scrollWidth,
22185
+ height: body.offsetHeight,
22186
+ visibleWidth: scroll.clientWidth,
22187
+ });
22188
+ measure();
22189
+ const observer = new ResizeObserver(measure);
22190
+ observer.observe(scroll);
22191
+ observer.observe(body);
22192
+ return () => observer.disconnect();
22193
+ }, [loading, scrollRef, headRef, bodyRef]);
22194
+ return box;
22195
+ }
21639
22196
 
21640
22197
  function normalizeOptions(options) {
21641
22198
  return options.map((opt) => typeof opt === 'string'
@@ -21666,6 +22223,30 @@ function pinnedHeaderClass() {
21666
22223
  function pinnedCellClass(pinnedBg) {
21667
22224
  return cn('sticky right-0 z-10', PINNED_BEFORE, PINNED_SHADOW, pinnedBg);
21668
22225
  }
22226
+ const PINNED_RIGHT_WIDTH = '72px';
22227
+ /** Width for a header/body/filter cell: the resized width var while resized or dragging, a fixed width for the pinned actions column. */
22228
+ function getColumnWidthStyle(key, isSized, isPinnedRight) {
22229
+ if (isSized) {
22230
+ const width = `var(--col-w-${key})`;
22231
+ return { width, minWidth: width, maxWidth: width };
22232
+ }
22233
+ return isPinnedRight
22234
+ ? {
22235
+ width: PINNED_RIGHT_WIDTH,
22236
+ minWidth: PINNED_RIGHT_WIDTH,
22237
+ maxWidth: PINNED_RIGHT_WIDTH,
22238
+ }
22239
+ : undefined;
22240
+ }
22241
+ function hasFilterRow(columns, filterRowLeading) {
22242
+ return (filterRowLeading != null || columns.some((col) => col.filter !== undefined));
22243
+ }
22244
+ /** `TableRowsSkeleton` bar (52px) plus its gap (8px). */
22245
+ const SKELETON_ROW_PX = 60;
22246
+ /** How many skeleton bars fill a rows area of `height` px (at least one). */
22247
+ function getSkeletonRowCount(height) {
22248
+ return Math.max(1, Math.floor(height / SKELETON_ROW_PX));
22249
+ }
21669
22250
 
21670
22251
  const isValidHex = (v) => /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(v);
21671
22252
  /**
@@ -21757,8 +22338,52 @@ function EditableCellContent({ col, row, value, isEditing, width, onEditValueCha
21757
22338
  }
21758
22339
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: clipToWidth(stringValue, width) });
21759
22340
  }
22341
+ const FILTER_CELL = 'px-0.5 py-0.5 font-normal border-b border-solid !border-border';
22342
+ /** Opt-in second header row holding each column's filter control. */
22343
+ function FilterRow({ columns, leading, showEditColumn, showSelectionColumn, isArchiveView, vBorder, localWidths, draggingKey, }) {
22344
+ const leadingCellCount = Number(showEditColumn) + Number(showSelectionColumn);
22345
+ return (jsxRuntime.jsxs("tr", { children: [Array.from({ length: leadingCellCount }, (_, index) => (jsxRuntime.jsx("th", { className: cn(FILTER_CELL, 'first:!pl-6 text-left', vBorder), children: index === 0 ? leading : null }, `leading-${index}`))), columns.map((col) => {
22346
+ const isPinnedRight = col.key === 'actions';
22347
+ return (jsxRuntime.jsx("th", { className: cn(FILTER_CELL, 'first:!pl-6 text-left', vBorder, isArchiveView && !isPinnedRight && 'pl-1', isPinnedRight && pinnedHeaderClass()), style: getColumnWidthStyle(col.key, Boolean(localWidths[col.key]) || draggingKey === col.key, isPinnedRight), children: col.filter }, col.key.toString()));
22348
+ })] }));
22349
+ }
22350
+ /** Keeps the real pagination in the layout (hidden) and lays a placeholder over it, so the footer height never jumps. */
22351
+ function PaginationLoading({ children, }) {
22352
+ return (jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("div", { className: "invisible", children: children }), jsxRuntime.jsxs("div", { "aria-hidden": "true", className: "absolute inset-0 flex items-center justify-between bg-card px-4", children: [jsxRuntime.jsx(SquareSkeleton, { height: 14, width: 160, rounded: "sm" }), jsxRuntime.jsx(SquareSkeleton, { height: 28, width: 220, rounded: "md" })] })] }));
22353
+ }
22354
+
22355
+ /** Label line + input block — mirrors a `Field`. */
22356
+ function FieldSkeleton() {
22357
+ return (jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 40, className: "w-full", rounded: "md" })] }));
22358
+ }
22359
+ /**
22360
+ * Loading placeholder that matches a `FormSectionCard` — the tinted header band
22361
+ * (icon square + title + description) above a body of `Field` placeholders and
22362
+ * an optional footer action row.
22363
+ */
22364
+ function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
22365
+ return (jsxRuntime.jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-xl border border-border bg-card shadow-card", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsxRuntime.jsx(SquareSkeleton, { height: 40, width: 40, rounded: "md" }), jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [jsxRuntime.jsx(SquareSkeleton, { height: 14, width: 180, rounded: "full" }), description && jsxRuntime.jsx(SquareSkeleton, { height: 11, width: 260, rounded: "full" })] })] }), jsxRuntime.jsxs("div", { className: "p-5", children: [jsxRuntime.jsx("div", { className: cn('grid gap-x-6 gap-y-5', columns === 2 ? 'grid-cols-1 md:grid-cols-2' : 'grid-cols-1'), children: Array.from({ length: fields }).map((_, i) => (jsxRuntime.jsx(FieldSkeleton, {}, i))) }), footer !== 'none' && (jsxRuntime.jsxs("div", { className: cn('mt-8 flex items-center gap-3 pt-4', footer === 'between' ? 'justify-between' : 'justify-end'), children: [footer === 'between' && (jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 90, rounded: "md" })), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 120, rounded: "md" })] }))] })] }));
22366
+ }
22367
+ /** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
22368
+ function TableSkeleton({ rows = 8 }) {
22369
+ return (jsxRuntime.jsxs("div", { className: "space-y-3", children: [jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx(SquareSkeleton, { className: "h-9 flex-1", rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { className: "h-9 w-44", rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { className: "h-9 w-48", rounded: "md" })] }), Array.from({ length: rows }).map((_, i) => (jsxRuntime.jsx(SquareSkeleton, { className: "h-12 w-full", rounded: "md" }, i)))] }));
22370
+ }
22371
+ /** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
22372
+ function TableRowsSkeleton({ rows = 10, className }) {
22373
+ return (jsxRuntime.jsx("div", { className: cn('flex w-full flex-col gap-2 overflow-hidden', className), "aria-busy": "true", "aria-label": "Loading", children: Array.from({ length: rows }).map((_, i) => (
22374
+ // shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
22375
+ jsxRuntime.jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
22376
+ }
22377
+ /** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
22378
+ function DetailPageSkeleton({ sections = 3, }) {
22379
+ return (jsxRuntime.jsxs("div", { className: "space-y-5", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx(SquareSkeleton, { height: 32, width: 32, rounded: "md" }), jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [jsxRuntime.jsx(SquareSkeleton, { height: 20, width: 192, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 128, rounded: "full" })] })] }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 128, rounded: "md" })] }), Array.from({ length: sections }).map((_, s) => (jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-xl border border-border bg-card", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsxRuntime.jsx(SquareSkeleton, { height: 32, width: 32, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 16, width: 160, rounded: "full" })] }), jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-5 p-5 md:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [jsxRuntime.jsx(SquareSkeleton, { height: 10, width: 80, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 14, width: 128, rounded: "full" })] }, i))) })] }, s)))] }));
22380
+ }
22381
+ /** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
22382
+ function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
22383
+ return (jsxRuntime.jsxs("div", { role: "status", "aria-busy": "true", "aria-label": label, className: "space-y-4", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx(SquareSkeleton, { height: 14, width: 80, rounded: "full" }), jsxRuntime.jsx("span", { className: "h-5 w-px bg-border" }), jsxRuntime.jsx(SquareSkeleton, { height: 28, width: 200, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 22, width: 72, rounded: "full" })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 112, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 80, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 128, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 36, rounded: "lg" })] })] }), jsxRuntime.jsxs("section", { "aria-hidden": "true", className: "grid grid-cols-1 overflow-hidden rounded-2xl border border-border bg-card md:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)]", children: [jsxRuntime.jsxs("div", { className: "flex flex-col justify-center space-y-3 px-5 py-4 sm:px-7 sm:py-4", children: [jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 40, width: 220, rounded: "md" }), aside !== 'none' && (jsxRuntime.jsxs("div", { className: "w-full max-w-xl space-y-2 pt-1", children: [jsxRuntime.jsx(SquareSkeleton, { height: 8, className: "w-full", rounded: "full" }), jsxRuntime.jsxs("div", { className: "flex justify-between", children: [jsxRuntime.jsx(SquareSkeleton, { height: 11, width: 88, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 11, width: 40, rounded: "full" })] })] }))] }), jsxRuntime.jsx("div", { className: "border-t border-border bg-muted/40 px-5 py-2 md:border-l md:border-t-0", children: [0, 1, 2, 3].map((i) => (jsxRuntime.jsxs("div", { className: "flex min-h-10 items-center gap-3 border-b border-border py-1.5 last:border-b-0", children: [jsxRuntime.jsx(SquareSkeleton, { height: 24, width: 24, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 72, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 88, rounded: "full", className: "ml-auto" })] }, i))) })] }), Array.from({ length: sections }).map((_, s) => (jsxRuntime.jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-2xl border border-border bg-card", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-3", children: [jsxRuntime.jsx(SquareSkeleton, { height: 28, width: 28, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 15, width: 128, rounded: "full" })] }), jsxRuntime.jsx("div", { className: "space-y-3 p-4", children: Array.from({ length: s === 1 ? 4 : 2 }).map((__, row) => (jsxRuntime.jsx(SquareSkeleton, { height: s === 1 ? 36 : 14, className: row % 2 ? 'w-3/4' : 'w-full', rounded: "md" }, row))) })] }, s))), jsxRuntime.jsx("span", { className: "sr-only", children: label })] }));
22384
+ }
21760
22385
 
21761
- function DataEditableTable({ data, columns, onRowClick, enableSelection = false, columnStyles = {}, onEditChange, onSaveRow, sortBy, setSortBy, sortOrder, setSortOrder, saving, selectedRows = [], onSelectionChange, isArchiveView = false, selectionInArchiveView = false, permissionKey = '', columnWidths, onColumnResize, pagination, fetchBusinessContacts, showGrid = true, striped = true, emptyState, }) {
22386
+ function DataEditableTable({ data, columns, onRowClick, enableSelection = false, columnStyles = {}, onEditChange, onSaveRow, sortBy, setSortBy, sortOrder, setSortOrder, saving, selectedRows = [], onSelectionChange, isArchiveView = false, selectionInArchiveView = false, permissionKey = '', columnWidths, onColumnResize, pagination, fetchBusinessContacts, showGrid = true, striped = true, emptyState, loading = false, loadingRows = 10, filterRowLeading, }) {
21762
22387
  const showSelectionColumn = enableSelection && (!isArchiveView || selectionInArchiveView);
21763
22388
  const vBorder = showGrid ? 'border-r' : '';
21764
22389
  const { localWidths, draggingKey, tableRef, handleResizeMouseDown } = useColumnResize({
@@ -21771,6 +22396,11 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21771
22396
  onSelectionChange,
21772
22397
  });
21773
22398
  const { editingRow, editValues, savingRow, handleEditValueChange, handleEditIconClick, } = useRowEditing({ saving, onEditChange, onSaveRow });
22399
+ const scrollRef = React.useRef(null);
22400
+ const headRef = React.useRef(null);
22401
+ const bodyRef = React.useRef(null);
22402
+ // Rows stay in the layout while loading; the skeleton covers them so nothing resizes.
22403
+ const overlay = useLoadingOverlay(scrollRef, headRef, bodyRef, loading);
21774
22404
  const handleColumnClick = (columnKey, sortable) => {
21775
22405
  if (!sortable || !setSortBy || !setSortOrder)
21776
22406
  return;
@@ -21782,25 +22412,17 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21782
22412
  setSortOrder('asc');
21783
22413
  }
21784
22414
  };
21785
- return (jsxRuntime.jsxs("div", { className: "w-full h-full rounded-lg border border-border bg-card flex flex-col overflow-hidden", children: [jsxRuntime.jsxs("div", { className: "overflow-auto flex-1", children: [jsxRuntime.jsxs("table", { ref: tableRef, className: "min-w-[70vh] w-full text-xs text-center border-separate", style: { borderSpacing: 0 }, children: [jsxRuntime.jsx("thead", { className: "sticky top-0 z-20 !bg-table-header border-b border-border text-secondary-foreground text-sm", children: jsxRuntime.jsxs("tr", { className: "h-[40px]", children: [!isArchiveView && (jsxRuntime.jsx("th", { className: cn('px-3 py-1.5 text-left font-semibold w-8 first:!pl-6 border-b border-solid !border-border', vBorder) })), showSelectionColumn && (jsxRuntime.jsx("th", { className: cn('px-3 py-1.5 text-center font-semibold first:!pl-6 border-b border-solid !border-border', vBorder), children: jsxRuntime.jsx(Checkbox, { checked: allSelected
21786
- ? true
21787
- : someSelected
21788
- ? 'indeterminate'
21789
- : false, onCheckedChange: toggleSelectAll }) })), columns.map((col) => {
21790
- const w = localWidths[col.key];
21791
- const isDragging = draggingKey === col.key;
21792
- const isPinnedRight = col.key === 'actions';
21793
- const thStyle = w || isDragging
21794
- ? {
21795
- width: `var(--col-w-${col.key})`,
21796
- minWidth: `var(--col-w-${col.key})`,
21797
- maxWidth: `var(--col-w-${col.key})`,
21798
- }
21799
- : isPinnedRight
21800
- ? { width: '72px', minWidth: '72px', maxWidth: '72px' }
21801
- : undefined;
21802
- return (jsxRuntime.jsxs("th", { className: cn('px-4 py-1.5 relative first:!pl-6 text-left whitespace-nowrap font-semibold text-sm border-b border-solid !border-border', vBorder, isArchiveView && !isPinnedRight && 'pl-1', col.sortable && '!cursor-pointer hover:bg-muted/60', isDragging && 'bg-primary/10', isPinnedRight && pinnedHeaderClass()), style: thStyle, onClick: () => handleColumnClick(col.key, col.sortable), children: [jsxRuntime.jsxs("div", { className: cn('gap-2', w && 'overflow-hidden', col.sortable && 'flex items-center !cursor-pointer', isPinnedRight && 'flex items-center justify-center'), children: [w && typeof col.header === 'string' ? (jsxRuntime.jsx("span", { className: "truncate", title: col.header, children: col.header })) : (col.header), col.sortable && (jsxRuntime.jsx(SortIcon, { active: sortBy === col.key, order: sortOrder }))] }), jsxRuntime.jsx("div", { className: cn('absolute right-0 top-0 h-full w-1.5 z-20 cursor-col-resize select-none transition-colors hover:bg-primary/40', isDragging && 'bg-primary/40'), onMouseDown: (e) => handleResizeMouseDown(e, col.key), onClick: (e) => e.stopPropagation() })] }, col.key.toString()));
21803
- })] }) }), jsxRuntime.jsx("tbody", { children: data.map((row, rowIndex) => {
22415
+ return (jsxRuntime.jsxs("div", { className: "w-full h-full rounded-lg border border-border bg-card flex flex-col overflow-hidden", children: [jsxRuntime.jsxs("div", { ref: scrollRef, className: "relative overflow-auto flex-1", children: [jsxRuntime.jsxs("table", { ref: tableRef, className: "min-w-[70vh] w-full text-xs text-center border-separate", style: { borderSpacing: 0 }, children: [jsxRuntime.jsxs("thead", { ref: headRef, className: "sticky top-0 z-20 !bg-table-header border-b border-border text-secondary-foreground text-sm", children: [jsxRuntime.jsxs("tr", { className: "h-[40px]", children: [!isArchiveView && (jsxRuntime.jsx("th", { className: cn('px-3 py-1.5 text-left font-semibold w-8 first:!pl-6 border-b border-solid !border-border', vBorder) })), showSelectionColumn && (jsxRuntime.jsx("th", { className: cn('px-3 py-1.5 text-center font-semibold first:!pl-6 border-b border-solid !border-border', vBorder), children: jsxRuntime.jsx(Checkbox, { checked: allSelected
22416
+ ? true
22417
+ : someSelected
22418
+ ? 'indeterminate'
22419
+ : false, onCheckedChange: toggleSelectAll }) })), columns.map((col) => {
22420
+ const w = localWidths[col.key];
22421
+ const isDragging = draggingKey === col.key;
22422
+ const isPinnedRight = col.key === 'actions';
22423
+ const thStyle = getColumnWidthStyle(col.key, Boolean(w) || isDragging, isPinnedRight);
22424
+ return (jsxRuntime.jsxs("th", { className: cn('px-4 py-1.5 relative first:!pl-6 text-left whitespace-nowrap font-semibold text-sm border-b border-solid !border-border', vBorder, isArchiveView && !isPinnedRight && 'pl-1', col.sortable && '!cursor-pointer hover:bg-muted/60', isDragging && 'bg-primary/10', isPinnedRight && pinnedHeaderClass()), style: thStyle, onClick: () => handleColumnClick(col.key, col.sortable), children: [jsxRuntime.jsxs("div", { className: cn('gap-2', w && 'overflow-hidden', col.sortable && 'flex items-center !cursor-pointer', col.filterActive && 'flex items-center', isPinnedRight && 'flex items-center justify-center'), children: [w && typeof col.header === 'string' ? (jsxRuntime.jsx("span", { className: "truncate", title: col.header, children: col.header })) : (col.header), col.filterActive && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Funnel, { "aria-hidden": "true", className: "size-3 shrink-0 text-primary" }), jsxRuntime.jsx("span", { className: "sr-only", children: "Filtered" })] })), col.sortable && (jsxRuntime.jsx(SortIcon, { active: sortBy === col.key, order: sortOrder }))] }), jsxRuntime.jsx("div", { className: cn('absolute right-0 top-0 h-full w-1.5 z-20 cursor-col-resize select-none transition-colors hover:bg-primary/40', isDragging && 'bg-primary/40'), onMouseDown: (e) => handleResizeMouseDown(e, col.key), onClick: (e) => e.stopPropagation() })] }, col.key.toString()));
22425
+ })] }), hasFilterRow(columns, filterRowLeading) && (jsxRuntime.jsx(FilterRow, { columns: columns, leading: filterRowLeading, showEditColumn: !isArchiveView, showSelectionColumn: showSelectionColumn, isArchiveView: isArchiveView, vBorder: vBorder, localWidths: localWidths, draggingKey: draggingKey }))] }), jsxRuntime.jsx("tbody", { ref: bodyRef, "aria-busy": loading || undefined, className: cn(loading && 'invisible'), children: data.map((row, rowIndex) => {
21804
22426
  const isEditing = editingRow === row.id && editingRow !== null;
21805
22427
  const isSaving = savingRow === row.id;
21806
22428
  const isSelected = selectedSet.has(row.id);
@@ -21820,19 +22442,7 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21820
22442
  : row[col.key];
21821
22443
  const w = localWidths[col.key];
21822
22444
  const isPinnedRight = col.key === 'actions';
21823
- const tdStyle = w || draggingKey === col.key
21824
- ? {
21825
- width: `var(--col-w-${col.key})`,
21826
- minWidth: `var(--col-w-${col.key})`,
21827
- maxWidth: `var(--col-w-${col.key})`,
21828
- }
21829
- : isPinnedRight
21830
- ? {
21831
- width: '72px',
21832
- minWidth: '72px',
21833
- maxWidth: '72px',
21834
- }
21835
- : undefined;
22445
+ const tdStyle = getColumnWidthStyle(col.key, Boolean(w) || draggingKey === col.key, isPinnedRight);
21836
22446
  // Pinned cells need an OPAQUE bg matching the row state so the
21837
22447
  // scrolling content underneath doesn't bleed through — no alpha tints.
21838
22448
  const pinnedBg = isPinnedRight
@@ -21848,7 +22458,13 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21848
22458
  ? 'text-right'
21849
22459
  : 'text-left', isArchiveView && !isPinnedRight && 'pl-2', columnStyles?.[col.key.toString()] || '', draggingKey === col.key && 'bg-primary/5', isPinnedRight && pinnedCellClass(pinnedBg)), style: tdStyle, children: jsxRuntime.jsx(EditableCellContent, { col: col, row: row, value: value, isEditing: isEditing, width: w, onEditValueChange: handleEditValueChange, fetchBusinessContacts: fetchBusinessContacts }) }, col.key.toString()));
21850
22460
  })] }, row.id));
21851
- }) })] }), data.length === 0 && (jsxRuntime.jsx("div", { className: "sticky left-0 flex w-full items-center justify-center p-6 text-sm text-muted-foreground", children: emptyState ?? 'No data available' }))] }), pagination] }));
22461
+ }) })] }), overlay && overlay.height > 0 ? (
22462
+ // `overflow-clip`, not `hidden`: hidden makes this box the sticky skeleton's scroller, pinning it to scrollLeft 0.
22463
+ jsxRuntime.jsx("div", { className: "absolute left-0 z-10 overflow-clip bg-card", style: {
22464
+ top: overlay.top,
22465
+ width: overlay.width,
22466
+ height: overlay.height,
22467
+ }, children: jsxRuntime.jsx("div", { className: "sticky left-0 p-3", style: { width: overlay.visibleWidth }, children: jsxRuntime.jsx(TableRowsSkeleton, { rows: getSkeletonRowCount(overlay.height) }) }) })) : (loading && (jsxRuntime.jsx("div", { className: "sticky left-0 w-full p-3", children: jsxRuntime.jsx(TableRowsSkeleton, { rows: loadingRows }) }))), !loading && data.length === 0 && (jsxRuntime.jsx("div", { className: "sticky left-0 flex w-full items-center justify-center p-6 text-sm text-muted-foreground", children: emptyState ?? 'No data available' }))] }), loading && pagination ? (jsxRuntime.jsx(PaginationLoading, { children: pagination })) : (pagination)] }));
21852
22468
  }
21853
22469
 
21854
22470
  /**
@@ -37234,7 +37850,11 @@ function DateInput({ value, onChange, onBlur, name, id, className, min, max, dis
37234
37850
 
37235
37851
  /** The permanent-delete confirmation for a document (quotation, memo, proforma…). */
37236
37852
  function DocumentDeleteDialog({ open, onOpenChange, documentLabel, documentNumber, info, busy, onConfirm, }) {
37237
- return (jsxRuntime.jsx(ConfirmDialog, { open: open, onOpenChange: onOpenChange, title: `Delete ${documentLabel}`, description: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("span", { children: ["Are you sure you want to permanently delete ", documentLabel, documentNumber ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("span", { className: "font-semibold", children: documentNumber })] })) : null, "?"] }), jsxRuntime.jsx("div", { className: "mt-1", children: "This action cannot be undone." })] }), info: info, confirmLabel: `Yes, Delete ${documentLabel}`, cancelLabel: "No, Keep It", confirmVariant: "destructive", disabled: busy, onConfirm: onConfirm }));
37853
+ const noun = documentLabel.toLowerCase();
37854
+ const summary = info == null || (typeof info === 'object' && !React.isValidElement(info))
37855
+ ? { invoiceNumber: documentNumber, ...(info ?? {}) }
37856
+ : info;
37857
+ return (jsxRuntime.jsx(ConfirmDialog, { open: open, onOpenChange: onOpenChange, title: `Delete ${noun}?`, info: summary, confirmLabel: "Delete", cancelLabel: "Cancel", confirmVariant: "destructive", disabled: busy, onConfirm: onConfirm }));
37238
37858
  }
37239
37859
 
37240
37860
  function clampPercent$1(value) {
@@ -37864,6 +38484,487 @@ function fieldTypeIcon(type) {
37864
38484
  return FIELD_TYPE_ICONS[type] ?? Type;
37865
38485
  }
37866
38486
 
38487
+ const getRemoveChipLabel = (label) => `Remove ${label} filter`;
38488
+ const FILTERED_BY_LABEL = 'Filtered by';
38489
+
38490
+ /** Compact badge shape with the filter chip colours. */
38491
+ const CHIP_CLASS = 'inline-flex h-6 max-w-full items-center gap-1 rounded-md border border-primary/30 bg-primary/5 px-2 text-xs text-foreground';
38492
+ const REMOVE_BUTTON_CLASS = 'inline-flex size-4 shrink-0 cursor-pointer items-center justify-center rounded-full text-muted-foreground outline-none hover:bg-primary/10 hover:text-foreground focus-visible:ring-2 focus-visible:ring-primary/30';
38493
+ const CLEAR_ALL_CLASS = cn(FILTER_LINK_CLASS_NAME, 'underline');
38494
+ function getChipLabelText(label, variant) {
38495
+ return variant === 'inline' ? `${label}:` : label;
38496
+ }
38497
+
38498
+ /** Applied filters as removable chips, with an optional Clear all. */
38499
+ function ActiveFilterChips({ chips, onRemove, onClearAll, variant = 'inline', className, }) {
38500
+ if (chips.length === 0)
38501
+ return null;
38502
+ return (jsxRuntime.jsxs("div", { className: cn('flex flex-wrap items-center gap-1.5', className), children: [variant === 'inline' && (jsxRuntime.jsx("span", { className: "mr-0.5 text-xs text-muted-foreground", children: FILTERED_BY_LABEL })), chips.map((chip) => (jsxRuntime.jsxs("span", { className: CHIP_CLASS, children: [jsxRuntime.jsx("span", { className: "shrink-0 font-semibold", children: getChipLabelText(chip.label, variant) }), jsxRuntime.jsx(TruncatedLabel, { text: chip.value }), onRemove && (jsxRuntime.jsx("button", { type: "button", "aria-label": getRemoveChipLabel(chip.label), onClick: () => onRemove(chip.id), className: REMOVE_BUTTON_CLASS, children: jsxRuntime.jsx(X$2, { "aria-hidden": "true", className: "size-3" }) }))] }, chip.id))), onClearAll && (jsxRuntime.jsx("button", { type: "button", onClick: onClearAll, className: CLEAR_ALL_CLASS, children: "Clear all" }))] }));
38503
+ }
38504
+
38505
+ const DEFAULT_CONTAINS_PLACEHOLDER = 'Contains…';
38506
+
38507
+ /**
38508
+ * Local text for a typed filter. It resets to `externalText` only when the applied value
38509
+ * (`externalKey`) changes from outside — e.g. Clear all — not when the change is this field's own commit.
38510
+ */
38511
+ function useFilterDraft(externalKey, externalText) {
38512
+ const [draft, setDraft] = React.useState(externalText);
38513
+ const [seenKey, setSeenKey] = React.useState(externalKey);
38514
+ const [committedKey, setCommittedKey] = React.useState(externalKey);
38515
+ if (seenKey !== externalKey) {
38516
+ setSeenKey(externalKey);
38517
+ if (externalKey !== committedKey) {
38518
+ setCommittedKey(externalKey);
38519
+ setDraft(externalText);
38520
+ }
38521
+ }
38522
+ return { draft, setDraft, markCommitted: setCommittedKey };
38523
+ }
38524
+ /** Debounces `callback`; a call still pending when the field unmounts (e.g. its popover closes) is flushed, not lost. */
38525
+ function useDebouncedCallback(callback, delay) {
38526
+ const callbackRef = React.useRef(callback);
38527
+ const timerRef = React.useRef(null);
38528
+ const pendingRef = React.useRef(null);
38529
+ React.useEffect(() => {
38530
+ callbackRef.current = callback;
38531
+ }, [callback]);
38532
+ const cancel = React.useCallback(() => {
38533
+ if (timerRef.current)
38534
+ clearTimeout(timerRef.current);
38535
+ timerRef.current = null;
38536
+ pendingRef.current = null;
38537
+ }, []);
38538
+ const flush = React.useCallback(() => {
38539
+ const pending = pendingRef.current;
38540
+ cancel();
38541
+ if (pending)
38542
+ callbackRef.current(...pending);
38543
+ }, [cancel]);
38544
+ const schedule = React.useCallback((...args) => {
38545
+ if (timerRef.current)
38546
+ clearTimeout(timerRef.current);
38547
+ pendingRef.current = args;
38548
+ timerRef.current = setTimeout(flush, delay);
38549
+ }, [delay, flush]);
38550
+ React.useEffect(() => flush, [flush]);
38551
+ return { schedule, flush, cancel };
38552
+ }
38553
+
38554
+ const COMMIT_DELAY_MS$2 = 400;
38555
+ function useContainsFilter(value, onChange) {
38556
+ const { draft, setDraft, markCommitted } = useFilterDraft(value, value);
38557
+ const commit = React.useCallback((text) => {
38558
+ const trimmed = text.trim();
38559
+ markCommitted(trimmed);
38560
+ if (trimmed !== value)
38561
+ onChange(trimmed);
38562
+ }, [markCommitted, onChange, value]);
38563
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$2);
38564
+ return {
38565
+ draft,
38566
+ handleChange: (event) => {
38567
+ setDraft(event.target.value);
38568
+ debounced.schedule(event.target.value);
38569
+ },
38570
+ handleKeyDown: (event) => {
38571
+ if (event.key === 'Enter')
38572
+ debounced.flush();
38573
+ },
38574
+ handleBlur: debounced.flush,
38575
+ };
38576
+ }
38577
+
38578
+ function getContainsClassName(size, applied, className) {
38579
+ if (size === 'cell')
38580
+ return getFilterFieldClassName(applied ? 'applied' : 'empty', className);
38581
+ return cn('h-9 text-sm', applied && 'border-primary bg-primary/5', className);
38582
+ }
38583
+
38584
+ /** "Contains…" text filter, as a filter-row cell or a full-size card field. */
38585
+ function ContainsFilter({ value, onChange, ariaLabel, placeholder = DEFAULT_CONTAINS_PLACEHOLDER, size = 'cell', className, }) {
38586
+ const { draft, handleChange, handleKeyDown, handleBlur } = useContainsFilter(value, onChange);
38587
+ const inputProps = {
38588
+ type: 'text',
38589
+ value: draft,
38590
+ placeholder,
38591
+ 'aria-label': ariaLabel,
38592
+ onChange: handleChange,
38593
+ onKeyDown: handleKeyDown,
38594
+ onBlur: handleBlur,
38595
+ className: getContainsClassName(size, value.trim() !== '', className),
38596
+ };
38597
+ return size === 'cell' ? (jsxRuntime.jsx("input", { ...inputProps })) : (jsxRuntime.jsx(Input, { ...inputProps }));
38598
+ }
38599
+
38600
+ const getPresetGroupLabel = (ariaLabel) => `${ariaLabel} presets`;
38601
+ const getDateInputLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
38602
+
38603
+ /** Dates shown in the inputs: a preset's resolved range, or the custom range. */
38604
+ function getDisplayedRange(value, today, fiscalYearStartMonth) {
38605
+ if (value?.preset)
38606
+ return resolveDatePreset(value.preset, today, fiscalYearStartMonth);
38607
+ return { from: value?.from ?? '', to: value?.to ?? '' };
38608
+ }
38609
+ function buildCustomRange(from, to) {
38610
+ return from || to
38611
+ ? { from: from || undefined, to: to || undefined }
38612
+ : undefined;
38613
+ }
38614
+ function togglePreset(value, preset) {
38615
+ return value?.preset === preset ? undefined : { preset };
38616
+ }
38617
+ /** Preset row; the picked one gets the primary tint, as in the design. */
38618
+ function getPresetClassName$1(selected) {
38619
+ return cn('w-full cursor-pointer whitespace-nowrap rounded-md px-3 py-2 text-left text-sm text-foreground transition-colors', FILTER_FOCUS_RING, selected ? 'bg-primary/5 font-semibold text-primary' : 'hover:bg-muted/60');
38620
+ }
38621
+
38622
+ const toIsoOrEmpty = (date) => date ? toIsoDate(date) : '';
38623
+ function useDateRangeFilter(value, onChange, today, fiscalYearStartMonth) {
38624
+ const { from, to } = getDisplayedRange(value, today, fiscalYearStartMonth);
38625
+ return {
38626
+ from,
38627
+ to,
38628
+ selectPreset: (preset) => onChange(togglePreset(value, preset)),
38629
+ handleFromChange: (date) => onChange(buildCustomRange(toIsoOrEmpty(date), to)),
38630
+ handleToChange: (date) => onChange(buildCustomRange(from, toIsoOrEmpty(date))),
38631
+ clear: () => onChange(undefined),
38632
+ };
38633
+ }
38634
+
38635
+ /** Date filter body: presets on the left, a From / To range on the right. */
38636
+ function DateRangeFilter({ value, onChange, ariaLabel, fiscalYearStartMonth = 1, today = new Date(), }) {
38637
+ const { from, to, selectPreset, handleFromChange, handleToChange, clear } = useDateRangeFilter(value, onChange, today, fiscalYearStartMonth);
38638
+ return (jsxRuntime.jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)] divide-x divide-border text-xs", children: [jsxRuntime.jsx("div", { role: "group", "aria-label": getPresetGroupLabel(ariaLabel), className: "flex flex-col gap-1 pr-3", children: DATE_PRESET_OPTIONS.map((preset) => (jsxRuntime.jsx("button", { type: "button", "aria-pressed": value?.preset === preset.value, onClick: () => selectPreset(preset.value), className: getPresetClassName$1(value?.preset === preset.value), children: preset.label }, preset.value))) }), jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-3 pl-3", children: [jsxRuntime.jsxs("label", { className: "flex min-w-0 flex-col gap-1 text-muted-foreground", children: ["From", jsxRuntime.jsx(DateInput, { value: fromIsoDate(from), max: to || undefined, ariaLabel: getDateInputLabel(ariaLabel, 'from'), onChange: handleFromChange })] }), jsxRuntime.jsxs("label", { className: "flex min-w-0 flex-col gap-1 text-muted-foreground", children: ["To", jsxRuntime.jsx(DateInput, { value: fromIsoDate(to), min: from || undefined, ariaLabel: getDateInputLabel(ariaLabel, 'to'), onChange: handleToChange, align: "end" })] }), value && (jsxRuntime.jsx("button", { type: "button", onClick: clear, className: cn('self-start', FILTER_LINK_CLASS_NAME), children: "Clear" }))] })] }));
38639
+ }
38640
+
38641
+ const getClearButtonLabel = (ariaLabel) => `Clear ${ariaLabel}`;
38642
+ const NOT_FILTERABLE_LABEL = "This column can't be filtered";
38643
+
38644
+ /** Select-like filter-row control: a compact trigger that opens the filter's panel in a popover. */
38645
+ function FilterCellPopover({ label, placeholder, ariaLabel, state, disabledLabel = NOT_FILTERABLE_LABEL, icon, onClear, showChevron = true, open, onOpenChange, contentClassName, className, children, }) {
38646
+ if (state === 'disabled') {
38647
+ return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("span", { tabIndex: 0, "aria-label": disabledLabel, className: "block outline-none", children: jsxRuntime.jsx("div", { role: "presentation", className: getFilterFieldClassName('disabled', className) }) }) }), jsxRuntime.jsx(TooltipContent, { side: "top", children: disabledLabel })] }) }));
38648
+ }
38649
+ return (jsxRuntime.jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [jsxRuntime.jsx(PopoverAnchor, { asChild: true, children: jsxRuntime.jsxs("div", { className: getFilterFieldClassName(state, cn('pr-1 focus-within:ring-2 focus-within:ring-primary/30', className)), children: [jsxRuntime.jsxs(PopoverTrigger, { "aria-label": ariaLabel, className: "flex h-full min-w-0 flex-1 cursor-pointer items-center gap-1 text-left outline-none", children: [icon && jsxRuntime.jsx("span", { className: "shrink-0 [&_svg]:size-3.5", children: icon }), jsxRuntime.jsx(TruncatedLabel, { text: label || placeholder, className: cn('min-w-0 flex-1', !label && 'font-normal text-placeholder') }), showChevron && (jsxRuntime.jsx(ChevronDown, { "aria-hidden": "true", className: "size-3.5 shrink-0 text-muted-foreground" }))] }), onClear && label && (jsxRuntime.jsx("button", { type: "button", "aria-label": getClearButtonLabel(ariaLabel), onClick: onClear, className: "inline-flex size-4 shrink-0 cursor-pointer items-center justify-center rounded-sm outline-none hover:bg-primary/10", children: jsxRuntime.jsx(X$2, { "aria-hidden": "true", className: "size-3" }) }))] }) }), jsxRuntime.jsx(PopoverContent, { align: "start",
38650
+ // The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
38651
+ updatePositionStrategy: "always", sideOffset: 4, className: cn('w-72 p-0', contentClassName), children: children })] }));
38652
+ }
38653
+
38654
+ const COUNT_WORDS = [
38655
+ 'One',
38656
+ 'Two',
38657
+ 'Three',
38658
+ 'Four',
38659
+ 'Five',
38660
+ 'Six',
38661
+ 'Seven',
38662
+ 'Eight',
38663
+ 'Nine',
38664
+ 'Ten',
38665
+ ];
38666
+ /** `4` → `Four` for 1–10; any other count stays as digits. */
38667
+ function countToWord(count) {
38668
+ return COUNT_WORDS[count - 1] ?? String(count);
38669
+ }
38670
+ function getEmptyStateTitle(itemNoun) {
38671
+ return `No ${itemNoun}s match these filters`;
38672
+ }
38673
+ function getEmptyStateDescription(itemNoun, activeCount) {
38674
+ const filters = activeCount === 1 ? 'column filter is' : 'column filters are';
38675
+ return `${countToWord(activeCount)} ${filters} active. Loosen one, or clear them all to see every ${itemNoun}.`;
38676
+ }
38677
+
38678
+ /** Shown in place of rows when the applied column filters match nothing. */
38679
+ function FilterEmptyState({ itemNoun, title, description, activeCount, onClearAll, className, }) {
38680
+ return (jsxRuntime.jsxs("div", { className: cn('flex flex-col items-center py-12 text-center', className), children: [jsxRuntime.jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-muted text-primary", children: jsxRuntime.jsx(FunnelX, { "aria-hidden": "true", className: "size-5" }) }), jsxRuntime.jsx("p", { className: "mt-4 text-base font-semibold text-foreground", children: title ?? getEmptyStateTitle(itemNoun) }), jsxRuntime.jsx("p", { className: "mt-1.5 max-w-sm text-sm text-muted-foreground", children: description ?? getEmptyStateDescription(itemNoun, activeCount) }), jsxRuntime.jsx(Button, { appearance: "outline", color: "primary", size: "md", onClick: onClearAll, leftIcon: jsxRuntime.jsx(RotateCcw, {}), className: "mt-5", children: "Clear all filters" })] }));
38681
+ }
38682
+
38683
+ function getScalePosition(options, value, option) {
38684
+ if (!value)
38685
+ return 'outside';
38686
+ if (option === value.from || option === value.to)
38687
+ return 'end';
38688
+ return expandScaleRange(options, value).includes(option)
38689
+ ? 'between'
38690
+ : 'outside';
38691
+ }
38692
+ /** Next range after clicking `scale`: a fresh single-option range, or the end of the pending one. */
38693
+ function getNextScaleRange(anchor, option) {
38694
+ return anchor === null
38695
+ ? { from: option, to: option }
38696
+ : { from: anchor, to: option };
38697
+ }
38698
+ function getScaleButtonClassName(position, fill = false) {
38699
+ return cn('flex min-w-0 cursor-pointer flex-col items-center justify-center rounded-md border text-center transition-colors', fill ? 'min-h-12 px-2 py-1.5 text-sm' : 'min-h-10 px-1.5 py-1 text-xs', FILTER_FOCUS_RING,
38700
+ // Unselected options look exactly like unselected pick-list tiles.
38701
+ position === 'outside' && getSelectableOptionClassName(false), position === 'end' &&
38702
+ 'border-primary bg-primary font-medium text-primary-foreground', position === 'between' &&
38703
+ 'border-primary/30 bg-primary/10 font-medium text-primary');
38704
+ }
38705
+
38706
+ /** First click picks the start option, the next click the end option; a click after that starts over. */
38707
+ function useScaleRangeFilter({ value, onChange, }) {
38708
+ const [anchor, setAnchor] = React.useState(null);
38709
+ // The start point only holds while the value is still that one option; Clear or any outside change drops it.
38710
+ const start = anchor !== null && value?.from === anchor && value.to === anchor
38711
+ ? anchor
38712
+ : null;
38713
+ const selectOption = React.useCallback((option) => {
38714
+ onChange(getNextScaleRange(start, option));
38715
+ setAnchor(start === null ? option : null);
38716
+ }, [start, onChange]);
38717
+ return { selectOption };
38718
+ }
38719
+
38720
+ /** Ordered-scale filter: click a start option, then an end option. */
38721
+ function ScaleRangeFilter({ options, value, onChange, ariaLabel, columns, fill = false, }) {
38722
+ const { selectOption } = useScaleRangeFilter({ value, onChange });
38723
+ return (jsxRuntime.jsx("div", { role: "group", "aria-label": ariaLabel, className: fill ? 'grid gap-2' : 'grid gap-1.5', style: getGridColumnsStyle(columns), children: options.map((option) => {
38724
+ const position = getScalePosition(options, value, option.value);
38725
+ return (jsxRuntime.jsx("button", { type: "button", "aria-pressed": position !== 'outside', "aria-label": option.label, onClick: () => selectOption(option.value), className: getScaleButtonClassName(position, fill), children: jsxRuntime.jsx("span", { className: "line-clamp-2 leading-tight", children: option.label }) }, option.value));
38726
+ }) }));
38727
+ }
38728
+
38729
+ const getClearIdsLabel = (ariaLabel) => `Clear ${ariaLabel}`;
38730
+
38731
+ const DEFAULT_ID_HELPER_TEXT = 'Paste from Excel or an email. Commas, spaces and new lines all split IDs.';
38732
+ function toIdsKey(ids) {
38733
+ return ids.join('\n');
38734
+ }
38735
+ function formatIdCount(count) {
38736
+ return `${count} ${count === 1 ? 'ID' : 'IDs'}`;
38737
+ }
38738
+
38739
+ const COMMIT_DELAY_MS$1 = 300;
38740
+ function useIdListInput(value, onChange) {
38741
+ const appliedKey = toIdsKey(value);
38742
+ const { draft, setDraft, markCommitted } = useFilterDraft(appliedKey, value.join(', '));
38743
+ const commit = React.useCallback((text) => {
38744
+ const ids = splitIdList(text);
38745
+ const key = toIdsKey(ids);
38746
+ markCommitted(key);
38747
+ if (key !== appliedKey)
38748
+ onChange(ids);
38749
+ }, [appliedKey, markCommitted, onChange]);
38750
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$1);
38751
+ return {
38752
+ draft,
38753
+ parsedIds: splitIdList(draft),
38754
+ handleChange: (event) => {
38755
+ setDraft(event.target.value);
38756
+ debounced.schedule(event.target.value);
38757
+ },
38758
+ handleBlur: debounced.flush,
38759
+ clear: () => {
38760
+ debounced.cancel();
38761
+ setDraft('');
38762
+ commit('');
38763
+ },
38764
+ };
38765
+ }
38766
+
38767
+ /** Paste-a-list body: a textarea split into IDs on commas, spaces and new lines, with the parsed IDs as chips. */
38768
+ function IdListInput({ value, onChange, ariaLabel, placeholder, helperText = DEFAULT_ID_HELPER_TEXT, showSummary = true, }) {
38769
+ const { draft, parsedIds, handleChange, handleBlur, clear } = useIdListInput(value, onChange);
38770
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(Textarea, { value: draft, placeholder: placeholder, "aria-label": ariaLabel, onChange: handleChange, onBlur: handleBlur, className: "min-h-20 bg-card" }), helperText && (jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: helperText })), showSummary && parsedIds.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-1.5", children: parsedIds.map((id) => (jsxRuntime.jsx("li", { className: "inline-flex h-6 items-center rounded-full border border-primary/20 bg-primary/5 px-2 text-xs text-primary", children: id }, id))) }), jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs", children: [jsxRuntime.jsx("span", { className: "text-muted-foreground", children: formatIdCount(parsedIds.length) }), jsxRuntime.jsx("button", { type: "button", "aria-label": getClearIdsLabel(ariaLabel), onClick: clear, className: FILTER_LINK_CLASS_NAME, children: "Clear" })] })] }))] }));
38771
+ }
38772
+
38773
+ const NUMBER_HELP_HEADING = 'Type a value or a rule';
38774
+ const NUMBER_HELP_SUBTITLE = 'Click a rule to use it.';
38775
+ const getNumberErrorId = (baseId) => `${baseId}-error`;
38776
+ const getUseRuleLabel = (rule, meaning) => `Use ${rule}: ${meaning}`;
38777
+
38778
+ function getNumberFieldState(parsed) {
38779
+ if (!parsed.ok)
38780
+ return 'invalid';
38781
+ return parsed.range ? 'applied' : 'empty';
38782
+ }
38783
+ function getNumberInputClassName(state, className) {
38784
+ return getFilterFieldClassName(state, cn('text-right tabular-nums', className));
38785
+ }
38786
+ /** Cheat-sheet row: the whole row is the click target, highlighted on hover. */
38787
+ const RULE_BUTTON_CLASS_NAME = cn('flex h-8 w-full cursor-pointer items-center gap-3 rounded-md px-2 text-left text-xs transition-colors hover:bg-muted', FILTER_FOCUS_RING);
38788
+ /** Key-cap chip for the rule, fixed width so every meaning lines up. */
38789
+ const RULE_CHIP_CLASS_NAME = 'inline-flex h-6 min-w-12 shrink-0 items-center justify-center rounded border border-border bg-background px-1.5 font-mono text-xs font-semibold text-foreground shadow-xs';
38790
+
38791
+ const COMMIT_DELAY_MS = 400;
38792
+ function useNumberExpressionFilter(value, onChange) {
38793
+ const applied = formatNumberRange(value);
38794
+ const { draft, setDraft, markCommitted } = useFilterDraft(applied, applied);
38795
+ const [helpOpen, setHelpOpen] = React.useState(false);
38796
+ const errorId = React.useId();
38797
+ const commit = React.useCallback((text) => {
38798
+ const parsed = parseNumberExpression(text);
38799
+ if (!parsed.ok)
38800
+ return;
38801
+ const key = formatNumberRange(parsed.range);
38802
+ markCommitted(key);
38803
+ if (key !== applied)
38804
+ onChange(parsed.range);
38805
+ }, [applied, markCommitted, onChange]);
38806
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS);
38807
+ const handleChange = (event) => {
38808
+ setDraft(event.target.value);
38809
+ setHelpOpen(true);
38810
+ debounced.schedule(event.target.value);
38811
+ };
38812
+ const handleKeyDown = (event) => {
38813
+ if (event.key === 'Enter')
38814
+ debounced.flush();
38815
+ if (event.key === 'Escape')
38816
+ setHelpOpen(false);
38817
+ };
38818
+ const handleBlur = () => {
38819
+ debounced.flush();
38820
+ setHelpOpen(false);
38821
+ };
38822
+ const applyRule = (rule) => {
38823
+ debounced.cancel();
38824
+ setDraft(rule);
38825
+ commit(rule);
38826
+ setHelpOpen(false);
38827
+ };
38828
+ return {
38829
+ draft,
38830
+ state: getNumberFieldState(parseNumberExpression(draft)),
38831
+ helpOpen,
38832
+ errorId,
38833
+ handleChange,
38834
+ handleKeyDown,
38835
+ handleFocus: () => setHelpOpen(true),
38836
+ handleBlur,
38837
+ applyRule,
38838
+ };
38839
+ }
38840
+
38841
+ /** Filter-row number cell: type a value or a rule (`>1`, `1–3`, `1.52`). Invalid text never reaches the table. */
38842
+ function NumberExpressionFilter({ value, onChange, ariaLabel, placeholder, note, className, }) {
38843
+ const { draft, state, helpOpen, errorId, handleChange, handleKeyDown, handleFocus, handleBlur, applyRule, } = useNumberExpressionFilter(value, onChange);
38844
+ const invalid = state === 'invalid';
38845
+ return (jsxRuntime.jsxs(Popover, { open: helpOpen, children: [jsxRuntime.jsx(PopoverAnchor, { asChild: true, children: jsxRuntime.jsx("input", { type: "text", inputMode: "decimal", value: draft, placeholder: placeholder, "aria-label": ariaLabel, "aria-invalid": invalid || undefined, "aria-describedby": invalid ? getNumberErrorId(errorId) : undefined, onChange: handleChange, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, className: getNumberInputClassName(state, className) }) }), jsxRuntime.jsxs(PopoverContent, { align: "start",
38846
+ // The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
38847
+ updatePositionStrategy: "always", onOpenAutoFocus: (event) => event.preventDefault(), className: "flex w-72 flex-col gap-2 p-2 text-xs", children: [jsxRuntime.jsxs("div", { className: "px-2 pt-1", children: [jsxRuntime.jsx("p", { className: "font-medium text-foreground", children: NUMBER_HELP_HEADING }), jsxRuntime.jsx("p", { className: "text-muted-foreground", children: NUMBER_HELP_SUBTITLE })] }), jsxRuntime.jsx("ul", { className: "flex flex-col", children: NUMBER_EXPRESSION_HELP.map(({ rule, meaning }) => (jsxRuntime.jsx("li", { children: jsxRuntime.jsxs("button", { type: "button", "aria-label": getUseRuleLabel(rule, meaning),
38848
+ // Keep focus in the field so it doesn't blur and close this help first.
38849
+ onMouseDown: (event) => event.preventDefault(), onClick: () => applyRule(rule), className: RULE_BUTTON_CLASS_NAME, children: [jsxRuntime.jsx("span", { className: RULE_CHIP_CLASS_NAME, children: rule }), jsxRuntime.jsx("span", { className: "whitespace-nowrap text-muted-foreground", children: meaning })] }) }, rule))) }), note && (jsxRuntime.jsxs("div", { className: "flex gap-2 rounded-md bg-muted/50 p-2 text-muted-foreground", children: [jsxRuntime.jsx(Info, { "aria-hidden": "true", className: "mt-0.5 size-3.5 shrink-0" }), jsxRuntime.jsx("div", { children: note })] })), invalid && (jsxRuntime.jsxs("div", { id: getNumberErrorId(errorId), role: "alert", className: "flex gap-2 rounded-md bg-destructive/10 p-2 text-destructive", children: [jsxRuntime.jsx(CircleAlert, { "aria-hidden": "true", className: "mt-0.5 size-3.5 shrink-0" }), jsxRuntime.jsxs("p", { children: ["Can't read \u201C", draft, "\u201D. Try ", jsxRuntime.jsx("strong", { children: "1\u20133" }), ",", ' ', jsxRuntime.jsx("strong", { children: ">1" }), " or ", jsxRuntime.jsx("strong", { children: "<=3" }), "."] })] }))] })] }));
38850
+ }
38851
+
38852
+ const REVERSED_RANGE_MESSAGE = 'From must not be more than To.';
38853
+ const getBoundLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
38854
+
38855
+ const DECIMAL_DRAFT_RE = /^\d*\.?\d*$/;
38856
+ /** Allows partial decimals (`1.`) while typing; rejects anything else. */
38857
+ function isDecimalDraft(text) {
38858
+ return DECIMAL_DRAFT_RE.test(text);
38859
+ }
38860
+ function toBound(text) {
38861
+ if (!text || text === '.')
38862
+ return undefined;
38863
+ return Number(text);
38864
+ }
38865
+ function toBoundText(bound) {
38866
+ return bound === undefined ? '' : String(bound);
38867
+ }
38868
+ /** Replaces one bound with a typed (inclusive) number, keeping the other bound and its `>` / `<`. */
38869
+ function withBound(range, bound, next) {
38870
+ const min = bound === 'min' ? next : range?.min;
38871
+ const max = bound === 'max' ? next : range?.max;
38872
+ if (min === undefined && max === undefined)
38873
+ return undefined;
38874
+ const result = { min, max };
38875
+ if (bound === 'max' && range?.minExclusive)
38876
+ result.minExclusive = true;
38877
+ if (bound === 'min' && range?.maxExclusive)
38878
+ result.maxExclusive = true;
38879
+ return result;
38880
+ }
38881
+ function isReversedRange(min, max) {
38882
+ return min !== undefined && max !== undefined && min > max;
38883
+ }
38884
+ function isSameRange(a, b) {
38885
+ return a?.min === b.min && a?.max === b.max;
38886
+ }
38887
+ function getBoundInputClassName(filled) {
38888
+ return cn('h-9 min-w-0 flex-1 text-sm', filled && 'border-primary bg-primary/5');
38889
+ }
38890
+ function getPresetClassName(selected) {
38891
+ return getSelectableOptionClassName(selected, 'inline-flex h-7 items-center rounded-full px-2.5');
38892
+ }
38893
+
38894
+ function useNumberRangeInputs(value, onChange) {
38895
+ const minText = toBoundText(value?.min);
38896
+ const maxText = toBoundText(value?.max);
38897
+ const from = useFilterDraft(minText, minText);
38898
+ const to = useFilterDraft(maxText, maxText);
38899
+ const handleBoundChange = (bound) => (event) => {
38900
+ const text = event.target.value;
38901
+ if (!isDecimalDraft(text))
38902
+ return;
38903
+ const draft = bound === 'min' ? from : to;
38904
+ const parsed = toBound(text);
38905
+ draft.setDraft(text);
38906
+ const next = withBound(value, bound, parsed);
38907
+ if (isReversedRange(next?.min, next?.max))
38908
+ return;
38909
+ draft.markCommitted(toBoundText(parsed));
38910
+ onChange(next);
38911
+ };
38912
+ return {
38913
+ fromDraft: from.draft,
38914
+ toDraft: to.draft,
38915
+ reversed: isReversedRange(toBound(from.draft), toBound(to.draft)),
38916
+ handleFromChange: handleBoundChange('min'),
38917
+ handleToChange: handleBoundChange('max'),
38918
+ isPresetSelected: (preset) => isSameRange(value, preset.range),
38919
+ togglePreset: (preset) => onChange(isSameRange(value, preset.range) ? undefined : preset.range),
38920
+ };
38921
+ }
38922
+
38923
+ /** From – To number inputs for full-page filter cards, with optional quick-pick presets. */
38924
+ function NumberRangeInputs({ value, onChange, ariaLabel, fromPlaceholder = 'From', toPlaceholder = 'To', presets, presetsLabel, }) {
38925
+ const { fromDraft, toDraft, reversed, handleFromChange, handleToChange, isPresetSelected, togglePreset, } = useNumberRangeInputs(value, onChange);
38926
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(Input, { inputMode: "decimal", value: fromDraft, placeholder: fromPlaceholder, "aria-label": getBoundLabel(ariaLabel, 'from'), "aria-invalid": reversed || undefined, onChange: handleFromChange, className: getBoundInputClassName(fromDraft !== '') }), jsxRuntime.jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2013" }), jsxRuntime.jsx(Input, { inputMode: "decimal", value: toDraft, placeholder: toPlaceholder, "aria-label": getBoundLabel(ariaLabel, 'to'), "aria-invalid": reversed || undefined, onChange: handleToChange, className: getBoundInputClassName(toDraft !== '') })] }), reversed && (jsxRuntime.jsx("p", { role: "alert", className: "text-xs text-destructive", children: REVERSED_RANGE_MESSAGE })), presets && presets.length > 0 && (jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [presetsLabel && (jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: presetsLabel })), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: presets.map((preset) => (jsxRuntime.jsx("button", { type: "button", "aria-pressed": isPresetSelected(preset), onClick: () => togglePreset(preset), className: getPresetClassName(isPresetSelected(preset)), children: preset.label }, preset.label))) })] }))] }));
38927
+ }
38928
+
38929
+ const NEXT_KEYS = new Set(['ArrowDown', 'ArrowRight']);
38930
+ const PREVIOUS_KEYS = new Set(['ArrowUp', 'ArrowLeft']);
38931
+ /** Arrow keys move and select within the radio group, wrapping at either end. */
38932
+ function getArrowKeyTarget(current, key) {
38933
+ const step = NEXT_KEYS.has(key) ? 1 : PREVIOUS_KEYS.has(key) ? -1 : 0;
38934
+ if (step === 0)
38935
+ return null;
38936
+ const index = TRI_STATE_OPTIONS.findIndex((option) => option.value === current);
38937
+ const nextIndex = (index + step + TRI_STATE_OPTIONS.length) % TRI_STATE_OPTIONS.length;
38938
+ return TRI_STATE_OPTIONS[nextIndex].value;
38939
+ }
38940
+ function createRadioGroupKeyDownHandler(current, onChange) {
38941
+ return (event) => {
38942
+ const target = getArrowKeyTarget(current, event.key);
38943
+ if (!target)
38944
+ return;
38945
+ event.preventDefault();
38946
+ onChange(target);
38947
+ event.currentTarget
38948
+ .querySelector(`[data-value="${target}"]`)
38949
+ ?.focus();
38950
+ };
38951
+ }
38952
+
38953
+ function getRadioRowClassName(checked) {
38954
+ return cn('flex w-full cursor-pointer items-center gap-2.5 rounded-md px-2.5 py-2 text-left text-xs text-foreground transition-colors', FILTER_FOCUS_RING, checked ? 'bg-muted font-medium' : 'hover:bg-muted/50');
38955
+ }
38956
+ function getRadioCircleClassName(checked) {
38957
+ return cn('flex size-4 shrink-0 items-center justify-center rounded-full border', checked ? 'border-primary' : 'border-input-border');
38958
+ }
38959
+
38960
+ /** Any / Yes / No radio group for boolean columns (e.g. Active). */
38961
+ function TriStateFilter({ value, onChange, ariaLabel, }) {
38962
+ return (jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": ariaLabel, onKeyDown: createRadioGroupKeyDownHandler(value, onChange), className: "flex flex-col gap-0.5", children: TRI_STATE_OPTIONS.map((option) => {
38963
+ const checked = option.value === value;
38964
+ return (jsxRuntime.jsxs("button", { type: "button", role: "radio", "aria-checked": checked, tabIndex: checked ? 0 : -1, "data-value": option.value, onClick: () => onChange(option.value), className: getRadioRowClassName(checked), children: [jsxRuntime.jsx("span", { "aria-hidden": "true", className: getRadioCircleClassName(checked), children: checked && jsxRuntime.jsx("span", { className: "size-2 rounded-full bg-primary" }) }), option.label] }, option.value));
38965
+ }) }));
38966
+ }
38967
+
37867
38968
  /**
37868
38969
  * Compact "time ago" label, e.g. "5m ago". Falls back to a locale date past a
37869
38970
  * week so older entries stay scannable.
@@ -38217,23 +39318,26 @@ function InventoryComboBox({ inventoryType, selectedItem, onSelect, fetchGems, f
38217
39318
  } }), jsxRuntime.jsx("span", { className: "truncate text-sm font-normal", children: sel.label })] })) : (jsxRuntime.jsx("span", { className: "truncate text-sm font-normal text-muted-foreground", children: searchPlaceholder })), renderOption: ({ item }) => (jsxRuntime.jsx(InventoryItemRow, { type: inventoryType, ...buildInventoryRowProps(item.data, inventoryType, showCostPrice ? { priceBasis: 'cost' } : undefined), className: "w-full" })), fetchPage: fetchPage, searchPlaceholder: searchPlaceholder, emptyMessage: inventoryType === 'gem' ? 'No gems found.' : 'No diamonds found.', disabled: disabled, className: className, align: align, debounceMs: 300, hideTriggerSearchIcon: hideTriggerSearchIcon }));
38218
39319
  }
38219
39320
 
38220
- const OwnershipFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Ownership", options: [
38221
- { value: 'owned', label: 'Owned' },
38222
- { value: 'partner', label: 'Partner' },
38223
- { value: 'memo_in', label: 'Memo In' },
38224
- ] }));
38225
- const StockTypeFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Stock Type", options: [
38226
- { value: 'single', label: 'Single' },
38227
- { value: 'parcel', label: 'Parcel' },
38228
- { value: 'set', label: 'Set' },
38229
- { value: 'pair', label: 'Pair' },
38230
- ] }));
38231
- const StatusFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Status", options: [
38232
- { value: 'in_stock', label: 'In Stock' },
38233
- { value: 'out_of_stock', label: 'Out of Stock' },
38234
- { value: 'sold', label: 'Sold' },
38235
- { value: 'memo_out', label: 'Memo Out' },
38236
- ] }));
39321
+ const OWNERSHIP_STATUS_OPTIONS = [
39322
+ { value: 'owned', label: 'Owned' },
39323
+ { value: 'partner', label: 'Partner' },
39324
+ { value: 'memo_in', label: 'Memo In' },
39325
+ ];
39326
+ const STOCK_TYPE_OPTIONS = [
39327
+ { value: 'single', label: 'Single' },
39328
+ { value: 'parcel', label: 'Parcel' },
39329
+ { value: 'set', label: 'Set' },
39330
+ { value: 'pair', label: 'Pair' },
39331
+ ];
39332
+ const INVENTORY_STATUS_OPTIONS = [
39333
+ { value: 'in_stock', label: 'In Stock' },
39334
+ { value: 'out_of_stock', label: 'Out of Stock' },
39335
+ { value: 'sold', label: 'Sold' },
39336
+ { value: 'memo_out', label: 'Memo Out' },
39337
+ ];
39338
+ const OwnershipFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Ownership", searchPlaceholder: "Search ownership", options: [...OWNERSHIP_STATUS_OPTIONS] }));
39339
+ const StockTypeFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Stock Type", searchPlaceholder: "Search stock types", options: [...STOCK_TYPE_OPTIONS] }));
39340
+ const StatusFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Status", searchPlaceholder: "Search statuses", options: [...INVENTORY_STATUS_OPTIONS] }));
38237
39341
  const WarehouseFilter = ({ getWarehouseList, ...props }) => {
38238
39342
  const [warehouses, setWarehouses] = React.useState([]);
38239
39343
  React.useEffect(() => {
@@ -38241,7 +39345,7 @@ const WarehouseFilter = ({ getWarehouseList, ...props }) => {
38241
39345
  .then(setWarehouses)
38242
39346
  .catch(() => { });
38243
39347
  }, [getWarehouseList]);
38244
- return (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Warehouse", contentClassName: "min-w-[250px] w-fit", options: warehouses.map((w) => ({
39348
+ return (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Warehouse", searchPlaceholder: "Search warehouses", options: warehouses.map((w) => ({
38245
39349
  value: w.id,
38246
39350
  label: `${w.warehouseId} · ${w.name}`,
38247
39351
  })) }));
@@ -38473,25 +39577,15 @@ const TONE_ICON_BG = {
38473
39577
  };
38474
39578
  const MetricTile = ({ label, value, sub, icon, tone, className, }) => (jsxRuntime.jsxs("div", { className: cn('flex min-w-0 items-center gap-3 rounded-xl border px-4 py-3', TONE_TILE_BG[tone], className), children: [jsxRuntime.jsx("span", { "aria-hidden": "true", className: cn('inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-md [&_svg]:h-5 [&_svg]:w-5', TONE_ICON_BG[tone]), children: icon }), jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [jsxRuntime.jsx("span", { className: "truncate text-xs text-muted-foreground", children: label }), jsxRuntime.jsx("span", { className: "truncate text-lg font-semibold text-foreground", children: value }), sub && (jsxRuntime.jsx("span", { className: "truncate text-xs text-muted-foreground", children: sub }))] })] }));
38475
39579
 
38476
- const SIZE_WIDTH = {
38477
- sm: 480,
38478
- md: 640,
38479
- lg: 760,
38480
- xl: 960,
38481
- };
38482
39580
  /**
38483
39581
  * App-wide modal wrapper with a fixed header / body / footer layout.
38484
39582
  * Built on top of shadcn DialogContent, so it inherits viewport-centered
38485
39583
  * positioning, focus trapping, portal rendering, and overlay handling.
38486
39584
  */
38487
- function Modal({ open, onClose, title, icon, children, footer, size = 'md', hideCloseButton = false, className, bodyClassName, }) {
38488
- const maxWidth = SIZE_WIDTH[size];
39585
+ function Modal({ open, onClose, title, description, icon, children, footer, size = 'default', hideCloseButton = false, className, bodyClassName, }) {
38489
39586
  // See ConfirmDialog: overlapping dismissable layers leak the <body> lock.
38490
39587
  useOverlayBodyLockRelease(open);
38491
- return (jsxRuntime.jsx(Dialog, { open: open, onOpenChange: (o) => !o && onClose(), children: jsxRuntime.jsxs(DialogContent, { hideCloseButton: true, style: {
38492
- width: `min(${maxWidth}px, calc(100vw - 2rem))`,
38493
- maxWidth: `${maxWidth}px`,
38494
- }, className: cn('flex max-h-[calc(100vh-2rem)] flex-col gap-0 overflow-hidden p-0 sm:max-w-none', className), children: [jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-4 border-b border-border px-6 py-4", children: [jsxRuntime.jsx(DialogPrimitive__namespace.Title, { asChild: true, children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-base font-medium text-foreground", children: [icon, jsxRuntime.jsx("span", { children: title })] }) }), !hideCloseButton && (jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "aria-label": "Close", className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-label transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30", children: jsxRuntime.jsx(X$2, { className: "h-4 w-4" }) }))] }), jsxRuntime.jsx("div", { className: cn('flex-1 overflow-y-auto', bodyClassName), children: children }), footer && (jsxRuntime.jsx("footer", { className: "flex items-center justify-end gap-3 border-t border-border px-6 py-4", children: footer }))] }) }));
39588
+ return (jsxRuntime.jsx(Dialog, { open: open, onOpenChange: (o) => !o && onClose(), children: jsxRuntime.jsxs(DialogContent, { hideCloseButton: true, size: size === 'wide' ? 'wide' : 'default', className: cn('flex flex-col gap-0 overflow-hidden p-0', className), children: [jsxRuntime.jsxs("header", { className: "flex shrink-0 items-start justify-between gap-4 px-6 pt-5 pb-4", children: [jsxRuntime.jsxs("div", { className: cn('flex min-w-0 gap-3.5', description ? 'items-start' : 'items-center'), children: [icon ? jsxRuntime.jsx(DialogIcon, { children: icon }) : null, jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [jsxRuntime.jsx(DialogPrimitive__namespace.Title, { className: "m-0 text-lg font-semibold leading-6 text-foreground", children: title }), description ? (jsxRuntime.jsx(DialogPrimitive__namespace.Description, { className: "m-0 text-sm leading-5 text-muted-foreground", children: description })) : null] })] }), !hideCloseButton && (jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "aria-label": "Close", className: "-mr-1.5 inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: jsxRuntime.jsx(X$2, { className: "h-4 w-4" }) }))] }), jsxRuntime.jsx("div", { className: cn('flex-1 overflow-y-auto', bodyClassName), children: children }), footer && (jsxRuntime.jsx("footer", { className: cn('flex items-center justify-end gap-3 border-t border-border bg-[color-mix(in_srgb,var(--muted)_40%,var(--card))] px-6 py-4', DIALOG_FOOTER_BUTTONS), children: footer }))] }) }));
38495
39589
  }
38496
39590
 
38497
39591
  /**
@@ -67199,59 +68293,6 @@ function useIsTablet() {
67199
68293
  return useMediaQuery(`(min-width: ${MOBILE_MAX + 1}px) and (max-width: ${TABLET_MAX}px)`);
67200
68294
  }
67201
68295
 
67202
- // Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
67203
- // labels that are not actually clipped.
67204
- const OVERFLOW_TOLERANCE_PX = 1;
67205
- function findClippedLabel(root) {
67206
- const spans = root.querySelectorAll(':scope > span');
67207
- for (const span of Array.from(spans)) {
67208
- if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX) {
67209
- return span;
67210
- }
67211
- }
67212
- return null;
67213
- }
67214
- /**
67215
- * Returns the full text of the first direct-child `<span>` of `ref` that is
67216
- * clipped by its container (i.e. showing an ellipsis), else `null` — so callers
67217
- * can surface a tooltip only when the label is actually unreadable.
67218
- *
67219
- * Re-measures on element resize (sidebar expand/collapse, window resize) and on
67220
- * label text changes.
67221
- */
67222
- function useTruncatedText(ref) {
67223
- const [text, setText] = React.useState(null);
67224
- React.useEffect(() => {
67225
- const el = ref.current;
67226
- if (!el)
67227
- return;
67228
- let frame = 0;
67229
- const measure = () => {
67230
- const label = findClippedLabel(el);
67231
- setText(label?.textContent?.trim() || null);
67232
- };
67233
- const schedule = () => {
67234
- cancelAnimationFrame(frame);
67235
- frame = requestAnimationFrame(measure);
67236
- };
67237
- schedule();
67238
- const resizeObserver = new ResizeObserver(schedule);
67239
- resizeObserver.observe(el);
67240
- const mutationObserver = new MutationObserver(schedule);
67241
- mutationObserver.observe(el, {
67242
- characterData: true,
67243
- childList: true,
67244
- subtree: true,
67245
- });
67246
- return () => {
67247
- cancelAnimationFrame(frame);
67248
- resizeObserver.disconnect();
67249
- mutationObserver.disconnect();
67250
- };
67251
- }, [ref]);
67252
- return text;
67253
- }
67254
-
67255
68296
  const SIDEBAR_COOKIE_NAME = 'sidebar_state';
67256
68297
  const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
67257
68298
  const SIDEBAR_WIDTH = '16rem';
@@ -67490,37 +68531,6 @@ const AppSidebar = ({ brand, navGroups = [], footer, className, }) => {
67490
68531
  return (jsxRuntime.jsxs(Sidebar, { collapsible: "icon", className: className, children: [brand && (jsxRuntime.jsx(SidebarHeader, { children: jsxRuntime.jsx(BrandHeader$1, { brand: brand }) })), jsxRuntime.jsx(SidebarContent, { children: navGroups.map((group) => (jsxRuntime.jsx(NavGroupSection, { group: group }, group.label ?? 'nav-group'))) }), footer && jsxRuntime.jsx(SidebarFooter, { children: footer }), jsxRuntime.jsx(SidebarRail, {})] }));
67491
68532
  };
67492
68533
 
67493
- /** Label line + input block — mirrors a `Field`. */
67494
- function FieldSkeleton() {
67495
- return (jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 40, className: "w-full", rounded: "md" })] }));
67496
- }
67497
- /**
67498
- * Loading placeholder that matches a `FormSectionCard` — the tinted header band
67499
- * (icon square + title + description) above a body of `Field` placeholders and
67500
- * an optional footer action row.
67501
- */
67502
- function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
67503
- return (jsxRuntime.jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-xl border border-border bg-card shadow-card", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsxRuntime.jsx(SquareSkeleton, { height: 40, width: 40, rounded: "md" }), jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [jsxRuntime.jsx(SquareSkeleton, { height: 14, width: 180, rounded: "full" }), description && jsxRuntime.jsx(SquareSkeleton, { height: 11, width: 260, rounded: "full" })] })] }), jsxRuntime.jsxs("div", { className: "p-5", children: [jsxRuntime.jsx("div", { className: cn('grid gap-x-6 gap-y-5', columns === 2 ? 'grid-cols-1 md:grid-cols-2' : 'grid-cols-1'), children: Array.from({ length: fields }).map((_, i) => (jsxRuntime.jsx(FieldSkeleton, {}, i))) }), footer !== 'none' && (jsxRuntime.jsxs("div", { className: cn('mt-8 flex items-center gap-3 pt-4', footer === 'between' ? 'justify-between' : 'justify-end'), children: [footer === 'between' && (jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 90, rounded: "md" })), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 120, rounded: "md" })] }))] })] }));
67504
- }
67505
- /** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
67506
- function TableSkeleton({ rows = 8 }) {
67507
- return (jsxRuntime.jsxs("div", { className: "space-y-3", children: [jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx(SquareSkeleton, { className: "h-9 flex-1", rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { className: "h-9 w-44", rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { className: "h-9 w-48", rounded: "md" })] }), Array.from({ length: rows }).map((_, i) => (jsxRuntime.jsx(SquareSkeleton, { className: "h-12 w-full", rounded: "md" }, i)))] }));
67508
- }
67509
- /** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
67510
- function TableRowsSkeleton({ rows = 10, className }) {
67511
- return (jsxRuntime.jsx("div", { className: cn('flex w-full flex-col gap-2 overflow-hidden', className), "aria-busy": "true", "aria-label": "Loading", children: Array.from({ length: rows }).map((_, i) => (
67512
- // shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
67513
- jsxRuntime.jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
67514
- }
67515
- /** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
67516
- function DetailPageSkeleton({ sections = 3, }) {
67517
- return (jsxRuntime.jsxs("div", { className: "space-y-5", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx(SquareSkeleton, { height: 32, width: 32, rounded: "md" }), jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [jsxRuntime.jsx(SquareSkeleton, { height: 20, width: 192, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 128, rounded: "full" })] })] }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 128, rounded: "md" })] }), Array.from({ length: sections }).map((_, s) => (jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-xl border border-border bg-card", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsxRuntime.jsx(SquareSkeleton, { height: 32, width: 32, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 16, width: 160, rounded: "full" })] }), jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-5 p-5 md:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [jsxRuntime.jsx(SquareSkeleton, { height: 10, width: 80, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 14, width: 128, rounded: "full" })] }, i))) })] }, s)))] }));
67518
- }
67519
- /** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
67520
- function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
67521
- return (jsxRuntime.jsxs("div", { role: "status", "aria-busy": "true", "aria-label": label, className: "space-y-4", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx(SquareSkeleton, { height: 14, width: 80, rounded: "full" }), jsxRuntime.jsx("span", { className: "h-5 w-px bg-border" }), jsxRuntime.jsx(SquareSkeleton, { height: 28, width: 200, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 22, width: 72, rounded: "full" })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 112, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 80, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 128, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, width: 36, rounded: "lg" })] })] }), jsxRuntime.jsxs("section", { "aria-hidden": "true", className: "grid grid-cols-1 overflow-hidden rounded-2xl border border-border bg-card md:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)]", children: [jsxRuntime.jsxs("div", { className: "flex flex-col justify-center space-y-3 px-5 py-4 sm:px-7 sm:py-4", children: [jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 40, width: 220, rounded: "md" }), aside !== 'none' && (jsxRuntime.jsxs("div", { className: "w-full max-w-xl space-y-2 pt-1", children: [jsxRuntime.jsx(SquareSkeleton, { height: 8, className: "w-full", rounded: "full" }), jsxRuntime.jsxs("div", { className: "flex justify-between", children: [jsxRuntime.jsx(SquareSkeleton, { height: 11, width: 88, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 11, width: 40, rounded: "full" })] })] }))] }), jsxRuntime.jsx("div", { className: "border-t border-border bg-muted/40 px-5 py-2 md:border-l md:border-t-0", children: [0, 1, 2, 3].map((i) => (jsxRuntime.jsxs("div", { className: "flex min-h-10 items-center gap-3 border-b border-border py-1.5 last:border-b-0", children: [jsxRuntime.jsx(SquareSkeleton, { height: 24, width: 24, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 72, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 88, rounded: "full", className: "ml-auto" })] }, i))) })] }), Array.from({ length: sections }).map((_, s) => (jsxRuntime.jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-2xl border border-border bg-card", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-3", children: [jsxRuntime.jsx(SquareSkeleton, { height: 28, width: 28, rounded: "lg" }), jsxRuntime.jsx(SquareSkeleton, { height: 15, width: 128, rounded: "full" })] }), jsxRuntime.jsx("div", { className: "space-y-3 p-4", children: Array.from({ length: s === 1 ? 4 : 2 }).map((__, row) => (jsxRuntime.jsx(SquareSkeleton, { height: s === 1 ? 36 : 14, className: row % 2 ? 'w-3/4' : 'w-full', rounded: "md" }, row))) })] }, s))), jsxRuntime.jsx("span", { className: "sr-only", children: label })] }));
67522
- }
67523
-
67524
68534
  const SlideOut = ({ open, onOpenChange, ...props }) => {
67525
68535
  const scheduleLockRelease = useOverlayBodyLockRelease(open);
67526
68536
  return (jsxRuntime.jsx(DialogPrimitive__namespace.Root, { ...props, open: open, onOpenChange: (next) => {
@@ -75332,7 +76342,7 @@ function ImageCropModal({ open, imageUrl, fileType, onCancel, onConfirm, }) {
75332
76342
  const blob = await getCroppedBlob(imgRef.current, completedCrop, fileType);
75333
76343
  onConfirm(blob);
75334
76344
  };
75335
- return (jsxRuntime.jsxs(Modal, { open: open, onClose: onCancel, size: "lg", icon: jsxRuntime.jsx(Scissors, { className: "h-5 w-5 text-foreground", strokeWidth: 1.5 }), title: "Crop Image", footer: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Button$1, { type: "button", variant: "outline", onClick: onCancel, className: "border-border bg-muted text-foreground hover:bg-muted/80", children: "Cancel" }), jsxRuntime.jsx(Button$1, { type: "button", onClick: handleConfirm, className: "bg-primary text-primary-foreground hover:bg-hover", children: "Crop & Add" })] }), children: [jsxRuntime.jsxs("div", { className: "space-y-3 px-6 py-4", children: [jsxRuntime.jsx("p", { className: "text-[13px] text-label", children: "Aspect ratio" }), jsxRuntime.jsx("div", { className: "grid grid-cols-5 gap-3", children: ASPECTS.map((a) => {
76345
+ return (jsxRuntime.jsxs(Modal, { open: open, onClose: onCancel, size: "wide", icon: jsxRuntime.jsx(Scissors, { className: "h-5 w-5 text-foreground", strokeWidth: 1.5 }), title: "Crop Image", footer: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Button$1, { type: "button", variant: "outline", onClick: onCancel, children: "Cancel" }), jsxRuntime.jsx(Button$1, { type: "button", onClick: handleConfirm, className: "bg-primary text-primary-foreground hover:bg-hover", children: "Crop & Add" })] }), children: [jsxRuntime.jsxs("div", { className: "space-y-3 px-6 pb-4", children: [jsxRuntime.jsx("p", { className: "text-[13px] text-label", children: "Aspect ratio" }), jsxRuntime.jsx("div", { className: "grid grid-cols-5 gap-3", children: ASPECTS.map((a) => {
75336
76346
  const selected = aspectKey === a.key;
75337
76347
  return (jsxRuntime.jsxs("button", { type: "button", onClick: () => setAspectKey(a.key), className: cn('flex cursor-pointer flex-col items-center justify-center gap-1 rounded-lg border px-3 py-3 text-xs transition-colors', selected
75338
76348
  ? 'border-primary bg-primary/10 text-primary'
@@ -75468,6 +76478,219 @@ const FileUploader = ({ accept, multiple = true, maxSize = 50, maxFiles = 5, lab
75468
76478
  return (jsxRuntime.jsxs("div", { className: cn('flex flex-col gap-4', className), children: [label && (jsxRuntime.jsx("label", { className: "text-sm font-medium text-foreground", children: label })), jsxRuntime.jsx(DropZone, { uploadSubject: uploadSubject, supportedFormats: supportedFormats, maxSize: maxSize, maxFiles: maxFiles, accept: accept, multiple: multiple, disabled: disabled, onFiles: handlePickerFiles }), files.length > 0 && (jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsx("p", { className: "text-[13px] text-label", children: "Uploaded File" }), jsxRuntime.jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: onDragEnd, children: jsxRuntime.jsx(SortableContext, { items: files.map((f) => f.id), strategy: rectSortingStrategy, children: jsxRuntime.jsx("div", { className: "flex flex-wrap gap-3", children: files.map((file) => (jsxRuntime.jsx(FileCard, { file: file, sortable: sortable, disabled: disabled, onRemove: handleRemove, onPreview: previewFile }, file.id))) }) }) })] })), enableUrlInput && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm font-normal text-label", children: [jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" }), jsxRuntime.jsx("span", { children: "or" }), jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })] }), jsxRuntime.jsx(UrlImportRow, { disabled: disabled, onAdd: handleAddUrl })] })), cropImages && currentCropFile && cropPreviewUrl && (jsxRuntime.jsx(ImageCropModal, { open: true, imageUrl: cropPreviewUrl, fileName: currentCropFile.name, fileType: currentCropFile.type, onCancel: handleCropCancel, onConfirm: handleCropConfirm }))] }));
75469
76479
  };
75470
76480
 
76481
+ /** The value narrowed to one control type, or undefined when it holds another (or none). */
76482
+ function valueOfType(value, type) {
76483
+ return value?.type === type ? value : undefined;
76484
+ }
76485
+ /** Each builder returns `undefined` for an empty selection so cleared filters drop out of state. */
76486
+ const toListValue = (values) => values.length ? { type: 'list', values } : undefined;
76487
+ const toScaleValue = (range) => (range ? { type: 'scale', range } : undefined);
76488
+ const toNumberValue = (range) => range && (range.min !== undefined || range.max !== undefined)
76489
+ ? { type: 'number', range }
76490
+ : undefined;
76491
+ const toIdsValue = (ids) => ids.length ? { type: 'ids', ids } : undefined;
76492
+ const toContainsValue = (text) => text.trim() ? { type: 'contains', text: text.trim() } : undefined;
76493
+ const toDateValue = (range) => range && (range.preset || range.from || range.to)
76494
+ ? { type: 'date', range }
76495
+ : undefined;
76496
+ const toBoolValue = (value) => value === 'any' ? undefined : { type: 'bool', value };
76497
+ const DEFAULT_CELL_PLACEHOLDERS = {
76498
+ list: 'All',
76499
+ scale: 'All',
76500
+ number: '',
76501
+ ids: 'Paste IDs…',
76502
+ contains: 'Contains…',
76503
+ date: 'Any date',
76504
+ bool: 'Any',
76505
+ };
76506
+ function getCellState(field, value) {
76507
+ if (field.disabled)
76508
+ return 'disabled';
76509
+ return isFilterValueActive(value) ? 'applied' : 'empty';
76510
+ }
76511
+ /** Human-readable value for chips and card summaries, e.g. `Red, Blue`, `1–3`, `Last 30 days`. */
76512
+ function describeFilterValue(field, value) {
76513
+ if (!value || !isFilterValueActive(value))
76514
+ return '';
76515
+ const options = field.options ?? [];
76516
+ switch (value.type) {
76517
+ case 'list':
76518
+ return options
76519
+ .filter((option) => value.values.includes(option.value))
76520
+ .map((option) => option.label)
76521
+ .concat(value.values.filter((v) => !options.some((option) => option.value === v)))
76522
+ .join(', ');
76523
+ case 'scale':
76524
+ return formatScaleRange(options, value.range);
76525
+ case 'number':
76526
+ return formatNumberRange(value.range);
76527
+ case 'ids':
76528
+ return value.ids.length === 1 ? value.ids[0] : `${value.ids.length} IDs`;
76529
+ case 'contains':
76530
+ return `“${value.text}”`;
76531
+ case 'date':
76532
+ return formatDateRange(value.range);
76533
+ case 'bool':
76534
+ return getOptionLabel([
76535
+ { value: 'yes', label: 'Yes' },
76536
+ { value: 'no', label: 'No' },
76537
+ ], value.value);
76538
+ }
76539
+ }
76540
+ /** Short value shown on the filter-row trigger, e.g. `Red +1`, `VG – F`, `3 IDs`. */
76541
+ function getCellLabel(field, value) {
76542
+ if (!value || !isFilterValueActive(value))
76543
+ return '';
76544
+ if (value.type === 'list')
76545
+ return summarizeSelection(value.values, field.options ?? []);
76546
+ if (value.type === 'scale')
76547
+ return formatScaleRange(field.options ?? [], value.range, field.shortLabels);
76548
+ if (value.type === 'ids')
76549
+ return `${value.ids.length} IDs`;
76550
+ return describeFilterValue(field, value);
76551
+ }
76552
+ /** Filter-row popovers hold the filter's card at a compact, fixed width. */
76553
+ function getPopoverWidthClassName(field) {
76554
+ if (field.type === 'date')
76555
+ return 'w-96';
76556
+ if (field.type === 'bool')
76557
+ return 'w-60';
76558
+ return 'w-64';
76559
+ }
76560
+ const POPOVER_TILE_COLUMNS = 2;
76561
+ /** Above this many options, chips / tiles give way to the searchable checkbox list. */
76562
+ const MAX_PILL_OPTIONS = 10;
76563
+ /** The list layout actually used: the configured one, or the checkbox list once there are too many options for pills. */
76564
+ function resolveListLayout(field) {
76565
+ return (field.options?.length ?? 0) > MAX_PILL_OPTIONS
76566
+ ? 'list'
76567
+ : (field.layout ?? 'chips');
76568
+ }
76569
+ /** Popover variant: tile and option grids drop to two columns; chip lists become the checkbox list. */
76570
+ function toPopoverField(field) {
76571
+ if (field.type === 'scale' ||
76572
+ (field.type === 'list' && resolveListLayout(field) === 'tiles')) {
76573
+ return { ...field, columns: POPOVER_TILE_COLUMNS };
76574
+ }
76575
+ // Chip filters read better as the checkbox list in a narrow popover.
76576
+ return field.type === 'list' ? { ...field, layout: 'list' } : field;
76577
+ }
76578
+ /** ID lists and searchable lists carry their own "x selected · Clear" row, so the card skips its Clear (and, in a popover, its title). */
76579
+ const ownsClearRow = (field) => field.type === 'ids' ||
76580
+ (field.type === 'list' && resolveListLayout(field) === 'list');
76581
+ /** Popover header text in place of the title: `2 of 17 selected`, or the applied value (`VG – F`, `Last 30 days`). */
76582
+ function getPopoverStatus(field, value) {
76583
+ if (ownsClearRow(field))
76584
+ return undefined;
76585
+ if (field.type === 'list') {
76586
+ return formatSelectedCount(valueOfType(value, 'list')?.values.length ?? 0, field.options?.length ?? 0);
76587
+ }
76588
+ return describeFilterValue(field, value) || 'Any';
76589
+ }
76590
+ /** The empty single-select trigger: `inputPlaceholder`, else `Any <label>` (lowercased — set `inputPlaceholder` for acronyms). */
76591
+ const getSingleSelectPlaceholder = (field) => field.inputPlaceholder ?? `Any ${field.label.toLowerCase()}`;
76592
+
76593
+ /** Single-choice list as a searchable dropdown, e.g. "Any vendor". */
76594
+ function SingleSelectFilter({ field, selected, onSelect, }) {
76595
+ const options = field.options ?? [];
76596
+ return (jsxRuntime.jsx(SearchableSelect, { options: options, selectedItem: options.find((option) => option.value === selected) ?? null, onChange: (option) => onSelect(option.value), getOptionKey: (option) => option.value, getOptionLabel: (option) => option.label, searchPlaceholder: getSingleSelectPlaceholder(field), hideTriggerSearchIcon: true }));
76597
+ }
76598
+ /** The control alone — identical in a filter-row popover and on a card, except the list layout. Compose it into custom cards. */
76599
+ function FilterFieldControl({ field, value, onChange, fiscalYearStartMonth, fill, inPopover, }) {
76600
+ const ariaLabel = `${field.label} filter`;
76601
+ switch (field.type) {
76602
+ case 'list': {
76603
+ if (field.single && !inPopover) {
76604
+ return (jsxRuntime.jsx(SingleSelectFilter, { field: field, selected: valueOfType(value, 'list')?.values[0], onSelect: (next) => onChange(toListValue([next])) }));
76605
+ }
76606
+ const layout = resolveListLayout(field);
76607
+ return (jsxRuntime.jsx(PickListFilter, { ariaLabel: ariaLabel, options: field.options ?? [], value: valueOfType(value, 'list')?.values ?? [], onChange: (values) => onChange(toListValue(values)), layout: layout, searchPlaceholder: layout === 'list' ? field.searchPlaceholder : undefined, columns: field.columns, fill: fill }));
76608
+ }
76609
+ case 'scale':
76610
+ return (jsxRuntime.jsx(ScaleRangeFilter, { ariaLabel: ariaLabel, options: field.options ?? [], value: valueOfType(value, 'scale')?.range, onChange: (range) => onChange(toScaleValue(range)), columns: field.columns, fill: fill }));
76611
+ case 'number':
76612
+ return (jsxRuntime.jsx(NumberRangeInputs, { ariaLabel: field.label, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), presets: field.presets, presetsLabel: field.presetsLabel }));
76613
+ case 'ids':
76614
+ return (jsxRuntime.jsx(IdListInput, { ariaLabel: ariaLabel, value: valueOfType(value, 'ids')?.ids ?? [], onChange: (ids) => onChange(toIdsValue(ids)), placeholder: field.inputPlaceholder,
76615
+ // Cards show one shared hint instead of a helper under every box.
76616
+ helperText: inPopover ? field.helperText : '' }));
76617
+ case 'contains':
76618
+ return (jsxRuntime.jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "field", value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)) }));
76619
+ case 'date':
76620
+ return (jsxRuntime.jsx(DateRangeFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'date')?.range, onChange: (range) => onChange(toDateValue(range)), fiscalYearStartMonth: fiscalYearStartMonth }));
76621
+ case 'bool':
76622
+ return (jsxRuntime.jsx(TriStateFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'bool')?.value ?? 'any', onChange: (next) => onChange(toBoolValue(next)) }));
76623
+ }
76624
+ }
76625
+ /** Filter-row cell: inline input for number/contains, otherwise a trigger that opens the control in a popover. */
76626
+ function FilterFieldCell({ field, value, onChange, fiscalYearStartMonth, className, }) {
76627
+ const state = getCellState(field, value);
76628
+ const ariaLabel = `${field.label} filter`;
76629
+ const placeholder = field.placeholder ?? DEFAULT_CELL_PLACEHOLDERS[field.type];
76630
+ const clear = () => onChange(undefined);
76631
+ if (field.type === 'number' && state !== 'disabled') {
76632
+ return (jsxRuntime.jsx(NumberExpressionFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), placeholder: placeholder, note: field.note, className: className }));
76633
+ }
76634
+ if (field.type === 'contains' && state !== 'disabled') {
76635
+ return (jsxRuntime.jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "cell", value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)), placeholder: placeholder, className: className }));
76636
+ }
76637
+ return (jsxRuntime.jsx(FilterCellPopover, { label: getCellLabel(field, value), placeholder: placeholder, ariaLabel: ariaLabel, state: state, disabledLabel: field.disabledLabel, icon: field.type === 'ids' ? jsxRuntime.jsx(List, {}) : undefined, showChevron: field.type !== 'ids', onClear: field.type === 'ids' ? clear : undefined, contentClassName: getPopoverWidthClassName(field), className: className, children: jsxRuntime.jsx(FilterFieldCard, { mode: "popover", field: toPopoverField(field), value: value, onChange: onChange, fiscalYearStartMonth: fiscalYearStartMonth }) }));
76638
+ }
76639
+ /** The filter's card: on a full-page surface (`card`), in a filter-row popover (`popover`), or as a titled block inside a composite card (`section`). */
76640
+ function FilterFieldCard({ field, value, onChange, fiscalYearStartMonth, action, className, mode, }) {
76641
+ const active = isFilterValueActive(value);
76642
+ const listCount = valueOfType(value, 'list')?.values.length;
76643
+ // In a filter-row popover the column header already names the filter.
76644
+ const inPopover = mode === 'popover';
76645
+ return (jsxRuntime.jsx(FilterPanel, { variant: mode, title: inPopover ? undefined : field.label, status: inPopover ? getPopoverStatus(field, value) : undefined, selectedCount: inPopover ? undefined : listCount, summary: !inPopover && field.type !== 'list' && field.type !== 'ids'
76646
+ ? describeFilterValue(field, value)
76647
+ : undefined, action: action, onClear: active && !ownsClearRow(field)
76648
+ ? () => onChange(undefined)
76649
+ : undefined, hint: field.hint, active: active, className: className, children: jsxRuntime.jsx(FilterFieldControl, { field: field, value: value, onChange: onChange, fiscalYearStartMonth: fiscalYearStartMonth, fill: mode === 'card', inPopover: mode === 'popover' }) }));
76650
+ }
76651
+ function FilterField(props) {
76652
+ const { mode, ...rest } = props;
76653
+ return mode === 'cell' ? (jsxRuntime.jsx(FilterFieldCell, { ...rest })) : (jsxRuntime.jsx(FilterFieldCard, { mode: mode, ...rest }));
76654
+ }
76655
+
76656
+ /** Both leave without applying — the draft is discarded. */
76657
+ const BACK_LABEL = 'Back without applying';
76658
+ const CLOSE_LABEL = 'Close without applying';
76659
+
76660
+ function useCloseOnEscape(onClose) {
76661
+ React.useEffect(() => {
76662
+ const handleKeyDown = (event) => {
76663
+ if (event.key !== 'Escape' || event.defaultPrevented)
76664
+ return;
76665
+ // Escape inside an open popover only closes that popover (Radix doesn't mark the event handled).
76666
+ if (event.target instanceof Element &&
76667
+ event.target.closest('[data-slot="popover-content"]'))
76668
+ return;
76669
+ onClose();
76670
+ };
76671
+ document.addEventListener('keydown', handleKeyDown);
76672
+ return () => document.removeEventListener('keydown', handleKeyDown);
76673
+ }, [onClose]);
76674
+ }
76675
+ function useFilterSurfaceMore(defaultExpanded = false) {
76676
+ const [expanded, setExpanded] = React.useState(defaultExpanded);
76677
+ return { expanded, toggle: () => setExpanded((current) => !current) };
76678
+ }
76679
+
76680
+ /** Full-page filter screen (e.g. an advanced search): header, scrolling card grid, sticky apply footer. */
76681
+ function FilterSurface({ title, headerActions, footerChips, footerActions, onClose, children, }) {
76682
+ useCloseOnEscape(onClose);
76683
+ return (jsxRuntime.jsxs("div", { role: "region", "aria-label": title, className: "flex h-full min-h-0 flex-col bg-background", children: [jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pt-2 pb-3", children: [jsxRuntime.jsxs("header", { className: "mb-3 flex flex-wrap items-end justify-between gap-3", children: [jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(IconButton, { appearance: "ghost", size: "sm", "aria-label": BACK_LABEL, title: BACK_LABEL, onClick: onClose, children: jsxRuntime.jsx(ArrowLeft, {}) }), jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-foreground", children: title })] }) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [headerActions, jsxRuntime.jsx(IconButton, { appearance: "outline", size: "md", "aria-label": CLOSE_LABEL, title: CLOSE_LABEL, onClick: onClose, children: jsxRuntime.jsx(X$2, {}) })] })] }), jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: children })] }), (footerChips || footerActions) && (jsxRuntime.jsxs("footer", { className: "flex flex-wrap items-center justify-between gap-3 border-t border-border bg-card px-3 py-2", children: [jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: footerChips }), jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: footerActions })] }))] }));
76684
+ }
76685
+ function FilterSurfaceGroup({ title, className, children, }) {
76686
+ return (jsxRuntime.jsxs("section", { className: "flex flex-col gap-3", children: [title && (jsxRuntime.jsx("h2", { className: "text-xs font-semibold uppercase tracking-wide text-label", children: title })), jsxRuntime.jsx("div", { className: cn('grid grid-cols-1 gap-4 lg:grid-cols-6', className), children: children })] }));
76687
+ }
76688
+ /** Collapsed "More filters" divider that reveals extra cards. */
76689
+ function FilterSurfaceMore({ label, defaultExpanded, children, }) {
76690
+ const { expanded, toggle } = useFilterSurfaceMore(defaultExpanded);
76691
+ return (jsxRuntime.jsxs("section", { className: "flex flex-col gap-6", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" }), jsxRuntime.jsxs("button", { type: "button", "aria-expanded": expanded, onClick: toggle, className: "inline-flex cursor-pointer items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-xs font-medium text-primary outline-none hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-primary/30", children: [label, jsxRuntime.jsx(ChevronDown, { "aria-hidden": "true", className: cn('size-3.5 transition-transform', expanded && 'rotate-180') })] }), jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })] }), expanded && children] }));
76692
+ }
76693
+
75471
76694
  /** Falls back to counting the current page when the caller has no total. */
75472
76695
  function resolveUnreadCount(notifications, unreadCount) {
75473
76696
  if (typeof unreadCount === 'number')
@@ -78045,6 +79268,7 @@ exports.ACTIVITY_CATEGORIES = ACTIVITY_CATEGORIES;
78045
79268
  exports.ACTIVITY_CATEGORY_META = ACTIVITY_CATEGORY_META;
78046
79269
  exports.ActionBadge = ActionBadge;
78047
79270
  exports.ActionButtonWithTooltip = ActionButtonWithTooltip;
79271
+ exports.ActiveFilterChips = ActiveFilterChips;
78048
79272
  exports.ActivityFeed = ActivityFeed;
78049
79273
  exports.AdvancedSearchDrawer = AdvancedSearchDrawer;
78050
79274
  exports.Alert = Alert;
@@ -78068,6 +79292,7 @@ exports.CollapsibleTrigger = CollapsibleTrigger;
78068
79292
  exports.CompanyCard = CompanyCard;
78069
79293
  exports.ConfirmDialog = ConfirmDialog;
78070
79294
  exports.ContactTypeFilter = ContactTypeFilter;
79295
+ exports.ContainsFilter = ContainsFilter;
78071
79296
  exports.CopyButton = CopyButton;
78072
79297
  exports.CountrySelect = CountrySelect;
78073
79298
  exports.CreateFormPageHeader = CreateFormPageHeader;
@@ -78080,11 +79305,13 @@ exports.CustomFieldInput = CustomFieldInput;
78080
79305
  exports.CustomFieldValue = CustomFieldValue;
78081
79306
  exports.CustomTable = CustomTable;
78082
79307
  exports.CustomizeColumnsDrawer = CustomizeColumnsDrawer;
79308
+ exports.DATE_PRESET_OPTIONS = DATE_PRESET_OPTIONS;
78083
79309
  exports.DIAMOND_AUDIT_CONFIG = DIAMOND_AUDIT_CONFIG;
78084
79310
  exports.DashboardShell = DashboardShell;
78085
79311
  exports.DataEditableTable = DataEditableTable;
78086
79312
  exports.DataTable = DataTable;
78087
79313
  exports.DateInput = DateInput;
79314
+ exports.DateRangeFilter = DateRangeFilter;
78088
79315
  exports.DetailChip = DetailChip;
78089
79316
  exports.DetailPageLayout = DetailPageLayout;
78090
79317
  exports.DetailPageSkeleton = DetailPageSkeleton;
@@ -78112,8 +79339,18 @@ exports.EntityHeader = EntityHeader;
78112
79339
  exports.Field = Field;
78113
79340
  exports.FieldSkeleton = FieldSkeleton;
78114
79341
  exports.FileUploader = FileUploader;
79342
+ exports.FilterCellPopover = FilterCellPopover;
79343
+ exports.FilterEmptyState = FilterEmptyState;
79344
+ exports.FilterField = FilterField;
79345
+ exports.FilterFieldCard = FilterFieldCard;
79346
+ exports.FilterFieldCell = FilterFieldCell;
79347
+ exports.FilterFieldControl = FilterFieldControl;
78115
79348
  exports.FilterMultiSelect = FilterMultiSelect;
79349
+ exports.FilterPanel = FilterPanel;
78116
79350
  exports.FilterSelect = FilterSelect;
79351
+ exports.FilterSurface = FilterSurface;
79352
+ exports.FilterSurfaceGroup = FilterSurfaceGroup;
79353
+ exports.FilterSurfaceMore = FilterSurfaceMore;
78117
79354
  exports.FormSectionCard = FormSectionCard;
78118
79355
  exports.FormSectionCardSkeleton = FormSectionCardSkeleton;
78119
79356
  exports.GEM_AUDIT_CONFIG = GEM_AUDIT_CONFIG;
@@ -78123,6 +79360,7 @@ exports.HistoryTimelineShimmer = HistoryTimelineShimmer;
78123
79360
  exports.INVOICE_AUDIT_CONFIG = INVOICE_AUDIT_CONFIG;
78124
79361
  exports.IconButton = IconButton;
78125
79362
  exports.IdHyperlinkText = IdHyperlinkText;
79363
+ exports.IdListInput = IdListInput;
78126
79364
  exports.InAppNotificationCard = InAppNotificationCard;
78127
79365
  exports.InAppNotificationsPanel = InAppNotificationsPanel;
78128
79366
  exports.InfoBanner = InfoBanner;
@@ -78158,7 +79396,9 @@ exports.NavbarAvatar = NavbarAvatar;
78158
79396
  exports.NavbarIconButton = NavbarIconButton;
78159
79397
  exports.NavbarSearch = NavbarSearch;
78160
79398
  exports.NavbarTitle = NavbarTitle;
79399
+ exports.NumberExpressionFilter = NumberExpressionFilter;
78161
79400
  exports.NumberInput = NumberInput;
79401
+ exports.NumberRangeInputs = NumberRangeInputs;
78162
79402
  exports.NumberedStepCard = NumberedStepCard;
78163
79403
  exports.OtpInput = OtpInput;
78164
79404
  exports.OwnershipFilter = OwnershipFilter;
@@ -78169,6 +79409,7 @@ exports.PageTabs = PageTabs;
78169
79409
  exports.Pagination = Pagination;
78170
79410
  exports.PaginationSelect = PaginationSelect;
78171
79411
  exports.PartnerShareCard = PartnerShareCard;
79412
+ exports.PickListFilter = PickListFilter;
78172
79413
  exports.PriceInput = PriceInput;
78173
79414
  exports.Protected = Protected;
78174
79415
  exports.PurchaseOrderComboBox = PurchaseOrderComboBox;
@@ -78179,6 +79420,8 @@ exports.RefreshButton = RefreshButton;
78179
79420
  exports.RichTextarea = RichTextarea$1;
78180
79421
  exports.SEARCHABLE_SELECT_PAGE_SIZE = SEARCHABLE_SELECT_PAGE_SIZE;
78181
79422
  exports.SafeImage = SafeImage;
79423
+ exports.ScaleRangeFilter = ScaleRangeFilter;
79424
+ exports.ScrollFade = ScrollFade;
78182
79425
  exports.SearchBox = SearchBox;
78183
79426
  exports.SearchInput = SearchInput;
78184
79427
  exports.SearchableSelect = SearchableSelect;
@@ -78235,7 +79478,9 @@ exports.TagsInput = TagsInput;
78235
79478
  exports.TextHyperlink = TextHyperlink;
78236
79479
  exports.TimePicker = TimePicker;
78237
79480
  exports.ToggleSwitch = ToggleSwitch;
79481
+ exports.TriStateFilter = TriStateFilter;
78238
79482
  exports.TruncateTooltip = TruncateTooltip;
79483
+ exports.TruncatedLabel = TruncatedLabel;
78239
79484
  exports.WarehouseComboBox = WarehouseComboBox;
78240
79485
  exports.WarehouseFilter = WarehouseFilter;
78241
79486
  exports.ZoomSplitViewer = ZoomSplitViewer;
@@ -78253,12 +79498,18 @@ exports.cn = cn;
78253
79498
  exports.countries = countries;
78254
79499
  exports.countryByCode = countryByCode;
78255
79500
  exports.createVideoMediaItem = createVideoMediaItem;
79501
+ exports.describeFilterValue = describeFilterValue;
78256
79502
  exports.dropdownMenuItemDestructiveClass = dropdownMenuItemDestructiveClass;
79503
+ exports.expandScaleRange = expandScaleRange;
78257
79504
  exports.fieldTypeIcon = fieldTypeIcon;
78258
79505
  exports.findRegion = findRegion;
78259
79506
  exports.flagEmoji = flagEmoji;
78260
79507
  exports.formatAddressLocation = formatAddressLocation;
79508
+ exports.formatDateRange = formatDateRange;
78261
79509
  exports.formatFileSize = formatFileSize;
79510
+ exports.formatNumberRange = formatNumberRange;
79511
+ exports.formatScaleRange = formatScaleRange;
79512
+ exports.formatSelectedCount = formatSelectedCount;
78262
79513
  exports.generateActionDescription = generateActionDescription;
78263
79514
  exports.generateTitle = generateTitle;
78264
79515
  exports.getBadgeTypeForStatus = getBadgeTypeForStatus;
@@ -78270,16 +79521,28 @@ exports.iconButtonVariants = iconButtonVariants;
78270
79521
  exports.inAppNotificationCardA11y = inAppNotificationCardA11y;
78271
79522
  exports.inAppNotificationsPanelA11y = inAppNotificationsPanelA11y;
78272
79523
  exports.isBlank = isBlank;
79524
+ exports.isFilterValueActive = isFilterValueActive;
78273
79525
  exports.isIndiaCountry = isIndiaCountry;
78274
79526
  exports.isKnownRegion = isKnownRegion;
78275
79527
  exports.isPathActive = isPathActive;
78276
79528
  exports.isValidAlpha2CountryCode = isValidAlpha2CountryCode;
78277
79529
  exports.isValueEmpty = isValueEmpty;
78278
79530
  exports.notify = notify;
79531
+ exports.parseNumberExpression = parseNumberExpression;
78279
79532
  exports.releaseStaleOverlayBodyLock = releaseStaleOverlayBodyLock;
78280
79533
  exports.renderBadge = renderBadge;
78281
79534
  exports.resolveCountryCode = resolveCountryCode;
79535
+ exports.resolveDatePreset = resolveDatePreset;
79536
+ exports.resolveDateRange = resolveDateRange;
79537
+ exports.splitIdList = splitIdList;
78282
79538
  exports.toAddressFormValues = toAddressFormValues;
79539
+ exports.toBoolValue = toBoolValue;
79540
+ exports.toContainsValue = toContainsValue;
79541
+ exports.toDateValue = toDateValue;
79542
+ exports.toIdsValue = toIdsValue;
79543
+ exports.toListValue = toListValue;
79544
+ exports.toNumberValue = toNumberValue;
79545
+ exports.toScaleValue = toScaleValue;
78283
79546
  exports.useAuditShowMore = useAuditShowMore;
78284
79547
  exports.useBadge = useBadge;
78285
79548
  exports.useButton = useButton;
@@ -78287,6 +79550,7 @@ exports.useDropdownMenu = useDropdownMenu;
78287
79550
  exports.useInAppNotificationsPanel = useInAppNotificationsPanel;
78288
79551
  exports.useNavbar = useNavbar;
78289
79552
  exports.useSidebar = useSidebar;
79553
+ exports.valueOfType = valueOfType;
78290
79554
  exports.videoThumbnailSrc = videoThumbnailSrc;
78291
79555
  exports.watchOverlayBodyLock = watchOverlayBodyLock;
78292
79556
  //# sourceMappingURL=index.cjs.js.map