@caratlogic/design-system 0.1.32 → 0.1.34

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 (247) hide show
  1. package/dist/components/atoms/ActionButtonWithTooltip/ActionButtonWithTooltip.d.ts.map +1 -1
  2. package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts +1 -1
  3. package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts.map +1 -1
  4. package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts +16 -0
  5. package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts.map +1 -1
  6. package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts +8 -1
  7. package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts.map +1 -1
  8. package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts +20 -0
  9. package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts.map +1 -1
  10. package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts +7 -1
  11. package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts.map +1 -1
  12. package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts +8 -3
  13. package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts.map +1 -1
  14. package/dist/components/molecules/FilterSelect/FilterSelect.d.ts.map +1 -1
  15. package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts +10 -1
  16. package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts.map +1 -1
  17. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts +3 -0
  18. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts.map +1 -0
  19. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts +6 -0
  20. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts.map +1 -0
  21. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts +19 -0
  22. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts.map +1 -0
  23. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts +7 -0
  24. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts.map +1 -0
  25. package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts +3 -0
  26. package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts.map +1 -0
  27. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts +2 -0
  28. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts.map +1 -0
  29. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts +6 -0
  30. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts.map +1 -0
  31. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts +9 -0
  32. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts.map +1 -0
  33. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts +11 -0
  34. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts.map +1 -0
  35. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts +3 -0
  36. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts.map +1 -0
  37. package/dist/components/molecules/Filters/ContainsFilter/index.d.ts +3 -0
  38. package/dist/components/molecules/Filters/ContainsFilter/index.d.ts.map +1 -0
  39. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts +3 -0
  40. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts.map +1 -0
  41. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts +6 -0
  42. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts.map +1 -0
  43. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts +11 -0
  44. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts.map +1 -0
  45. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts +10 -0
  46. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts.map +1 -0
  47. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts +11 -0
  48. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts.map +1 -0
  49. package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts +3 -0
  50. package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts.map +1 -0
  51. package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.d.ts +6 -0
  52. package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.d.ts.map +1 -0
  53. package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.types.d.ts +8 -0
  54. package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.types.d.ts.map +1 -0
  55. package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.utils.d.ts +6 -0
  56. package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.utils.d.ts.map +1 -0
  57. package/dist/components/molecules/Filters/FilterCardSkeleton/index.d.ts +3 -0
  58. package/dist/components/molecules/Filters/FilterCardSkeleton/index.d.ts.map +1 -0
  59. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts +3 -0
  60. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts.map +1 -0
  61. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts +6 -0
  62. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts.map +1 -0
  63. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts +24 -0
  64. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts.map +1 -0
  65. package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts +3 -0
  66. package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts.map +1 -0
  67. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts +6 -0
  68. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts.map +1 -0
  69. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts +14 -0
  70. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts.map +1 -0
  71. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts +5 -0
  72. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts.map +1 -0
  73. package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts +3 -0
  74. package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts.map +1 -0
  75. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts +6 -0
  76. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts.map +1 -0
  77. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts +28 -0
  78. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts.map +1 -0
  79. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts +4 -0
  80. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts.map +1 -0
  81. package/dist/components/molecules/Filters/FilterPanel/index.d.ts +3 -0
  82. package/dist/components/molecules/Filters/FilterPanel/index.d.ts.map +1 -0
  83. package/dist/components/molecules/Filters/Filters.hooks.d.ts +20 -0
  84. package/dist/components/molecules/Filters/Filters.hooks.d.ts.map +1 -0
  85. package/dist/components/molecules/Filters/Filters.types.d.ts +75 -0
  86. package/dist/components/molecules/Filters/Filters.types.d.ts.map +1 -0
  87. package/dist/components/molecules/Filters/Filters.utils.d.ts +66 -0
  88. package/dist/components/molecules/Filters/Filters.utils.d.ts.map +1 -0
  89. package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts +2 -0
  90. package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts.map +1 -0
  91. package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts +6 -0
  92. package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts.map +1 -0
  93. package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts +10 -0
  94. package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts.map +1 -0
  95. package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts +10 -0
  96. package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts.map +1 -0
  97. package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts +4 -0
  98. package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts.map +1 -0
  99. package/dist/components/molecules/Filters/IdListInput/index.d.ts +3 -0
  100. package/dist/components/molecules/Filters/IdListInput/index.d.ts.map +1 -0
  101. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts +5 -0
  102. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts.map +1 -0
  103. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts +6 -0
  104. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts.map +1 -0
  105. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts +18 -0
  106. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts.map +1 -0
  107. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts +16 -0
  108. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts.map +1 -0
  109. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts +19 -0
  110. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts.map +1 -0
  111. package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts +3 -0
  112. package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts.map +1 -0
  113. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts +3 -0
  114. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts.map +1 -0
  115. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts +6 -0
  116. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts.map +1 -0
  117. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts +15 -0
  118. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts.map +1 -0
  119. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts +17 -0
  120. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts.map +1 -0
  121. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts +13 -0
  122. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts.map +1 -0
  123. package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts +3 -0
  124. package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts.map +1 -0
  125. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts +2 -0
  126. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts.map +1 -0
  127. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts +6 -0
  128. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts.map +1 -0
  129. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts +3 -0
  130. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts.map +1 -0
  131. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts +34 -0
  132. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts.map +1 -0
  133. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts +24 -0
  134. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts.map +1 -0
  135. package/dist/components/molecules/Filters/PickListFilter/index.d.ts +3 -0
  136. package/dist/components/molecules/Filters/PickListFilter/index.d.ts.map +1 -0
  137. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts +6 -0
  138. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts.map +1 -0
  139. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts +4 -0
  140. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts.map +1 -0
  141. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts +22 -0
  142. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts.map +1 -0
  143. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts +7 -0
  144. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts.map +1 -0
  145. package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts +3 -0
  146. package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts.map +1 -0
  147. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts +6 -0
  148. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts.map +1 -0
  149. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts +7 -0
  150. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts.map +1 -0
  151. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts +15 -0
  152. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts.map +1 -0
  153. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts +4 -0
  154. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts.map +1 -0
  155. package/dist/components/molecules/Filters/ScrollFade/index.d.ts +3 -0
  156. package/dist/components/molecules/Filters/ScrollFade/index.d.ts.map +1 -0
  157. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts +6 -0
  158. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts.map +1 -0
  159. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts +6 -0
  160. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts.map +1 -0
  161. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts +7 -0
  162. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts.map +1 -0
  163. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts +3 -0
  164. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts.map +1 -0
  165. package/dist/components/molecules/Filters/TriStateFilter/index.d.ts +3 -0
  166. package/dist/components/molecules/Filters/TriStateFilter/index.d.ts.map +1 -0
  167. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts +6 -0
  168. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts.map +1 -0
  169. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts +5 -0
  170. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts.map +1 -0
  171. package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts +3 -0
  172. package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts.map +1 -0
  173. package/dist/components/molecules/Filters/index.d.ts +18 -0
  174. package/dist/components/molecules/Filters/index.d.ts.map +1 -0
  175. package/dist/components/molecules/InventoryFilterSelects.d.ts.map +1 -1
  176. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.accessibility.d.ts +11 -0
  177. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.accessibility.d.ts.map +1 -0
  178. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.d.ts +6 -0
  179. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.d.ts.map +1 -0
  180. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.hooks.d.ts +9 -0
  181. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.hooks.d.ts.map +1 -0
  182. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.parts.d.ts +5 -0
  183. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.parts.d.ts.map +1 -0
  184. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.types.d.ts +66 -0
  185. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.types.d.ts.map +1 -0
  186. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.utils.d.ts +14 -0
  187. package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.utils.d.ts.map +1 -0
  188. package/dist/components/molecules/SavedSearches/SaveSearchDialog/index.d.ts +5 -0
  189. package/dist/components/molecules/SavedSearches/SaveSearchDialog/index.d.ts.map +1 -0
  190. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.d.ts +6 -0
  191. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.d.ts.map +1 -0
  192. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.hooks.d.ts +7 -0
  193. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.hooks.d.ts.map +1 -0
  194. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.types.d.ts +19 -0
  195. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.types.d.ts.map +1 -0
  196. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.utils.d.ts +5 -0
  197. package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.utils.d.ts.map +1 -0
  198. package/dist/components/molecules/SavedSearches/SavedSearchChipList/index.d.ts +3 -0
  199. package/dist/components/molecules/SavedSearches/SavedSearchChipList/index.d.ts.map +1 -0
  200. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.accessibility.d.ts +6 -0
  201. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.accessibility.d.ts.map +1 -0
  202. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.d.ts +6 -0
  203. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.d.ts.map +1 -0
  204. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.hooks.d.ts +3 -0
  205. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.hooks.d.ts.map +1 -0
  206. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.parts.d.ts +7 -0
  207. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.parts.d.ts.map +1 -0
  208. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.types.d.ts +56 -0
  209. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.types.d.ts.map +1 -0
  210. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.utils.d.ts +18 -0
  211. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.utils.d.ts.map +1 -0
  212. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/index.d.ts +4 -0
  213. package/dist/components/molecules/SavedSearches/SavedSearchesMenu/index.d.ts.map +1 -0
  214. package/dist/components/molecules/SavedSearches/index.d.ts +4 -0
  215. package/dist/components/molecules/SavedSearches/index.d.ts.map +1 -0
  216. package/dist/components/organisms/Filters/FilterField/FilterField.d.ts +11 -0
  217. package/dist/components/organisms/Filters/FilterField/FilterField.d.ts.map +1 -0
  218. package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts +68 -0
  219. package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts.map +1 -0
  220. package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts +38 -0
  221. package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts.map +1 -0
  222. package/dist/components/organisms/Filters/FilterField/index.d.ts +4 -0
  223. package/dist/components/organisms/Filters/FilterField/index.d.ts.map +1 -0
  224. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts +8 -0
  225. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts.map +1 -0
  226. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts +9 -0
  227. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts.map +1 -0
  228. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts +6 -0
  229. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts.map +1 -0
  230. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.parts.d.ts +7 -0
  231. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.parts.d.ts.map +1 -0
  232. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts +42 -0
  233. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts.map +1 -0
  234. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.utils.d.ts +4 -0
  235. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.utils.d.ts.map +1 -0
  236. package/dist/components/organisms/Filters/FilterSurface/index.d.ts +3 -0
  237. package/dist/components/organisms/Filters/FilterSurface/index.d.ts.map +1 -0
  238. package/dist/components/organisms/Filters/index.d.ts +3 -0
  239. package/dist/components/organisms/Filters/index.d.ts.map +1 -0
  240. package/dist/hooks/useTruncatedText.d.ts.map +1 -1
  241. package/dist/index.cjs.js +1979 -320
  242. package/dist/index.cjs.js.map +1 -1
  243. package/dist/index.d.ts +3 -0
  244. package/dist/index.d.ts.map +1 -1
  245. package/dist/index.esm.js +1930 -322
  246. package/dist/index.esm.js.map +1 -1
  247. package/package.json +1 -1
package/dist/index.cjs.js CHANGED
@@ -2698,12 +2698,12 @@ const createLucideIcon = (iconName, iconNode) => {
2698
2698
  */
2699
2699
 
2700
2700
 
2701
- const __iconNode$1t = [
2701
+ const __iconNode$1x = [
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$1t);
2706
+ const AlignLeft = createLucideIcon("align-left", __iconNode$1x);
2707
2707
 
2708
2708
  /**
2709
2709
  * @license lucide-react v0.539.0 - ISC
@@ -2713,12 +2713,12 @@ const AlignLeft = createLucideIcon("align-left", __iconNode$1t);
2713
2713
  */
2714
2714
 
2715
2715
 
2716
- const __iconNode$1s = [
2716
+ const __iconNode$1w = [
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$1s);
2721
+ const Archive = createLucideIcon("archive", __iconNode$1w);
2722
2722
 
2723
2723
  /**
2724
2724
  * @license lucide-react v0.539.0 - ISC
@@ -2728,11 +2728,11 @@ const Archive = createLucideIcon("archive", __iconNode$1s);
2728
2728
  */
2729
2729
 
2730
2730
 
2731
- const __iconNode$1r = [
2731
+ const __iconNode$1v = [
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$1r);
2735
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1v);
2736
2736
 
2737
2737
  /**
2738
2738
  * @license lucide-react v0.539.0 - ISC
@@ -2742,11 +2742,11 @@ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1r);
2742
2742
  */
2743
2743
 
2744
2744
 
2745
- const __iconNode$1q = [
2745
+ const __iconNode$1u = [
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$1q);
2749
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$1u);
2750
2750
 
2751
2751
  /**
2752
2752
  * @license lucide-react v0.539.0 - ISC
@@ -2756,11 +2756,11 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$1q);
2756
2756
  */
2757
2757
 
2758
2758
 
2759
- const __iconNode$1p = [
2759
+ const __iconNode$1t = [
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$1p);
2763
+ const Ban = createLucideIcon("ban", __iconNode$1t);
2764
2764
 
2765
2765
  /**
2766
2766
  * @license lucide-react v0.539.0 - ISC
@@ -2770,7 +2770,7 @@ const Ban = createLucideIcon("ban", __iconNode$1p);
2770
2770
  */
2771
2771
 
2772
2772
 
2773
- const __iconNode$1o = [
2773
+ const __iconNode$1s = [
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$1o = [
2781
2781
  ],
2782
2782
  ["circle", { cx: "18", cy: "8", r: "3", key: "1g0gzu" }]
2783
2783
  ];
2784
- const BellDot = createLucideIcon("bell-dot", __iconNode$1o);
2784
+ const BellDot = createLucideIcon("bell-dot", __iconNode$1s);
2785
2785
 
2786
2786
  /**
2787
2787
  * @license lucide-react v0.539.0 - ISC
@@ -2791,7 +2791,7 @@ const BellDot = createLucideIcon("bell-dot", __iconNode$1o);
2791
2791
  */
2792
2792
 
2793
2793
 
2794
- const __iconNode$1n = [
2794
+ const __iconNode$1r = [
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$1n = [
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$1n);
2806
+ const BellRing = createLucideIcon("bell-ring", __iconNode$1r);
2807
2807
 
2808
2808
  /**
2809
2809
  * @license lucide-react v0.539.0 - ISC
@@ -2813,7 +2813,7 @@ const BellRing = createLucideIcon("bell-ring", __iconNode$1n);
2813
2813
  */
2814
2814
 
2815
2815
 
2816
- const __iconNode$1m = [
2816
+ const __iconNode$1q = [
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$1m = [
2823
2823
  }
2824
2824
  ]
2825
2825
  ];
2826
- const Bell = createLucideIcon("bell", __iconNode$1m);
2826
+ const Bell = createLucideIcon("bell", __iconNode$1q);
2827
2827
 
2828
2828
  /**
2829
2829
  * @license lucide-react v0.539.0 - ISC
@@ -2833,13 +2833,13 @@ const Bell = createLucideIcon("bell", __iconNode$1m);
2833
2833
  */
2834
2834
 
2835
2835
 
2836
- const __iconNode$1l = [
2836
+ const __iconNode$1p = [
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$1l);
2842
+ const Bold$1 = createLucideIcon("bold", __iconNode$1p);
2843
2843
 
2844
2844
  /**
2845
2845
  * @license lucide-react v0.539.0 - ISC
@@ -2849,7 +2849,20 @@ const Bold$1 = createLucideIcon("bold", __iconNode$1l);
2849
2849
  */
2850
2850
 
2851
2851
 
2852
- const __iconNode$1k = [
2852
+ const __iconNode$1o = [
2853
+ ["path", { d: "m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z", key: "1fy3hk" }]
2854
+ ];
2855
+ const Bookmark = createLucideIcon("bookmark", __iconNode$1o);
2856
+
2857
+ /**
2858
+ * @license lucide-react v0.539.0 - ISC
2859
+ *
2860
+ * This source code is licensed under the ISC license.
2861
+ * See the LICENSE file in the root directory of this source tree.
2862
+ */
2863
+
2864
+
2865
+ const __iconNode$1n = [
2853
2866
  [
2854
2867
  "path",
2855
2868
  {
@@ -2860,7 +2873,7 @@ const __iconNode$1k = [
2860
2873
  ["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
2861
2874
  ["path", { d: "M12 22V12", key: "d0xqtd" }]
2862
2875
  ];
2863
- const Box = createLucideIcon("box", __iconNode$1k);
2876
+ const Box = createLucideIcon("box", __iconNode$1n);
2864
2877
 
2865
2878
  /**
2866
2879
  * @license lucide-react v0.539.0 - ISC
@@ -2870,7 +2883,7 @@ const Box = createLucideIcon("box", __iconNode$1k);
2870
2883
  */
2871
2884
 
2872
2885
 
2873
- const __iconNode$1j = [
2886
+ const __iconNode$1m = [
2874
2887
  ["path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z", key: "1b4qmf" }],
2875
2888
  ["path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2", key: "i71pzd" }],
2876
2889
  ["path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2", key: "10jefs" }],
@@ -2879,7 +2892,7 @@ const __iconNode$1j = [
2879
2892
  ["path", { d: "M10 14h4", key: "kelpxr" }],
2880
2893
  ["path", { d: "M10 18h4", key: "1ulq68" }]
2881
2894
  ];
2882
- const Building2 = createLucideIcon("building-2", __iconNode$1j);
2895
+ const Building2 = createLucideIcon("building-2", __iconNode$1m);
2883
2896
 
2884
2897
  /**
2885
2898
  * @license lucide-react v0.539.0 - ISC
@@ -2889,7 +2902,7 @@ const Building2 = createLucideIcon("building-2", __iconNode$1j);
2889
2902
  */
2890
2903
 
2891
2904
 
2892
- const __iconNode$1i = [
2905
+ const __iconNode$1l = [
2893
2906
  ["path", { d: "M8 2v4", key: "1cmpym" }],
2894
2907
  ["path", { d: "M16 2v4", key: "4m81vk" }],
2895
2908
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
@@ -2901,7 +2914,7 @@ const __iconNode$1i = [
2901
2914
  ["path", { d: "M12 18h.01", key: "mhygvu" }],
2902
2915
  ["path", { d: "M16 18h.01", key: "kzsmim" }]
2903
2916
  ];
2904
- const CalendarDays = createLucideIcon("calendar-days", __iconNode$1i);
2917
+ const CalendarDays = createLucideIcon("calendar-days", __iconNode$1l);
2905
2918
 
2906
2919
  /**
2907
2920
  * @license lucide-react v0.539.0 - ISC
@@ -2911,13 +2924,13 @@ const CalendarDays = createLucideIcon("calendar-days", __iconNode$1i);
2911
2924
  */
2912
2925
 
2913
2926
 
2914
- const __iconNode$1h = [
2927
+ const __iconNode$1k = [
2915
2928
  ["path", { d: "M8 2v4", key: "1cmpym" }],
2916
2929
  ["path", { d: "M16 2v4", key: "4m81vk" }],
2917
2930
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
2918
2931
  ["path", { d: "M3 10h18", key: "8toen8" }]
2919
2932
  ];
2920
- const Calendar$1 = createLucideIcon("calendar", __iconNode$1h);
2933
+ const Calendar$1 = createLucideIcon("calendar", __iconNode$1k);
2921
2934
 
2922
2935
  /**
2923
2936
  * @license lucide-react v0.539.0 - ISC
@@ -2927,11 +2940,11 @@ const Calendar$1 = createLucideIcon("calendar", __iconNode$1h);
2927
2940
  */
2928
2941
 
2929
2942
 
2930
- const __iconNode$1g = [
2943
+ const __iconNode$1j = [
2931
2944
  ["path", { d: "M18 6 7 17l-5-5", key: "116fxf" }],
2932
2945
  ["path", { d: "m22 10-7.5 7.5L13 16", key: "ke71qq" }]
2933
2946
  ];
2934
- const CheckCheck = createLucideIcon("check-check", __iconNode$1g);
2947
+ const CheckCheck = createLucideIcon("check-check", __iconNode$1j);
2935
2948
 
2936
2949
  /**
2937
2950
  * @license lucide-react v0.539.0 - ISC
@@ -2941,8 +2954,8 @@ const CheckCheck = createLucideIcon("check-check", __iconNode$1g);
2941
2954
  */
2942
2955
 
2943
2956
 
2944
- const __iconNode$1f = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
2945
- const Check = createLucideIcon("check", __iconNode$1f);
2957
+ const __iconNode$1i = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
2958
+ const Check = createLucideIcon("check", __iconNode$1i);
2946
2959
 
2947
2960
  /**
2948
2961
  * @license lucide-react v0.539.0 - ISC
@@ -2952,8 +2965,8 @@ const Check = createLucideIcon("check", __iconNode$1f);
2952
2965
  */
2953
2966
 
2954
2967
 
2955
- const __iconNode$1e = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
2956
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$1e);
2968
+ const __iconNode$1h = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
2969
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1h);
2957
2970
 
2958
2971
  /**
2959
2972
  * @license lucide-react v0.539.0 - ISC
@@ -2963,8 +2976,8 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1e);
2963
2976
  */
2964
2977
 
2965
2978
 
2966
- const __iconNode$1d = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
2967
- const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1d);
2979
+ const __iconNode$1g = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
2980
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1g);
2968
2981
 
2969
2982
  /**
2970
2983
  * @license lucide-react v0.539.0 - ISC
@@ -2974,8 +2987,8 @@ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1d);
2974
2987
  */
2975
2988
 
2976
2989
 
2977
- const __iconNode$1c = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
2978
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$1c);
2990
+ const __iconNode$1f = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
2991
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1f);
2979
2992
 
2980
2993
  /**
2981
2994
  * @license lucide-react v0.539.0 - ISC
@@ -2985,8 +2998,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1c);
2985
2998
  */
2986
2999
 
2987
3000
 
2988
- const __iconNode$1b = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
2989
- const ChevronUp = createLucideIcon("chevron-up", __iconNode$1b);
3001
+ const __iconNode$1e = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
3002
+ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1e);
2990
3003
 
2991
3004
  /**
2992
3005
  * @license lucide-react v0.539.0 - ISC
@@ -2996,11 +3009,11 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1b);
2996
3009
  */
2997
3010
 
2998
3011
 
2999
- const __iconNode$1a = [
3012
+ const __iconNode$1d = [
3000
3013
  ["path", { d: "m11 17-5-5 5-5", key: "13zhaf" }],
3001
3014
  ["path", { d: "m18 17-5-5 5-5", key: "h8a8et" }]
3002
3015
  ];
3003
- const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1a);
3016
+ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1d);
3004
3017
 
3005
3018
  /**
3006
3019
  * @license lucide-react v0.539.0 - ISC
@@ -3010,11 +3023,11 @@ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1a);
3010
3023
  */
3011
3024
 
3012
3025
 
3013
- const __iconNode$19 = [
3026
+ const __iconNode$1c = [
3014
3027
  ["path", { d: "m6 17 5-5-5-5", key: "xnjwq" }],
3015
3028
  ["path", { d: "m13 17 5-5-5-5", key: "17xmmf" }]
3016
3029
  ];
3017
- const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$19);
3030
+ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$1c);
3018
3031
 
3019
3032
  /**
3020
3033
  * @license lucide-react v0.539.0 - ISC
@@ -3024,12 +3037,12 @@ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$19);
3024
3037
  */
3025
3038
 
3026
3039
 
3027
- const __iconNode$18 = [
3040
+ const __iconNode$1b = [
3028
3041
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3029
3042
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
3030
3043
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
3031
3044
  ];
3032
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$18);
3045
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$1b);
3033
3046
 
3034
3047
  /**
3035
3048
  * @license lucide-react v0.539.0 - ISC
@@ -3039,11 +3052,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$18);
3039
3052
  */
3040
3053
 
3041
3054
 
3042
- const __iconNode$17 = [
3055
+ const __iconNode$1a = [
3043
3056
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
3044
3057
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
3045
3058
  ];
3046
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$17);
3059
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$1a);
3047
3060
 
3048
3061
  /**
3049
3062
  * @license lucide-react v0.539.0 - ISC
@@ -3053,11 +3066,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$17);
3053
3066
  */
3054
3067
 
3055
3068
 
3056
- const __iconNode$16 = [
3069
+ const __iconNode$19 = [
3057
3070
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3058
3071
  ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
3059
3072
  ];
3060
- const CircleCheck = createLucideIcon("circle-check", __iconNode$16);
3073
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$19);
3061
3074
 
3062
3075
  /**
3063
3076
  * @license lucide-react v0.539.0 - ISC
@@ -3067,11 +3080,11 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$16);
3067
3080
  */
3068
3081
 
3069
3082
 
3070
- const __iconNode$15 = [
3083
+ const __iconNode$18 = [
3071
3084
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3072
3085
  ["path", { d: "m16 10-4 4-4-4", key: "894hmk" }]
3073
3086
  ];
3074
- const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$15);
3087
+ const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$18);
3075
3088
 
3076
3089
  /**
3077
3090
  * @license lucide-react v0.539.0 - ISC
@@ -3081,11 +3094,11 @@ const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$15)
3081
3094
  */
3082
3095
 
3083
3096
 
3084
- const __iconNode$14 = [
3097
+ const __iconNode$17 = [
3085
3098
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3086
3099
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }]
3087
3100
  ];
3088
- const CircleDot = createLucideIcon("circle-dot", __iconNode$14);
3101
+ const CircleDot = createLucideIcon("circle-dot", __iconNode$17);
3089
3102
 
3090
3103
  /**
3091
3104
  * @license lucide-react v0.539.0 - ISC
@@ -3095,12 +3108,12 @@ const CircleDot = createLucideIcon("circle-dot", __iconNode$14);
3095
3108
  */
3096
3109
 
3097
3110
 
3098
- const __iconNode$13 = [
3111
+ const __iconNode$16 = [
3099
3112
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3100
3113
  ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
3101
3114
  ["path", { d: "m9 9 6 6", key: "z0biqf" }]
3102
3115
  ];
3103
- const CircleX = createLucideIcon("circle-x", __iconNode$13);
3116
+ const CircleX = createLucideIcon("circle-x", __iconNode$16);
3104
3117
 
3105
3118
  /**
3106
3119
  * @license lucide-react v0.539.0 - ISC
@@ -3110,8 +3123,8 @@ const CircleX = createLucideIcon("circle-x", __iconNode$13);
3110
3123
  */
3111
3124
 
3112
3125
 
3113
- const __iconNode$12 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
3114
- const Circle = createLucideIcon("circle", __iconNode$12);
3126
+ const __iconNode$15 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
3127
+ const Circle = createLucideIcon("circle", __iconNode$15);
3115
3128
 
3116
3129
  /**
3117
3130
  * @license lucide-react v0.539.0 - ISC
@@ -3121,11 +3134,11 @@ const Circle = createLucideIcon("circle", __iconNode$12);
3121
3134
  */
3122
3135
 
3123
3136
 
3124
- const __iconNode$11 = [
3137
+ const __iconNode$14 = [
3125
3138
  ["path", { d: "M12 6v6l4 2", key: "mmk7yg" }],
3126
3139
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
3127
3140
  ];
3128
- const Clock = createLucideIcon("clock", __iconNode$11);
3141
+ const Clock = createLucideIcon("clock", __iconNode$14);
3129
3142
 
3130
3143
  /**
3131
3144
  * @license lucide-react v0.539.0 - ISC
@@ -3135,11 +3148,11 @@ const Clock = createLucideIcon("clock", __iconNode$11);
3135
3148
  */
3136
3149
 
3137
3150
 
3138
- const __iconNode$10 = [
3151
+ const __iconNode$13 = [
3139
3152
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
3140
3153
  ["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
3154
  ];
3142
- const Copy = createLucideIcon("copy", __iconNode$10);
3155
+ const Copy = createLucideIcon("copy", __iconNode$13);
3143
3156
 
3144
3157
  /**
3145
3158
  * @license lucide-react v0.539.0 - ISC
@@ -3149,11 +3162,11 @@ const Copy = createLucideIcon("copy", __iconNode$10);
3149
3162
  */
3150
3163
 
3151
3164
 
3152
- const __iconNode$$ = [
3165
+ const __iconNode$12 = [
3153
3166
  ["path", { d: "M6 2v14a2 2 0 0 0 2 2h14", key: "ron5a4" }],
3154
3167
  ["path", { d: "M18 22V8a2 2 0 0 0-2-2H2", key: "7s9ehn" }]
3155
3168
  ];
3156
- const Crop = createLucideIcon("crop", __iconNode$$);
3169
+ const Crop = createLucideIcon("crop", __iconNode$12);
3157
3170
 
3158
3171
  /**
3159
3172
  * @license lucide-react v0.539.0 - ISC
@@ -3163,12 +3176,12 @@ const Crop = createLucideIcon("crop", __iconNode$$);
3163
3176
  */
3164
3177
 
3165
3178
 
3166
- const __iconNode$_ = [
3179
+ const __iconNode$11 = [
3167
3180
  ["path", { d: "M12 15V3", key: "m9g1x1" }],
3168
3181
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
3169
3182
  ["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
3170
3183
  ];
3171
- const Download = createLucideIcon("download", __iconNode$_);
3184
+ const Download = createLucideIcon("download", __iconNode$11);
3172
3185
 
3173
3186
  /**
3174
3187
  * @license lucide-react v0.539.0 - ISC
@@ -3178,12 +3191,12 @@ const Download = createLucideIcon("download", __iconNode$_);
3178
3191
  */
3179
3192
 
3180
3193
 
3181
- const __iconNode$Z = [
3194
+ const __iconNode$10 = [
3182
3195
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3183
3196
  ["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
3184
3197
  ["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
3185
3198
  ];
3186
- const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$Z);
3199
+ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$10);
3187
3200
 
3188
3201
  /**
3189
3202
  * @license lucide-react v0.539.0 - ISC
@@ -3193,12 +3206,12 @@ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$Z);
3193
3206
  */
3194
3207
 
3195
3208
 
3196
- const __iconNode$Y = [
3209
+ const __iconNode$$ = [
3197
3210
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3198
3211
  ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
3199
3212
  ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
3200
3213
  ];
3201
- const Ellipsis = createLucideIcon("ellipsis", __iconNode$Y);
3214
+ const Ellipsis = createLucideIcon("ellipsis", __iconNode$$);
3202
3215
 
3203
3216
  /**
3204
3217
  * @license lucide-react v0.539.0 - ISC
@@ -3208,12 +3221,12 @@ const Ellipsis = createLucideIcon("ellipsis", __iconNode$Y);
3208
3221
  */
3209
3222
 
3210
3223
 
3211
- const __iconNode$X = [
3224
+ const __iconNode$_ = [
3212
3225
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3213
3226
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
3214
3227
  ["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
3228
  ];
3216
- const ExternalLink = createLucideIcon("external-link", __iconNode$X);
3229
+ const ExternalLink = createLucideIcon("external-link", __iconNode$_);
3217
3230
 
3218
3231
  /**
3219
3232
  * @license lucide-react v0.539.0 - ISC
@@ -3223,7 +3236,7 @@ const ExternalLink = createLucideIcon("external-link", __iconNode$X);
3223
3236
  */
3224
3237
 
3225
3238
 
3226
- const __iconNode$W = [
3239
+ const __iconNode$Z = [
3227
3240
  [
3228
3241
  "path",
3229
3242
  {
@@ -3233,7 +3246,7 @@ const __iconNode$W = [
3233
3246
  ],
3234
3247
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
3235
3248
  ];
3236
- const Eye = createLucideIcon("eye", __iconNode$W);
3249
+ const Eye = createLucideIcon("eye", __iconNode$Z);
3237
3250
 
3238
3251
  /**
3239
3252
  * @license lucide-react v0.539.0 - ISC
@@ -3243,13 +3256,13 @@ const Eye = createLucideIcon("eye", __iconNode$W);
3243
3256
  */
3244
3257
 
3245
3258
 
3246
- const __iconNode$V = [
3259
+ const __iconNode$Y = [
3247
3260
  [
3248
3261
  "path",
3249
3262
  { d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z", key: "1jg4f8" }
3250
3263
  ]
3251
3264
  ];
3252
- const Facebook = createLucideIcon("facebook", __iconNode$V);
3265
+ const Facebook = createLucideIcon("facebook", __iconNode$Y);
3253
3266
 
3254
3267
  /**
3255
3268
  * @license lucide-react v0.539.0 - ISC
@@ -3259,7 +3272,7 @@ const Facebook = createLucideIcon("facebook", __iconNode$V);
3259
3272
  */
3260
3273
 
3261
3274
 
3262
- const __iconNode$U = [
3275
+ const __iconNode$X = [
3263
3276
  ["path", { d: "M12 22h6a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3.072", key: "n6s66f" }],
3264
3277
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3265
3278
  [
@@ -3271,7 +3284,7 @@ const __iconNode$U = [
3271
3284
  ],
3272
3285
  ["circle", { cx: "5", cy: "14", r: "3", key: "ufru5t" }]
3273
3286
  ];
3274
- const FileBadge = createLucideIcon("file-badge", __iconNode$U);
3287
+ const FileBadge = createLucideIcon("file-badge", __iconNode$X);
3275
3288
 
3276
3289
  /**
3277
3290
  * @license lucide-react v0.539.0 - ISC
@@ -3281,12 +3294,12 @@ const FileBadge = createLucideIcon("file-badge", __iconNode$U);
3281
3294
  */
3282
3295
 
3283
3296
 
3284
- const __iconNode$T = [
3297
+ const __iconNode$W = [
3285
3298
  ["path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4", key: "1pf5j1" }],
3286
3299
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3287
3300
  ["path", { d: "m3 15 2 2 4-4", key: "1lhrkk" }]
3288
3301
  ];
3289
- const FileCheck2 = createLucideIcon("file-check-2", __iconNode$T);
3302
+ const FileCheck2 = createLucideIcon("file-check-2", __iconNode$W);
3290
3303
 
3291
3304
  /**
3292
3305
  * @license lucide-react v0.539.0 - ISC
@@ -3296,14 +3309,14 @@ const FileCheck2 = createLucideIcon("file-check-2", __iconNode$T);
3296
3309
  */
3297
3310
 
3298
3311
 
3299
- const __iconNode$S = [
3312
+ const __iconNode$V = [
3300
3313
  ["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
3314
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3302
3315
  ["path", { d: "M10 9H8", key: "b1mrlr" }],
3303
3316
  ["path", { d: "M16 13H8", key: "t4e002" }],
3304
3317
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
3305
3318
  ];
3306
- const FileText = createLucideIcon("file-text", __iconNode$S);
3319
+ const FileText = createLucideIcon("file-text", __iconNode$V);
3307
3320
 
3308
3321
  /**
3309
3322
  * @license lucide-react v0.539.0 - ISC
@@ -3313,7 +3326,28 @@ const FileText = createLucideIcon("file-text", __iconNode$S);
3313
3326
  */
3314
3327
 
3315
3328
 
3316
- const __iconNode$R = [
3329
+ const __iconNode$U = [
3330
+ [
3331
+ "path",
3332
+ {
3333
+ 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",
3334
+ key: "ol2ft2"
3335
+ }
3336
+ ],
3337
+ ["path", { d: "m16.5 3.5 5 5", key: "15e6fa" }],
3338
+ ["path", { d: "m21.5 3.5-5 5", key: "m0lwru" }]
3339
+ ];
3340
+ const FunnelX = createLucideIcon("funnel-x", __iconNode$U);
3341
+
3342
+ /**
3343
+ * @license lucide-react v0.539.0 - ISC
3344
+ *
3345
+ * This source code is licensed under the ISC license.
3346
+ * See the LICENSE file in the root directory of this source tree.
3347
+ */
3348
+
3349
+
3350
+ const __iconNode$T = [
3317
3351
  [
3318
3352
  "path",
3319
3353
  {
@@ -3322,7 +3356,7 @@ const __iconNode$R = [
3322
3356
  }
3323
3357
  ]
3324
3358
  ];
3325
- const Funnel = createLucideIcon("funnel", __iconNode$R);
3359
+ const Funnel = createLucideIcon("funnel", __iconNode$T);
3326
3360
 
3327
3361
  /**
3328
3362
  * @license lucide-react v0.539.0 - ISC
@@ -3332,7 +3366,7 @@ const Funnel = createLucideIcon("funnel", __iconNode$R);
3332
3366
  */
3333
3367
 
3334
3368
 
3335
- const __iconNode$Q = [
3369
+ const __iconNode$S = [
3336
3370
  ["path", { d: "M10.5 3 8 9l4 13 4-13-2.5-6", key: "b3dvk1" }],
3337
3371
  [
3338
3372
  "path",
@@ -3343,7 +3377,7 @@ const __iconNode$Q = [
3343
3377
  ],
3344
3378
  ["path", { d: "M2 9h20", key: "16fsjt" }]
3345
3379
  ];
3346
- const Gem = createLucideIcon("gem", __iconNode$Q);
3380
+ const Gem = createLucideIcon("gem", __iconNode$S);
3347
3381
 
3348
3382
  /**
3349
3383
  * @license lucide-react v0.539.0 - ISC
@@ -3353,7 +3387,7 @@ const Gem = createLucideIcon("gem", __iconNode$Q);
3353
3387
  */
3354
3388
 
3355
3389
 
3356
- const __iconNode$P = [
3390
+ const __iconNode$R = [
3357
3391
  ["circle", { cx: "12", cy: "9", r: "1", key: "124mty" }],
3358
3392
  ["circle", { cx: "19", cy: "9", r: "1", key: "1ruzo2" }],
3359
3393
  ["circle", { cx: "5", cy: "9", r: "1", key: "1a8b28" }],
@@ -3361,7 +3395,7 @@ const __iconNode$P = [
3361
3395
  ["circle", { cx: "19", cy: "15", r: "1", key: "1a92ep" }],
3362
3396
  ["circle", { cx: "5", cy: "15", r: "1", key: "5r1jwy" }]
3363
3397
  ];
3364
- const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$P);
3398
+ const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$R);
3365
3399
 
3366
3400
  /**
3367
3401
  * @license lucide-react v0.539.0 - ISC
@@ -3371,7 +3405,7 @@ const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$P);
3371
3405
  */
3372
3406
 
3373
3407
 
3374
- const __iconNode$O = [
3408
+ const __iconNode$Q = [
3375
3409
  ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
3376
3410
  ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
3377
3411
  ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
@@ -3379,7 +3413,7 @@ const __iconNode$O = [
3379
3413
  ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
3380
3414
  ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
3381
3415
  ];
3382
- const GripVertical = createLucideIcon("grip-vertical", __iconNode$O);
3416
+ const GripVertical = createLucideIcon("grip-vertical", __iconNode$Q);
3383
3417
 
3384
3418
  /**
3385
3419
  * @license lucide-react v0.539.0 - ISC
@@ -3389,13 +3423,13 @@ const GripVertical = createLucideIcon("grip-vertical", __iconNode$O);
3389
3423
  */
3390
3424
 
3391
3425
 
3392
- const __iconNode$N = [
3426
+ const __iconNode$P = [
3393
3427
  ["line", { x1: "4", x2: "20", y1: "9", y2: "9", key: "4lhtct" }],
3394
3428
  ["line", { x1: "4", x2: "20", y1: "15", y2: "15", key: "vyu0kd" }],
3395
3429
  ["line", { x1: "10", x2: "8", y1: "3", y2: "21", key: "1ggp8o" }],
3396
3430
  ["line", { x1: "16", x2: "14", y1: "3", y2: "21", key: "weycgp" }]
3397
3431
  ];
3398
- const Hash = createLucideIcon("hash", __iconNode$N);
3432
+ const Hash = createLucideIcon("hash", __iconNode$P);
3399
3433
 
3400
3434
  /**
3401
3435
  * @license lucide-react v0.539.0 - ISC
@@ -3405,13 +3439,13 @@ const Hash = createLucideIcon("hash", __iconNode$N);
3405
3439
  */
3406
3440
 
3407
3441
 
3408
- const __iconNode$M = [
3442
+ const __iconNode$O = [
3409
3443
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3410
3444
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3411
3445
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3412
3446
  ["path", { d: "m17 12 3-2v8", key: "1hhhft" }]
3413
3447
  ];
3414
- const Heading1 = createLucideIcon("heading-1", __iconNode$M);
3448
+ const Heading1 = createLucideIcon("heading-1", __iconNode$O);
3415
3449
 
3416
3450
  /**
3417
3451
  * @license lucide-react v0.539.0 - ISC
@@ -3421,13 +3455,13 @@ const Heading1 = createLucideIcon("heading-1", __iconNode$M);
3421
3455
  */
3422
3456
 
3423
3457
 
3424
- const __iconNode$L = [
3458
+ const __iconNode$N = [
3425
3459
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3426
3460
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3427
3461
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3428
3462
  ["path", { d: "M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1", key: "9jr5yi" }]
3429
3463
  ];
3430
- const Heading2 = createLucideIcon("heading-2", __iconNode$L);
3464
+ const Heading2 = createLucideIcon("heading-2", __iconNode$N);
3431
3465
 
3432
3466
  /**
3433
3467
  * @license lucide-react v0.539.0 - ISC
@@ -3437,14 +3471,14 @@ const Heading2 = createLucideIcon("heading-2", __iconNode$L);
3437
3471
  */
3438
3472
 
3439
3473
 
3440
- const __iconNode$K = [
3474
+ const __iconNode$M = [
3441
3475
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3442
3476
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3443
3477
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3444
3478
  ["path", { d: "M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2", key: "68ncm8" }],
3445
3479
  ["path", { d: "M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2", key: "1ejuhz" }]
3446
3480
  ];
3447
- const Heading3 = createLucideIcon("heading-3", __iconNode$K);
3481
+ const Heading3 = createLucideIcon("heading-3", __iconNode$M);
3448
3482
 
3449
3483
  /**
3450
3484
  * @license lucide-react v0.539.0 - ISC
@@ -3454,12 +3488,12 @@ const Heading3 = createLucideIcon("heading-3", __iconNode$K);
3454
3488
  */
3455
3489
 
3456
3490
 
3457
- const __iconNode$J = [
3491
+ const __iconNode$L = [
3458
3492
  ["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
3493
  ["path", { d: "M3 3v5h5", key: "1xhq8a" }],
3460
3494
  ["path", { d: "M12 7v5l4 2", key: "1fdv2h" }]
3461
3495
  ];
3462
- const History = createLucideIcon("history", __iconNode$J);
3496
+ const History = createLucideIcon("history", __iconNode$L);
3463
3497
 
3464
3498
  /**
3465
3499
  * @license lucide-react v0.539.0 - ISC
@@ -3469,12 +3503,12 @@ const History = createLucideIcon("history", __iconNode$J);
3469
3503
  */
3470
3504
 
3471
3505
 
3472
- const __iconNode$I = [
3506
+ const __iconNode$K = [
3473
3507
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
3474
3508
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
3475
3509
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
3476
3510
  ];
3477
- const Image$1 = createLucideIcon("image", __iconNode$I);
3511
+ const Image$1 = createLucideIcon("image", __iconNode$K);
3478
3512
 
3479
3513
  /**
3480
3514
  * @license lucide-react v0.539.0 - ISC
@@ -3484,12 +3518,12 @@ const Image$1 = createLucideIcon("image", __iconNode$I);
3484
3518
  */
3485
3519
 
3486
3520
 
3487
- const __iconNode$H = [
3521
+ const __iconNode$J = [
3488
3522
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3489
3523
  ["path", { d: "M12 16v-4", key: "1dtifu" }],
3490
3524
  ["path", { d: "M12 8h.01", key: "e9boi3" }]
3491
3525
  ];
3492
- const Info = createLucideIcon("info", __iconNode$H);
3526
+ const Info = createLucideIcon("info", __iconNode$J);
3493
3527
 
3494
3528
  /**
3495
3529
  * @license lucide-react v0.539.0 - ISC
@@ -3499,12 +3533,12 @@ const Info = createLucideIcon("info", __iconNode$H);
3499
3533
  */
3500
3534
 
3501
3535
 
3502
- const __iconNode$G = [
3536
+ const __iconNode$I = [
3503
3537
  ["line", { x1: "19", x2: "10", y1: "4", y2: "4", key: "15jd3p" }],
3504
3538
  ["line", { x1: "14", x2: "5", y1: "20", y2: "20", key: "bu0au3" }],
3505
3539
  ["line", { x1: "15", x2: "9", y1: "4", y2: "20", key: "uljnxc" }]
3506
3540
  ];
3507
- const Italic$1 = createLucideIcon("italic", __iconNode$G);
3541
+ const Italic$1 = createLucideIcon("italic", __iconNode$I);
3508
3542
 
3509
3543
  /**
3510
3544
  * @license lucide-react v0.539.0 - ISC
@@ -3514,7 +3548,7 @@ const Italic$1 = createLucideIcon("italic", __iconNode$G);
3514
3548
  */
3515
3549
 
3516
3550
 
3517
- const __iconNode$F = [
3551
+ const __iconNode$H = [
3518
3552
  [
3519
3553
  "path",
3520
3554
  {
@@ -3524,7 +3558,7 @@ const __iconNode$F = [
3524
3558
  ],
3525
3559
  ["circle", { cx: "16.5", cy: "7.5", r: ".5", fill: "currentColor", key: "w0ekpg" }]
3526
3560
  ];
3527
- const KeyRound = createLucideIcon("key-round", __iconNode$F);
3561
+ const KeyRound = createLucideIcon("key-round", __iconNode$H);
3528
3562
 
3529
3563
  /**
3530
3564
  * @license lucide-react v0.539.0 - ISC
@@ -3534,12 +3568,12 @@ const KeyRound = createLucideIcon("key-round", __iconNode$F);
3534
3568
  */
3535
3569
 
3536
3570
 
3537
- const __iconNode$E = [
3571
+ const __iconNode$G = [
3538
3572
  ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
3539
3573
  ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
3540
3574
  ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
3541
3575
  ];
3542
- const Link2 = createLucideIcon("link-2", __iconNode$E);
3576
+ const Link2 = createLucideIcon("link-2", __iconNode$G);
3543
3577
 
3544
3578
  /**
3545
3579
  * @license lucide-react v0.539.0 - ISC
@@ -3549,14 +3583,14 @@ const Link2 = createLucideIcon("link-2", __iconNode$E);
3549
3583
  */
3550
3584
 
3551
3585
 
3552
- const __iconNode$D = [
3586
+ const __iconNode$F = [
3553
3587
  ["path", { d: "m3 17 2 2 4-4", key: "1jhpwq" }],
3554
3588
  ["path", { d: "m3 7 2 2 4-4", key: "1obspn" }],
3555
3589
  ["path", { d: "M13 6h8", key: "15sg57" }],
3556
3590
  ["path", { d: "M13 12h8", key: "h98zly" }],
3557
3591
  ["path", { d: "M13 18h8", key: "oe0vm4" }]
3558
3592
  ];
3559
- const ListChecks = createLucideIcon("list-checks", __iconNode$D);
3593
+ const ListChecks = createLucideIcon("list-checks", __iconNode$F);
3560
3594
 
3561
3595
  /**
3562
3596
  * @license lucide-react v0.539.0 - ISC
@@ -3566,7 +3600,7 @@ const ListChecks = createLucideIcon("list-checks", __iconNode$D);
3566
3600
  */
3567
3601
 
3568
3602
 
3569
- const __iconNode$C = [
3603
+ const __iconNode$E = [
3570
3604
  ["path", { d: "M10 12h11", key: "6m4ad9" }],
3571
3605
  ["path", { d: "M10 18h11", key: "11hvi2" }],
3572
3606
  ["path", { d: "M10 6h11", key: "c7qv1k" }],
@@ -3574,7 +3608,7 @@ const __iconNode$C = [
3574
3608
  ["path", { d: "M4 6h1v4", key: "cnovpq" }],
3575
3609
  ["path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1", key: "m9a95d" }]
3576
3610
  ];
3577
- const ListOrdered = createLucideIcon("list-ordered", __iconNode$C);
3611
+ const ListOrdered = createLucideIcon("list-ordered", __iconNode$E);
3578
3612
 
3579
3613
  /**
3580
3614
  * @license lucide-react v0.539.0 - ISC
@@ -3584,7 +3618,7 @@ const ListOrdered = createLucideIcon("list-ordered", __iconNode$C);
3584
3618
  */
3585
3619
 
3586
3620
 
3587
- const __iconNode$B = [
3621
+ const __iconNode$D = [
3588
3622
  ["path", { d: "M3 12h.01", key: "nlz23k" }],
3589
3623
  ["path", { d: "M3 18h.01", key: "1tta3j" }],
3590
3624
  ["path", { d: "M3 6h.01", key: "1rqtza" }],
@@ -3592,7 +3626,7 @@ const __iconNode$B = [
3592
3626
  ["path", { d: "M8 18h13", key: "1lx6n3" }],
3593
3627
  ["path", { d: "M8 6h13", key: "ik3vkj" }]
3594
3628
  ];
3595
- const List = createLucideIcon("list", __iconNode$B);
3629
+ const List = createLucideIcon("list", __iconNode$D);
3596
3630
 
3597
3631
  /**
3598
3632
  * @license lucide-react v0.539.0 - ISC
@@ -3602,8 +3636,8 @@ const List = createLucideIcon("list", __iconNode$B);
3602
3636
  */
3603
3637
 
3604
3638
 
3605
- const __iconNode$A = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3606
- const LoaderCircle = createLucideIcon("loader-circle", __iconNode$A);
3639
+ const __iconNode$C = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3640
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$C);
3607
3641
 
3608
3642
  /**
3609
3643
  * @license lucide-react v0.539.0 - ISC
@@ -3613,7 +3647,7 @@ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$A);
3613
3647
  */
3614
3648
 
3615
3649
 
3616
- const __iconNode$z = [
3650
+ const __iconNode$B = [
3617
3651
  ["path", { d: "M12 2v4", key: "3427ic" }],
3618
3652
  ["path", { d: "m16.2 7.8 2.9-2.9", key: "r700ao" }],
3619
3653
  ["path", { d: "M18 12h4", key: "wj9ykh" }],
@@ -3623,7 +3657,7 @@ const __iconNode$z = [
3623
3657
  ["path", { d: "M2 12h4", key: "j09sii" }],
3624
3658
  ["path", { d: "m4.9 4.9 2.9 2.9", key: "giyufr" }]
3625
3659
  ];
3626
- const Loader = createLucideIcon("loader", __iconNode$z);
3660
+ const Loader = createLucideIcon("loader", __iconNode$B);
3627
3661
 
3628
3662
  /**
3629
3663
  * @license lucide-react v0.539.0 - ISC
@@ -3633,12 +3667,12 @@ const Loader = createLucideIcon("loader", __iconNode$z);
3633
3667
  */
3634
3668
 
3635
3669
 
3636
- const __iconNode$y = [
3670
+ const __iconNode$A = [
3637
3671
  ["path", { d: "m16 17 5-5-5-5", key: "1bji2h" }],
3638
3672
  ["path", { d: "M21 12H9", key: "dn1m92" }],
3639
3673
  ["path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4", key: "1uf3rs" }]
3640
3674
  ];
3641
- const LogOut = createLucideIcon("log-out", __iconNode$y);
3675
+ const LogOut = createLucideIcon("log-out", __iconNode$A);
3642
3676
 
3643
3677
  /**
3644
3678
  * @license lucide-react v0.539.0 - ISC
@@ -3648,11 +3682,11 @@ const LogOut = createLucideIcon("log-out", __iconNode$y);
3648
3682
  */
3649
3683
 
3650
3684
 
3651
- const __iconNode$x = [
3685
+ const __iconNode$z = [
3652
3686
  ["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
3653
3687
  ["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
3654
3688
  ];
3655
- const Mail = createLucideIcon("mail", __iconNode$x);
3689
+ const Mail = createLucideIcon("mail", __iconNode$z);
3656
3690
 
3657
3691
  /**
3658
3692
  * @license lucide-react v0.539.0 - ISC
@@ -3662,12 +3696,12 @@ const Mail = createLucideIcon("mail", __iconNode$x);
3662
3696
  */
3663
3697
 
3664
3698
 
3665
- const __iconNode$w = [
3699
+ const __iconNode$y = [
3666
3700
  ["path", { d: "M4 12h16", key: "1lakjw" }],
3667
3701
  ["path", { d: "M4 18h16", key: "19g7jn" }],
3668
3702
  ["path", { d: "M4 6h16", key: "1o0s65" }]
3669
3703
  ];
3670
- const Menu = createLucideIcon("menu", __iconNode$w);
3704
+ const Menu = createLucideIcon("menu", __iconNode$y);
3671
3705
 
3672
3706
  /**
3673
3707
  * @license lucide-react v0.539.0 - ISC
@@ -3677,8 +3711,8 @@ const Menu = createLucideIcon("menu", __iconNode$w);
3677
3711
  */
3678
3712
 
3679
3713
 
3680
- const __iconNode$v = [["path", { d: "M5 12h14", key: "1ays0h" }]];
3681
- const Minus = createLucideIcon("minus", __iconNode$v);
3714
+ const __iconNode$x = [["path", { d: "M5 12h14", key: "1ays0h" }]];
3715
+ const Minus = createLucideIcon("minus", __iconNode$x);
3682
3716
 
3683
3717
  /**
3684
3718
  * @license lucide-react v0.539.0 - ISC
@@ -3688,7 +3722,7 @@ const Minus = createLucideIcon("minus", __iconNode$v);
3688
3722
  */
3689
3723
 
3690
3724
 
3691
- const __iconNode$u = [
3725
+ const __iconNode$w = [
3692
3726
  [
3693
3727
  "path",
3694
3728
  {
@@ -3697,7 +3731,7 @@ const __iconNode$u = [
3697
3731
  }
3698
3732
  ]
3699
3733
  ];
3700
- const Moon = createLucideIcon("moon", __iconNode$u);
3734
+ const Moon = createLucideIcon("moon", __iconNode$w);
3701
3735
 
3702
3736
  /**
3703
3737
  * @license lucide-react v0.539.0 - ISC
@@ -3707,7 +3741,7 @@ const Moon = createLucideIcon("moon", __iconNode$u);
3707
3741
  */
3708
3742
 
3709
3743
 
3710
- const __iconNode$t = [
3744
+ const __iconNode$v = [
3711
3745
  [
3712
3746
  "path",
3713
3747
  {
@@ -3720,7 +3754,7 @@ const __iconNode$t = [
3720
3754
  ["circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor", key: "qy21gx" }],
3721
3755
  ["circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor", key: "fotxhn" }]
3722
3756
  ];
3723
- const Palette = createLucideIcon("palette", __iconNode$t);
3757
+ const Palette = createLucideIcon("palette", __iconNode$v);
3724
3758
 
3725
3759
  /**
3726
3760
  * @license lucide-react v0.539.0 - ISC
@@ -3730,12 +3764,12 @@ const Palette = createLucideIcon("palette", __iconNode$t);
3730
3764
  */
3731
3765
 
3732
3766
 
3733
- const __iconNode$s = [
3767
+ const __iconNode$u = [
3734
3768
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
3735
3769
  ["path", { d: "M9 3v18", key: "fh3hqa" }],
3736
3770
  ["path", { d: "m16 15-3-3 3-3", key: "14y99z" }]
3737
3771
  ];
3738
- const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$s);
3772
+ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$u);
3739
3773
 
3740
3774
  /**
3741
3775
  * @license lucide-react v0.539.0 - ISC
@@ -3745,7 +3779,7 @@ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$s);
3745
3779
  */
3746
3780
 
3747
3781
 
3748
- const __iconNode$r = [
3782
+ const __iconNode$t = [
3749
3783
  [
3750
3784
  "path",
3751
3785
  {
@@ -3754,7 +3788,7 @@ const __iconNode$r = [
3754
3788
  }
3755
3789
  ]
3756
3790
  ];
3757
- const Paperclip = createLucideIcon("paperclip", __iconNode$r);
3791
+ const Paperclip = createLucideIcon("paperclip", __iconNode$t);
3758
3792
 
3759
3793
  /**
3760
3794
  * @license lucide-react v0.539.0 - ISC
@@ -3764,7 +3798,7 @@ const Paperclip = createLucideIcon("paperclip", __iconNode$r);
3764
3798
  */
3765
3799
 
3766
3800
 
3767
- const __iconNode$q = [
3801
+ const __iconNode$s = [
3768
3802
  [
3769
3803
  "path",
3770
3804
  {
@@ -3774,7 +3808,7 @@ const __iconNode$q = [
3774
3808
  ],
3775
3809
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
3776
3810
  ];
3777
- const Pencil = createLucideIcon("pencil", __iconNode$q);
3811
+ const Pencil = createLucideIcon("pencil", __iconNode$s);
3778
3812
 
3779
3813
  /**
3780
3814
  * @license lucide-react v0.539.0 - ISC
@@ -3784,7 +3818,7 @@ const Pencil = createLucideIcon("pencil", __iconNode$q);
3784
3818
  */
3785
3819
 
3786
3820
 
3787
- const __iconNode$p = [
3821
+ const __iconNode$r = [
3788
3822
  [
3789
3823
  "path",
3790
3824
  {
@@ -3793,7 +3827,7 @@ const __iconNode$p = [
3793
3827
  }
3794
3828
  ]
3795
3829
  ];
3796
- const Phone = createLucideIcon("phone", __iconNode$p);
3830
+ const Phone = createLucideIcon("phone", __iconNode$r);
3797
3831
 
3798
3832
  /**
3799
3833
  * @license lucide-react v0.539.0 - ISC
@@ -3803,7 +3837,7 @@ const Phone = createLucideIcon("phone", __iconNode$p);
3803
3837
  */
3804
3838
 
3805
3839
 
3806
- const __iconNode$o = [
3840
+ const __iconNode$q = [
3807
3841
  [
3808
3842
  "path",
3809
3843
  {
@@ -3812,7 +3846,7 @@ const __iconNode$o = [
3812
3846
  }
3813
3847
  ]
3814
3848
  ];
3815
- const Play = createLucideIcon("play", __iconNode$o);
3849
+ const Play = createLucideIcon("play", __iconNode$q);
3816
3850
 
3817
3851
  /**
3818
3852
  * @license lucide-react v0.539.0 - ISC
@@ -3822,11 +3856,11 @@ const Play = createLucideIcon("play", __iconNode$o);
3822
3856
  */
3823
3857
 
3824
3858
 
3825
- const __iconNode$n = [
3859
+ const __iconNode$p = [
3826
3860
  ["path", { d: "M5 12h14", key: "1ays0h" }],
3827
3861
  ["path", { d: "M12 5v14", key: "s699le" }]
3828
3862
  ];
3829
- const Plus = createLucideIcon("plus", __iconNode$n);
3863
+ const Plus = createLucideIcon("plus", __iconNode$p);
3830
3864
 
3831
3865
  /**
3832
3866
  * @license lucide-react v0.539.0 - ISC
@@ -3836,10 +3870,10 @@ const Plus = createLucideIcon("plus", __iconNode$n);
3836
3870
  */
3837
3871
 
3838
3872
 
3839
- const __iconNode$m = [
3873
+ const __iconNode$o = [
3840
3874
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
3841
3875
  ];
3842
- const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$m);
3876
+ const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$o);
3843
3877
 
3844
3878
  /**
3845
3879
  * @license lucide-react v0.539.0 - ISC
@@ -3849,11 +3883,11 @@ const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$
3849
3883
  */
3850
3884
 
3851
3885
 
3852
- const __iconNode$l = [
3886
+ const __iconNode$n = [
3853
3887
  ["path", { d: "M21 7v6h-6", key: "3ptur4" }],
3854
3888
  ["path", { d: "M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3l3 2.7", key: "1kgawr" }]
3855
3889
  ];
3856
- const Redo = createLucideIcon("redo", __iconNode$l);
3890
+ const Redo = createLucideIcon("redo", __iconNode$n);
3857
3891
 
3858
3892
  /**
3859
3893
  * @license lucide-react v0.539.0 - ISC
@@ -3863,13 +3897,13 @@ const Redo = createLucideIcon("redo", __iconNode$l);
3863
3897
  */
3864
3898
 
3865
3899
 
3866
- const __iconNode$k = [
3900
+ const __iconNode$m = [
3867
3901
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
3868
3902
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
3869
3903
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
3870
3904
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
3871
3905
  ];
3872
- const RefreshCw = createLucideIcon("refresh-cw", __iconNode$k);
3906
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$m);
3873
3907
 
3874
3908
  /**
3875
3909
  * @license lucide-react v0.539.0 - ISC
@@ -3879,14 +3913,14 @@ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$k);
3879
3913
  */
3880
3914
 
3881
3915
 
3882
- const __iconNode$j = [
3916
+ const __iconNode$l = [
3883
3917
  ["path", { d: "M4 7V4h16v3", key: "9msm58" }],
3884
3918
  ["path", { d: "M5 20h6", key: "1h6pxn" }],
3885
3919
  ["path", { d: "M13 4 8 20", key: "kqq6aj" }],
3886
3920
  ["path", { d: "m15 15 5 5", key: "me55sn" }],
3887
3921
  ["path", { d: "m20 15-5 5", key: "11p7ol" }]
3888
3922
  ];
3889
- const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$j);
3923
+ const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$l);
3890
3924
 
3891
3925
  /**
3892
3926
  * @license lucide-react v0.539.0 - ISC
@@ -3896,14 +3930,44 @@ const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$j);
3896
3930
  */
3897
3931
 
3898
3932
 
3899
- const __iconNode$i = [
3933
+ const __iconNode$k = [
3934
+ ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
3935
+ ["path", { d: "M3 3v5h5", key: "1xhq8a" }]
3936
+ ];
3937
+ const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$k);
3938
+
3939
+ /**
3940
+ * @license lucide-react v0.539.0 - ISC
3941
+ *
3942
+ * This source code is licensed under the ISC license.
3943
+ * See the LICENSE file in the root directory of this source tree.
3944
+ */
3945
+
3946
+
3947
+ const __iconNode$j = [
3900
3948
  ["circle", { cx: "6", cy: "6", r: "3", key: "1lh9wr" }],
3901
3949
  ["path", { d: "M8.12 8.12 12 12", key: "1alkpv" }],
3902
3950
  ["path", { d: "M20 4 8.12 15.88", key: "xgtan2" }],
3903
3951
  ["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
3904
3952
  ["path", { d: "M14.8 14.8 20 20", key: "ptml3r" }]
3905
3953
  ];
3906
- const Scissors = createLucideIcon("scissors", __iconNode$i);
3954
+ const Scissors = createLucideIcon("scissors", __iconNode$j);
3955
+
3956
+ /**
3957
+ * @license lucide-react v0.539.0 - ISC
3958
+ *
3959
+ * This source code is licensed under the ISC license.
3960
+ * See the LICENSE file in the root directory of this source tree.
3961
+ */
3962
+
3963
+
3964
+ const __iconNode$i = [
3965
+ ["path", { d: "m13.5 8.5-5 5", key: "1cs55j" }],
3966
+ ["path", { d: "m8.5 8.5 5 5", key: "a8mexj" }],
3967
+ ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
3968
+ ["path", { d: "m21 21-4.3-4.3", key: "1qie3q" }]
3969
+ ];
3970
+ const SearchX = createLucideIcon("search-x", __iconNode$i);
3907
3971
 
3908
3972
  /**
3909
3973
  * @license lucide-react v0.539.0 - ISC
@@ -13489,7 +13553,7 @@ collisionPadding = 8, ...props }, ref) {
13489
13553
  });
13490
13554
 
13491
13555
  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', }) => {
13492
- 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) => {
13556
+ 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) => {
13493
13557
  e.stopPropagation();
13494
13558
  onClick?.(e);
13495
13559
  }, disabled: disabled, children: icon }) }) }), jsxRuntime.jsx(TooltipContent, { children: tooltip })] }) }));
@@ -15411,36 +15475,537 @@ function ApiComboBox({ contactType, selectedItem, onSelect, fetchBusinessContact
15411
15475
  : '', fetchPage: fetchPage, resolveById: resolveById, preSelectedId: customerCode, searchPlaceholder: searchPlaceholder, emptyMessage: "No business contacts found.", disabled: disabled, className: className, align: align, debounceMs: 300, hideTriggerSearchIcon: hideTriggerSearchIcon }));
15412
15476
  }
15413
15477
 
15478
+ // A number with an optional `k` (thousand), `M` (million) or `B` (billion), any case, e.g. `1.5`, `2k`, `1.2M`.
15479
+ const NUMBER = String.raw `((?:\d+(?:\.\d+)?|\.\d+)[kKmMbB]?)`;
15480
+ const SUFFIX_MULTIPLIER = {
15481
+ k: 1000,
15482
+ m: 1000000,
15483
+ b: 1000000000,
15484
+ };
15485
+ function toExpressionNumber(raw) {
15486
+ const suffix = raw.slice(-1).toLowerCase();
15487
+ const multiplier = SUFFIX_MULTIPLIER[suffix];
15488
+ return multiplier
15489
+ ? Math.round(Number(raw.slice(0, -1)) * multiplier * 1e6) / 1e6
15490
+ : Number(raw);
15491
+ }
15492
+ const COMPARISON_RE = new RegExp(`^(>=|<=|>|<)${NUMBER}$`);
15493
+ const BETWEEN_RE = new RegExp(`^${NUMBER}-${NUMBER}$`);
15494
+ const EXACT_RE = new RegExp(`^${NUMBER}$`);
15495
+ /** Neutral defaults for a number column with no known scale. */
15496
+ const DEFAULT_NUMBER_RULE_EXAMPLES = {
15497
+ low: 1,
15498
+ high: 10,
15499
+ exact: 5,
15500
+ };
15501
+ const SHORT_SCALES = [
15502
+ [1000000000, 'B'],
15503
+ [1000000, 'M'],
15504
+ [1000, 'k'],
15505
+ ];
15506
+ /** Rule text for a value: `1k`, `2.5k`, `1M`, `1B` so chips stay short; the parser reads them back. */
15507
+ function formatRuleNumber(value) {
15508
+ const [divisor, suffix] = SHORT_SCALES.find(([scale]) => Math.abs(value) >= scale) ?? [1, ''];
15509
+ const scaled = Math.round((value / divisor) * 100) / 100;
15510
+ return `${scaled}${suffix}`;
15511
+ }
15512
+ function formatRuleValue(value, unit) {
15513
+ const number = value.toLocaleString('en-US', { maximumFractionDigits: 2 });
15514
+ if (!unit)
15515
+ return number;
15516
+ return unit === '%' ? `${number}%` : `${number} ${unit}`;
15517
+ }
15518
+ /** The help popover's rule list for a column's typical range; rules use short numbers (`1k`) that the field accepts as typed. */
15519
+ function buildNumberRuleHelp({ low, high, exact, unit, } = DEFAULT_NUMBER_RULE_EXAMPLES) {
15520
+ const lowText = formatRuleValue(low, unit);
15521
+ const highText = formatRuleValue(high, unit);
15522
+ const lowRule = formatRuleNumber(low);
15523
+ const highRule = formatRuleNumber(high);
15524
+ // Smallest value first: the low bound, the range, a value inside it, then the high bound.
15525
+ return [
15526
+ { rule: `>${lowRule}`, meaning: `More than ${lowText}` },
15527
+ { rule: `>=${lowRule}`, meaning: `${lowText} or more` },
15528
+ { rule: `${lowRule}–${highRule}`, meaning: `${lowText} to ${highText}` },
15529
+ {
15530
+ rule: formatRuleNumber(exact),
15531
+ meaning: `Exactly ${formatRuleValue(exact, unit)}`,
15532
+ },
15533
+ { rule: `<${highRule}`, meaning: `Less than ${highText}` },
15534
+ { rule: `<=${highRule}`, meaning: `${highText} or less` },
15535
+ ];
15536
+ }
15537
+ /** Parses the typed rules listed by `buildNumberRuleHelp`. Accepts `-`, `–` or `—` for ranges and ignores spaces and thousands commas. */
15538
+ function parseNumberExpression(text) {
15539
+ const normalized = text.replace(/[\s,]/g, '').replace(/[–—]/g, '-');
15540
+ if (!normalized)
15541
+ return { ok: true, range: undefined };
15542
+ const comparison = COMPARISON_RE.exec(normalized);
15543
+ if (comparison) {
15544
+ const [, operator, raw] = comparison;
15545
+ const value = toExpressionNumber(raw);
15546
+ if (operator.startsWith('>')) {
15547
+ return {
15548
+ ok: true,
15549
+ range: { min: value, minExclusive: operator === '>' },
15550
+ };
15551
+ }
15552
+ return { ok: true, range: { max: value, maxExclusive: operator === '<' } };
15553
+ }
15554
+ const between = BETWEEN_RE.exec(normalized);
15555
+ if (between) {
15556
+ const min = toExpressionNumber(between[1]);
15557
+ const max = toExpressionNumber(between[2]);
15558
+ return min <= max ? { ok: true, range: { min, max } } : { ok: false };
15559
+ }
15560
+ const exact = EXACT_RE.exec(normalized);
15561
+ if (exact) {
15562
+ const value = toExpressionNumber(exact[1]);
15563
+ return { ok: true, range: { min: value, max: value } };
15564
+ }
15565
+ return { ok: false };
15566
+ }
15567
+ function formatNumberRange(range) {
15568
+ if (!range)
15569
+ return '';
15570
+ const { min, max, minExclusive, maxExclusive } = range;
15571
+ if (min !== undefined && max !== undefined) {
15572
+ return min === max ? String(min) : `${min}–${max}`;
15573
+ }
15574
+ if (min !== undefined)
15575
+ return `${minExclusive ? '>' : '>='}${min}`;
15576
+ if (max !== undefined)
15577
+ return `${maxExclusive ? '<' : '<='}${max}`;
15578
+ return '';
15579
+ }
15580
+ /** Splits a pasted list — commas, semicolons, spaces and new lines all separate IDs. Keeps first-seen order, drops duplicates. */
15581
+ function splitIdList(text) {
15582
+ return Array.from(new Set(text
15583
+ .split(/[\s,;]+/)
15584
+ .map((id) => id.trim())
15585
+ .filter(Boolean)));
15586
+ }
15587
+ function getOptionLabel(options, value) {
15588
+ return options.find((option) => option.value === value)?.label ?? value;
15589
+ }
15590
+ /** Trigger summary for a multi-select: the first selected option (in option order) plus how many more, e.g. `Red +1`. */
15591
+ function summarizeSelection(values, options) {
15592
+ if (values.length === 0)
15593
+ return '';
15594
+ const first = options.find((option) => values.includes(option.value))?.label ?? values[0];
15595
+ return values.length > 1 ? `${first} +${values.length - 1}` : first;
15596
+ }
15597
+ function formatSelectedCount(selected, total) {
15598
+ return `${selected} of ${total} selected`;
15599
+ }
15600
+ function toggleValue(values, value) {
15601
+ return values.includes(value)
15602
+ ? values.filter((v) => v !== value)
15603
+ : [...values, value];
15604
+ }
15605
+ /** Every option between the two ends of the range, inclusive, in scale order. */
15606
+ function expandScaleRange(options, range) {
15607
+ const fromIndex = options.findIndex((option) => option.value === range.from);
15608
+ const toIndex = options.findIndex((option) => option.value === range.to);
15609
+ if (fromIndex < 0 || toIndex < 0)
15610
+ return [];
15611
+ const [start, end] = fromIndex <= toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
15612
+ return options.slice(start, end + 1).map((option) => option.value);
15613
+ }
15614
+ /** `Very Good` → `VG`, `Fair` → `F`. */
15615
+ function toInitials(label) {
15616
+ return label
15617
+ .split(/[\s-]+/)
15618
+ .filter(Boolean)
15619
+ .map((word) => word[0].toUpperCase())
15620
+ .join('');
15621
+ }
15622
+ function formatScaleRange(options, range, short = false) {
15623
+ const values = expandScaleRange(options, range);
15624
+ if (values.length === 0)
15625
+ return '';
15626
+ const labelOf = (value) => {
15627
+ const label = getOptionLabel(options, value);
15628
+ return short ? toInitials(label) : label;
15629
+ };
15630
+ const first = labelOf(values[0]);
15631
+ return values.length === 1
15632
+ ? first
15633
+ : `${first} – ${labelOf(values[values.length - 1])}`;
15634
+ }
15635
+ const DATE_PRESET_OPTIONS = [
15636
+ { value: 'today', label: 'Today' },
15637
+ { value: 'last7Days', label: 'Last 7 days' },
15638
+ { value: 'last30Days', label: 'Last 30 days' },
15639
+ { value: 'thisMonth', label: 'This month' },
15640
+ { value: 'thisFiscalYear', label: 'This fiscal year' },
15641
+ ];
15642
+ function toIsoDate(date) {
15643
+ const month = String(date.getMonth() + 1).padStart(2, '0');
15644
+ const day = String(date.getDate()).padStart(2, '0');
15645
+ return `${date.getFullYear()}-${month}-${day}`;
15646
+ }
15647
+ /** `YYYY-MM-DD` → local date (no timezone shift); empty → undefined. */
15648
+ function fromIsoDate(iso) {
15649
+ if (!iso)
15650
+ return undefined;
15651
+ const [year, month, day] = iso.split('-').map(Number);
15652
+ return new Date(year, month - 1, day);
15653
+ }
15654
+ function daysBefore(today, days) {
15655
+ return new Date(today.getFullYear(), today.getMonth(), today.getDate() - days);
15656
+ }
15657
+ /** `fiscalYearStartMonth` is 1–12 (1 = January, 4 = April). */
15658
+ function resolveDatePreset(preset, today, fiscalYearStartMonth = 1) {
15659
+ const to = toIsoDate(today);
15660
+ switch (preset) {
15661
+ case 'today':
15662
+ return { from: to, to };
15663
+ case 'last7Days':
15664
+ return { from: toIsoDate(daysBefore(today, 6)), to };
15665
+ case 'last30Days':
15666
+ return { from: toIsoDate(daysBefore(today, 29)), to };
15667
+ case 'thisMonth':
15668
+ return {
15669
+ from: toIsoDate(new Date(today.getFullYear(), today.getMonth(), 1)),
15670
+ to,
15671
+ };
15672
+ case 'thisFiscalYear': {
15673
+ const startMonthIndex = fiscalYearStartMonth - 1;
15674
+ const startYear = today.getMonth() >= startMonthIndex
15675
+ ? today.getFullYear()
15676
+ : today.getFullYear() - 1;
15677
+ return { from: toIsoDate(new Date(startYear, startMonthIndex, 1)), to };
15678
+ }
15679
+ }
15680
+ }
15681
+ function resolveDateRange(range, today, fiscalYearStartMonth = 1) {
15682
+ if (range.preset)
15683
+ return resolveDatePreset(range.preset, today, fiscalYearStartMonth);
15684
+ return { from: range.from, to: range.to };
15685
+ }
15686
+ function formatIsoDate(iso) {
15687
+ const [year, month, day] = iso.split('-').map(Number);
15688
+ return new Date(year, month - 1, day).toLocaleDateString('en-GB', {
15689
+ day: 'numeric',
15690
+ month: 'short',
15691
+ year: 'numeric',
15692
+ });
15693
+ }
15694
+ function formatDateRange(range) {
15695
+ if (range.preset)
15696
+ return (DATE_PRESET_OPTIONS.find((option) => option.value === range.preset)
15697
+ ?.label ?? '');
15698
+ if (range.from && range.to)
15699
+ return `${formatIsoDate(range.from)} – ${formatIsoDate(range.to)}`;
15700
+ if (range.from)
15701
+ return `From ${formatIsoDate(range.from)}`;
15702
+ if (range.to)
15703
+ return `Until ${formatIsoDate(range.to)}`;
15704
+ return '';
15705
+ }
15706
+ const TRI_STATE_OPTIONS = [
15707
+ { value: 'any', label: 'Any' },
15708
+ { value: 'yes', label: 'Yes' },
15709
+ { value: 'no', label: 'No' },
15710
+ ];
15711
+ function isFilterValueActive(value) {
15712
+ if (!value)
15713
+ return false;
15714
+ switch (value.type) {
15715
+ case 'list':
15716
+ return value.values.length > 0;
15717
+ case 'ids':
15718
+ return value.ids.length > 0;
15719
+ case 'contains':
15720
+ return value.text.trim().length > 0;
15721
+ case 'number':
15722
+ return value.range.min !== undefined || value.range.max !== undefined;
15723
+ case 'date':
15724
+ return Boolean(value.range.preset || value.range.from || value.range.to);
15725
+ case 'scale':
15726
+ case 'bool':
15727
+ return true;
15728
+ }
15729
+ }
15730
+ const FILTER_FOCUS_RING = 'outline-none focus-visible:ring-2 focus-visible:ring-primary/30';
15731
+ /** Text-link actions such as Clear and "Show all". */
15732
+ const FILTER_LINK_CLASS_NAME = cn('cursor-pointer rounded-sm text-xs font-medium text-primary hover:underline', FILTER_FOCUS_RING);
15733
+ /** One look for every pickable row in a filter (list rows, Yes/No, date presets, number rules). */
15734
+ function getOptionRowClassName(selected = false, className) {
15735
+ return cn('flex w-full cursor-pointer items-center gap-3 rounded-md px-2 py-2 text-left text-sm text-foreground transition-colors', FILTER_FOCUS_RING, selected ? 'bg-primary/5 font-medium text-primary' : 'hover:bg-muted/60', className);
15736
+ }
15737
+ /** A selectable pill (chip options, range presets); one height and shape everywhere. */
15738
+ function getPillClassName(selected) {
15739
+ return getSelectableOptionClassName(selected, 'inline-flex h-8 items-center gap-1.5 rounded-full px-3');
15740
+ }
15741
+ /** Search box above a list (pick lists, saved searches); matches the inputs' height and corners. */
15742
+ const FILTER_SEARCH_BOX_CLASS_NAME = 'flex h-9 items-center gap-2 rounded-md border border-input bg-card px-3 focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/30';
15743
+ /** Solid count bubble, e.g. a filter button's or card title's selected count. */
15744
+ const FILTER_COUNT_BADGE_CLASS_NAME = 'inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-primary px-1.5 text-xs font-semibold leading-none text-primary-foreground';
15745
+ /** A fixed column count, or (when omitted) as many columns as fit at `minWidth` each. */
15746
+ function getGridColumnsStyle(columns, minWidth = '7rem') {
15747
+ return {
15748
+ gridTemplateColumns: columns
15749
+ ? `repeat(${columns}, minmax(0, 1fr))`
15750
+ : `repeat(auto-fill, minmax(${minWidth}, 1fr))`,
15751
+ };
15752
+ }
15753
+ /** 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. */
15754
+ function getSelectableOptionClassName(selected, className) {
15755
+ return cn('cursor-pointer border text-xs transition-colors', FILTER_FOCUS_RING, selected
15756
+ ? 'border-primary bg-primary/5 font-medium text-primary'
15757
+ : 'border-border bg-background text-foreground hover:bg-secondary dark:bg-muted/60 dark:hover:bg-muted', className);
15758
+ }
15759
+ /** Shared look of every filter-row control (trigger buttons and inline inputs). */
15760
+ function getFilterFieldClassName(state, className) {
15761
+ return cn('flex h-7 w-full min-w-0 items-center gap-1 rounded-md border px-2 text-xs transition-colors outline-none', 'focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-primary/30', state === 'empty' &&
15762
+ 'border-input bg-card text-foreground placeholder:text-placeholder', state === 'applied' &&
15763
+ 'border-primary bg-primary/5 font-medium text-primary', state === 'invalid' && 'border-destructive bg-card text-destructive', state === 'disabled' &&
15764
+ 'pointer-events-none border-dashed border-border bg-transparent', className);
15765
+ }
15766
+
15767
+ function getPanelClassName(variant, active, className) {
15768
+ 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);
15769
+ }
15770
+ function getTitleClassName(variant) {
15771
+ return cn('flex items-center gap-2 text-foreground', variant === 'section'
15772
+ ? 'text-xs font-medium text-label'
15773
+ : 'text-sm font-semibold');
15774
+ }
15775
+
15776
+ /** Shell for one filter: title, selected badge, applied summary, Clear and a hint. Same content in popovers and on full-page surfaces. */
15777
+ function FilterPanel({ title, status, selectedCount, summary, action, onClear, hint, active = false, variant = 'card', className, children, }) {
15778
+ const hasHeader = Boolean(title || status || summary || action || onClear);
15779
+ 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: FILTER_COUNT_BADGE_CLASS_NAME, 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 })] }));
15780
+ }
15781
+
15414
15782
  function Checkbox({ className, ...props }) {
15415
15783
  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" }) }) }));
15416
15784
  }
15417
15785
 
15786
+ // Sub-pixel rounding leaves scrollTop a hair short of the end.
15787
+ const EDGE_TOLERANCE_PX = 1;
15788
+ function getScrollFadeState(el) {
15789
+ const { scrollTop, scrollHeight, clientHeight } = el;
15790
+ return {
15791
+ top: scrollTop > EDGE_TOLERANCE_PX,
15792
+ bottom: scrollTop + clientHeight < scrollHeight - EDGE_TOLERANCE_PX,
15793
+ };
15794
+ }
15795
+ const FADE_BASE_CLASS_NAME = 'pointer-events-none absolute inset-x-0 h-8 from-card to-transparent';
15796
+
15797
+ function useScrollFade() {
15798
+ const ref = React.useRef(null);
15799
+ const [state, setState] = React.useState({
15800
+ top: false,
15801
+ bottom: false,
15802
+ });
15803
+ const update = React.useCallback(() => {
15804
+ if (!ref.current)
15805
+ return;
15806
+ const next = getScrollFadeState(ref.current);
15807
+ // Skip no-op updates (observers fire often).
15808
+ setState((current) => current.top === next.top && current.bottom === next.bottom
15809
+ ? current
15810
+ : next);
15811
+ }, []);
15812
+ React.useEffect(() => {
15813
+ const el = ref.current;
15814
+ if (!el)
15815
+ return;
15816
+ update();
15817
+ const resizeObserver = new ResizeObserver(update);
15818
+ resizeObserver.observe(el);
15819
+ const mutationObserver = new MutationObserver(update);
15820
+ mutationObserver.observe(el, { childList: true, subtree: true });
15821
+ return () => {
15822
+ resizeObserver.disconnect();
15823
+ mutationObserver.disconnect();
15824
+ };
15825
+ }, [update]);
15826
+ return { ref, update, ...state };
15827
+ }
15828
+
15829
+ /** Scroll container that fades its top / bottom edge while more content is hidden there, so it reads as scrollable. */
15830
+ function ScrollFade({ className, wrapperClassName, children, ...props }) {
15831
+ const { ref, update, top, bottom } = useScrollFade();
15832
+ 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') }))] }));
15833
+ }
15834
+
15835
+ // Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
15836
+ // labels that are not actually clipped.
15837
+ const OVERFLOW_TOLERANCE_PX = 1;
15838
+ function findClippedLabel(root) {
15839
+ const spans = root.querySelectorAll(':scope > span');
15840
+ for (const span of Array.from(spans)) {
15841
+ // Width for a single-line ellipsis; height for a multi-line clamp.
15842
+ if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX ||
15843
+ span.scrollHeight > span.clientHeight + OVERFLOW_TOLERANCE_PX) {
15844
+ return span;
15845
+ }
15846
+ }
15847
+ return null;
15848
+ }
15849
+ /**
15850
+ * Returns the full text of the first direct-child `<span>` of `ref` that is
15851
+ * clipped by its container (i.e. showing an ellipsis), else `null` — so callers
15852
+ * can surface a tooltip only when the label is actually unreadable.
15853
+ *
15854
+ * Re-measures on element resize (sidebar expand/collapse, window resize) and on
15855
+ * label text changes.
15856
+ */
15857
+ function useTruncatedText(ref) {
15858
+ const [text, setText] = React.useState(null);
15859
+ React.useEffect(() => {
15860
+ const el = ref.current;
15861
+ if (!el)
15862
+ return;
15863
+ let frame = 0;
15864
+ const measure = () => {
15865
+ const label = findClippedLabel(el);
15866
+ setText(label?.textContent?.trim() || null);
15867
+ };
15868
+ const schedule = () => {
15869
+ cancelAnimationFrame(frame);
15870
+ frame = requestAnimationFrame(measure);
15871
+ };
15872
+ schedule();
15873
+ const resizeObserver = new ResizeObserver(schedule);
15874
+ resizeObserver.observe(el);
15875
+ const mutationObserver = new MutationObserver(schedule);
15876
+ mutationObserver.observe(el, {
15877
+ characterData: true,
15878
+ childList: true,
15879
+ subtree: true,
15880
+ });
15881
+ return () => {
15882
+ cancelAnimationFrame(frame);
15883
+ resizeObserver.disconnect();
15884
+ mutationObserver.disconnect();
15885
+ };
15886
+ }, [ref]);
15887
+ return text;
15888
+ }
15889
+
15890
+ /** Single-line label that shows its full text in a tooltip, only while it is cut off. */
15891
+ function TruncatedLabel({ text, className, }) {
15892
+ const ref = React.useRef(null);
15893
+ const clipped = useTruncatedText(ref);
15894
+ 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 })] }) }));
15895
+ }
15896
+
15897
+ function filterOptionsByQuery(options, query) {
15898
+ const needle = query.trim().toLowerCase();
15899
+ if (!needle)
15900
+ return [...options];
15901
+ return options.filter((option) => option.label.toLowerCase().includes(needle));
15902
+ }
15903
+ const getChipClassName = getPillClassName;
15904
+ function getTileClassName(selected) {
15905
+ return getSelectableOptionClassName(selected, 'flex min-h-12 min-w-0 flex-col items-center justify-center gap-0.5 rounded-md px-2 py-1.5 text-center');
15906
+ }
15907
+ /** The list's search box only appears once there are enough options to need it. */
15908
+ const SEARCH_MIN_OPTIONS = 9;
15909
+ /** Long option sets scroll inside the card or popover instead of growing it. */
15910
+ const OPTIONS_SCROLL_CLASS_NAME = 'max-h-48 overflow-y-auto';
15911
+ /** Fills a stretched card: at least the usual height, growing into any space the row gives it (never driving the row height). */
15912
+ const OPTIONS_FILL_CLASS_NAME = 'min-h-48 flex-1 basis-0 overflow-y-auto';
15913
+ const FILL_WRAPPER_CLASS_NAME = 'flex min-h-0 flex-1 flex-col';
15914
+ /** Card lists flow into as many columns as fit; popover lists stay one column. */
15915
+ const LIST_COLUMN_MIN_WIDTH = '10rem';
15916
+ const getOptionsScrollClassName = (fill) => fill ? OPTIONS_FILL_CLASS_NAME : OPTIONS_SCROLL_CLASS_NAME;
15917
+ const LIST_ROW_CLASS_NAME = getOptionRowClassName();
15918
+ /** Picking a value: a single-choice list replaces (or clears) it, a multi-choice list toggles it. */
15919
+ const pickValue = (values, value, single) => {
15920
+ if (!single)
15921
+ return toggleValue(values, value);
15922
+ return values.includes(value) ? [] : [value];
15923
+ };
15924
+ /** The single-choice counterpart of the checkbox: same size, primary dot when picked. */
15925
+ const LIST_RADIO_CLASS_NAME = 'size-4.5 shrink-0 cursor-pointer accent-primary';
15926
+ /** Outlined (not filled) box until checked; the border is dark enough to read on white. */
15927
+ const LIST_CHECKBOX_CLASS_NAME = 'size-4.5 border-muted-foreground/50 bg-card dark:border-muted-foreground/60 dark:bg-transparent';
15928
+ const SEARCH_BOX_CLASS_NAME = FILTER_SEARCH_BOX_CLASS_NAME;
15929
+
15930
+ function usePickListFilter({ options, value, layout, }) {
15931
+ const [query, setQuery] = React.useState('');
15932
+ const visibleOptions = React.useMemo(() => (layout === 'list' ? filterOptionsByQuery(options, query) : options), [layout, options, query]);
15933
+ const selectedCount = React.useMemo(() => options.filter((option) => value.includes(option.value)).length, [options, value]);
15934
+ return { query, setQuery, visibleOptions, selectedCount };
15935
+ }
15936
+
15937
+ const getSearchInputLabel = (ariaLabel) => `Search ${ariaLabel}`;
15938
+
15939
+ function OptionSwatch({ color, round, }) {
15940
+ if (!color)
15941
+ return null;
15942
+ 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 } }));
15943
+ }
15944
+ /** Multi-select filter: a searchable checkbox list, or pill / tile toggles. Long sets scroll within a max height. */
15945
+ function PickListFilter({ options, value, onChange, ariaLabel, layout = 'list', searchPlaceholder, alwaysSearchable = false, columns = 5, fill = false, listClassName, single = false, }) {
15946
+ const { query, setQuery, visibleOptions, selectedCount } = usePickListFilter({
15947
+ options,
15948
+ value,
15949
+ layout,
15950
+ });
15951
+ const radioName = React.useId();
15952
+ const scrollClassName = getOptionsScrollClassName(fill);
15953
+ // Rows with a right-hand hint read best in one column.
15954
+ const multiColumn = fill && !options.some((option) => option.hint);
15955
+ const wrapperClassName = fill ? FILL_WRAPPER_CLASS_NAME : undefined;
15956
+ const toggle = (option) => onChange(pickValue(value, option.value, single));
15957
+ if (options.length === 0) {
15958
+ return (jsxRuntime.jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No options available" }));
15959
+ }
15960
+ if (layout === 'list') {
15961
+ return (jsxRuntime.jsxs("div", { className: cn('flex flex-col gap-2', fill && FILL_WRAPPER_CLASS_NAME), "aria-label": ariaLabel, role: "group", children: [searchPlaceholder !== undefined &&
15962
+ (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
15963
+ ? getGridColumnsStyle(undefined, LIST_COLUMN_MIN_WIDTH)
15964
+ : undefined, wrapperClassName: wrapperClassName, children: visibleOptions.map((option) => (jsxRuntime.jsxs("label", { className: LIST_ROW_CLASS_NAME, children: [single ? (jsxRuntime.jsx("input", { type: "radio", name: radioName, checked: value.includes(option.value),
15965
+ // A click on the picked row clears it (radios can't be unticked natively).
15966
+ onClick: () => toggle(option), onChange: () => undefined, className: LIST_RADIO_CLASS_NAME })) : (jsxRuntime.jsx(Checkbox, { className: LIST_CHECKBOX_CLASS_NAME, checked: value.includes(option.value), onCheckedChange: () => toggle(option) })), 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 })), jsxRuntime.jsx(OptionSwatch, { color: option.swatch })] }, option.value))) })] }));
15967
+ }
15968
+ if (layout === 'tiles') {
15969
+ 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))) }));
15970
+ }
15971
+ 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))) }));
15972
+ }
15973
+
15418
15974
  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';
15419
- const TRIGGER_ACTIVE = '!border-primary text-primary shadow-[0_0_0_3px_rgba(49,122,81,0.10)]';
15975
+ const TRIGGER_ACTIVE = '!border-primary bg-primary/5 text-primary';
15420
15976
  const CONTENT_BASE = 'min-w-[8rem]';
15421
15977
  const isFilterActive = (value, resetValue) => !!value && value !== resetValue;
15978
+ function collectText(node) {
15979
+ if (typeof node === 'string' || typeof node === 'number')
15980
+ return String(node);
15981
+ if (Array.isArray(node))
15982
+ return node.map(collectText).join(' ');
15983
+ if (React.isValidElement(node))
15984
+ return React.Children.toArray(node.props.children).map(collectText).join(' ');
15985
+ return '';
15986
+ }
15987
+ /** The visible text inside a label, e.g. a JSX name + description becomes "Name Description". */
15988
+ const getNodeText = (node) => collectText(node).replace(/\s+/g, ' ').trim();
15989
+ /** A JSX label keeps its look as the row's `content`; its text (or the value) is what search and screen readers use. */
15990
+ const toPickListOptions = (options) => options.map((option) => typeof option.label === 'string'
15991
+ ? { value: option.value, label: option.label }
15992
+ : {
15993
+ value: option.value,
15994
+ label: getNodeText(option.label) || option.value,
15995
+ content: option.label,
15996
+ });
15422
15997
 
15423
15998
  /**
15424
- * Multi-select filter dropdown — Popover + checkbox list, matching the
15425
- * `FilterSelect` trigger look (filter icon + count badge when active).
15426
- * Selecting items keeps the popover open; the trigger shows the count.
15999
+ * Multi-select filter dropdown with the `FilterSelect` trigger look (filter icon + count badge when active).
16000
+ * Opens a pick list: a searchable checkbox list with "x of y selected · Clear", or chips/tiles under a
16001
+ * title, count and Clear. Selecting keeps the popover open.
15427
16002
  */
15428
- const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, }) => {
16003
+ const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, pickListLayout = 'list', searchPlaceholder, }) => {
15429
16004
  const active = value.length > 0;
15430
- const toggle = (optValue) => {
15431
- if (value.includes(optValue)) {
15432
- onChange(value.filter((v) => v !== optValue));
15433
- }
15434
- else {
15435
- onChange([...value, optValue]);
15436
- }
15437
- };
15438
- 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) => {
15439
- const checked = value.includes(opt.value);
15440
- 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),
15441
- // Stop the inner checkbox click from double-toggling via the button.
15442
- onClick: (e) => e.stopPropagation() }), jsxRuntime.jsx("span", { className: "flex-1 truncate", children: opt.label })] }, opt.value));
15443
- }) }) })] }));
16005
+ const isList = pickListLayout === 'list';
16006
+ 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: cn('ml-1', FILTER_COUNT_BADGE_CLASS_NAME), children: value.length }))] }) }), jsxRuntime.jsx(PopoverContent, { align: "start", sideOffset: 4, className: cn('w-64 p-0', contentClassName), children: jsxRuntime.jsx(FilterPanel, { variant: "popover",
16007
+ // A searchable list has its own "x of y selected · Clear" row.
16008
+ 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 }) }) })] }));
15444
16009
  };
15445
16010
 
15446
16011
  const KYC_STATUS = {
@@ -21699,6 +22264,34 @@ function useRowEditing({ saving, onEditChange, onSaveRow, }) {
21699
22264
  handleEditIconClick,
21700
22265
  };
21701
22266
  }
22267
+ /**
22268
+ * Measures the rows area so a loading skeleton can cover exactly the rows it replaces —
22269
+ * the rows stay in the layout (hidden), so column widths and table height never jump.
22270
+ */
22271
+ function useLoadingOverlay(scrollRef, headRef, bodyRef, loading) {
22272
+ const [box, setBox] = React.useState(null);
22273
+ React.useLayoutEffect(() => {
22274
+ const scroll = scrollRef.current;
22275
+ const head = headRef.current;
22276
+ const body = bodyRef.current;
22277
+ if (!loading || !scroll || !head || !body) {
22278
+ setBox(null);
22279
+ return;
22280
+ }
22281
+ const measure = () => setBox({
22282
+ top: head.offsetHeight,
22283
+ width: scroll.scrollWidth,
22284
+ height: body.offsetHeight,
22285
+ visibleWidth: scroll.clientWidth,
22286
+ });
22287
+ measure();
22288
+ const observer = new ResizeObserver(measure);
22289
+ observer.observe(scroll);
22290
+ observer.observe(body);
22291
+ return () => observer.disconnect();
22292
+ }, [loading, scrollRef, headRef, bodyRef]);
22293
+ return box;
22294
+ }
21702
22295
 
21703
22296
  function normalizeOptions(options) {
21704
22297
  return options.map((opt) => typeof opt === 'string'
@@ -21729,6 +22322,30 @@ function pinnedHeaderClass() {
21729
22322
  function pinnedCellClass(pinnedBg) {
21730
22323
  return cn('sticky right-0 z-10', PINNED_BEFORE, PINNED_SHADOW, pinnedBg);
21731
22324
  }
22325
+ const PINNED_RIGHT_WIDTH = '72px';
22326
+ /** Width for a header/body/filter cell: the resized width var while resized or dragging, a fixed width for the pinned actions column. */
22327
+ function getColumnWidthStyle(key, isSized, isPinnedRight) {
22328
+ if (isSized) {
22329
+ const width = `var(--col-w-${key})`;
22330
+ return { width, minWidth: width, maxWidth: width };
22331
+ }
22332
+ return isPinnedRight
22333
+ ? {
22334
+ width: PINNED_RIGHT_WIDTH,
22335
+ minWidth: PINNED_RIGHT_WIDTH,
22336
+ maxWidth: PINNED_RIGHT_WIDTH,
22337
+ }
22338
+ : undefined;
22339
+ }
22340
+ function hasFilterRow(columns, filterRowLeading) {
22341
+ return (filterRowLeading != null || columns.some((col) => col.filter !== undefined));
22342
+ }
22343
+ /** `TableRowsSkeleton` bar (52px) plus its gap (8px). */
22344
+ const SKELETON_ROW_PX = 60;
22345
+ /** How many skeleton bars fill a rows area of `height` px (at least one). */
22346
+ function getSkeletonRowCount(height) {
22347
+ return Math.max(1, Math.floor(height / SKELETON_ROW_PX));
22348
+ }
21732
22349
 
21733
22350
  const isValidHex = (v) => /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(v);
21734
22351
  /**
@@ -21820,8 +22437,52 @@ function EditableCellContent({ col, row, value, isEditing, width, onEditValueCha
21820
22437
  }
21821
22438
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: clipToWidth(stringValue, width) });
21822
22439
  }
22440
+ const FILTER_CELL = 'px-0.5 py-0.5 font-normal border-b border-solid !border-border';
22441
+ /** Opt-in second header row holding each column's filter control. */
22442
+ function FilterRow({ columns, leading, showEditColumn, showSelectionColumn, isArchiveView, vBorder, localWidths, draggingKey, }) {
22443
+ const leadingCellCount = Number(showEditColumn) + Number(showSelectionColumn);
22444
+ 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) => {
22445
+ const isPinnedRight = col.key === 'actions';
22446
+ 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()));
22447
+ })] }));
22448
+ }
22449
+ /** Keeps the real pagination in the layout (hidden) and lays a placeholder over it, so the footer height never jumps. */
22450
+ function PaginationLoading({ children, }) {
22451
+ 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" })] })] }));
22452
+ }
21823
22453
 
21824
- 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, }) {
22454
+ /** Label line + input block — mirrors a `Field`. */
22455
+ function FieldSkeleton() {
22456
+ 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" })] }));
22457
+ }
22458
+ /**
22459
+ * Loading placeholder that matches a `FormSectionCard` — the tinted header band
22460
+ * (icon square + title + description) above a body of `Field` placeholders and
22461
+ * an optional footer action row.
22462
+ */
22463
+ function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
22464
+ 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" })] }))] })] }));
22465
+ }
22466
+ /** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
22467
+ function TableSkeleton({ rows = 8 }) {
22468
+ 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)))] }));
22469
+ }
22470
+ /** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
22471
+ function TableRowsSkeleton({ rows = 10, className }) {
22472
+ 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) => (
22473
+ // shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
22474
+ jsxRuntime.jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
22475
+ }
22476
+ /** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
22477
+ function DetailPageSkeleton({ sections = 3, }) {
22478
+ 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)))] }));
22479
+ }
22480
+ /** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
22481
+ function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
22482
+ 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 })] }));
22483
+ }
22484
+
22485
+ 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, }) {
21825
22486
  const showSelectionColumn = enableSelection && (!isArchiveView || selectionInArchiveView);
21826
22487
  const vBorder = showGrid ? 'border-r' : '';
21827
22488
  const { localWidths, draggingKey, tableRef, handleResizeMouseDown } = useColumnResize({
@@ -21834,6 +22495,11 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21834
22495
  onSelectionChange,
21835
22496
  });
21836
22497
  const { editingRow, editValues, savingRow, handleEditValueChange, handleEditIconClick, } = useRowEditing({ saving, onEditChange, onSaveRow });
22498
+ const scrollRef = React.useRef(null);
22499
+ const headRef = React.useRef(null);
22500
+ const bodyRef = React.useRef(null);
22501
+ // Rows stay in the layout while loading; the skeleton covers them so nothing resizes.
22502
+ const overlay = useLoadingOverlay(scrollRef, headRef, bodyRef, loading);
21837
22503
  const handleColumnClick = (columnKey, sortable) => {
21838
22504
  if (!sortable || !setSortBy || !setSortOrder)
21839
22505
  return;
@@ -21845,25 +22511,17 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21845
22511
  setSortOrder('asc');
21846
22512
  }
21847
22513
  };
21848
- 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
21849
- ? true
21850
- : someSelected
21851
- ? 'indeterminate'
21852
- : false, onCheckedChange: toggleSelectAll }) })), columns.map((col) => {
21853
- const w = localWidths[col.key];
21854
- const isDragging = draggingKey === col.key;
21855
- const isPinnedRight = col.key === 'actions';
21856
- const thStyle = w || isDragging
21857
- ? {
21858
- width: `var(--col-w-${col.key})`,
21859
- minWidth: `var(--col-w-${col.key})`,
21860
- maxWidth: `var(--col-w-${col.key})`,
21861
- }
21862
- : isPinnedRight
21863
- ? { width: '72px', minWidth: '72px', maxWidth: '72px' }
21864
- : undefined;
21865
- 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()));
21866
- })] }) }), jsxRuntime.jsx("tbody", { children: data.map((row, rowIndex) => {
22514
+ 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
22515
+ ? true
22516
+ : someSelected
22517
+ ? 'indeterminate'
22518
+ : false, onCheckedChange: toggleSelectAll }) })), columns.map((col) => {
22519
+ const w = localWidths[col.key];
22520
+ const isDragging = draggingKey === col.key;
22521
+ const isPinnedRight = col.key === 'actions';
22522
+ const thStyle = getColumnWidthStyle(col.key, Boolean(w) || isDragging, isPinnedRight);
22523
+ 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()));
22524
+ })] }), 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) => {
21867
22525
  const isEditing = editingRow === row.id && editingRow !== null;
21868
22526
  const isSaving = savingRow === row.id;
21869
22527
  const isSelected = selectedSet.has(row.id);
@@ -21883,19 +22541,7 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21883
22541
  : row[col.key];
21884
22542
  const w = localWidths[col.key];
21885
22543
  const isPinnedRight = col.key === 'actions';
21886
- const tdStyle = w || draggingKey === col.key
21887
- ? {
21888
- width: `var(--col-w-${col.key})`,
21889
- minWidth: `var(--col-w-${col.key})`,
21890
- maxWidth: `var(--col-w-${col.key})`,
21891
- }
21892
- : isPinnedRight
21893
- ? {
21894
- width: '72px',
21895
- minWidth: '72px',
21896
- maxWidth: '72px',
21897
- }
21898
- : undefined;
22544
+ const tdStyle = getColumnWidthStyle(col.key, Boolean(w) || draggingKey === col.key, isPinnedRight);
21899
22545
  // Pinned cells need an OPAQUE bg matching the row state so the
21900
22546
  // scrolling content underneath doesn't bleed through — no alpha tints.
21901
22547
  const pinnedBg = isPinnedRight
@@ -21911,7 +22557,13 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21911
22557
  ? 'text-right'
21912
22558
  : '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()));
21913
22559
  })] }, row.id));
21914
- }) })] }), 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] }));
22560
+ }) })] }), overlay && overlay.height > 0 ? (
22561
+ // `overflow-clip`, not `hidden`: hidden makes this box the sticky skeleton's scroller, pinning it to scrollLeft 0.
22562
+ jsxRuntime.jsx("div", { className: "absolute left-0 z-10 overflow-clip bg-card", style: {
22563
+ top: overlay.top,
22564
+ width: overlay.width,
22565
+ height: overlay.height,
22566
+ }, 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)] }));
21915
22567
  }
21916
22568
 
21917
22569
  /**
@@ -37586,7 +38238,7 @@ function SelectScrollDownButton({ className, ...props }) {
37586
38238
 
37587
38239
  const FilterSelect = ({ label, value, onValueChange, options, resetValue = 'all', activeCount = 1, searchable, triggerClassName, contentClassName, }) => {
37588
38240
  const active = isFilterActive(value, resetValue);
37589
- return (jsxRuntime.jsxs(Select, { value: value, onValueChange: onValueChange, keepOpenOnSelect: true, children: [jsxRuntime.jsxs(SelectTrigger, { className: cn(TRIGGER_BASE, active && TRIGGER_ACTIVE, triggerClassName), children: [jsxRuntime.jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [jsxRuntime.jsx(SelectValue, { placeholder: 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: activeCount }))] })] }), jsxRuntime.jsxs(SelectContent, { className: cn(CONTENT_BASE, contentClassName), searchable: searchable, children: [jsxRuntime.jsx(SelectItem, { value: resetValue, withCheckbox: true, children: label }), options.map((opt) => (jsxRuntime.jsx(SelectItem, { value: opt.value, searchValue: opt.searchValue, withCheckbox: true, children: opt.label }, opt.value)))] })] }));
38241
+ return (jsxRuntime.jsxs(Select, { value: value, onValueChange: onValueChange, keepOpenOnSelect: true, children: [jsxRuntime.jsxs(SelectTrigger, { className: cn(TRIGGER_BASE, active && TRIGGER_ACTIVE, triggerClassName), children: [jsxRuntime.jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [jsxRuntime.jsx(SelectValue, { placeholder: label }), active && (jsxRuntime.jsx("span", { className: cn('ml-1', FILTER_COUNT_BADGE_CLASS_NAME), children: activeCount }))] })] }), jsxRuntime.jsxs(SelectContent, { className: cn(CONTENT_BASE, contentClassName), searchable: searchable, children: [jsxRuntime.jsx(SelectItem, { value: resetValue, withCheckbox: true, children: label }), options.map((opt) => (jsxRuntime.jsx(SelectItem, { value: opt.value, searchValue: opt.searchValue, withCheckbox: true, children: opt.label }, opt.value)))] })] }));
37590
38242
  };
37591
38243
 
37592
38244
  /**
@@ -37931,6 +38583,824 @@ function fieldTypeIcon(type) {
37931
38583
  return FIELD_TYPE_ICONS[type] ?? Type;
37932
38584
  }
37933
38585
 
38586
+ const getRemoveChipLabel = (label) => `Remove ${label} filter`;
38587
+ const FILTERED_BY_LABEL = 'Filtered by';
38588
+
38589
+ /** Compact badge shape with the filter chip colours. */
38590
+ const CHIP_CLASS = 'inline-flex h-7 max-w-full items-center gap-1 rounded-md border border-primary/30 bg-primary/5 px-2.5 text-xs text-foreground';
38591
+ 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';
38592
+ const CLEAR_ALL_CLASS = cn(FILTER_LINK_CLASS_NAME, 'underline');
38593
+ function getChipLabelText(label, variant) {
38594
+ return variant === 'inline' ? `${label}:` : label;
38595
+ }
38596
+
38597
+ /** Applied filters as removable chips, with an optional Clear all. */
38598
+ function ActiveFilterChips({ chips, onRemove, onClearAll, variant = 'inline', actions, className, }) {
38599
+ if (chips.length === 0)
38600
+ return null;
38601
+ const clearAll = onClearAll && (jsxRuntime.jsx("button", { type: "button", onClick: onClearAll, className: CLEAR_ALL_CLASS, children: "Clear all" }));
38602
+ 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))), actions ? (
38603
+ // With actions, Clear all joins them at the row's right end.
38604
+ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-3 pl-3", children: [clearAll, actions] })) : (clearAll)] }));
38605
+ }
38606
+
38607
+ const DEFAULT_CONTAINS_PLACEHOLDER = 'Contains…';
38608
+
38609
+ /**
38610
+ * Local text for a typed filter. It resets to `externalText` only when the applied value
38611
+ * (`externalKey`) changes from outside — e.g. Clear all — not when the change is this field's own commit.
38612
+ */
38613
+ function useFilterDraft(externalKey, externalText) {
38614
+ const [draft, setDraft] = React.useState(externalText);
38615
+ const [seenKey, setSeenKey] = React.useState(externalKey);
38616
+ const [committedKey, setCommittedKey] = React.useState(externalKey);
38617
+ if (seenKey !== externalKey) {
38618
+ setSeenKey(externalKey);
38619
+ if (externalKey !== committedKey) {
38620
+ setCommittedKey(externalKey);
38621
+ setDraft(externalText);
38622
+ }
38623
+ }
38624
+ return { draft, setDraft, markCommitted: setCommittedKey };
38625
+ }
38626
+ /** Debounces `callback`; a call still pending when the field unmounts (e.g. its popover closes) is flushed, not lost. */
38627
+ function useDebouncedCallback(callback, delay) {
38628
+ const callbackRef = React.useRef(callback);
38629
+ const timerRef = React.useRef(null);
38630
+ const pendingRef = React.useRef(null);
38631
+ React.useEffect(() => {
38632
+ callbackRef.current = callback;
38633
+ }, [callback]);
38634
+ const cancel = React.useCallback(() => {
38635
+ if (timerRef.current)
38636
+ clearTimeout(timerRef.current);
38637
+ timerRef.current = null;
38638
+ pendingRef.current = null;
38639
+ }, []);
38640
+ const flush = React.useCallback(() => {
38641
+ const pending = pendingRef.current;
38642
+ cancel();
38643
+ if (pending)
38644
+ callbackRef.current(...pending);
38645
+ }, [cancel]);
38646
+ const schedule = React.useCallback((...args) => {
38647
+ if (timerRef.current)
38648
+ clearTimeout(timerRef.current);
38649
+ pendingRef.current = args;
38650
+ timerRef.current = setTimeout(flush, delay);
38651
+ }, [delay, flush]);
38652
+ React.useEffect(() => flush, [flush]);
38653
+ return { schedule, flush, cancel };
38654
+ }
38655
+
38656
+ const COMMIT_DELAY_MS$2 = 400;
38657
+ function useContainsFilter(value, onChange) {
38658
+ const { draft, setDraft, markCommitted } = useFilterDraft(value, value);
38659
+ const commit = React.useCallback((text) => {
38660
+ const trimmed = text.trim();
38661
+ markCommitted(trimmed);
38662
+ if (trimmed !== value)
38663
+ onChange(trimmed);
38664
+ }, [markCommitted, onChange, value]);
38665
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$2);
38666
+ return {
38667
+ draft,
38668
+ handleChange: (event) => {
38669
+ setDraft(event.target.value);
38670
+ debounced.schedule(event.target.value);
38671
+ },
38672
+ handleKeyDown: (event) => {
38673
+ if (event.key === 'Enter')
38674
+ debounced.flush();
38675
+ },
38676
+ handleBlur: debounced.flush,
38677
+ };
38678
+ }
38679
+
38680
+ function getContainsClassName(size, applied, className) {
38681
+ if (size === 'cell')
38682
+ return getFilterFieldClassName(applied ? 'applied' : 'empty', className);
38683
+ return cn('h-9 text-sm', applied && 'border-primary bg-primary/5', className);
38684
+ }
38685
+
38686
+ /** "Contains…" text filter, as a filter-row cell or a full-size card field. */
38687
+ function ContainsFilter({ value, onChange, ariaLabel, placeholder = DEFAULT_CONTAINS_PLACEHOLDER, size = 'cell', className, }) {
38688
+ const { draft, handleChange, handleKeyDown, handleBlur } = useContainsFilter(value, onChange);
38689
+ const inputProps = {
38690
+ type: 'text',
38691
+ value: draft,
38692
+ placeholder,
38693
+ 'aria-label': ariaLabel,
38694
+ onChange: handleChange,
38695
+ onKeyDown: handleKeyDown,
38696
+ onBlur: handleBlur,
38697
+ className: getContainsClassName(size, value.trim() !== '', className),
38698
+ };
38699
+ return size === 'cell' ? (jsxRuntime.jsx("input", { ...inputProps })) : (jsxRuntime.jsx(Input, { ...inputProps }));
38700
+ }
38701
+
38702
+ const getPresetGroupLabel = (ariaLabel) => `${ariaLabel} presets`;
38703
+ const getDateInputLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
38704
+
38705
+ /** Dates shown in the inputs: a preset's resolved range, or the custom range. */
38706
+ function getDisplayedRange(value, today, fiscalYearStartMonth) {
38707
+ if (value?.preset)
38708
+ return resolveDatePreset(value.preset, today, fiscalYearStartMonth);
38709
+ return { from: value?.from ?? '', to: value?.to ?? '' };
38710
+ }
38711
+ function buildCustomRange(from, to) {
38712
+ return from || to
38713
+ ? { from: from || undefined, to: to || undefined }
38714
+ : undefined;
38715
+ }
38716
+ function togglePreset(value, preset) {
38717
+ return value?.preset === preset ? undefined : { preset };
38718
+ }
38719
+ /** Preset row; the picked one gets the primary tint, as in the design. */
38720
+ const getPresetClassName$1 = (selected) => getOptionRowClassName(selected, 'whitespace-nowrap');
38721
+
38722
+ const toIsoOrEmpty = (date) => date ? toIsoDate(date) : '';
38723
+ function useDateRangeFilter(value, onChange, today, fiscalYearStartMonth) {
38724
+ const { from, to } = getDisplayedRange(value, today, fiscalYearStartMonth);
38725
+ return {
38726
+ from,
38727
+ to,
38728
+ selectPreset: (preset) => onChange(togglePreset(value, preset)),
38729
+ handleFromChange: (date) => onChange(buildCustomRange(toIsoOrEmpty(date), to)),
38730
+ handleToChange: (date) => onChange(buildCustomRange(from, toIsoOrEmpty(date))),
38731
+ clear: () => onChange(undefined),
38732
+ };
38733
+ }
38734
+
38735
+ /** Date filter body: presets on the left, a From / To range on the right. */
38736
+ function DateRangeFilter({ value, onChange, ariaLabel, fiscalYearStartMonth = 1, today = new Date(), }) {
38737
+ const { from, to, selectPreset, handleFromChange, handleToChange, clear } = useDateRangeFilter(value, onChange, today, fiscalYearStartMonth);
38738
+ 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
38739
+ // The inputs sit on the card's right; an end-aligned calendar stays under them.
38740
+ , {
38741
+ // The inputs sit on the card's right; an end-aligned calendar stays under them.
38742
+ align: "end", 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" }))] })] }));
38743
+ }
38744
+
38745
+ const getClearButtonLabel = (ariaLabel) => `Clear ${ariaLabel}`;
38746
+ const NOT_FILTERABLE_LABEL = "This column can't be filtered";
38747
+
38748
+ /** Select-like filter-row control: a compact trigger that opens the filter's panel in a popover. */
38749
+ function FilterCellPopover({ label, placeholder, ariaLabel, state, disabledLabel = NOT_FILTERABLE_LABEL, icon, onClear, showChevron = true, open, onOpenChange, contentClassName, className, children, }) {
38750
+ if (state === 'disabled') {
38751
+ 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 })] }) }));
38752
+ }
38753
+ 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-full outline-none hover:bg-primary/10", children: jsxRuntime.jsx(X$2, { "aria-hidden": "true", className: "size-3" }) }))] }) }), jsxRuntime.jsx(PopoverContent, { align: "start",
38754
+ // The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
38755
+ updatePositionStrategy: "always", sideOffset: 4, className: cn('w-72 p-0', contentClassName), children: children })] }));
38756
+ }
38757
+
38758
+ const COUNT_WORDS = [
38759
+ 'One',
38760
+ 'Two',
38761
+ 'Three',
38762
+ 'Four',
38763
+ 'Five',
38764
+ 'Six',
38765
+ 'Seven',
38766
+ 'Eight',
38767
+ 'Nine',
38768
+ 'Ten',
38769
+ ];
38770
+ /** `4` → `Four` for 1–10; any other count stays as digits. */
38771
+ function countToWord(count) {
38772
+ return COUNT_WORDS[count - 1] ?? String(count);
38773
+ }
38774
+ function getEmptyStateTitle(itemNoun) {
38775
+ return `No ${itemNoun}s match these filters`;
38776
+ }
38777
+ function getEmptyStateDescription(itemNoun, activeCount) {
38778
+ const filters = activeCount === 1 ? 'column filter is' : 'column filters are';
38779
+ return `${countToWord(activeCount)} ${filters} active. Loosen one, or clear them all to see every ${itemNoun}.`;
38780
+ }
38781
+
38782
+ /** Shown in place of rows when the applied column filters match nothing. */
38783
+ function FilterEmptyState({ itemNoun, title, description, activeCount, onClearAll, className, }) {
38784
+ 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" })] }));
38785
+ }
38786
+
38787
+ function getScalePosition(options, value, option) {
38788
+ if (!value)
38789
+ return 'outside';
38790
+ if (option === value.from || option === value.to)
38791
+ return 'end';
38792
+ return expandScaleRange(options, value).includes(option)
38793
+ ? 'between'
38794
+ : 'outside';
38795
+ }
38796
+ /** Next range after clicking `scale`: a fresh single-option range, or the end of the pending one. */
38797
+ function getNextScaleRange(anchor, option) {
38798
+ return anchor === null
38799
+ ? { from: option, to: option }
38800
+ : { from: anchor, to: option };
38801
+ }
38802
+ function getScaleButtonClassName(position, fill = false) {
38803
+ 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,
38804
+ // Unselected options look exactly like unselected pick-list tiles.
38805
+ position === 'outside' && getSelectableOptionClassName(false), position === 'end' &&
38806
+ 'border-primary bg-primary font-medium text-primary-foreground', position === 'between' &&
38807
+ 'border-primary/30 bg-primary/10 font-medium text-primary');
38808
+ }
38809
+
38810
+ /** First click picks the start option, the next click the end option; a click after that starts over. */
38811
+ function useScaleRangeFilter({ value, onChange, }) {
38812
+ const [anchor, setAnchor] = React.useState(null);
38813
+ // The start point only holds while the value is still that one option; Clear or any outside change drops it.
38814
+ const start = anchor !== null && value?.from === anchor && value.to === anchor
38815
+ ? anchor
38816
+ : null;
38817
+ const selectOption = React.useCallback((option) => {
38818
+ onChange(getNextScaleRange(start, option));
38819
+ setAnchor(start === null ? option : null);
38820
+ }, [start, onChange]);
38821
+ return { selectOption };
38822
+ }
38823
+
38824
+ /** Ordered-scale filter: click a start option, then an end option. */
38825
+ function ScaleRangeFilter({ options, value, onChange, ariaLabel, columns, fill = false, }) {
38826
+ const { selectOption } = useScaleRangeFilter({ value, onChange });
38827
+ 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) => {
38828
+ const position = getScalePosition(options, value, option.value);
38829
+ 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(TruncatedLabel, { text: option.label }) }, option.value));
38830
+ }) }));
38831
+ }
38832
+
38833
+ /** Varied widths so placeholder rows and pills read as text, not a block. */
38834
+ const LIST_ROW_WIDTHS = ['55%', '40%', '62%', '48%', '35%'];
38835
+ const PILL_WIDTHS = [72, 88, 64, 96, 76, 84];
38836
+ const TILE_KEYS = ['a', 'b', 'c', 'd'];
38837
+ const CARD_CLASS_NAME = 'flex h-full min-w-0 flex-col gap-3 rounded-xl border border-border bg-card p-4';
38838
+
38839
+ function Pills({ count }) {
38840
+ return (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: PILL_WIDTHS.slice(0, count).map((width) => (jsxRuntime.jsx(SquareSkeleton, { height: 32, width: width, rounded: "full" }, width))) }));
38841
+ }
38842
+ function Body({ variant, }) {
38843
+ switch (variant) {
38844
+ case 'list':
38845
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SquareSkeleton, { height: 36, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 96, rounded: "sm" }), jsxRuntime.jsx("div", { className: "flex flex-col gap-3 px-2 pt-1", children: LIST_ROW_WIDTHS.map((width) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx(SquareSkeleton, { height: 18, width: 18, rounded: "sm" }), jsxRuntime.jsx(SquareSkeleton, { height: 14, width: width, rounded: "sm" })] }, width))) })] }));
38846
+ case 'chips':
38847
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 64, rounded: "sm" }), jsxRuntime.jsx(Pills, { count: 3 }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 80, rounded: "sm" }), jsxRuntime.jsx(Pills, { count: 4 })] }));
38848
+ case 'tiles':
38849
+ return (jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: TILE_KEYS.map((key) => (jsxRuntime.jsx(SquareSkeleton, { height: 48, rounded: "md" }, key))) }));
38850
+ case 'range':
38851
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(SquareSkeleton, { height: 36, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 2, width: 8, rounded: "full" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, rounded: "md" })] }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 88, rounded: "sm" }), jsxRuntime.jsx(Pills, { count: 6 })] }));
38852
+ case 'ids':
38853
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 64, rounded: "sm" }), jsxRuntime.jsx(SquareSkeleton, { height: 80, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: "75%", rounded: "sm" }), jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 56, rounded: "sm" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, rounded: "md" })] }));
38854
+ case 'select':
38855
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 64, rounded: "sm" }), jsxRuntime.jsx(SquareSkeleton, { height: 36, rounded: "md" })] }));
38856
+ }
38857
+ }
38858
+ /** Placeholder for one filter card while the filters load, shaped like the control it will hold. */
38859
+ function FilterCardSkeleton({ variant = 'list', className, }) {
38860
+ return (jsxRuntime.jsxs("div", { "aria-hidden": "true", className: cn(CARD_CLASS_NAME, className), children: [jsxRuntime.jsx(SquareSkeleton, { height: 16, width: 96, rounded: "sm" }), jsxRuntime.jsx(Body, { variant: variant })] }));
38861
+ }
38862
+
38863
+ const getClearIdsLabel = (ariaLabel) => `Clear ${ariaLabel}`;
38864
+
38865
+ const DEFAULT_ID_HELPER_TEXT = 'Paste from Excel or an email. Commas, spaces and new lines all split IDs.';
38866
+ function toIdsKey(ids) {
38867
+ return ids.join('\n');
38868
+ }
38869
+ function formatIdCount(count) {
38870
+ return `${count} ${count === 1 ? 'ID' : 'IDs'}`;
38871
+ }
38872
+
38873
+ const COMMIT_DELAY_MS$1 = 300;
38874
+ function useIdListInput(value, onChange) {
38875
+ const appliedKey = toIdsKey(value);
38876
+ const { draft, setDraft, markCommitted } = useFilterDraft(appliedKey, value.join(', '));
38877
+ const commit = React.useCallback((text) => {
38878
+ const ids = splitIdList(text);
38879
+ const key = toIdsKey(ids);
38880
+ markCommitted(key);
38881
+ if (key !== appliedKey)
38882
+ onChange(ids);
38883
+ }, [appliedKey, markCommitted, onChange]);
38884
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$1);
38885
+ return {
38886
+ draft,
38887
+ parsedIds: splitIdList(draft),
38888
+ handleChange: (event) => {
38889
+ setDraft(event.target.value);
38890
+ debounced.schedule(event.target.value);
38891
+ },
38892
+ handleBlur: debounced.flush,
38893
+ clear: () => {
38894
+ debounced.cancel();
38895
+ setDraft('');
38896
+ commit('');
38897
+ },
38898
+ };
38899
+ }
38900
+
38901
+ /** Paste-a-list body: a textarea split into IDs on commas, spaces and new lines, with the parsed IDs as chips. */
38902
+ function IdListInput({ value, onChange, ariaLabel, placeholder, helperText = DEFAULT_ID_HELPER_TEXT, showSummary = true, }) {
38903
+ const { draft, parsedIds, handleChange, handleBlur, clear } = useIdListInput(value, onChange);
38904
+ 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/30 bg-primary/5 px-2 text-xs text-foreground", 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" })] })] }))] }));
38905
+ }
38906
+
38907
+ const NUMBER_HELP_HEADING = 'Type a value or a rule';
38908
+ const NUMBER_HELP_SUBTITLE = 'Click a rule to use it.';
38909
+ const getNumberErrorId = (baseId) => `${baseId}-error`;
38910
+ const getUseRuleLabel = (rule, meaning) => `Use ${rule}: ${meaning}`;
38911
+
38912
+ function getNumberFieldState(parsed) {
38913
+ if (!parsed.ok)
38914
+ return 'invalid';
38915
+ return parsed.range ? 'applied' : 'empty';
38916
+ }
38917
+ function getNumberInputClassName(state, className) {
38918
+ return getFilterFieldClassName(state, cn('text-right tabular-nums', className));
38919
+ }
38920
+ /** Cheat-sheet row: the whole row is the click target, highlighted on hover. */
38921
+ const RULE_BUTTON_CLASS_NAME = getOptionRowClassName(false, 'py-1.5');
38922
+ /** Key-cap chip for the rule, fixed width so every meaning lines up. */
38923
+ // Every chip is as wide as the longest rule, so the meanings start at the same x.
38924
+ const RULE_CHIP_CLASS_NAME = 'inline-flex h-6 w-[calc(var(--rule-width)+1.25rem)] min-w-14 shrink-0 whitespace-nowrap items-center justify-center rounded-full border border-border bg-background px-2 text-xs font-semibold tabular-nums text-foreground';
38925
+ /** Note / error box in the help popover; text on a fixed 16px line. */
38926
+ const MESSAGE_CLASS_NAME = 'flex gap-2 rounded-md p-2 leading-4';
38927
+ /** One text line tall, so the icon centres on the first line however the text wraps. */
38928
+ const MESSAGE_ICON_SLOT_CLASS_NAME = 'flex h-4 shrink-0 items-center';
38929
+ /** Sets `--rule-width` to the longest rule, which sizes every chip in the list. */
38930
+ function getRuleListStyle(rules) {
38931
+ const longest = Math.max(...rules.map(({ rule }) => rule.length));
38932
+ return { '--rule-width': `${longest}ch` };
38933
+ }
38934
+
38935
+ const COMMIT_DELAY_MS = 400;
38936
+ function useNumberExpressionFilter(value, onChange) {
38937
+ const applied = formatNumberRange(value);
38938
+ const { draft, setDraft, markCommitted } = useFilterDraft(applied, applied);
38939
+ const [helpOpen, setHelpOpen] = React.useState(false);
38940
+ const errorId = React.useId();
38941
+ const commit = React.useCallback((text) => {
38942
+ const parsed = parseNumberExpression(text);
38943
+ if (!parsed.ok)
38944
+ return;
38945
+ const key = formatNumberRange(parsed.range);
38946
+ markCommitted(key);
38947
+ if (key !== applied)
38948
+ onChange(parsed.range);
38949
+ }, [applied, markCommitted, onChange]);
38950
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS);
38951
+ const handleChange = (event) => {
38952
+ setDraft(event.target.value);
38953
+ setHelpOpen(true);
38954
+ debounced.schedule(event.target.value);
38955
+ };
38956
+ const handleKeyDown = (event) => {
38957
+ if (event.key === 'Enter')
38958
+ debounced.flush();
38959
+ if (event.key === 'Escape')
38960
+ setHelpOpen(false);
38961
+ };
38962
+ const handleBlur = () => {
38963
+ debounced.flush();
38964
+ setHelpOpen(false);
38965
+ };
38966
+ const applyRule = (rule) => {
38967
+ debounced.cancel();
38968
+ setDraft(rule);
38969
+ commit(rule);
38970
+ setHelpOpen(false);
38971
+ };
38972
+ return {
38973
+ draft,
38974
+ state: getNumberFieldState(parseNumberExpression(draft)),
38975
+ helpOpen,
38976
+ errorId,
38977
+ handleChange,
38978
+ handleKeyDown,
38979
+ handleFocus: () => setHelpOpen(true),
38980
+ handleClick: () => setHelpOpen(true),
38981
+ handleBlur,
38982
+ applyRule,
38983
+ };
38984
+ }
38985
+
38986
+ /** Filter-row number cell: type a value or a rule (`>1`, `1–3`, `1.52`). Invalid text never reaches the table. */
38987
+ function NumberExpressionFilter({ value, onChange, ariaLabel, placeholder, note, ruleExamples, className, }) {
38988
+ const { draft, state, helpOpen, errorId, handleChange, handleKeyDown, handleFocus, handleClick, handleBlur, applyRule, } = useNumberExpressionFilter(value, onChange);
38989
+ const invalid = state === 'invalid';
38990
+ const rules = buildNumberRuleHelp(ruleExamples);
38991
+ 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, onClick: handleClick, onBlur: handleBlur, className: getNumberInputClassName(state, className) }) }), jsxRuntime.jsxs(PopoverContent, { align: "start",
38992
+ // The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
38993
+ 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", style: getRuleListStyle(rules), children: rules.map(({ rule, meaning }) => (jsxRuntime.jsx("li", { children: jsxRuntime.jsxs("button", { type: "button", "aria-label": getUseRuleLabel(rule, meaning),
38994
+ // Keep focus in the field so it doesn't blur and close this help first.
38995
+ 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: cn(MESSAGE_CLASS_NAME, 'bg-muted/50 text-muted-foreground'), children: [jsxRuntime.jsx("span", { className: MESSAGE_ICON_SLOT_CLASS_NAME, children: jsxRuntime.jsx(Info, { "aria-hidden": "true", className: "size-3.5" }) }), jsxRuntime.jsx("div", { children: note })] })), invalid && (jsxRuntime.jsxs("div", { id: getNumberErrorId(errorId), role: "alert", className: cn(MESSAGE_CLASS_NAME, 'bg-destructive/10 text-destructive'), children: [jsxRuntime.jsx("span", { className: MESSAGE_ICON_SLOT_CLASS_NAME, children: jsxRuntime.jsx(CircleAlert, { "aria-hidden": "true", className: "size-3.5" }) }), 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" }), "."] })] }))] })] }));
38996
+ }
38997
+
38998
+ const REVERSED_RANGE_MESSAGE = 'From must not be more than To.';
38999
+ const getBoundLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
39000
+
39001
+ const DECIMAL_DRAFT_RE = /^\d*\.?\d*$/;
39002
+ /** Allows partial decimals (`1.`) while typing; rejects anything else. */
39003
+ function isDecimalDraft(text) {
39004
+ return DECIMAL_DRAFT_RE.test(text);
39005
+ }
39006
+ function toBound(text) {
39007
+ if (!text || text === '.')
39008
+ return undefined;
39009
+ return Number(text);
39010
+ }
39011
+ function toBoundText(bound) {
39012
+ return bound === undefined ? '' : String(bound);
39013
+ }
39014
+ /** Replaces one bound with a typed (inclusive) number, keeping the other bound and its `>` / `<`. */
39015
+ function withBound(range, bound, next) {
39016
+ const min = bound === 'min' ? next : range?.min;
39017
+ const max = bound === 'max' ? next : range?.max;
39018
+ if (min === undefined && max === undefined)
39019
+ return undefined;
39020
+ const result = { min, max };
39021
+ if (bound === 'max' && range?.minExclusive)
39022
+ result.minExclusive = true;
39023
+ if (bound === 'min' && range?.maxExclusive)
39024
+ result.maxExclusive = true;
39025
+ return result;
39026
+ }
39027
+ function isReversedRange(min, max) {
39028
+ return min !== undefined && max !== undefined && min > max;
39029
+ }
39030
+ function isSameRange(a, b) {
39031
+ return a?.min === b.min && a?.max === b.max;
39032
+ }
39033
+ function getBoundInputClassName(filled) {
39034
+ return cn('h-9 min-w-0 flex-1 text-sm', filled && 'border-primary bg-primary/5');
39035
+ }
39036
+ const getPresetClassName = getPillClassName;
39037
+
39038
+ function useNumberRangeInputs(value, onChange) {
39039
+ const minText = toBoundText(value?.min);
39040
+ const maxText = toBoundText(value?.max);
39041
+ const from = useFilterDraft(minText, minText);
39042
+ const to = useFilterDraft(maxText, maxText);
39043
+ const handleBoundChange = (bound) => (event) => {
39044
+ const text = event.target.value;
39045
+ if (!isDecimalDraft(text))
39046
+ return;
39047
+ const draft = bound === 'min' ? from : to;
39048
+ const parsed = toBound(text);
39049
+ draft.setDraft(text);
39050
+ const next = withBound(value, bound, parsed);
39051
+ if (isReversedRange(next?.min, next?.max))
39052
+ return;
39053
+ draft.markCommitted(toBoundText(parsed));
39054
+ onChange(next);
39055
+ };
39056
+ return {
39057
+ fromDraft: from.draft,
39058
+ toDraft: to.draft,
39059
+ reversed: isReversedRange(toBound(from.draft), toBound(to.draft)),
39060
+ handleFromChange: handleBoundChange('min'),
39061
+ handleToChange: handleBoundChange('max'),
39062
+ isPresetSelected: (preset) => isSameRange(value, preset.range),
39063
+ togglePreset: (preset) => onChange(isSameRange(value, preset.range) ? undefined : preset.range),
39064
+ };
39065
+ }
39066
+
39067
+ /** From – To number inputs for full-page filter cards, with optional quick-pick presets. */
39068
+ function NumberRangeInputs({ value, onChange, ariaLabel, fromPlaceholder = 'From', toPlaceholder = 'To', presets, presetsLabel, }) {
39069
+ const { fromDraft, toDraft, reversed, handleFromChange, handleToChange, isPresetSelected, togglePreset, } = useNumberRangeInputs(value, onChange);
39070
+ 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))) })] }))] }));
39071
+ }
39072
+
39073
+ const NEXT_KEYS = new Set(['ArrowDown', 'ArrowRight']);
39074
+ const PREVIOUS_KEYS = new Set(['ArrowUp', 'ArrowLeft']);
39075
+ /** Arrow keys move and select within the radio group, wrapping at either end. */
39076
+ function getArrowKeyTarget(current, key) {
39077
+ const step = NEXT_KEYS.has(key) ? 1 : PREVIOUS_KEYS.has(key) ? -1 : 0;
39078
+ if (step === 0)
39079
+ return null;
39080
+ const index = TRI_STATE_OPTIONS.findIndex((option) => option.value === current);
39081
+ const nextIndex = (index + step + TRI_STATE_OPTIONS.length) % TRI_STATE_OPTIONS.length;
39082
+ return TRI_STATE_OPTIONS[nextIndex].value;
39083
+ }
39084
+ function createRadioGroupKeyDownHandler(current, onChange) {
39085
+ return (event) => {
39086
+ const target = getArrowKeyTarget(current, event.key);
39087
+ if (!target)
39088
+ return;
39089
+ event.preventDefault();
39090
+ onChange(target);
39091
+ event.currentTarget
39092
+ .querySelector(`[data-value="${target}"]`)
39093
+ ?.focus();
39094
+ };
39095
+ }
39096
+
39097
+ const getRadioRowClassName = (checked) => getOptionRowClassName(checked);
39098
+ function getRadioCircleClassName(checked) {
39099
+ return cn('flex size-4 shrink-0 items-center justify-center rounded-full border', checked ? 'border-primary' : 'border-input-border');
39100
+ }
39101
+
39102
+ /** Any / Yes / No radio group for boolean columns (e.g. Active). */
39103
+ function TriStateFilter({ value, onChange, ariaLabel, }) {
39104
+ 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) => {
39105
+ const checked = option.value === value;
39106
+ 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));
39107
+ }) }));
39108
+ }
39109
+
39110
+ const SAVED_SEARCH_CHIP_CLASS_NAME = 'inline-flex h-6 min-w-0 max-w-full items-center rounded-full border border-primary/30 bg-primary/5 px-2 text-xs text-foreground';
39111
+ /** Children laid out below the first one's line. */
39112
+ function countWrapped(items) {
39113
+ if (items.length === 0)
39114
+ return 0;
39115
+ const firstTop = items[0].offsetTop;
39116
+ return items.filter((item) => item.offsetTop > firstTop).length;
39117
+ }
39118
+ const getShowMoreLabel = (hiddenCount) => `+${hiddenCount} more`;
39119
+
39120
+ /**
39121
+ * Fits chips on one line with the "+N more" link right after the last one. Renders every chip, counts
39122
+ * how many wrap, then drops chips until the link itself fits; a resize starts the measurement over.
39123
+ */
39124
+ function useChipOverflow(chips, enabled) {
39125
+ const [list, setList] = React.useState(null);
39126
+ const [expanded, setExpanded] = React.useState(false);
39127
+ const [visibleCount, setVisibleCount] = React.useState(chips.length);
39128
+ const collapsed = enabled && !expanded;
39129
+ const [measuredLength, setMeasuredLength] = React.useState(chips.length);
39130
+ if (measuredLength !== chips.length) {
39131
+ setMeasuredLength(chips.length);
39132
+ setVisibleCount(chips.length);
39133
+ }
39134
+ React.useLayoutEffect(() => {
39135
+ if (!collapsed || !list)
39136
+ return;
39137
+ const items = Array.from(list.children);
39138
+ if (visibleCount >= chips.length) {
39139
+ const wrapped = countWrapped(items);
39140
+ if (wrapped > 0)
39141
+ setVisibleCount(chips.length - wrapped);
39142
+ return;
39143
+ }
39144
+ // The last child is the "+N more" link; if it wrapped, give it one more chip's room.
39145
+ if (countWrapped(items) > 0 && visibleCount > 1)
39146
+ setVisibleCount(visibleCount - 1);
39147
+ }, [collapsed, list, visibleCount, chips.length]);
39148
+ React.useEffect(() => {
39149
+ if (!collapsed || !list)
39150
+ return;
39151
+ let width = list.clientWidth;
39152
+ const observer = new ResizeObserver(() => {
39153
+ if (list.clientWidth === width)
39154
+ return;
39155
+ width = list.clientWidth;
39156
+ setVisibleCount(chips.length);
39157
+ });
39158
+ observer.observe(list);
39159
+ return () => observer.disconnect();
39160
+ }, [collapsed, list, chips.length]);
39161
+ const shown = collapsed ? Math.min(visibleCount, chips.length) : chips.length;
39162
+ return {
39163
+ listRef: React.useCallback((node) => setList(node), []),
39164
+ expanded,
39165
+ toggle: () => {
39166
+ setExpanded((current) => !current);
39167
+ setVisibleCount(chips.length);
39168
+ },
39169
+ visibleChips: chips.slice(0, shown),
39170
+ hiddenCount: chips.length - shown,
39171
+ };
39172
+ }
39173
+
39174
+ /** Read-only filter summaries of a saved search, as pills; optionally one line ending in "+N more". */
39175
+ function SavedSearchChipList({ chips, emptyText = 'No filters', collapsible = false, className, }) {
39176
+ const { listRef, expanded, toggle, visibleChips, hiddenCount } = useChipOverflow(chips, collapsible);
39177
+ if (chips.length === 0) {
39178
+ return (jsxRuntime.jsx("p", { className: cn('text-xs text-muted-foreground', className), children: emptyText }));
39179
+ }
39180
+ const showToggle = collapsible && (expanded || hiddenCount > 0);
39181
+ return (jsxRuntime.jsxs("ul", { ref: listRef, className: cn('flex min-w-0 flex-wrap items-center gap-1.5', className), children: [visibleChips.map((chip) => (jsxRuntime.jsx("li", { className: SAVED_SEARCH_CHIP_CLASS_NAME, children: jsxRuntime.jsx(TruncatedLabel, { text: chip }) }, chip))), showToggle && (jsxRuntime.jsx("li", { className: "flex h-6 shrink-0 items-center", children: jsxRuntime.jsx("button", { type: "button", "aria-expanded": expanded, onClick: toggle,
39182
+ // Above a parent's stretched click area (e.g. a saved-search row).
39183
+ className: cn(FILTER_LINK_CLASS_NAME, 'relative z-10 whitespace-nowrap px-1 underline underline-offset-2'), children: expanded ? 'Show less' : getShowMoreLabel(hiddenCount) }) }))] }));
39184
+ }
39185
+
39186
+ const SEARCH_INPUT_LABEL = 'Find a saved search';
39187
+ const getRenameLabel = (name) => `Rename ${name}`;
39188
+ const getDeleteLabel = (name) => `Delete ${name}`;
39189
+ const NO_MATCH_TITLE = 'No matches';
39190
+ const getNoMatchText = (query) => `No saved searches match “${query.trim()}”.`;
39191
+
39192
+ /** Matches the name or any filter summary, ignoring case. */
39193
+ function filterSavedSearches(items, query) {
39194
+ const needle = query.trim().toLowerCase();
39195
+ if (!needle)
39196
+ return [...items];
39197
+ return items.filter((item) => [item.name, ...item.chips].some((text) => text.toLowerCase().includes(needle)));
39198
+ }
39199
+ const ROW_CLASS_NAME = 'relative flex items-center gap-4 rounded-md px-2 py-2.5 transition-colors hover:bg-muted/60';
39200
+ /** The name is the row's button; its `::after` stretches over the whole row so the row is the click target. */
39201
+ const ROW_BUTTON_CLASS_NAME = "block min-w-0 max-w-full cursor-pointer text-left text-sm font-semibold text-foreground outline-none after:absolute after:inset-0 after:rounded-md after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-primary/30";
39202
+ /** Lifts the name above the button's stretched area so its overflow tooltip gets the hover; clicks still reach the button. */
39203
+ const ROW_NAME_CLASS_NAME = 'relative z-10 block min-w-0';
39204
+ /** Rename / Delete as one outlined, button-shaped group with a divider between them. */
39205
+ const ROW_ACTIONS_CLASS_NAME = 'flex shrink-0 items-center divide-x divide-border overflow-hidden rounded-md border border-border bg-card shadow-xs';
39206
+ /** A cell of the actions group; Delete turns destructive on hover. */
39207
+ function getRowActionClassName(destructive) {
39208
+ return cn('size-7 rounded-none text-foreground/70 [&_svg]:size-3.5', destructive
39209
+ ? 'hover:bg-destructive/10 hover:text-destructive'
39210
+ : 'hover:bg-muted hover:text-foreground');
39211
+ }
39212
+ /** Controls inside the row that sit above the stretched button. */
39213
+ const ROW_CONTROL_CLASS_NAME = 'relative z-10';
39214
+ /** About three rows (name line + one pill line each) before the list scrolls. */
39215
+ const LIST_SCROLL_CLASS_NAME = 'max-h-54 overflow-y-auto';
39216
+
39217
+ function useSavedSearchesMenu(items, onOpenChange) {
39218
+ const [open, setOpenState] = React.useState(false);
39219
+ const [query, setQuery] = React.useState('');
39220
+ const setOpen = (next) => {
39221
+ setOpenState(next);
39222
+ if (!next)
39223
+ setQuery('');
39224
+ onOpenChange?.(next);
39225
+ };
39226
+ const visibleItems = React.useMemo(() => filterSavedSearches(items, query), [items, query]);
39227
+ const closeThen = (action, item) => () => {
39228
+ setOpen(false);
39229
+ action(item);
39230
+ };
39231
+ return { open, setOpen, query, setQuery, visibleItems, closeThen };
39232
+ }
39233
+
39234
+ /** Small icon button on a row, named by its tooltip. */
39235
+ function RowActionButton({ label, onClick, destructive = false, children, }) {
39236
+ return (jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx(IconButton, { appearance: "ghost", size: "xs", "aria-label": label, onClick: onClick, className: getRowActionClassName(destructive), children: children }) }), jsxRuntime.jsx(TooltipContent, { side: "top", children: label })] }));
39237
+ }
39238
+ /** One saved search: name, filter pills, when it was saved, and Rename / Delete buttons. */
39239
+ function SavedSearchRow({ item, onSelect, onRename, onDelete, }) {
39240
+ const hasCount = item.countLoading || item.count !== undefined;
39241
+ return (jsxRuntime.jsxs("li", { className: ROW_CLASS_NAME, children: [jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [jsxRuntime.jsxs("div", { className: "flex min-w-0 items-baseline gap-2", children: [jsxRuntime.jsx("button", { type: "button", onClick: onSelect, className: ROW_BUTTON_CLASS_NAME, children: jsxRuntime.jsx("span", { className: ROW_NAME_CLASS_NAME, children: jsxRuntime.jsx(TruncatedLabel, { text: item.name }) }) }), hasCount &&
39242
+ (item.countLoading ? (jsxRuntime.jsx(SquareSkeleton, { height: 12, width: 40, rounded: "sm" })) : (jsxRuntime.jsx("span", { className: "shrink-0 text-xs font-medium tabular-nums text-foreground", children: item.countLabel ?? item.count }))), item.meta && (jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground before:mr-2 before:content-['\u00B7']", children: item.meta }))] }), jsxRuntime.jsx(SavedSearchChipList, { chips: item.chips, collapsible: true })] }), (onRename || onDelete) && (jsxRuntime.jsxs("div", { className: cn(ROW_CONTROL_CLASS_NAME, ROW_ACTIONS_CLASS_NAME), children: [onRename && (jsxRuntime.jsx(RowActionButton, { label: getRenameLabel(item.name), onClick: onRename, children: jsxRuntime.jsx(Pencil, {}) })), onDelete && (jsxRuntime.jsx(RowActionButton, { label: getDeleteLabel(item.name), onClick: onDelete, destructive: true, children: jsxRuntime.jsx(Trash2, {}) }))] }))] }));
39243
+ }
39244
+ /** Centered empty / no-match state inside the dropdown. */
39245
+ function SavedSearchesEmpty({ icon, title, description, }) {
39246
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1 px-4 py-6 text-center", children: [jsxRuntime.jsx("span", { className: "mb-2 flex size-10 items-center justify-center rounded-full bg-muted text-primary [&>svg]:size-5", children: icon }), jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: title }), jsxRuntime.jsx("p", { className: "max-w-xs text-xs text-muted-foreground", children: description })] }));
39247
+ }
39248
+
39249
+ /** "Saved searches" dropdown: find, pick, rename or delete a saved filter set. */
39250
+ function SavedSearchesMenu({ items, onSelect, onRename, onDelete, loading = false, onOpenChange, label = 'Saved searches', footnote, emptyTitle = 'No saved searches yet', emptyDescription = 'Apply some filters, then choose Save search to keep them here.', align = 'start', triggerClassName, }) {
39251
+ const { open, setOpen, query, setQuery, visibleItems, closeThen } = useSavedSearchesMenu(items, onOpenChange);
39252
+ const hasNone = !loading && items.length === 0;
39253
+ return (jsxRuntime.jsxs(Popover, { open: open, onOpenChange: setOpen, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsx(Button, { appearance: "outline", color: open ? 'primary' : 'secondary', size: "md", leftIcon: jsxRuntime.jsx(Bookmark, {}), rightIcon: open ? jsxRuntime.jsx(ChevronUp, {}) : jsxRuntime.jsx(ChevronDown, {}), className: triggerClassName, children: label }) }), jsxRuntime.jsxs(PopoverContent, { align: align, sideOffset: 4, className: "flex w-120 max-w-[calc(100vw-2rem)] flex-col gap-2 p-2", children: [!hasNone && (jsxRuntime.jsxs("label", { className: FILTER_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: SEARCH_INPUT_LABEL, "aria-label": SEARCH_INPUT_LABEL, className: "min-w-0 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-placeholder" })] })), loading ? (jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 p-2", "aria-busy": "true", children: [jsxRuntime.jsx(SquareSkeleton, { height: 44, rounded: "md" }), jsxRuntime.jsx(SquareSkeleton, { height: 44, rounded: "md" })] })) : hasNone ? (jsxRuntime.jsx(SavedSearchesEmpty, { icon: jsxRuntime.jsx(Bookmark, {}), title: emptyTitle, description: emptyDescription })) : visibleItems.length === 0 ? (jsxRuntime.jsx(SavedSearchesEmpty, { icon: jsxRuntime.jsx(SearchX, {}), title: NO_MATCH_TITLE, description: getNoMatchText(query) })) : (jsxRuntime.jsx(ScrollFade, { className: LIST_SCROLL_CLASS_NAME, children: jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntime.jsx("ul", { className: "flex flex-col", children: visibleItems.map((item) => (jsxRuntime.jsx(SavedSearchRow, { item: item, onSelect: closeThen(onSelect, item), onRename: onRename && closeThen(onRename, item), onDelete: onDelete && closeThen(onDelete, item) }, item.id))) }) }) })), footnote && !hasNone && (jsxRuntime.jsx("p", { className: "border-t border-border px-2 pt-2 text-xs text-muted-foreground", children: footnote }))] })] }));
39254
+ }
39255
+
39256
+ /**
39257
+ * App-wide modal wrapper with a fixed header / body / footer layout.
39258
+ * Built on top of shadcn DialogContent, so it inherits viewport-centered
39259
+ * positioning, focus trapping, portal rendering, and overlay handling.
39260
+ */
39261
+ function Modal({ open, onClose, title, description, icon, children, footer, size = 'default', hideCloseButton = false, className, bodyClassName, }) {
39262
+ // See ConfirmDialog: overlapping dismissable layers leak the <body> lock.
39263
+ useOverlayBodyLockRelease(open);
39264
+ 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 }))] }) }));
39265
+ }
39266
+
39267
+ const NAME_LABEL = 'Name';
39268
+ const FILTERS_LABEL = 'Filters saved';
39269
+ const NAME_REQUIRED_ERROR = 'Enter a name for this search.';
39270
+ const DUPLICATE_TITLE = 'Name already in use';
39271
+ const DUPLICATE_DESCRIPTION = 'Save another search with this name?';
39272
+ const DUPLICATE_DETAIL_LABEL = 'Existing saved search';
39273
+ const SAVE_ANYWAY_LABEL = 'Save anyway';
39274
+ const CHANGE_NAME_LABEL = 'Change name';
39275
+ const GO_BACK_LABEL = 'Go back';
39276
+ const CANCEL_LABEL = 'Cancel';
39277
+
39278
+ const SAVED_SEARCH_NAME_MAX_LENGTH = 100;
39279
+ const isValidSearchName = (name) => {
39280
+ const trimmed = name.trim();
39281
+ return trimmed.length > 0 && trimmed.length <= SAVED_SEARCH_NAME_MAX_LENGTH;
39282
+ };
39283
+ const isDuplicateSearchName = (name, existingNames) => {
39284
+ const needle = name.trim().toLowerCase();
39285
+ return existingNames.some((taken) => taken.trim().toLowerCase() === needle);
39286
+ };
39287
+ const FILTERS_PANEL_CLASS_NAME = 'rounded-lg border border-border bg-muted/40 p-3';
39288
+ /** The warning for a step: the caller's for the limit and already-saved steps, built-in copy for a reused name. */
39289
+ function getStepWarning(step, name, warnings) {
39290
+ if (step === 'limit')
39291
+ return warnings.limitWarning;
39292
+ if (step === 'existing')
39293
+ return warnings.existingWarning;
39294
+ if (step === 'duplicate') {
39295
+ return {
39296
+ title: DUPLICATE_TITLE,
39297
+ description: DUPLICATE_DESCRIPTION,
39298
+ detail: { label: DUPLICATE_DETAIL_LABEL, value: name.trim() },
39299
+ };
39300
+ }
39301
+ return undefined;
39302
+ }
39303
+ /** Cancel closes before the form; later warnings go back to it. */
39304
+ function getWarningCancelLabel(step) {
39305
+ if (step === 'existing')
39306
+ return CANCEL_LABEL;
39307
+ if (step === 'limit')
39308
+ return GO_BACK_LABEL;
39309
+ return CHANGE_NAME_LABEL;
39310
+ }
39311
+ const WARNING_DETAIL_CLASS_NAME = 'flex min-w-0 flex-col gap-0.5 rounded-xl border border-border bg-muted/30 px-3.5 py-3';
39312
+
39313
+ /**
39314
+ * The name field restarts from `defaultName` every time the dialog opens. Save stays enabled and reports a
39315
+ * missing name; an optional warning can come before the form (e.g. already saved), and a reused name, then the
39316
+ * saved-search limit, each get a follow-up warning that replaces the
39317
+ * form until the user confirms (the last one stays up, showing progress, until the caller closes on success).
39318
+ */
39319
+ function useSaveSearchDialog({ open, defaultName, onSave, saving, existingNames, hasLimitWarning, hasExistingWarning, onClose, }) {
39320
+ const formId = React.useId();
39321
+ const inputId = React.useId();
39322
+ const [name, setNameState] = React.useState(defaultName);
39323
+ const [error, setError] = React.useState();
39324
+ const firstStep = hasExistingWarning ? 'existing' : 'form';
39325
+ const [step, setStep] = React.useState(firstStep);
39326
+ const [wasOpen, setWasOpen] = React.useState(open);
39327
+ if (open !== wasOpen) {
39328
+ setWasOpen(open);
39329
+ if (open) {
39330
+ setNameState(defaultName);
39331
+ setError(undefined);
39332
+ setStep(firstStep);
39333
+ }
39334
+ }
39335
+ const save = () => onSave(name.trim());
39336
+ const afterDuplicate = () => hasLimitWarning ? setStep('limit') : save();
39337
+ return {
39338
+ formId,
39339
+ inputId,
39340
+ name,
39341
+ setName: (next) => {
39342
+ setNameState(next);
39343
+ if (error)
39344
+ setError(undefined);
39345
+ },
39346
+ error,
39347
+ submit: () => {
39348
+ if (saving)
39349
+ return;
39350
+ if (!isValidSearchName(name)) {
39351
+ setError(NAME_REQUIRED_ERROR);
39352
+ return;
39353
+ }
39354
+ if (isDuplicateSearchName(name, existingNames)) {
39355
+ setStep('duplicate');
39356
+ return;
39357
+ }
39358
+ afterDuplicate();
39359
+ },
39360
+ step,
39361
+ confirmWarning: () => {
39362
+ if (step === 'existing')
39363
+ setStep('form');
39364
+ else if (step === 'duplicate')
39365
+ afterDuplicate();
39366
+ else
39367
+ save();
39368
+ },
39369
+ cancelWarning: () => step === 'existing' ? onClose() : setStep('form'),
39370
+ };
39371
+ }
39372
+
39373
+ /** The search a warning is about, in the dialog body (long names stay on one line, full text on hover). */
39374
+ function WarningDetail({ label, value, }) {
39375
+ return (jsxRuntime.jsxs("div", { className: WARNING_DETAIL_CLASS_NAME, children: [jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: label }), jsxRuntime.jsx(TruncatedLabel, { text: value, className: "text-sm font-semibold text-foreground" })] }));
39376
+ }
39377
+
39378
+ /** Names the current filters and saves them; also used to rename a saved search. */
39379
+ function SaveSearchDialog({ open, onClose, onSave, defaultName = '', chips, title = 'Save search', icon = jsxRuntime.jsx(Bookmark, { className: "size-5" }), submitLabel = 'Save search', note, existingNames, limitWarning, existingWarning, saving = false, }) {
39380
+ const { formId, inputId, name, setName, error, submit, step, confirmWarning, cancelWarning, } = useSaveSearchDialog({
39381
+ open,
39382
+ defaultName,
39383
+ onSave,
39384
+ saving,
39385
+ existingNames: existingNames ?? [],
39386
+ hasLimitWarning: Boolean(limitWarning),
39387
+ hasExistingWarning: Boolean(existingWarning),
39388
+ onClose,
39389
+ });
39390
+ const warning = getStepWarning(step, name, {
39391
+ limitWarning,
39392
+ existingWarning,
39393
+ });
39394
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Modal
39395
+ // One dialog at a time: the duplicate-name warning replaces this one and hands back to it.
39396
+ , {
39397
+ // One dialog at a time: the duplicate-name warning replaces this one and hands back to it.
39398
+ open: open && step === 'form', onClose: onClose, title: title, icon: icon, footer: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Button, { appearance: "outline", color: "secondary", size: "md", onClick: onClose, children: "Cancel" }), jsxRuntime.jsx(Button, { appearance: "solid", color: "primary", size: "md", type: "submit", form: formId, loading: saving, children: submitLabel })] }), children: jsxRuntime.jsxs("form", { id: formId, noValidate: true, className: "flex flex-col gap-4 px-6 pb-5", onSubmit: (event) => {
39399
+ event.preventDefault();
39400
+ submit();
39401
+ }, children: [jsxRuntime.jsx(Field, { label: NAME_LABEL, required: true, error: error, input: jsxRuntime.jsx(Input, { id: inputId, "aria-label": NAME_LABEL, "aria-invalid": Boolean(error) || undefined, value: name, maxLength: SAVED_SEARCH_NAME_MAX_LENGTH, onChange: (event) => setName(event.target.value), autoFocus: true }) }), chips && (jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [jsxRuntime.jsx("span", { className: "text-[13px] text-label", children: FILTERS_LABEL }), jsxRuntime.jsx(SavedSearchChipList, { chips: chips, className: FILTERS_PANEL_CLASS_NAME })] })), note && (jsxRuntime.jsxs("p", { className: "flex items-start gap-1.5 text-xs text-muted-foreground", children: [jsxRuntime.jsx(Info, { "aria-hidden": "true", className: "mt-px size-3.5 shrink-0" }), jsxRuntime.jsx("span", { children: note })] }))] }) }), jsxRuntime.jsx(ConfirmDialog, { open: open && step !== 'form', onOpenChange: (next) => !next && !saving && cancelWarning(), icon: TriangleAlert, title: warning?.title ?? '', description: warning?.description, cancelLabel: getWarningCancelLabel(step), confirmLabel: warning?.confirmLabel ?? SAVE_ANYWAY_LABEL, confirmVariant: "default", disabled: saving, onConfirm: confirmWarning, children: warning?.detail && jsxRuntime.jsx(WarningDetail, { ...warning.detail }) })] }));
39402
+ }
39403
+
37934
39404
  /**
37935
39405
  * Compact "time ago" label, e.g. "5m ago". Falls back to a locale date past a
37936
39406
  * week so older entries stay scannable.
@@ -38284,23 +39754,26 @@ function InventoryComboBox({ inventoryType, selectedItem, onSelect, fetchGems, f
38284
39754
  } }), 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 }));
38285
39755
  }
38286
39756
 
38287
- const OwnershipFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Ownership", options: [
38288
- { value: 'owned', label: 'Owned' },
38289
- { value: 'partner', label: 'Partner' },
38290
- { value: 'memo_in', label: 'Memo In' },
38291
- ] }));
38292
- const StockTypeFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Stock Type", options: [
38293
- { value: 'single', label: 'Single' },
38294
- { value: 'parcel', label: 'Parcel' },
38295
- { value: 'set', label: 'Set' },
38296
- { value: 'pair', label: 'Pair' },
38297
- ] }));
38298
- const StatusFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Status", options: [
38299
- { value: 'in_stock', label: 'In Stock' },
38300
- { value: 'out_of_stock', label: 'Out of Stock' },
38301
- { value: 'sold', label: 'Sold' },
38302
- { value: 'memo_out', label: 'Memo Out' },
38303
- ] }));
39757
+ const OWNERSHIP_STATUS_OPTIONS = [
39758
+ { value: 'owned', label: 'Owned' },
39759
+ { value: 'partner', label: 'Partner' },
39760
+ { value: 'memo_in', label: 'Memo In' },
39761
+ ];
39762
+ const STOCK_TYPE_OPTIONS = [
39763
+ { value: 'single', label: 'Single' },
39764
+ { value: 'parcel', label: 'Parcel' },
39765
+ { value: 'set', label: 'Set' },
39766
+ { value: 'pair', label: 'Pair' },
39767
+ ];
39768
+ const INVENTORY_STATUS_OPTIONS = [
39769
+ { value: 'in_stock', label: 'In Stock' },
39770
+ { value: 'out_of_stock', label: 'Out of Stock' },
39771
+ { value: 'sold', label: 'Sold' },
39772
+ { value: 'memo_out', label: 'Memo Out' },
39773
+ ];
39774
+ const OwnershipFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Ownership", searchPlaceholder: "Search ownership", options: [...OWNERSHIP_STATUS_OPTIONS] }));
39775
+ const StockTypeFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Stock Type", searchPlaceholder: "Search stock types", options: [...STOCK_TYPE_OPTIONS] }));
39776
+ const StatusFilter = (props) => (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Status", searchPlaceholder: "Search statuses", options: [...INVENTORY_STATUS_OPTIONS] }));
38304
39777
  const WarehouseFilter = ({ getWarehouseList, ...props }) => {
38305
39778
  const [warehouses, setWarehouses] = React.useState([]);
38306
39779
  React.useEffect(() => {
@@ -38308,7 +39781,7 @@ const WarehouseFilter = ({ getWarehouseList, ...props }) => {
38308
39781
  .then(setWarehouses)
38309
39782
  .catch(() => { });
38310
39783
  }, [getWarehouseList]);
38311
- return (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Warehouse", contentClassName: "min-w-[250px] w-fit", options: warehouses.map((w) => ({
39784
+ return (jsxRuntime.jsx(FilterMultiSelect, { ...props, label: "Warehouse", searchPlaceholder: "Search warehouses", options: warehouses.map((w) => ({
38312
39785
  value: w.id,
38313
39786
  label: `${w.warehouseId} · ${w.name}`,
38314
39787
  })) }));
@@ -38540,17 +40013,6 @@ const TONE_ICON_BG = {
38540
40013
  };
38541
40014
  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 }))] })] }));
38542
40015
 
38543
- /**
38544
- * App-wide modal wrapper with a fixed header / body / footer layout.
38545
- * Built on top of shadcn DialogContent, so it inherits viewport-centered
38546
- * positioning, focus trapping, portal rendering, and overlay handling.
38547
- */
38548
- function Modal({ open, onClose, title, description, icon, children, footer, size = 'default', hideCloseButton = false, className, bodyClassName, }) {
38549
- // See ConfirmDialog: overlapping dismissable layers leak the <body> lock.
38550
- useOverlayBodyLockRelease(open);
38551
- 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 }))] }) }));
38552
- }
38553
-
38554
40016
  /**
38555
40017
  * Side info panel that sits adjacent to the form content (not a modal/drawer).
38556
40018
  * The parent page is responsible for layout: render this inside a flex row
@@ -67256,59 +68718,6 @@ function useIsTablet() {
67256
68718
  return useMediaQuery(`(min-width: ${MOBILE_MAX + 1}px) and (max-width: ${TABLET_MAX}px)`);
67257
68719
  }
67258
68720
 
67259
- // Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
67260
- // labels that are not actually clipped.
67261
- const OVERFLOW_TOLERANCE_PX = 1;
67262
- function findClippedLabel(root) {
67263
- const spans = root.querySelectorAll(':scope > span');
67264
- for (const span of Array.from(spans)) {
67265
- if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX) {
67266
- return span;
67267
- }
67268
- }
67269
- return null;
67270
- }
67271
- /**
67272
- * Returns the full text of the first direct-child `<span>` of `ref` that is
67273
- * clipped by its container (i.e. showing an ellipsis), else `null` — so callers
67274
- * can surface a tooltip only when the label is actually unreadable.
67275
- *
67276
- * Re-measures on element resize (sidebar expand/collapse, window resize) and on
67277
- * label text changes.
67278
- */
67279
- function useTruncatedText(ref) {
67280
- const [text, setText] = React.useState(null);
67281
- React.useEffect(() => {
67282
- const el = ref.current;
67283
- if (!el)
67284
- return;
67285
- let frame = 0;
67286
- const measure = () => {
67287
- const label = findClippedLabel(el);
67288
- setText(label?.textContent?.trim() || null);
67289
- };
67290
- const schedule = () => {
67291
- cancelAnimationFrame(frame);
67292
- frame = requestAnimationFrame(measure);
67293
- };
67294
- schedule();
67295
- const resizeObserver = new ResizeObserver(schedule);
67296
- resizeObserver.observe(el);
67297
- const mutationObserver = new MutationObserver(schedule);
67298
- mutationObserver.observe(el, {
67299
- characterData: true,
67300
- childList: true,
67301
- subtree: true,
67302
- });
67303
- return () => {
67304
- cancelAnimationFrame(frame);
67305
- resizeObserver.disconnect();
67306
- mutationObserver.disconnect();
67307
- };
67308
- }, [ref]);
67309
- return text;
67310
- }
67311
-
67312
68721
  const SIDEBAR_COOKIE_NAME = 'sidebar_state';
67313
68722
  const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
67314
68723
  const SIDEBAR_WIDTH = '16rem';
@@ -67547,37 +68956,6 @@ const AppSidebar = ({ brand, navGroups = [], footer, className, }) => {
67547
68956
  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, {})] }));
67548
68957
  };
67549
68958
 
67550
- /** Label line + input block — mirrors a `Field`. */
67551
- function FieldSkeleton() {
67552
- 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" })] }));
67553
- }
67554
- /**
67555
- * Loading placeholder that matches a `FormSectionCard` — the tinted header band
67556
- * (icon square + title + description) above a body of `Field` placeholders and
67557
- * an optional footer action row.
67558
- */
67559
- function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
67560
- 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" })] }))] })] }));
67561
- }
67562
- /** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
67563
- function TableSkeleton({ rows = 8 }) {
67564
- 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)))] }));
67565
- }
67566
- /** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
67567
- function TableRowsSkeleton({ rows = 10, className }) {
67568
- 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) => (
67569
- // shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
67570
- jsxRuntime.jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
67571
- }
67572
- /** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
67573
- function DetailPageSkeleton({ sections = 3, }) {
67574
- 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)))] }));
67575
- }
67576
- /** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
67577
- function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
67578
- 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 })] }));
67579
- }
67580
-
67581
68959
  const SlideOut = ({ open, onOpenChange, ...props }) => {
67582
68960
  const scheduleLockRelease = useOverlayBodyLockRelease(open);
67583
68961
  return (jsxRuntime.jsx(DialogPrimitive__namespace.Root, { ...props, open: open, onOpenChange: (next) => {
@@ -75525,6 +76903,236 @@ const FileUploader = ({ accept, multiple = true, maxSize = 50, maxFiles = 5, lab
75525
76903
  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 }))] }));
75526
76904
  };
75527
76905
 
76906
+ /** The value narrowed to one control type, or undefined when it holds another (or none). */
76907
+ function valueOfType(value, type) {
76908
+ return value?.type === type ? value : undefined;
76909
+ }
76910
+ /** Each builder returns `undefined` for an empty selection so cleared filters drop out of state. */
76911
+ const toListValue = (values) => values.length ? { type: 'list', values } : undefined;
76912
+ const toScaleValue = (range) => (range ? { type: 'scale', range } : undefined);
76913
+ const toNumberValue = (range) => range && (range.min !== undefined || range.max !== undefined)
76914
+ ? { type: 'number', range }
76915
+ : undefined;
76916
+ const toIdsValue = (ids) => ids.length ? { type: 'ids', ids } : undefined;
76917
+ const toContainsValue = (text) => text.trim() ? { type: 'contains', text: text.trim() } : undefined;
76918
+ const toDateValue = (range) => range && (range.preset || range.from || range.to)
76919
+ ? { type: 'date', range }
76920
+ : undefined;
76921
+ const toBoolValue = (value) => value === 'any' ? undefined : { type: 'bool', value };
76922
+ const DEFAULT_CELL_PLACEHOLDERS = {
76923
+ list: 'All',
76924
+ scale: 'All',
76925
+ number: '',
76926
+ ids: 'Paste IDs…',
76927
+ contains: 'Contains…',
76928
+ date: 'Any date',
76929
+ bool: 'Any',
76930
+ };
76931
+ function getCellState(field, value) {
76932
+ if (field.disabled)
76933
+ return 'disabled';
76934
+ return isFilterValueActive(value) ? 'applied' : 'empty';
76935
+ }
76936
+ /** Human-readable value for chips and card summaries, e.g. `Red, Blue`, `1–3`, `Last 30 days`. */
76937
+ function describeFilterValue(field, value) {
76938
+ if (!value || !isFilterValueActive(value))
76939
+ return '';
76940
+ const options = field.options ?? [];
76941
+ switch (value.type) {
76942
+ case 'list':
76943
+ return options
76944
+ .filter((option) => value.values.includes(option.value))
76945
+ .map((option) => option.label)
76946
+ .concat(value.values.filter((v) => !options.some((option) => option.value === v)))
76947
+ .join(', ');
76948
+ case 'scale':
76949
+ return formatScaleRange(options, value.range);
76950
+ case 'number':
76951
+ return formatNumberRange(value.range);
76952
+ case 'ids':
76953
+ return value.ids.length === 1 ? value.ids[0] : `${value.ids.length} IDs`;
76954
+ case 'contains':
76955
+ return `“${value.text}”`;
76956
+ case 'date':
76957
+ return formatDateRange(value.range);
76958
+ case 'bool':
76959
+ return getOptionLabel([
76960
+ { value: 'yes', label: 'Yes' },
76961
+ { value: 'no', label: 'No' },
76962
+ ], value.value);
76963
+ }
76964
+ }
76965
+ /** Short value shown on the filter-row trigger, e.g. `Red +1`, `VG – F`, `A-102`, `3 IDs`. */
76966
+ function getCellLabel(field, value) {
76967
+ if (!value || !isFilterValueActive(value))
76968
+ return '';
76969
+ if (value.type === 'list')
76970
+ return summarizeSelection(value.values, field.options ?? []);
76971
+ if (value.type === 'scale')
76972
+ return formatScaleRange(field.options ?? [], value.range, field.shortLabels);
76973
+ return describeFilterValue(field, value);
76974
+ }
76975
+ /** Filter-row popovers hold the filter's card at a compact, fixed width. */
76976
+ function getPopoverWidthClassName(field) {
76977
+ if (field.type === 'date')
76978
+ return 'w-96';
76979
+ if (field.type === 'bool')
76980
+ return 'w-60';
76981
+ return 'w-64';
76982
+ }
76983
+ const POPOVER_TILE_COLUMNS = 2;
76984
+ /** Above this many options, chips / tiles give way to the searchable checkbox list. */
76985
+ const MAX_PILL_OPTIONS = 10;
76986
+ /** The list layout actually used: the configured one, or the checkbox list once there are too many options for pills. */
76987
+ function resolveListLayout(field) {
76988
+ return (field.options?.length ?? 0) > MAX_PILL_OPTIONS
76989
+ ? 'list'
76990
+ : (field.layout ?? 'chips');
76991
+ }
76992
+ /** The empty single-select dropdown on a card: `inputPlaceholder`, else `Any <label>` (set `inputPlaceholder` for acronyms). */
76993
+ const getSingleSelectPlaceholder = (field) => field.inputPlaceholder ?? `Any ${field.label.toLowerCase()}`;
76994
+ /** Popover variant: the same control and layout as the card (pills up to 10 options, then the list); tile grids drop to two columns. */
76995
+ function toPopoverField(field) {
76996
+ if (field.type === 'scale' ||
76997
+ (field.type === 'list' && resolveListLayout(field) === 'tiles')) {
76998
+ return { ...field, columns: POPOVER_TILE_COLUMNS };
76999
+ }
77000
+ return field;
77001
+ }
77002
+ /** ID lists and searchable lists carry their own "x selected · Clear" row, so the card skips its Clear (and, in a popover, its title). */
77003
+ const ownsClearRow = (field) => field.type === 'ids' ||
77004
+ (field.type === 'list' && resolveListLayout(field) === 'list');
77005
+ /** Popover header text in place of the title: `2 of 17 selected`, or the applied value (`VG – F`, `Last 30 days`); none when nothing is applied. */
77006
+ function getPopoverStatus(field, value) {
77007
+ if (ownsClearRow(field))
77008
+ return undefined;
77009
+ if (field.type === 'list') {
77010
+ return formatSelectedCount(valueOfType(value, 'list')?.values.length ?? 0, field.options?.length ?? 0);
77011
+ }
77012
+ // Nothing applied: the trigger already reads "Any", so the popover skips the header.
77013
+ return describeFilterValue(field, value) || undefined;
77014
+ }
77015
+
77016
+ /** Single-choice list on a card, as the design's dropdown ("Any supplier"); the filter row lists the same options as a pick-one list. */
77017
+ function SingleSelectFilter({ field, selected, onSelect, }) {
77018
+ const options = field.options ?? [];
77019
+ 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 }));
77020
+ }
77021
+ /** The control alone — identical in a filter-row popover and on a card, except the list layout. Compose it into custom cards. */
77022
+ function FilterFieldControl({ field, value, onChange, fiscalYearStartMonth, fill, inPopover, }) {
77023
+ const ariaLabel = `${field.label} filter`;
77024
+ switch (field.type) {
77025
+ case 'list': {
77026
+ if (field.single && !inPopover) {
77027
+ return (jsxRuntime.jsx(SingleSelectFilter, { field: field, selected: valueOfType(value, 'list')?.values[0], onSelect: (next) => onChange(toListValue([next])) }));
77028
+ }
77029
+ const layout = resolveListLayout(field);
77030
+ 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, single: field.single }));
77031
+ }
77032
+ case 'scale':
77033
+ return (jsxRuntime.jsx(ScaleRangeFilter, { ariaLabel: ariaLabel, options: field.options ?? [], value: valueOfType(value, 'scale')?.range, onChange: (range) => onChange(toScaleValue(range)), columns: field.columns, fill: fill }));
77034
+ case 'number':
77035
+ return (jsxRuntime.jsx(NumberRangeInputs, { ariaLabel: field.label, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), presets: field.presets, presetsLabel: field.presetsLabel }));
77036
+ case 'ids':
77037
+ return (jsxRuntime.jsx(IdListInput, { ariaLabel: ariaLabel, value: valueOfType(value, 'ids')?.ids ?? [], onChange: (ids) => onChange(toIdsValue(ids)), placeholder: field.inputPlaceholder,
77038
+ // Cards show one shared hint instead of a helper under every box.
77039
+ helperText: inPopover ? field.helperText : '' }));
77040
+ case 'contains':
77041
+ return (jsxRuntime.jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "field", placeholder: field.inputPlaceholder, value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)) }));
77042
+ case 'date':
77043
+ return (jsxRuntime.jsx(DateRangeFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'date')?.range, onChange: (range) => onChange(toDateValue(range)), fiscalYearStartMonth: fiscalYearStartMonth }));
77044
+ case 'bool':
77045
+ return (jsxRuntime.jsx(TriStateFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'bool')?.value ?? 'any', onChange: (next) => onChange(toBoolValue(next)) }));
77046
+ }
77047
+ }
77048
+ /** Filter-row cell: inline input for number/contains, otherwise a trigger that opens the control in a popover. */
77049
+ function FilterFieldCell({ field, value, onChange, fiscalYearStartMonth, className, }) {
77050
+ const state = getCellState(field, value);
77051
+ const ariaLabel = `${field.label} filter`;
77052
+ const placeholder = field.placeholder ?? DEFAULT_CELL_PLACEHOLDERS[field.type];
77053
+ const clear = () => onChange(undefined);
77054
+ if (field.type === 'number' && state !== 'disabled') {
77055
+ return (jsxRuntime.jsx(NumberExpressionFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), placeholder: placeholder, note: field.note, ruleExamples: field.ruleExamples, className: className }));
77056
+ }
77057
+ if (field.type === 'contains' && state !== 'disabled') {
77058
+ return (jsxRuntime.jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "cell", value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)), placeholder: placeholder, className: className }));
77059
+ }
77060
+ 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 }) }));
77061
+ }
77062
+ /** 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`). */
77063
+ function FilterFieldCard({ field, value, onChange, fiscalYearStartMonth, action, className, mode, }) {
77064
+ const active = isFilterValueActive(value);
77065
+ const listCount = valueOfType(value, 'list')?.values.length;
77066
+ // In a filter-row popover the column header already names the filter.
77067
+ const inPopover = mode === 'popover';
77068
+ 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'
77069
+ ? describeFilterValue(field, value)
77070
+ : undefined, action: action, onClear: active && !ownsClearRow(field)
77071
+ ? () => onChange(undefined)
77072
+ : 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' }) }));
77073
+ }
77074
+ function FilterField(props) {
77075
+ const { mode, ...rest } = props;
77076
+ return mode === 'cell' ? (jsxRuntime.jsx(FilterFieldCell, { ...rest })) : (jsxRuntime.jsx(FilterFieldCard, { mode: mode, ...rest }));
77077
+ }
77078
+
77079
+ /** Both leave without applying — the draft is discarded. */
77080
+ const BACK_LABEL = 'Back without applying';
77081
+ const CLOSE_LABEL = 'Close without applying';
77082
+ const LOADING_LABEL = 'Loading filters';
77083
+ const ERROR_TITLE = "Couldn't load filters";
77084
+ const DEFAULT_ERROR_MESSAGE = 'Something went wrong while loading the filters. Check your connection and try again.';
77085
+ const RETRY_LABEL = 'Try again';
77086
+
77087
+ /** Placeholder cards while the filters load; roughly the first rows of a card grid. */
77088
+ const SKELETON_CARD_COUNT = 8;
77089
+ const SKELETON_GRID_CLASS_NAME = 'grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4';
77090
+
77091
+ const DEFAULT_SKELETON_CARDS = Array.from({ length: SKELETON_CARD_COUNT }, (_, index) => `card-${index}`);
77092
+ /** Loading placeholder: the page's own skeleton, or generic list cards. */
77093
+ function FilterSurfaceSkeleton({ children, }) {
77094
+ return (jsxRuntime.jsx("div", { role: "status", "aria-label": LOADING_LABEL, children: children ?? (jsxRuntime.jsx("div", { className: SKELETON_GRID_CLASS_NAME, children: DEFAULT_SKELETON_CARDS.map((id) => (jsxRuntime.jsx(FilterCardSkeleton, {}, id))) })) }));
77095
+ }
77096
+ /** Shown in place of the cards when the filters couldn't load. */
77097
+ function FilterSurfaceError({ message, onRetry, }) {
77098
+ return (jsxRuntime.jsxs("div", { role: "alert", className: "flex flex-col items-center rounded-xl border border-border bg-card px-6 py-12 text-center", children: [jsxRuntime.jsx("span", { className: "flex size-10 items-center justify-center rounded-full bg-destructive/10 text-destructive", children: jsxRuntime.jsx(TriangleAlert, { "aria-hidden": "true", className: "size-5" }) }), jsxRuntime.jsx("p", { className: "mt-4 text-base font-semibold text-foreground", children: ERROR_TITLE }), jsxRuntime.jsx("p", { className: "mt-1.5 max-w-sm text-sm text-muted-foreground", children: message }), onRetry && (jsxRuntime.jsx(Button, { appearance: "outline", color: "secondary", size: "md", leftIcon: jsxRuntime.jsx(RotateCcw, {}), onClick: onRetry, className: "mt-5", children: RETRY_LABEL }))] }));
77099
+ }
77100
+
77101
+ const NESTED_LAYER_SELECTOR = '[data-slot="popover-content"], [role="dialog"], [role="menu"], [role="listbox"]';
77102
+ function useCloseOnEscape(onClose) {
77103
+ React.useEffect(() => {
77104
+ const handleKeyDown = (event) => {
77105
+ if (event.key !== 'Escape' || event.defaultPrevented)
77106
+ return;
77107
+ // Escape inside an open popover, dialog or menu only closes that layer (Radix doesn't mark the event handled).
77108
+ if (event.target instanceof Element &&
77109
+ event.target.closest(NESTED_LAYER_SELECTOR))
77110
+ return;
77111
+ onClose();
77112
+ };
77113
+ document.addEventListener('keydown', handleKeyDown);
77114
+ return () => document.removeEventListener('keydown', handleKeyDown);
77115
+ }, [onClose]);
77116
+ }
77117
+ function useFilterSurfaceMore(defaultExpanded = false) {
77118
+ const [expanded, setExpanded] = React.useState(defaultExpanded);
77119
+ return { expanded, toggle: () => setExpanded((current) => !current) };
77120
+ }
77121
+
77122
+ /** Full-page filter screen (e.g. an advanced search): header, scrolling card grid, sticky apply footer. */
77123
+ function FilterSurface({ title, headerActions, footerChips, footerActions, onClose, status = 'ready', errorMessage, onRetry, skeleton, children, }) {
77124
+ useCloseOnEscape(onClose);
77125
+ return (jsxRuntime.jsxs("div", { role: "region", "aria-label": title, className: "flex h-full min-h-0 flex-col bg-background", children: [jsxRuntime.jsxs("header", { className: "sticky top-0 z-20 flex shrink-0 flex-wrap items-end justify-between gap-3 bg-background px-3 pt-2 pb-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: "min-h-0 flex-1 overflow-y-auto px-3 pb-3", children: status === 'loading' ? (jsxRuntime.jsx(FilterSurfaceSkeleton, { children: skeleton })) : status === 'error' ? (jsxRuntime.jsx(FilterSurfaceError, { message: errorMessage ?? DEFAULT_ERROR_MESSAGE, onRetry: onRetry })) : (jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: children })) }), status === 'ready' && (footerChips || footerActions) && (jsxRuntime.jsxs("footer", { className: "sticky bottom-0 z-20 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 })] }))] }));
77126
+ }
77127
+ function FilterSurfaceGroup({ title, className, children, }) {
77128
+ 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-3 lg:grid-cols-6', className), children: children })] }));
77129
+ }
77130
+ /** Collapsed "More filters" divider that reveals extra cards. */
77131
+ function FilterSurfaceMore({ label, defaultExpanded, children, }) {
77132
+ const { expanded, toggle } = useFilterSurfaceMore(defaultExpanded);
77133
+ return (jsxRuntime.jsxs("section", { className: "flex flex-col gap-3", 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] }));
77134
+ }
77135
+
75528
77136
  /** Falls back to counting the current page when the caller has no total. */
75529
77137
  function resolveUnreadCount(notifications, unreadCount) {
75530
77138
  if (typeof unreadCount === 'number')
@@ -78102,6 +79710,7 @@ exports.ACTIVITY_CATEGORIES = ACTIVITY_CATEGORIES;
78102
79710
  exports.ACTIVITY_CATEGORY_META = ACTIVITY_CATEGORY_META;
78103
79711
  exports.ActionBadge = ActionBadge;
78104
79712
  exports.ActionButtonWithTooltip = ActionButtonWithTooltip;
79713
+ exports.ActiveFilterChips = ActiveFilterChips;
78105
79714
  exports.ActivityFeed = ActivityFeed;
78106
79715
  exports.AdvancedSearchDrawer = AdvancedSearchDrawer;
78107
79716
  exports.Alert = Alert;
@@ -78125,6 +79734,7 @@ exports.CollapsibleTrigger = CollapsibleTrigger;
78125
79734
  exports.CompanyCard = CompanyCard;
78126
79735
  exports.ConfirmDialog = ConfirmDialog;
78127
79736
  exports.ContactTypeFilter = ContactTypeFilter;
79737
+ exports.ContainsFilter = ContainsFilter;
78128
79738
  exports.CopyButton = CopyButton;
78129
79739
  exports.CountrySelect = CountrySelect;
78130
79740
  exports.CreateFormPageHeader = CreateFormPageHeader;
@@ -78137,11 +79747,13 @@ exports.CustomFieldInput = CustomFieldInput;
78137
79747
  exports.CustomFieldValue = CustomFieldValue;
78138
79748
  exports.CustomTable = CustomTable;
78139
79749
  exports.CustomizeColumnsDrawer = CustomizeColumnsDrawer;
79750
+ exports.DATE_PRESET_OPTIONS = DATE_PRESET_OPTIONS;
78140
79751
  exports.DIAMOND_AUDIT_CONFIG = DIAMOND_AUDIT_CONFIG;
78141
79752
  exports.DashboardShell = DashboardShell;
78142
79753
  exports.DataEditableTable = DataEditableTable;
78143
79754
  exports.DataTable = DataTable;
78144
79755
  exports.DateInput = DateInput;
79756
+ exports.DateRangeFilter = DateRangeFilter;
78145
79757
  exports.DetailChip = DetailChip;
78146
79758
  exports.DetailPageLayout = DetailPageLayout;
78147
79759
  exports.DetailPageSkeleton = DetailPageSkeleton;
@@ -78166,11 +79778,23 @@ exports.DropdownMenuSubTrigger = DropdownMenuSubTrigger;
78166
79778
  exports.DropdownMenuTrigger = DropdownMenuTrigger;
78167
79779
  exports.EmptyValue = EmptyValue;
78168
79780
  exports.EntityHeader = EntityHeader;
79781
+ exports.FILTER_COUNT_BADGE_CLASS_NAME = FILTER_COUNT_BADGE_CLASS_NAME;
78169
79782
  exports.Field = Field;
78170
79783
  exports.FieldSkeleton = FieldSkeleton;
78171
79784
  exports.FileUploader = FileUploader;
79785
+ exports.FilterCardSkeleton = FilterCardSkeleton;
79786
+ exports.FilterCellPopover = FilterCellPopover;
79787
+ exports.FilterEmptyState = FilterEmptyState;
79788
+ exports.FilterField = FilterField;
79789
+ exports.FilterFieldCard = FilterFieldCard;
79790
+ exports.FilterFieldCell = FilterFieldCell;
79791
+ exports.FilterFieldControl = FilterFieldControl;
78172
79792
  exports.FilterMultiSelect = FilterMultiSelect;
79793
+ exports.FilterPanel = FilterPanel;
78173
79794
  exports.FilterSelect = FilterSelect;
79795
+ exports.FilterSurface = FilterSurface;
79796
+ exports.FilterSurfaceGroup = FilterSurfaceGroup;
79797
+ exports.FilterSurfaceMore = FilterSurfaceMore;
78174
79798
  exports.FormSectionCard = FormSectionCard;
78175
79799
  exports.FormSectionCardSkeleton = FormSectionCardSkeleton;
78176
79800
  exports.GEM_AUDIT_CONFIG = GEM_AUDIT_CONFIG;
@@ -78180,6 +79804,7 @@ exports.HistoryTimelineShimmer = HistoryTimelineShimmer;
78180
79804
  exports.INVOICE_AUDIT_CONFIG = INVOICE_AUDIT_CONFIG;
78181
79805
  exports.IconButton = IconButton;
78182
79806
  exports.IdHyperlinkText = IdHyperlinkText;
79807
+ exports.IdListInput = IdListInput;
78183
79808
  exports.InAppNotificationCard = InAppNotificationCard;
78184
79809
  exports.InAppNotificationsPanel = InAppNotificationsPanel;
78185
79810
  exports.InfoBanner = InfoBanner;
@@ -78215,7 +79840,9 @@ exports.NavbarAvatar = NavbarAvatar;
78215
79840
  exports.NavbarIconButton = NavbarIconButton;
78216
79841
  exports.NavbarSearch = NavbarSearch;
78217
79842
  exports.NavbarTitle = NavbarTitle;
79843
+ exports.NumberExpressionFilter = NumberExpressionFilter;
78218
79844
  exports.NumberInput = NumberInput;
79845
+ exports.NumberRangeInputs = NumberRangeInputs;
78219
79846
  exports.NumberedStepCard = NumberedStepCard;
78220
79847
  exports.OtpInput = OtpInput;
78221
79848
  exports.OwnershipFilter = OwnershipFilter;
@@ -78226,6 +79853,7 @@ exports.PageTabs = PageTabs;
78226
79853
  exports.Pagination = Pagination;
78227
79854
  exports.PaginationSelect = PaginationSelect;
78228
79855
  exports.PartnerShareCard = PartnerShareCard;
79856
+ exports.PickListFilter = PickListFilter;
78229
79857
  exports.PriceInput = PriceInput;
78230
79858
  exports.Protected = Protected;
78231
79859
  exports.PurchaseOrderComboBox = PurchaseOrderComboBox;
@@ -78234,8 +79862,14 @@ exports.RadioCardGroup = RadioCardGroup;
78234
79862
  exports.ReadMoreText = ReadMoreText;
78235
79863
  exports.RefreshButton = RefreshButton;
78236
79864
  exports.RichTextarea = RichTextarea$1;
79865
+ exports.SAVED_SEARCH_NAME_MAX_LENGTH = SAVED_SEARCH_NAME_MAX_LENGTH;
78237
79866
  exports.SEARCHABLE_SELECT_PAGE_SIZE = SEARCHABLE_SELECT_PAGE_SIZE;
78238
79867
  exports.SafeImage = SafeImage;
79868
+ exports.SaveSearchDialog = SaveSearchDialog;
79869
+ exports.SavedSearchChipList = SavedSearchChipList;
79870
+ exports.SavedSearchesMenu = SavedSearchesMenu;
79871
+ exports.ScaleRangeFilter = ScaleRangeFilter;
79872
+ exports.ScrollFade = ScrollFade;
78239
79873
  exports.SearchBox = SearchBox;
78240
79874
  exports.SearchInput = SearchInput;
78241
79875
  exports.SearchableSelect = SearchableSelect;
@@ -78292,7 +79926,9 @@ exports.TagsInput = TagsInput;
78292
79926
  exports.TextHyperlink = TextHyperlink;
78293
79927
  exports.TimePicker = TimePicker;
78294
79928
  exports.ToggleSwitch = ToggleSwitch;
79929
+ exports.TriStateFilter = TriStateFilter;
78295
79930
  exports.TruncateTooltip = TruncateTooltip;
79931
+ exports.TruncatedLabel = TruncatedLabel;
78296
79932
  exports.WarehouseComboBox = WarehouseComboBox;
78297
79933
  exports.WarehouseFilter = WarehouseFilter;
78298
79934
  exports.ZoomSplitViewer = ZoomSplitViewer;
@@ -78304,18 +79940,26 @@ exports.buildBulkShareTitle = buildBulkShareTitle;
78304
79940
  exports.buildInventoryPublicUrl = buildInventoryPublicUrl;
78305
79941
  exports.buildInventoryRowProps = buildInventoryRowProps;
78306
79942
  exports.buildInventoryShareTitle = buildInventoryShareTitle;
79943
+ exports.buildNumberRuleHelp = buildNumberRuleHelp;
78307
79944
  exports.buildWhatsappUrl = buildWhatsappUrl;
78308
79945
  exports.buttonVariants = buttonVariants;
78309
79946
  exports.cn = cn;
78310
79947
  exports.countries = countries;
78311
79948
  exports.countryByCode = countryByCode;
78312
79949
  exports.createVideoMediaItem = createVideoMediaItem;
79950
+ exports.describeFilterValue = describeFilterValue;
78313
79951
  exports.dropdownMenuItemDestructiveClass = dropdownMenuItemDestructiveClass;
79952
+ exports.expandScaleRange = expandScaleRange;
78314
79953
  exports.fieldTypeIcon = fieldTypeIcon;
79954
+ exports.filterSavedSearches = filterSavedSearches;
78315
79955
  exports.findRegion = findRegion;
78316
79956
  exports.flagEmoji = flagEmoji;
78317
79957
  exports.formatAddressLocation = formatAddressLocation;
79958
+ exports.formatDateRange = formatDateRange;
78318
79959
  exports.formatFileSize = formatFileSize;
79960
+ exports.formatNumberRange = formatNumberRange;
79961
+ exports.formatScaleRange = formatScaleRange;
79962
+ exports.formatSelectedCount = formatSelectedCount;
78319
79963
  exports.generateActionDescription = generateActionDescription;
78320
79964
  exports.generateTitle = generateTitle;
78321
79965
  exports.getBadgeTypeForStatus = getBadgeTypeForStatus;
@@ -78327,16 +79971,30 @@ exports.iconButtonVariants = iconButtonVariants;
78327
79971
  exports.inAppNotificationCardA11y = inAppNotificationCardA11y;
78328
79972
  exports.inAppNotificationsPanelA11y = inAppNotificationsPanelA11y;
78329
79973
  exports.isBlank = isBlank;
79974
+ exports.isDuplicateSearchName = isDuplicateSearchName;
79975
+ exports.isFilterValueActive = isFilterValueActive;
78330
79976
  exports.isIndiaCountry = isIndiaCountry;
78331
79977
  exports.isKnownRegion = isKnownRegion;
78332
79978
  exports.isPathActive = isPathActive;
78333
79979
  exports.isValidAlpha2CountryCode = isValidAlpha2CountryCode;
79980
+ exports.isValidSearchName = isValidSearchName;
78334
79981
  exports.isValueEmpty = isValueEmpty;
78335
79982
  exports.notify = notify;
79983
+ exports.parseNumberExpression = parseNumberExpression;
78336
79984
  exports.releaseStaleOverlayBodyLock = releaseStaleOverlayBodyLock;
78337
79985
  exports.renderBadge = renderBadge;
78338
79986
  exports.resolveCountryCode = resolveCountryCode;
79987
+ exports.resolveDatePreset = resolveDatePreset;
79988
+ exports.resolveDateRange = resolveDateRange;
79989
+ exports.splitIdList = splitIdList;
78339
79990
  exports.toAddressFormValues = toAddressFormValues;
79991
+ exports.toBoolValue = toBoolValue;
79992
+ exports.toContainsValue = toContainsValue;
79993
+ exports.toDateValue = toDateValue;
79994
+ exports.toIdsValue = toIdsValue;
79995
+ exports.toListValue = toListValue;
79996
+ exports.toNumberValue = toNumberValue;
79997
+ exports.toScaleValue = toScaleValue;
78340
79998
  exports.useAuditShowMore = useAuditShowMore;
78341
79999
  exports.useBadge = useBadge;
78342
80000
  exports.useButton = useButton;
@@ -78344,6 +80002,7 @@ exports.useDropdownMenu = useDropdownMenu;
78344
80002
  exports.useInAppNotificationsPanel = useInAppNotificationsPanel;
78345
80003
  exports.useNavbar = useNavbar;
78346
80004
  exports.useSidebar = useSidebar;
80005
+ exports.valueOfType = valueOfType;
78347
80006
  exports.videoThumbnailSrc = videoThumbnailSrc;
78348
80007
  exports.watchOverlayBodyLock = watchOverlayBodyLock;
78349
80008
  //# sourceMappingURL=index.cjs.js.map