@caratlogic/design-system 0.1.31 → 0.1.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/components/atoms/ActionButtonWithTooltip/ActionButtonWithTooltip.d.ts.map +1 -1
  2. package/dist/components/atoms/NumberInput/NumberInput.d.ts.map +1 -1
  3. package/dist/components/atoms/NumberInput/NumberInput.types.d.ts +4 -0
  4. package/dist/components/atoms/NumberInput/NumberInput.types.d.ts.map +1 -1
  5. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.d.ts.map +1 -1
  6. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.parts.d.ts +1 -0
  7. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.parts.d.ts.map +1 -1
  8. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.types.d.ts +5 -11
  9. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.types.d.ts.map +1 -1
  10. package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts +1 -1
  11. package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts.map +1 -1
  12. package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts +16 -0
  13. package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts.map +1 -1
  14. package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts +8 -1
  15. package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts.map +1 -1
  16. package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts +20 -0
  17. package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts.map +1 -1
  18. package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts +7 -1
  19. package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts.map +1 -1
  20. package/dist/components/molecules/DocumentDeleteDialog/DocumentDeleteDialog.d.ts +1 -1
  21. package/dist/components/molecules/DocumentDeleteDialog/DocumentDeleteDialog.d.ts.map +1 -1
  22. package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts +8 -3
  23. package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts.map +1 -1
  24. package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts +9 -0
  25. package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts.map +1 -1
  26. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts +3 -0
  27. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts.map +1 -0
  28. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts +6 -0
  29. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts.map +1 -0
  30. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts +16 -0
  31. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts.map +1 -0
  32. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts +7 -0
  33. package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts.map +1 -0
  34. package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts +3 -0
  35. package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts.map +1 -0
  36. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts +2 -0
  37. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts.map +1 -0
  38. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts +6 -0
  39. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts.map +1 -0
  40. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts +9 -0
  41. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts.map +1 -0
  42. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts +11 -0
  43. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts.map +1 -0
  44. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts +3 -0
  45. package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts.map +1 -0
  46. package/dist/components/molecules/Filters/ContainsFilter/index.d.ts +3 -0
  47. package/dist/components/molecules/Filters/ContainsFilter/index.d.ts.map +1 -0
  48. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts +3 -0
  49. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts.map +1 -0
  50. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts +6 -0
  51. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts.map +1 -0
  52. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts +11 -0
  53. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts.map +1 -0
  54. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts +10 -0
  55. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts.map +1 -0
  56. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts +11 -0
  57. package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts.map +1 -0
  58. package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts +3 -0
  59. package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts.map +1 -0
  60. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts +3 -0
  61. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts.map +1 -0
  62. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts +6 -0
  63. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts.map +1 -0
  64. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts +24 -0
  65. package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts.map +1 -0
  66. package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts +3 -0
  67. package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts.map +1 -0
  68. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts +6 -0
  69. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts.map +1 -0
  70. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts +14 -0
  71. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts.map +1 -0
  72. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts +5 -0
  73. package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts.map +1 -0
  74. package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts +3 -0
  75. package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts.map +1 -0
  76. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts +6 -0
  77. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts.map +1 -0
  78. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts +28 -0
  79. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts.map +1 -0
  80. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts +4 -0
  81. package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts.map +1 -0
  82. package/dist/components/molecules/Filters/FilterPanel/index.d.ts +3 -0
  83. package/dist/components/molecules/Filters/FilterPanel/index.d.ts.map +1 -0
  84. package/dist/components/molecules/Filters/Filters.hooks.d.ts +20 -0
  85. package/dist/components/molecules/Filters/Filters.hooks.d.ts.map +1 -0
  86. package/dist/components/molecules/Filters/Filters.types.d.ts +66 -0
  87. package/dist/components/molecules/Filters/Filters.types.d.ts.map +1 -0
  88. package/dist/components/molecules/Filters/Filters.utils.d.ts +53 -0
  89. package/dist/components/molecules/Filters/Filters.utils.d.ts.map +1 -0
  90. package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts +2 -0
  91. package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts.map +1 -0
  92. package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts +6 -0
  93. package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts.map +1 -0
  94. package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts +10 -0
  95. package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts.map +1 -0
  96. package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts +10 -0
  97. package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts.map +1 -0
  98. package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts +4 -0
  99. package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts.map +1 -0
  100. package/dist/components/molecules/Filters/IdListInput/index.d.ts +3 -0
  101. package/dist/components/molecules/Filters/IdListInput/index.d.ts.map +1 -0
  102. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts +5 -0
  103. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts.map +1 -0
  104. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts +6 -0
  105. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts.map +1 -0
  106. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts +16 -0
  107. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts.map +1 -0
  108. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts +14 -0
  109. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts.map +1 -0
  110. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts +8 -0
  111. package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts.map +1 -0
  112. package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts +3 -0
  113. package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts.map +1 -0
  114. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts +3 -0
  115. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts.map +1 -0
  116. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts +6 -0
  117. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts.map +1 -0
  118. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts +15 -0
  119. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts.map +1 -0
  120. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts +17 -0
  121. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts.map +1 -0
  122. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts +12 -0
  123. package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts.map +1 -0
  124. package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts +3 -0
  125. package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts.map +1 -0
  126. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts +2 -0
  127. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts.map +1 -0
  128. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts +6 -0
  129. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts.map +1 -0
  130. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts +3 -0
  131. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts.map +1 -0
  132. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts +32 -0
  133. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts.map +1 -0
  134. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts +19 -0
  135. package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts.map +1 -0
  136. package/dist/components/molecules/Filters/PickListFilter/index.d.ts +3 -0
  137. package/dist/components/molecules/Filters/PickListFilter/index.d.ts.map +1 -0
  138. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts +6 -0
  139. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts.map +1 -0
  140. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts +4 -0
  141. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts.map +1 -0
  142. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts +22 -0
  143. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts.map +1 -0
  144. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts +7 -0
  145. package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts.map +1 -0
  146. package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts +3 -0
  147. package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts.map +1 -0
  148. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts +6 -0
  149. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts.map +1 -0
  150. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts +7 -0
  151. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts.map +1 -0
  152. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts +15 -0
  153. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts.map +1 -0
  154. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts +4 -0
  155. package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts.map +1 -0
  156. package/dist/components/molecules/Filters/ScrollFade/index.d.ts +3 -0
  157. package/dist/components/molecules/Filters/ScrollFade/index.d.ts.map +1 -0
  158. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts +6 -0
  159. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts.map +1 -0
  160. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts +6 -0
  161. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts.map +1 -0
  162. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts +7 -0
  163. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts.map +1 -0
  164. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts +3 -0
  165. package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts.map +1 -0
  166. package/dist/components/molecules/Filters/TriStateFilter/index.d.ts +3 -0
  167. package/dist/components/molecules/Filters/TriStateFilter/index.d.ts.map +1 -0
  168. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts +6 -0
  169. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts.map +1 -0
  170. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts +5 -0
  171. package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts.map +1 -0
  172. package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts +3 -0
  173. package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts.map +1 -0
  174. package/dist/components/molecules/Filters/index.d.ts +17 -0
  175. package/dist/components/molecules/Filters/index.d.ts.map +1 -0
  176. package/dist/components/molecules/InventoryFilterSelects.d.ts.map +1 -1
  177. package/dist/components/molecules/Modal/Modal.d.ts +1 -1
  178. package/dist/components/molecules/Modal/Modal.d.ts.map +1 -1
  179. package/dist/components/molecules/Modal/Modal.types.d.ts +9 -3
  180. package/dist/components/molecules/Modal/Modal.types.d.ts.map +1 -1
  181. package/dist/components/organisms/FileUploader/ImageCropModal.d.ts.map +1 -1
  182. package/dist/components/organisms/Filters/FilterField/FilterField.d.ts +11 -0
  183. package/dist/components/organisms/Filters/FilterField/FilterField.d.ts.map +1 -0
  184. package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts +66 -0
  185. package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts.map +1 -0
  186. package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts +38 -0
  187. package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts.map +1 -0
  188. package/dist/components/organisms/Filters/FilterField/index.d.ts +4 -0
  189. package/dist/components/organisms/Filters/FilterField/index.d.ts.map +1 -0
  190. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts +4 -0
  191. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts.map +1 -0
  192. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts +9 -0
  193. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts.map +1 -0
  194. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts +6 -0
  195. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts.map +1 -0
  196. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts +26 -0
  197. package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts.map +1 -0
  198. package/dist/components/organisms/Filters/FilterSurface/index.d.ts +3 -0
  199. package/dist/components/organisms/Filters/FilterSurface/index.d.ts.map +1 -0
  200. package/dist/components/organisms/Filters/index.d.ts +3 -0
  201. package/dist/components/organisms/Filters/index.d.ts.map +1 -0
  202. package/dist/components/ui/button.d.ts.map +1 -1
  203. package/dist/components/ui/dialog.d.ts +23 -2
  204. package/dist/components/ui/dialog.d.ts.map +1 -1
  205. package/dist/index.cjs.js +1617 -353
  206. package/dist/index.cjs.js.map +1 -1
  207. package/dist/index.d.ts +2 -0
  208. package/dist/index.d.ts.map +1 -1
  209. package/dist/index.esm.js +1578 -355
  210. package/dist/index.esm.js.map +1 -1
  211. package/dist/ui.cjs.js +60 -14
  212. package/dist/ui.cjs.js.map +1 -1
  213. package/dist/ui.esm.js +59 -15
  214. package/dist/ui.esm.js.map +1 -1
  215. package/package.json +1 -1
  216. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.hooks.d.ts +0 -3
  217. package/dist/components/molecules/ConfirmDialog/ConfirmDialog.hooks.d.ts.map +0 -1
package/dist/index.esm.js CHANGED
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment as Fragment$2 } from 'react/jsx-runtime';
2
2
  import { Slot } from '@radix-ui/react-slot';
3
3
  import { toast } from 'sonner';
4
4
  import * as React from 'react';
5
- import React__default, { forwardRef, createElement, useState, useCallback, useMemo, useEffect, useRef, Fragment as Fragment$3, createContext, useContext, useLayoutEffect, cloneElement, createRef, Component, useId as useId$2, lazy, Suspense, memo, useReducer, PureComponent, useDebugValue } from 'react';
5
+ import React__default, { forwardRef, createElement, useState, useCallback, useMemo, useEffect, useRef, Fragment as Fragment$3, createContext, useContext, isValidElement, Children, useLayoutEffect, cloneElement, createRef, Component, useId as useId$2, lazy, Suspense, memo, useReducer, PureComponent, useDebugValue } from 'react';
6
6
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
7
7
  import * as SliderPrimitive from '@radix-ui/react-slider';
8
8
  import * as TabsPrimitive from '@radix-ui/react-tabs';
@@ -2668,12 +2668,12 @@ const createLucideIcon = (iconName, iconNode) => {
2668
2668
  */
2669
2669
 
2670
2670
 
2671
- const __iconNode$1s = [
2671
+ const __iconNode$1v = [
2672
2672
  ["path", { d: "M15 12H3", key: "6jk70r" }],
2673
2673
  ["path", { d: "M17 18H3", key: "1amg6g" }],
2674
2674
  ["path", { d: "M21 6H3", key: "1jwq7v" }]
2675
2675
  ];
2676
- const AlignLeft = createLucideIcon("align-left", __iconNode$1s);
2676
+ const AlignLeft = createLucideIcon("align-left", __iconNode$1v);
2677
2677
 
2678
2678
  /**
2679
2679
  * @license lucide-react v0.539.0 - ISC
@@ -2683,12 +2683,12 @@ const AlignLeft = createLucideIcon("align-left", __iconNode$1s);
2683
2683
  */
2684
2684
 
2685
2685
 
2686
- const __iconNode$1r = [
2686
+ const __iconNode$1u = [
2687
2687
  ["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
2688
2688
  ["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
2689
2689
  ["path", { d: "M10 12h4", key: "a56b0p" }]
2690
2690
  ];
2691
- const Archive = createLucideIcon("archive", __iconNode$1r);
2691
+ const Archive = createLucideIcon("archive", __iconNode$1u);
2692
2692
 
2693
2693
  /**
2694
2694
  * @license lucide-react v0.539.0 - ISC
@@ -2698,11 +2698,11 @@ const Archive = createLucideIcon("archive", __iconNode$1r);
2698
2698
  */
2699
2699
 
2700
2700
 
2701
- const __iconNode$1q = [
2701
+ const __iconNode$1t = [
2702
2702
  ["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
2703
2703
  ["path", { d: "M19 12H5", key: "x3x0zl" }]
2704
2704
  ];
2705
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1q);
2705
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1t);
2706
2706
 
2707
2707
  /**
2708
2708
  * @license lucide-react v0.539.0 - ISC
@@ -2712,11 +2712,11 @@ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1q);
2712
2712
  */
2713
2713
 
2714
2714
 
2715
- const __iconNode$1p = [
2715
+ const __iconNode$1s = [
2716
2716
  ["path", { d: "M5 12h14", key: "1ays0h" }],
2717
2717
  ["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
2718
2718
  ];
2719
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$1p);
2719
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$1s);
2720
2720
 
2721
2721
  /**
2722
2722
  * @license lucide-react v0.539.0 - ISC
@@ -2726,11 +2726,11 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$1p);
2726
2726
  */
2727
2727
 
2728
2728
 
2729
- const __iconNode$1o = [
2729
+ const __iconNode$1r = [
2730
2730
  ["path", { d: "M4.929 4.929 19.07 19.071", key: "196cmz" }],
2731
2731
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
2732
2732
  ];
2733
- const Ban = createLucideIcon("ban", __iconNode$1o);
2733
+ const Ban = createLucideIcon("ban", __iconNode$1r);
2734
2734
 
2735
2735
  /**
2736
2736
  * @license lucide-react v0.539.0 - ISC
@@ -2740,7 +2740,7 @@ const Ban = createLucideIcon("ban", __iconNode$1o);
2740
2740
  */
2741
2741
 
2742
2742
 
2743
- const __iconNode$1n = [
2743
+ const __iconNode$1q = [
2744
2744
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
2745
2745
  [
2746
2746
  "path",
@@ -2751,7 +2751,7 @@ const __iconNode$1n = [
2751
2751
  ],
2752
2752
  ["circle", { cx: "18", cy: "8", r: "3", key: "1g0gzu" }]
2753
2753
  ];
2754
- const BellDot = createLucideIcon("bell-dot", __iconNode$1n);
2754
+ const BellDot = createLucideIcon("bell-dot", __iconNode$1q);
2755
2755
 
2756
2756
  /**
2757
2757
  * @license lucide-react v0.539.0 - ISC
@@ -2761,7 +2761,7 @@ const BellDot = createLucideIcon("bell-dot", __iconNode$1n);
2761
2761
  */
2762
2762
 
2763
2763
 
2764
- const __iconNode$1m = [
2764
+ const __iconNode$1p = [
2765
2765
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
2766
2766
  ["path", { d: "M22 8c0-2.3-.8-4.3-2-6", key: "5bb3ad" }],
2767
2767
  [
@@ -2773,7 +2773,7 @@ const __iconNode$1m = [
2773
2773
  ],
2774
2774
  ["path", { d: "M4 2C2.8 3.7 2 5.7 2 8", key: "tap9e0" }]
2775
2775
  ];
2776
- const BellRing = createLucideIcon("bell-ring", __iconNode$1m);
2776
+ const BellRing = createLucideIcon("bell-ring", __iconNode$1p);
2777
2777
 
2778
2778
  /**
2779
2779
  * @license lucide-react v0.539.0 - ISC
@@ -2783,7 +2783,7 @@ const BellRing = createLucideIcon("bell-ring", __iconNode$1m);
2783
2783
  */
2784
2784
 
2785
2785
 
2786
- const __iconNode$1l = [
2786
+ const __iconNode$1o = [
2787
2787
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
2788
2788
  [
2789
2789
  "path",
@@ -2793,7 +2793,7 @@ const __iconNode$1l = [
2793
2793
  }
2794
2794
  ]
2795
2795
  ];
2796
- const Bell = createLucideIcon("bell", __iconNode$1l);
2796
+ const Bell = createLucideIcon("bell", __iconNode$1o);
2797
2797
 
2798
2798
  /**
2799
2799
  * @license lucide-react v0.539.0 - ISC
@@ -2803,13 +2803,13 @@ const Bell = createLucideIcon("bell", __iconNode$1l);
2803
2803
  */
2804
2804
 
2805
2805
 
2806
- const __iconNode$1k = [
2806
+ const __iconNode$1n = [
2807
2807
  [
2808
2808
  "path",
2809
2809
  { 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" }
2810
2810
  ]
2811
2811
  ];
2812
- const Bold$1 = createLucideIcon("bold", __iconNode$1k);
2812
+ const Bold$1 = createLucideIcon("bold", __iconNode$1n);
2813
2813
 
2814
2814
  /**
2815
2815
  * @license lucide-react v0.539.0 - ISC
@@ -2819,7 +2819,7 @@ const Bold$1 = createLucideIcon("bold", __iconNode$1k);
2819
2819
  */
2820
2820
 
2821
2821
 
2822
- const __iconNode$1j = [
2822
+ const __iconNode$1m = [
2823
2823
  [
2824
2824
  "path",
2825
2825
  {
@@ -2830,7 +2830,7 @@ const __iconNode$1j = [
2830
2830
  ["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
2831
2831
  ["path", { d: "M12 22V12", key: "d0xqtd" }]
2832
2832
  ];
2833
- const Box = createLucideIcon("box", __iconNode$1j);
2833
+ const Box = createLucideIcon("box", __iconNode$1m);
2834
2834
 
2835
2835
  /**
2836
2836
  * @license lucide-react v0.539.0 - ISC
@@ -2840,7 +2840,7 @@ const Box = createLucideIcon("box", __iconNode$1j);
2840
2840
  */
2841
2841
 
2842
2842
 
2843
- const __iconNode$1i = [
2843
+ const __iconNode$1l = [
2844
2844
  ["path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z", key: "1b4qmf" }],
2845
2845
  ["path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2", key: "i71pzd" }],
2846
2846
  ["path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2", key: "10jefs" }],
@@ -2849,7 +2849,7 @@ const __iconNode$1i = [
2849
2849
  ["path", { d: "M10 14h4", key: "kelpxr" }],
2850
2850
  ["path", { d: "M10 18h4", key: "1ulq68" }]
2851
2851
  ];
2852
- const Building2 = createLucideIcon("building-2", __iconNode$1i);
2852
+ const Building2 = createLucideIcon("building-2", __iconNode$1l);
2853
2853
 
2854
2854
  /**
2855
2855
  * @license lucide-react v0.539.0 - ISC
@@ -2859,7 +2859,7 @@ const Building2 = createLucideIcon("building-2", __iconNode$1i);
2859
2859
  */
2860
2860
 
2861
2861
 
2862
- const __iconNode$1h = [
2862
+ const __iconNode$1k = [
2863
2863
  ["path", { d: "M8 2v4", key: "1cmpym" }],
2864
2864
  ["path", { d: "M16 2v4", key: "4m81vk" }],
2865
2865
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
@@ -2871,7 +2871,7 @@ const __iconNode$1h = [
2871
2871
  ["path", { d: "M12 18h.01", key: "mhygvu" }],
2872
2872
  ["path", { d: "M16 18h.01", key: "kzsmim" }]
2873
2873
  ];
2874
- const CalendarDays = createLucideIcon("calendar-days", __iconNode$1h);
2874
+ const CalendarDays = createLucideIcon("calendar-days", __iconNode$1k);
2875
2875
 
2876
2876
  /**
2877
2877
  * @license lucide-react v0.539.0 - ISC
@@ -2881,13 +2881,13 @@ const CalendarDays = createLucideIcon("calendar-days", __iconNode$1h);
2881
2881
  */
2882
2882
 
2883
2883
 
2884
- const __iconNode$1g = [
2884
+ const __iconNode$1j = [
2885
2885
  ["path", { d: "M8 2v4", key: "1cmpym" }],
2886
2886
  ["path", { d: "M16 2v4", key: "4m81vk" }],
2887
2887
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
2888
2888
  ["path", { d: "M3 10h18", key: "8toen8" }]
2889
2889
  ];
2890
- const Calendar$1 = createLucideIcon("calendar", __iconNode$1g);
2890
+ const Calendar$1 = createLucideIcon("calendar", __iconNode$1j);
2891
2891
 
2892
2892
  /**
2893
2893
  * @license lucide-react v0.539.0 - ISC
@@ -2897,11 +2897,11 @@ const Calendar$1 = createLucideIcon("calendar", __iconNode$1g);
2897
2897
  */
2898
2898
 
2899
2899
 
2900
- const __iconNode$1f = [
2900
+ const __iconNode$1i = [
2901
2901
  ["path", { d: "M18 6 7 17l-5-5", key: "116fxf" }],
2902
2902
  ["path", { d: "m22 10-7.5 7.5L13 16", key: "ke71qq" }]
2903
2903
  ];
2904
- const CheckCheck = createLucideIcon("check-check", __iconNode$1f);
2904
+ const CheckCheck = createLucideIcon("check-check", __iconNode$1i);
2905
2905
 
2906
2906
  /**
2907
2907
  * @license lucide-react v0.539.0 - ISC
@@ -2911,8 +2911,8 @@ const CheckCheck = createLucideIcon("check-check", __iconNode$1f);
2911
2911
  */
2912
2912
 
2913
2913
 
2914
- const __iconNode$1e = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
2915
- const Check = createLucideIcon("check", __iconNode$1e);
2914
+ const __iconNode$1h = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
2915
+ const Check = createLucideIcon("check", __iconNode$1h);
2916
2916
 
2917
2917
  /**
2918
2918
  * @license lucide-react v0.539.0 - ISC
@@ -2922,8 +2922,8 @@ const Check = createLucideIcon("check", __iconNode$1e);
2922
2922
  */
2923
2923
 
2924
2924
 
2925
- const __iconNode$1d = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
2926
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$1d);
2925
+ const __iconNode$1g = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
2926
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1g);
2927
2927
 
2928
2928
  /**
2929
2929
  * @license lucide-react v0.539.0 - ISC
@@ -2933,8 +2933,8 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1d);
2933
2933
  */
2934
2934
 
2935
2935
 
2936
- const __iconNode$1c = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
2937
- const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1c);
2936
+ const __iconNode$1f = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
2937
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1f);
2938
2938
 
2939
2939
  /**
2940
2940
  * @license lucide-react v0.539.0 - ISC
@@ -2944,8 +2944,8 @@ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1c);
2944
2944
  */
2945
2945
 
2946
2946
 
2947
- const __iconNode$1b = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
2948
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$1b);
2947
+ const __iconNode$1e = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
2948
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1e);
2949
2949
 
2950
2950
  /**
2951
2951
  * @license lucide-react v0.539.0 - ISC
@@ -2955,8 +2955,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1b);
2955
2955
  */
2956
2956
 
2957
2957
 
2958
- const __iconNode$1a = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
2959
- const ChevronUp = createLucideIcon("chevron-up", __iconNode$1a);
2958
+ const __iconNode$1d = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
2959
+ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1d);
2960
2960
 
2961
2961
  /**
2962
2962
  * @license lucide-react v0.539.0 - ISC
@@ -2966,11 +2966,11 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1a);
2966
2966
  */
2967
2967
 
2968
2968
 
2969
- const __iconNode$19 = [
2969
+ const __iconNode$1c = [
2970
2970
  ["path", { d: "m11 17-5-5 5-5", key: "13zhaf" }],
2971
2971
  ["path", { d: "m18 17-5-5 5-5", key: "h8a8et" }]
2972
2972
  ];
2973
- const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$19);
2973
+ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1c);
2974
2974
 
2975
2975
  /**
2976
2976
  * @license lucide-react v0.539.0 - ISC
@@ -2980,11 +2980,11 @@ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$19);
2980
2980
  */
2981
2981
 
2982
2982
 
2983
- const __iconNode$18 = [
2983
+ const __iconNode$1b = [
2984
2984
  ["path", { d: "m6 17 5-5-5-5", key: "xnjwq" }],
2985
2985
  ["path", { d: "m13 17 5-5-5-5", key: "17xmmf" }]
2986
2986
  ];
2987
- const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$18);
2987
+ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$1b);
2988
2988
 
2989
2989
  /**
2990
2990
  * @license lucide-react v0.539.0 - ISC
@@ -2994,12 +2994,12 @@ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$18);
2994
2994
  */
2995
2995
 
2996
2996
 
2997
- const __iconNode$17 = [
2997
+ const __iconNode$1a = [
2998
2998
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
2999
2999
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
3000
3000
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
3001
3001
  ];
3002
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$17);
3002
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$1a);
3003
3003
 
3004
3004
  /**
3005
3005
  * @license lucide-react v0.539.0 - ISC
@@ -3009,11 +3009,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$17);
3009
3009
  */
3010
3010
 
3011
3011
 
3012
- const __iconNode$16 = [
3012
+ const __iconNode$19 = [
3013
3013
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
3014
3014
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
3015
3015
  ];
3016
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$16);
3016
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$19);
3017
3017
 
3018
3018
  /**
3019
3019
  * @license lucide-react v0.539.0 - ISC
@@ -3023,11 +3023,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$16);
3023
3023
  */
3024
3024
 
3025
3025
 
3026
- const __iconNode$15 = [
3026
+ const __iconNode$18 = [
3027
3027
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3028
3028
  ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
3029
3029
  ];
3030
- const CircleCheck = createLucideIcon("circle-check", __iconNode$15);
3030
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$18);
3031
3031
 
3032
3032
  /**
3033
3033
  * @license lucide-react v0.539.0 - ISC
@@ -3037,11 +3037,11 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$15);
3037
3037
  */
3038
3038
 
3039
3039
 
3040
- const __iconNode$14 = [
3040
+ const __iconNode$17 = [
3041
3041
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3042
3042
  ["path", { d: "m16 10-4 4-4-4", key: "894hmk" }]
3043
3043
  ];
3044
- const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$14);
3044
+ const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$17);
3045
3045
 
3046
3046
  /**
3047
3047
  * @license lucide-react v0.539.0 - ISC
@@ -3051,11 +3051,11 @@ const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$14)
3051
3051
  */
3052
3052
 
3053
3053
 
3054
- const __iconNode$13 = [
3054
+ const __iconNode$16 = [
3055
3055
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3056
3056
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }]
3057
3057
  ];
3058
- const CircleDot = createLucideIcon("circle-dot", __iconNode$13);
3058
+ const CircleDot = createLucideIcon("circle-dot", __iconNode$16);
3059
3059
 
3060
3060
  /**
3061
3061
  * @license lucide-react v0.539.0 - ISC
@@ -3065,12 +3065,12 @@ const CircleDot = createLucideIcon("circle-dot", __iconNode$13);
3065
3065
  */
3066
3066
 
3067
3067
 
3068
- const __iconNode$12 = [
3068
+ const __iconNode$15 = [
3069
3069
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3070
3070
  ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
3071
3071
  ["path", { d: "m9 9 6 6", key: "z0biqf" }]
3072
3072
  ];
3073
- const CircleX = createLucideIcon("circle-x", __iconNode$12);
3073
+ const CircleX = createLucideIcon("circle-x", __iconNode$15);
3074
3074
 
3075
3075
  /**
3076
3076
  * @license lucide-react v0.539.0 - ISC
@@ -3080,8 +3080,8 @@ const CircleX = createLucideIcon("circle-x", __iconNode$12);
3080
3080
  */
3081
3081
 
3082
3082
 
3083
- const __iconNode$11 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
3084
- const Circle = createLucideIcon("circle", __iconNode$11);
3083
+ const __iconNode$14 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
3084
+ const Circle = createLucideIcon("circle", __iconNode$14);
3085
3085
 
3086
3086
  /**
3087
3087
  * @license lucide-react v0.539.0 - ISC
@@ -3091,11 +3091,11 @@ const Circle = createLucideIcon("circle", __iconNode$11);
3091
3091
  */
3092
3092
 
3093
3093
 
3094
- const __iconNode$10 = [
3094
+ const __iconNode$13 = [
3095
3095
  ["path", { d: "M12 6v6l4 2", key: "mmk7yg" }],
3096
3096
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
3097
3097
  ];
3098
- const Clock = createLucideIcon("clock", __iconNode$10);
3098
+ const Clock = createLucideIcon("clock", __iconNode$13);
3099
3099
 
3100
3100
  /**
3101
3101
  * @license lucide-react v0.539.0 - ISC
@@ -3105,11 +3105,11 @@ const Clock = createLucideIcon("clock", __iconNode$10);
3105
3105
  */
3106
3106
 
3107
3107
 
3108
- const __iconNode$$ = [
3108
+ const __iconNode$12 = [
3109
3109
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
3110
3110
  ["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" }]
3111
3111
  ];
3112
- const Copy = createLucideIcon("copy", __iconNode$$);
3112
+ const Copy = createLucideIcon("copy", __iconNode$12);
3113
3113
 
3114
3114
  /**
3115
3115
  * @license lucide-react v0.539.0 - ISC
@@ -3119,11 +3119,11 @@ const Copy = createLucideIcon("copy", __iconNode$$);
3119
3119
  */
3120
3120
 
3121
3121
 
3122
- const __iconNode$_ = [
3122
+ const __iconNode$11 = [
3123
3123
  ["path", { d: "M6 2v14a2 2 0 0 0 2 2h14", key: "ron5a4" }],
3124
3124
  ["path", { d: "M18 22V8a2 2 0 0 0-2-2H2", key: "7s9ehn" }]
3125
3125
  ];
3126
- const Crop = createLucideIcon("crop", __iconNode$_);
3126
+ const Crop = createLucideIcon("crop", __iconNode$11);
3127
3127
 
3128
3128
  /**
3129
3129
  * @license lucide-react v0.539.0 - ISC
@@ -3133,12 +3133,12 @@ const Crop = createLucideIcon("crop", __iconNode$_);
3133
3133
  */
3134
3134
 
3135
3135
 
3136
- const __iconNode$Z = [
3136
+ const __iconNode$10 = [
3137
3137
  ["path", { d: "M12 15V3", key: "m9g1x1" }],
3138
3138
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
3139
3139
  ["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
3140
3140
  ];
3141
- const Download = createLucideIcon("download", __iconNode$Z);
3141
+ const Download = createLucideIcon("download", __iconNode$10);
3142
3142
 
3143
3143
  /**
3144
3144
  * @license lucide-react v0.539.0 - ISC
@@ -3148,12 +3148,12 @@ const Download = createLucideIcon("download", __iconNode$Z);
3148
3148
  */
3149
3149
 
3150
3150
 
3151
- const __iconNode$Y = [
3151
+ const __iconNode$$ = [
3152
3152
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3153
3153
  ["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
3154
3154
  ["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
3155
3155
  ];
3156
- const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$Y);
3156
+ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$$);
3157
3157
 
3158
3158
  /**
3159
3159
  * @license lucide-react v0.539.0 - ISC
@@ -3163,12 +3163,12 @@ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$Y);
3163
3163
  */
3164
3164
 
3165
3165
 
3166
- const __iconNode$X = [
3166
+ const __iconNode$_ = [
3167
3167
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3168
3168
  ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
3169
3169
  ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
3170
3170
  ];
3171
- const Ellipsis = createLucideIcon("ellipsis", __iconNode$X);
3171
+ const Ellipsis = createLucideIcon("ellipsis", __iconNode$_);
3172
3172
 
3173
3173
  /**
3174
3174
  * @license lucide-react v0.539.0 - ISC
@@ -3178,12 +3178,12 @@ const Ellipsis = createLucideIcon("ellipsis", __iconNode$X);
3178
3178
  */
3179
3179
 
3180
3180
 
3181
- const __iconNode$W = [
3181
+ const __iconNode$Z = [
3182
3182
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3183
3183
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
3184
3184
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
3185
3185
  ];
3186
- const ExternalLink = createLucideIcon("external-link", __iconNode$W);
3186
+ const ExternalLink = createLucideIcon("external-link", __iconNode$Z);
3187
3187
 
3188
3188
  /**
3189
3189
  * @license lucide-react v0.539.0 - ISC
@@ -3193,7 +3193,7 @@ const ExternalLink = createLucideIcon("external-link", __iconNode$W);
3193
3193
  */
3194
3194
 
3195
3195
 
3196
- const __iconNode$V = [
3196
+ const __iconNode$Y = [
3197
3197
  [
3198
3198
  "path",
3199
3199
  {
@@ -3203,7 +3203,7 @@ const __iconNode$V = [
3203
3203
  ],
3204
3204
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
3205
3205
  ];
3206
- const Eye = createLucideIcon("eye", __iconNode$V);
3206
+ const Eye = createLucideIcon("eye", __iconNode$Y);
3207
3207
 
3208
3208
  /**
3209
3209
  * @license lucide-react v0.539.0 - ISC
@@ -3213,13 +3213,13 @@ const Eye = createLucideIcon("eye", __iconNode$V);
3213
3213
  */
3214
3214
 
3215
3215
 
3216
- const __iconNode$U = [
3216
+ const __iconNode$X = [
3217
3217
  [
3218
3218
  "path",
3219
3219
  { d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z", key: "1jg4f8" }
3220
3220
  ]
3221
3221
  ];
3222
- const Facebook = createLucideIcon("facebook", __iconNode$U);
3222
+ const Facebook = createLucideIcon("facebook", __iconNode$X);
3223
3223
 
3224
3224
  /**
3225
3225
  * @license lucide-react v0.539.0 - ISC
@@ -3229,7 +3229,7 @@ const Facebook = createLucideIcon("facebook", __iconNode$U);
3229
3229
  */
3230
3230
 
3231
3231
 
3232
- const __iconNode$T = [
3232
+ const __iconNode$W = [
3233
3233
  ["path", { d: "M12 22h6a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3.072", key: "n6s66f" }],
3234
3234
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3235
3235
  [
@@ -3241,7 +3241,7 @@ const __iconNode$T = [
3241
3241
  ],
3242
3242
  ["circle", { cx: "5", cy: "14", r: "3", key: "ufru5t" }]
3243
3243
  ];
3244
- const FileBadge = createLucideIcon("file-badge", __iconNode$T);
3244
+ const FileBadge = createLucideIcon("file-badge", __iconNode$W);
3245
3245
 
3246
3246
  /**
3247
3247
  * @license lucide-react v0.539.0 - ISC
@@ -3251,12 +3251,12 @@ const FileBadge = createLucideIcon("file-badge", __iconNode$T);
3251
3251
  */
3252
3252
 
3253
3253
 
3254
- const __iconNode$S = [
3254
+ const __iconNode$V = [
3255
3255
  ["path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4", key: "1pf5j1" }],
3256
3256
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3257
3257
  ["path", { d: "m3 15 2 2 4-4", key: "1lhrkk" }]
3258
3258
  ];
3259
- const FileCheck2 = createLucideIcon("file-check-2", __iconNode$S);
3259
+ const FileCheck2 = createLucideIcon("file-check-2", __iconNode$V);
3260
3260
 
3261
3261
  /**
3262
3262
  * @license lucide-react v0.539.0 - ISC
@@ -3266,14 +3266,14 @@ const FileCheck2 = createLucideIcon("file-check-2", __iconNode$S);
3266
3266
  */
3267
3267
 
3268
3268
 
3269
- const __iconNode$R = [
3269
+ const __iconNode$U = [
3270
3270
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
3271
3271
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
3272
3272
  ["path", { d: "M10 9H8", key: "b1mrlr" }],
3273
3273
  ["path", { d: "M16 13H8", key: "t4e002" }],
3274
3274
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
3275
3275
  ];
3276
- const FileText = createLucideIcon("file-text", __iconNode$R);
3276
+ const FileText = createLucideIcon("file-text", __iconNode$U);
3277
3277
 
3278
3278
  /**
3279
3279
  * @license lucide-react v0.539.0 - ISC
@@ -3283,7 +3283,28 @@ const FileText = createLucideIcon("file-text", __iconNode$R);
3283
3283
  */
3284
3284
 
3285
3285
 
3286
- const __iconNode$Q = [
3286
+ const __iconNode$T = [
3287
+ [
3288
+ "path",
3289
+ {
3290
+ 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",
3291
+ key: "ol2ft2"
3292
+ }
3293
+ ],
3294
+ ["path", { d: "m16.5 3.5 5 5", key: "15e6fa" }],
3295
+ ["path", { d: "m21.5 3.5-5 5", key: "m0lwru" }]
3296
+ ];
3297
+ const FunnelX = createLucideIcon("funnel-x", __iconNode$T);
3298
+
3299
+ /**
3300
+ * @license lucide-react v0.539.0 - ISC
3301
+ *
3302
+ * This source code is licensed under the ISC license.
3303
+ * See the LICENSE file in the root directory of this source tree.
3304
+ */
3305
+
3306
+
3307
+ const __iconNode$S = [
3287
3308
  [
3288
3309
  "path",
3289
3310
  {
@@ -3292,7 +3313,7 @@ const __iconNode$Q = [
3292
3313
  }
3293
3314
  ]
3294
3315
  ];
3295
- const Funnel = createLucideIcon("funnel", __iconNode$Q);
3316
+ const Funnel = createLucideIcon("funnel", __iconNode$S);
3296
3317
 
3297
3318
  /**
3298
3319
  * @license lucide-react v0.539.0 - ISC
@@ -3302,7 +3323,7 @@ const Funnel = createLucideIcon("funnel", __iconNode$Q);
3302
3323
  */
3303
3324
 
3304
3325
 
3305
- const __iconNode$P = [
3326
+ const __iconNode$R = [
3306
3327
  ["path", { d: "M10.5 3 8 9l4 13 4-13-2.5-6", key: "b3dvk1" }],
3307
3328
  [
3308
3329
  "path",
@@ -3313,7 +3334,7 @@ const __iconNode$P = [
3313
3334
  ],
3314
3335
  ["path", { d: "M2 9h20", key: "16fsjt" }]
3315
3336
  ];
3316
- const Gem = createLucideIcon("gem", __iconNode$P);
3337
+ const Gem = createLucideIcon("gem", __iconNode$R);
3317
3338
 
3318
3339
  /**
3319
3340
  * @license lucide-react v0.539.0 - ISC
@@ -3323,7 +3344,7 @@ const Gem = createLucideIcon("gem", __iconNode$P);
3323
3344
  */
3324
3345
 
3325
3346
 
3326
- const __iconNode$O = [
3347
+ const __iconNode$Q = [
3327
3348
  ["circle", { cx: "12", cy: "9", r: "1", key: "124mty" }],
3328
3349
  ["circle", { cx: "19", cy: "9", r: "1", key: "1ruzo2" }],
3329
3350
  ["circle", { cx: "5", cy: "9", r: "1", key: "1a8b28" }],
@@ -3331,7 +3352,7 @@ const __iconNode$O = [
3331
3352
  ["circle", { cx: "19", cy: "15", r: "1", key: "1a92ep" }],
3332
3353
  ["circle", { cx: "5", cy: "15", r: "1", key: "5r1jwy" }]
3333
3354
  ];
3334
- const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$O);
3355
+ const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$Q);
3335
3356
 
3336
3357
  /**
3337
3358
  * @license lucide-react v0.539.0 - ISC
@@ -3341,7 +3362,7 @@ const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$O);
3341
3362
  */
3342
3363
 
3343
3364
 
3344
- const __iconNode$N = [
3365
+ const __iconNode$P = [
3345
3366
  ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
3346
3367
  ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
3347
3368
  ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
@@ -3349,7 +3370,7 @@ const __iconNode$N = [
3349
3370
  ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
3350
3371
  ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
3351
3372
  ];
3352
- const GripVertical = createLucideIcon("grip-vertical", __iconNode$N);
3373
+ const GripVertical = createLucideIcon("grip-vertical", __iconNode$P);
3353
3374
 
3354
3375
  /**
3355
3376
  * @license lucide-react v0.539.0 - ISC
@@ -3359,13 +3380,13 @@ const GripVertical = createLucideIcon("grip-vertical", __iconNode$N);
3359
3380
  */
3360
3381
 
3361
3382
 
3362
- const __iconNode$M = [
3383
+ const __iconNode$O = [
3363
3384
  ["line", { x1: "4", x2: "20", y1: "9", y2: "9", key: "4lhtct" }],
3364
3385
  ["line", { x1: "4", x2: "20", y1: "15", y2: "15", key: "vyu0kd" }],
3365
3386
  ["line", { x1: "10", x2: "8", y1: "3", y2: "21", key: "1ggp8o" }],
3366
3387
  ["line", { x1: "16", x2: "14", y1: "3", y2: "21", key: "weycgp" }]
3367
3388
  ];
3368
- const Hash = createLucideIcon("hash", __iconNode$M);
3389
+ const Hash = createLucideIcon("hash", __iconNode$O);
3369
3390
 
3370
3391
  /**
3371
3392
  * @license lucide-react v0.539.0 - ISC
@@ -3375,13 +3396,13 @@ const Hash = createLucideIcon("hash", __iconNode$M);
3375
3396
  */
3376
3397
 
3377
3398
 
3378
- const __iconNode$L = [
3399
+ const __iconNode$N = [
3379
3400
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3380
3401
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3381
3402
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3382
3403
  ["path", { d: "m17 12 3-2v8", key: "1hhhft" }]
3383
3404
  ];
3384
- const Heading1 = createLucideIcon("heading-1", __iconNode$L);
3405
+ const Heading1 = createLucideIcon("heading-1", __iconNode$N);
3385
3406
 
3386
3407
  /**
3387
3408
  * @license lucide-react v0.539.0 - ISC
@@ -3391,13 +3412,13 @@ const Heading1 = createLucideIcon("heading-1", __iconNode$L);
3391
3412
  */
3392
3413
 
3393
3414
 
3394
- const __iconNode$K = [
3415
+ const __iconNode$M = [
3395
3416
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3396
3417
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3397
3418
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3398
3419
  ["path", { d: "M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1", key: "9jr5yi" }]
3399
3420
  ];
3400
- const Heading2 = createLucideIcon("heading-2", __iconNode$K);
3421
+ const Heading2 = createLucideIcon("heading-2", __iconNode$M);
3401
3422
 
3402
3423
  /**
3403
3424
  * @license lucide-react v0.539.0 - ISC
@@ -3407,14 +3428,14 @@ const Heading2 = createLucideIcon("heading-2", __iconNode$K);
3407
3428
  */
3408
3429
 
3409
3430
 
3410
- const __iconNode$J = [
3431
+ const __iconNode$L = [
3411
3432
  ["path", { d: "M4 12h8", key: "17cfdx" }],
3412
3433
  ["path", { d: "M4 18V6", key: "1rz3zl" }],
3413
3434
  ["path", { d: "M12 18V6", key: "zqpxq5" }],
3414
3435
  ["path", { d: "M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2", key: "68ncm8" }],
3415
3436
  ["path", { d: "M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2", key: "1ejuhz" }]
3416
3437
  ];
3417
- const Heading3 = createLucideIcon("heading-3", __iconNode$J);
3438
+ const Heading3 = createLucideIcon("heading-3", __iconNode$L);
3418
3439
 
3419
3440
  /**
3420
3441
  * @license lucide-react v0.539.0 - ISC
@@ -3424,12 +3445,12 @@ const Heading3 = createLucideIcon("heading-3", __iconNode$J);
3424
3445
  */
3425
3446
 
3426
3447
 
3427
- const __iconNode$I = [
3448
+ const __iconNode$K = [
3428
3449
  ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
3429
3450
  ["path", { d: "M3 3v5h5", key: "1xhq8a" }],
3430
3451
  ["path", { d: "M12 7v5l4 2", key: "1fdv2h" }]
3431
3452
  ];
3432
- const History = createLucideIcon("history", __iconNode$I);
3453
+ const History = createLucideIcon("history", __iconNode$K);
3433
3454
 
3434
3455
  /**
3435
3456
  * @license lucide-react v0.539.0 - ISC
@@ -3439,12 +3460,12 @@ const History = createLucideIcon("history", __iconNode$I);
3439
3460
  */
3440
3461
 
3441
3462
 
3442
- const __iconNode$H = [
3463
+ const __iconNode$J = [
3443
3464
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
3444
3465
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
3445
3466
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
3446
3467
  ];
3447
- const Image$1 = createLucideIcon("image", __iconNode$H);
3468
+ const Image$1 = createLucideIcon("image", __iconNode$J);
3448
3469
 
3449
3470
  /**
3450
3471
  * @license lucide-react v0.539.0 - ISC
@@ -3454,12 +3475,12 @@ const Image$1 = createLucideIcon("image", __iconNode$H);
3454
3475
  */
3455
3476
 
3456
3477
 
3457
- const __iconNode$G = [
3478
+ const __iconNode$I = [
3458
3479
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
3459
3480
  ["path", { d: "M12 16v-4", key: "1dtifu" }],
3460
3481
  ["path", { d: "M12 8h.01", key: "e9boi3" }]
3461
3482
  ];
3462
- const Info = createLucideIcon("info", __iconNode$G);
3483
+ const Info = createLucideIcon("info", __iconNode$I);
3463
3484
 
3464
3485
  /**
3465
3486
  * @license lucide-react v0.539.0 - ISC
@@ -3469,12 +3490,12 @@ const Info = createLucideIcon("info", __iconNode$G);
3469
3490
  */
3470
3491
 
3471
3492
 
3472
- const __iconNode$F = [
3493
+ const __iconNode$H = [
3473
3494
  ["line", { x1: "19", x2: "10", y1: "4", y2: "4", key: "15jd3p" }],
3474
3495
  ["line", { x1: "14", x2: "5", y1: "20", y2: "20", key: "bu0au3" }],
3475
3496
  ["line", { x1: "15", x2: "9", y1: "4", y2: "20", key: "uljnxc" }]
3476
3497
  ];
3477
- const Italic$1 = createLucideIcon("italic", __iconNode$F);
3498
+ const Italic$1 = createLucideIcon("italic", __iconNode$H);
3478
3499
 
3479
3500
  /**
3480
3501
  * @license lucide-react v0.539.0 - ISC
@@ -3484,7 +3505,7 @@ const Italic$1 = createLucideIcon("italic", __iconNode$F);
3484
3505
  */
3485
3506
 
3486
3507
 
3487
- const __iconNode$E = [
3508
+ const __iconNode$G = [
3488
3509
  [
3489
3510
  "path",
3490
3511
  {
@@ -3494,7 +3515,7 @@ const __iconNode$E = [
3494
3515
  ],
3495
3516
  ["circle", { cx: "16.5", cy: "7.5", r: ".5", fill: "currentColor", key: "w0ekpg" }]
3496
3517
  ];
3497
- const KeyRound = createLucideIcon("key-round", __iconNode$E);
3518
+ const KeyRound = createLucideIcon("key-round", __iconNode$G);
3498
3519
 
3499
3520
  /**
3500
3521
  * @license lucide-react v0.539.0 - ISC
@@ -3504,12 +3525,12 @@ const KeyRound = createLucideIcon("key-round", __iconNode$E);
3504
3525
  */
3505
3526
 
3506
3527
 
3507
- const __iconNode$D = [
3528
+ const __iconNode$F = [
3508
3529
  ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
3509
3530
  ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
3510
3531
  ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
3511
3532
  ];
3512
- const Link2 = createLucideIcon("link-2", __iconNode$D);
3533
+ const Link2 = createLucideIcon("link-2", __iconNode$F);
3513
3534
 
3514
3535
  /**
3515
3536
  * @license lucide-react v0.539.0 - ISC
@@ -3519,14 +3540,14 @@ const Link2 = createLucideIcon("link-2", __iconNode$D);
3519
3540
  */
3520
3541
 
3521
3542
 
3522
- const __iconNode$C = [
3543
+ const __iconNode$E = [
3523
3544
  ["path", { d: "m3 17 2 2 4-4", key: "1jhpwq" }],
3524
3545
  ["path", { d: "m3 7 2 2 4-4", key: "1obspn" }],
3525
3546
  ["path", { d: "M13 6h8", key: "15sg57" }],
3526
3547
  ["path", { d: "M13 12h8", key: "h98zly" }],
3527
3548
  ["path", { d: "M13 18h8", key: "oe0vm4" }]
3528
3549
  ];
3529
- const ListChecks = createLucideIcon("list-checks", __iconNode$C);
3550
+ const ListChecks = createLucideIcon("list-checks", __iconNode$E);
3530
3551
 
3531
3552
  /**
3532
3553
  * @license lucide-react v0.539.0 - ISC
@@ -3536,7 +3557,7 @@ const ListChecks = createLucideIcon("list-checks", __iconNode$C);
3536
3557
  */
3537
3558
 
3538
3559
 
3539
- const __iconNode$B = [
3560
+ const __iconNode$D = [
3540
3561
  ["path", { d: "M10 12h11", key: "6m4ad9" }],
3541
3562
  ["path", { d: "M10 18h11", key: "11hvi2" }],
3542
3563
  ["path", { d: "M10 6h11", key: "c7qv1k" }],
@@ -3544,7 +3565,7 @@ const __iconNode$B = [
3544
3565
  ["path", { d: "M4 6h1v4", key: "cnovpq" }],
3545
3566
  ["path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1", key: "m9a95d" }]
3546
3567
  ];
3547
- const ListOrdered = createLucideIcon("list-ordered", __iconNode$B);
3568
+ const ListOrdered = createLucideIcon("list-ordered", __iconNode$D);
3548
3569
 
3549
3570
  /**
3550
3571
  * @license lucide-react v0.539.0 - ISC
@@ -3554,7 +3575,7 @@ const ListOrdered = createLucideIcon("list-ordered", __iconNode$B);
3554
3575
  */
3555
3576
 
3556
3577
 
3557
- const __iconNode$A = [
3578
+ const __iconNode$C = [
3558
3579
  ["path", { d: "M3 12h.01", key: "nlz23k" }],
3559
3580
  ["path", { d: "M3 18h.01", key: "1tta3j" }],
3560
3581
  ["path", { d: "M3 6h.01", key: "1rqtza" }],
@@ -3562,7 +3583,7 @@ const __iconNode$A = [
3562
3583
  ["path", { d: "M8 18h13", key: "1lx6n3" }],
3563
3584
  ["path", { d: "M8 6h13", key: "ik3vkj" }]
3564
3585
  ];
3565
- const List = createLucideIcon("list", __iconNode$A);
3586
+ const List = createLucideIcon("list", __iconNode$C);
3566
3587
 
3567
3588
  /**
3568
3589
  * @license lucide-react v0.539.0 - ISC
@@ -3572,8 +3593,8 @@ const List = createLucideIcon("list", __iconNode$A);
3572
3593
  */
3573
3594
 
3574
3595
 
3575
- const __iconNode$z = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3576
- const LoaderCircle = createLucideIcon("loader-circle", __iconNode$z);
3596
+ const __iconNode$B = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
3597
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$B);
3577
3598
 
3578
3599
  /**
3579
3600
  * @license lucide-react v0.539.0 - ISC
@@ -3583,7 +3604,7 @@ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$z);
3583
3604
  */
3584
3605
 
3585
3606
 
3586
- const __iconNode$y = [
3607
+ const __iconNode$A = [
3587
3608
  ["path", { d: "M12 2v4", key: "3427ic" }],
3588
3609
  ["path", { d: "m16.2 7.8 2.9-2.9", key: "r700ao" }],
3589
3610
  ["path", { d: "M18 12h4", key: "wj9ykh" }],
@@ -3593,7 +3614,7 @@ const __iconNode$y = [
3593
3614
  ["path", { d: "M2 12h4", key: "j09sii" }],
3594
3615
  ["path", { d: "m4.9 4.9 2.9 2.9", key: "giyufr" }]
3595
3616
  ];
3596
- const Loader = createLucideIcon("loader", __iconNode$y);
3617
+ const Loader = createLucideIcon("loader", __iconNode$A);
3597
3618
 
3598
3619
  /**
3599
3620
  * @license lucide-react v0.539.0 - ISC
@@ -3603,12 +3624,12 @@ const Loader = createLucideIcon("loader", __iconNode$y);
3603
3624
  */
3604
3625
 
3605
3626
 
3606
- const __iconNode$x = [
3627
+ const __iconNode$z = [
3607
3628
  ["path", { d: "m16 17 5-5-5-5", key: "1bji2h" }],
3608
3629
  ["path", { d: "M21 12H9", key: "dn1m92" }],
3609
3630
  ["path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4", key: "1uf3rs" }]
3610
3631
  ];
3611
- const LogOut = createLucideIcon("log-out", __iconNode$x);
3632
+ const LogOut = createLucideIcon("log-out", __iconNode$z);
3612
3633
 
3613
3634
  /**
3614
3635
  * @license lucide-react v0.539.0 - ISC
@@ -3618,11 +3639,11 @@ const LogOut = createLucideIcon("log-out", __iconNode$x);
3618
3639
  */
3619
3640
 
3620
3641
 
3621
- const __iconNode$w = [
3642
+ const __iconNode$y = [
3622
3643
  ["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
3623
3644
  ["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
3624
3645
  ];
3625
- const Mail = createLucideIcon("mail", __iconNode$w);
3646
+ const Mail = createLucideIcon("mail", __iconNode$y);
3626
3647
 
3627
3648
  /**
3628
3649
  * @license lucide-react v0.539.0 - ISC
@@ -3632,12 +3653,12 @@ const Mail = createLucideIcon("mail", __iconNode$w);
3632
3653
  */
3633
3654
 
3634
3655
 
3635
- const __iconNode$v = [
3656
+ const __iconNode$x = [
3636
3657
  ["path", { d: "M4 12h16", key: "1lakjw" }],
3637
3658
  ["path", { d: "M4 18h16", key: "19g7jn" }],
3638
3659
  ["path", { d: "M4 6h16", key: "1o0s65" }]
3639
3660
  ];
3640
- const Menu = createLucideIcon("menu", __iconNode$v);
3661
+ const Menu = createLucideIcon("menu", __iconNode$x);
3641
3662
 
3642
3663
  /**
3643
3664
  * @license lucide-react v0.539.0 - ISC
@@ -3647,7 +3668,18 @@ const Menu = createLucideIcon("menu", __iconNode$v);
3647
3668
  */
3648
3669
 
3649
3670
 
3650
- const __iconNode$u = [
3671
+ const __iconNode$w = [["path", { d: "M5 12h14", key: "1ays0h" }]];
3672
+ const Minus = createLucideIcon("minus", __iconNode$w);
3673
+
3674
+ /**
3675
+ * @license lucide-react v0.539.0 - ISC
3676
+ *
3677
+ * This source code is licensed under the ISC license.
3678
+ * See the LICENSE file in the root directory of this source tree.
3679
+ */
3680
+
3681
+
3682
+ const __iconNode$v = [
3651
3683
  [
3652
3684
  "path",
3653
3685
  {
@@ -3656,7 +3688,7 @@ const __iconNode$u = [
3656
3688
  }
3657
3689
  ]
3658
3690
  ];
3659
- const Moon = createLucideIcon("moon", __iconNode$u);
3691
+ const Moon = createLucideIcon("moon", __iconNode$v);
3660
3692
 
3661
3693
  /**
3662
3694
  * @license lucide-react v0.539.0 - ISC
@@ -3666,7 +3698,7 @@ const Moon = createLucideIcon("moon", __iconNode$u);
3666
3698
  */
3667
3699
 
3668
3700
 
3669
- const __iconNode$t = [
3701
+ const __iconNode$u = [
3670
3702
  [
3671
3703
  "path",
3672
3704
  {
@@ -3679,7 +3711,7 @@ const __iconNode$t = [
3679
3711
  ["circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor", key: "qy21gx" }],
3680
3712
  ["circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor", key: "fotxhn" }]
3681
3713
  ];
3682
- const Palette = createLucideIcon("palette", __iconNode$t);
3714
+ const Palette = createLucideIcon("palette", __iconNode$u);
3683
3715
 
3684
3716
  /**
3685
3717
  * @license lucide-react v0.539.0 - ISC
@@ -3689,12 +3721,12 @@ const Palette = createLucideIcon("palette", __iconNode$t);
3689
3721
  */
3690
3722
 
3691
3723
 
3692
- const __iconNode$s = [
3724
+ const __iconNode$t = [
3693
3725
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
3694
3726
  ["path", { d: "M9 3v18", key: "fh3hqa" }],
3695
3727
  ["path", { d: "m16 15-3-3 3-3", key: "14y99z" }]
3696
3728
  ];
3697
- const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$s);
3729
+ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$t);
3698
3730
 
3699
3731
  /**
3700
3732
  * @license lucide-react v0.539.0 - ISC
@@ -3704,7 +3736,7 @@ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$s);
3704
3736
  */
3705
3737
 
3706
3738
 
3707
- const __iconNode$r = [
3739
+ const __iconNode$s = [
3708
3740
  [
3709
3741
  "path",
3710
3742
  {
@@ -3713,7 +3745,7 @@ const __iconNode$r = [
3713
3745
  }
3714
3746
  ]
3715
3747
  ];
3716
- const Paperclip = createLucideIcon("paperclip", __iconNode$r);
3748
+ const Paperclip = createLucideIcon("paperclip", __iconNode$s);
3717
3749
 
3718
3750
  /**
3719
3751
  * @license lucide-react v0.539.0 - ISC
@@ -3723,7 +3755,7 @@ const Paperclip = createLucideIcon("paperclip", __iconNode$r);
3723
3755
  */
3724
3756
 
3725
3757
 
3726
- const __iconNode$q = [
3758
+ const __iconNode$r = [
3727
3759
  [
3728
3760
  "path",
3729
3761
  {
@@ -3733,7 +3765,7 @@ const __iconNode$q = [
3733
3765
  ],
3734
3766
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
3735
3767
  ];
3736
- const Pencil = createLucideIcon("pencil", __iconNode$q);
3768
+ const Pencil = createLucideIcon("pencil", __iconNode$r);
3737
3769
 
3738
3770
  /**
3739
3771
  * @license lucide-react v0.539.0 - ISC
@@ -3743,7 +3775,7 @@ const Pencil = createLucideIcon("pencil", __iconNode$q);
3743
3775
  */
3744
3776
 
3745
3777
 
3746
- const __iconNode$p = [
3778
+ const __iconNode$q = [
3747
3779
  [
3748
3780
  "path",
3749
3781
  {
@@ -3752,7 +3784,7 @@ const __iconNode$p = [
3752
3784
  }
3753
3785
  ]
3754
3786
  ];
3755
- const Phone = createLucideIcon("phone", __iconNode$p);
3787
+ const Phone = createLucideIcon("phone", __iconNode$q);
3756
3788
 
3757
3789
  /**
3758
3790
  * @license lucide-react v0.539.0 - ISC
@@ -3762,7 +3794,7 @@ const Phone = createLucideIcon("phone", __iconNode$p);
3762
3794
  */
3763
3795
 
3764
3796
 
3765
- const __iconNode$o = [
3797
+ const __iconNode$p = [
3766
3798
  [
3767
3799
  "path",
3768
3800
  {
@@ -3771,7 +3803,7 @@ const __iconNode$o = [
3771
3803
  }
3772
3804
  ]
3773
3805
  ];
3774
- const Play = createLucideIcon("play", __iconNode$o);
3806
+ const Play = createLucideIcon("play", __iconNode$p);
3775
3807
 
3776
3808
  /**
3777
3809
  * @license lucide-react v0.539.0 - ISC
@@ -3781,11 +3813,11 @@ const Play = createLucideIcon("play", __iconNode$o);
3781
3813
  */
3782
3814
 
3783
3815
 
3784
- const __iconNode$n = [
3816
+ const __iconNode$o = [
3785
3817
  ["path", { d: "M5 12h14", key: "1ays0h" }],
3786
3818
  ["path", { d: "M12 5v14", key: "s699le" }]
3787
3819
  ];
3788
- const Plus = createLucideIcon("plus", __iconNode$n);
3820
+ const Plus = createLucideIcon("plus", __iconNode$o);
3789
3821
 
3790
3822
  /**
3791
3823
  * @license lucide-react v0.539.0 - ISC
@@ -3795,10 +3827,10 @@ const Plus = createLucideIcon("plus", __iconNode$n);
3795
3827
  */
3796
3828
 
3797
3829
 
3798
- const __iconNode$m = [
3830
+ const __iconNode$n = [
3799
3831
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
3800
3832
  ];
3801
- const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$m);
3833
+ const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$n);
3802
3834
 
3803
3835
  /**
3804
3836
  * @license lucide-react v0.539.0 - ISC
@@ -3808,11 +3840,11 @@ const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$
3808
3840
  */
3809
3841
 
3810
3842
 
3811
- const __iconNode$l = [
3843
+ const __iconNode$m = [
3812
3844
  ["path", { d: "M21 7v6h-6", key: "3ptur4" }],
3813
3845
  ["path", { d: "M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3l3 2.7", key: "1kgawr" }]
3814
3846
  ];
3815
- const Redo = createLucideIcon("redo", __iconNode$l);
3847
+ const Redo = createLucideIcon("redo", __iconNode$m);
3816
3848
 
3817
3849
  /**
3818
3850
  * @license lucide-react v0.539.0 - ISC
@@ -3822,13 +3854,13 @@ const Redo = createLucideIcon("redo", __iconNode$l);
3822
3854
  */
3823
3855
 
3824
3856
 
3825
- const __iconNode$k = [
3857
+ const __iconNode$l = [
3826
3858
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
3827
3859
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
3828
3860
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
3829
3861
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
3830
3862
  ];
3831
- const RefreshCw = createLucideIcon("refresh-cw", __iconNode$k);
3863
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$l);
3832
3864
 
3833
3865
  /**
3834
3866
  * @license lucide-react v0.539.0 - ISC
@@ -3838,14 +3870,28 @@ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$k);
3838
3870
  */
3839
3871
 
3840
3872
 
3841
- const __iconNode$j = [
3873
+ const __iconNode$k = [
3842
3874
  ["path", { d: "M4 7V4h16v3", key: "9msm58" }],
3843
3875
  ["path", { d: "M5 20h6", key: "1h6pxn" }],
3844
3876
  ["path", { d: "M13 4 8 20", key: "kqq6aj" }],
3845
3877
  ["path", { d: "m15 15 5 5", key: "me55sn" }],
3846
3878
  ["path", { d: "m20 15-5 5", key: "11p7ol" }]
3847
3879
  ];
3848
- const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$j);
3880
+ const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$k);
3881
+
3882
+ /**
3883
+ * @license lucide-react v0.539.0 - ISC
3884
+ *
3885
+ * This source code is licensed under the ISC license.
3886
+ * See the LICENSE file in the root directory of this source tree.
3887
+ */
3888
+
3889
+
3890
+ const __iconNode$j = [
3891
+ ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
3892
+ ["path", { d: "M3 3v5h5", key: "1xhq8a" }]
3893
+ ];
3894
+ const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$j);
3849
3895
 
3850
3896
  /**
3851
3897
  * @license lucide-react v0.539.0 - ISC
@@ -4654,7 +4700,7 @@ const buttonVariants$1 = cva("inline-flex items-center justify-center gap-2 whit
4654
4700
  });
4655
4701
  function Button$1({ className, variant, size, asChild = false, ...props }) {
4656
4702
  const Comp = asChild ? Slot : 'button';
4657
- return (jsx(Comp, { "data-slot": "button", className: cn(buttonVariants$1({ variant, size, className })), ...props }));
4703
+ return (jsx(Comp, { "data-slot": "button", "data-variant": variant ?? 'default', className: cn(buttonVariants$1({ variant, size, className })), ...props }));
4658
4704
  }
4659
4705
 
4660
4706
  const VARIANT_BY_KIND = {
@@ -13448,7 +13494,7 @@ collisionPadding = 8, ...props }, ref) {
13448
13494
  });
13449
13495
 
13450
13496
  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', }) => {
13451
- return (jsx(TooltipProvider, { delayDuration: 200, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { className: disabled ? 'cursor-not-allowed inline-flex' : 'inline-flex', children: jsx(Button$1, { size: "sm", variant: "ghost", className: colorClass, onClick: (e) => {
13497
+ return (jsx(TooltipProvider, { delayDuration: 200, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { className: disabled ? 'cursor-not-allowed inline-flex' : 'inline-flex', children: jsx(Button$1, { size: "sm", variant: "ghost", className: colorClass, "aria-label": tooltip, onClick: (e) => {
13452
13498
  e.stopPropagation();
13453
13499
  onClick?.(e);
13454
13500
  }, disabled: disabled, children: icon }) }) }), jsx(TooltipContent, { children: tooltip })] }) }));
@@ -14312,7 +14358,7 @@ function useNumberInput({ value, onChange, precision, min, max, emptyFallback, e
14312
14358
  return { raw, handleChange, handleFocus, handleBlur };
14313
14359
  }
14314
14360
 
14315
- const NumberInput = React.forwardRef(({ value, onChange, precision, min, max, step, className, emptyFallback = 0, emitUndefinedOnEmpty = false, trimTrailingZeros = false, ...rest }, ref) => {
14361
+ const NumberInput = React.forwardRef(({ value, onChange, precision, min, max, step, className, emptyFallback = 0, emitUndefinedOnEmpty = false, trimTrailingZeros = false, suffix, stepper = false, ...rest }, ref) => {
14316
14362
  const { onFocus: onFocusProp, onBlur: onBlurProp, ...inputRest } = rest;
14317
14363
  const { raw, handleChange, handleFocus, handleBlur } = useNumberInput({
14318
14364
  value,
@@ -14326,7 +14372,22 @@ const NumberInput = React.forwardRef(({ value, onChange, precision, min, max, st
14326
14372
  onFocusProp,
14327
14373
  onBlurProp,
14328
14374
  });
14329
- return (jsx(Input, { ref: ref, type: "text", inputMode: "decimal", className: className, value: raw, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, step: step, ...inputRest }));
14375
+ const input = (jsx(Input, { ref: ref, type: "text", inputMode: "decimal", className: cn(className, suffix != null && !stepper && 'pr-10', stepper && 'h-full border-0 bg-transparent px-1 text-center shadow-none focus-visible:ring-0'), value: raw, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, step: step, ...inputRest }));
14376
+ if (stepper) {
14377
+ const current = Number(value);
14378
+ const delta = step ?? 1;
14379
+ const at = Number.isFinite(current) ? current : (min ?? 0);
14380
+ const nudge = (direction) => {
14381
+ const next = at + direction * delta;
14382
+ onChange?.(Math.min(max ?? next, Math.max(min ?? next, next)));
14383
+ };
14384
+ const stepButton = 'flex size-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground transition-colors hover:bg-muted/70 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40';
14385
+ return (jsxs("div", { "aria-invalid": inputRest['aria-invalid'], className: cn('flex h-10 w-full items-center gap-1 rounded-md border border-input-border px-1.5 dark:bg-input/30', 'focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50', 'aria-invalid:border-destructive aria-invalid:ring-destructive/20'), children: [jsx("button", { type: "button", "aria-label": "Decrease", className: stepButton, disabled: inputRest.disabled || (min !== undefined && at <= min), onClick: () => nudge(-1), children: jsx(Minus, { className: "size-3.5" }) }), input, jsx("button", { type: "button", "aria-label": "Increase", className: stepButton, disabled: inputRest.disabled || (max !== undefined && at >= max), onClick: () => nudge(1), children: jsx(Plus, { className: "size-3.5" }) })] }));
14386
+ }
14387
+ if (suffix != null) {
14388
+ return (jsxs("div", { className: "relative w-full", children: [input, jsx("span", { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-sm text-muted-foreground", children: suffix })] }));
14389
+ }
14390
+ return input;
14330
14391
  });
14331
14392
  NumberInput.displayName = 'NumberInput';
14332
14393
 
@@ -14868,30 +14929,74 @@ const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (jsx(Di
14868
14929
  'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 ' +
14869
14930
  'fixed inset-0 z-50 bg-black/50', className), ...props })));
14870
14931
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
14871
- const DialogContent = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [jsx(DialogOverlay, {}), jsxs(DialogPrimitive.Content, { ref: ref, "data-slot": "dialog-content", className: cn('bg-background fixed top-[50%] left-[50%] z-50 grid ' +
14872
- 'w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] ' +
14873
- 'gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg ' +
14932
+ const DIALOG_WIDTH = {
14933
+ default: '32rem',
14934
+ wide: '50rem',
14935
+ };
14936
+ /** Every dialog stops growing here; taller content scrolls inside it. */
14937
+ const DIALOG_MAX_HEIGHT = 'min(85vh, 45rem)';
14938
+ const DialogContent = React.forwardRef(({ className, children, hideCloseButton, size = 'default', style, ...props }, ref) => (jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [jsx(DialogOverlay, {}), jsxs(DialogPrimitive.Content, { ref: ref, "data-slot": "dialog-content", className: cn('bg-card fixed top-[50%] left-[50%] z-50 grid ' +
14939
+ 'translate-x-[-50%] translate-y-[-50%] ' +
14940
+ 'gap-4 overflow-y-auto overscroll-contain rounded-2xl border border-border p-6 shadow-xl duration-200 ' +
14941
+ // A footer closes the panel itself; sticky can't sit in the padding a negative margin would bleed into.
14942
+ 'has-[[data-slot=dialog-footer]]:pb-0 ' +
14874
14943
  'data-[state=open]:animate-in data-[state=closed]:animate-out ' +
14875
14944
  'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 ' +
14876
- 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', className), ...props, children: [children, !hideCloseButton && (jsxs(DialogPrimitive.Close, { className: cn('absolute top-4 right-4 rounded-xs opacity-70 transition-opacity ' +
14877
- 'hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring ' +
14878
- 'focus:ring-offset-2 ring-offset-background disabled:pointer-events-none ' +
14879
- '[&_svg]:pointer-events-none [&_svg]:shrink-0 ' +
14945
+ 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', className), style: {
14946
+ ...style,
14947
+ width: 'calc(100vw - 2rem)',
14948
+ maxWidth: DIALOG_WIDTH[size],
14949
+ maxHeight: DIALOG_MAX_HEIGHT,
14950
+ }, ...props, children: [children, !hideCloseButton && (jsxs(DialogPrimitive.Close, { className: cn('absolute top-5 right-5 inline-flex size-7 items-center justify-center rounded-md ' +
14951
+ 'text-muted-foreground transition-colors hover:bg-muted hover:text-foreground ' +
14952
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ' +
14953
+ 'disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 ' +
14880
14954
  "[&_svg:not([class*='size-'])]:size-4"), children: [jsx(X$2, {}), jsx("span", { className: "sr-only", children: "Close" })] }))] })] })));
14881
14955
  DialogContent.displayName = DialogPrimitive.Content.displayName;
14882
- // Header
14883
- function DialogHeader({ className, ...props }) {
14884
- return (jsx("div", { "data-slot": "dialog-header", className: cn('flex flex-col gap-2 text-center sm:text-left', className), ...props }));
14956
+ const DIALOG_ICON_TONE = {
14957
+ primary: 'bg-primary/10 text-primary dark:bg-primary/20',
14958
+ neutral: 'bg-muted text-muted-foreground',
14959
+ warning: 'bg-badge-amber-bg text-badge-amber-text',
14960
+ destructive: 'bg-badge-destructive-bg text-destructive',
14961
+ };
14962
+ /** The tinted tile that names a dialog's action; shared by every dialog header. */
14963
+ function DialogIcon({ tone = 'primary', className, children, }) {
14964
+ return (jsx("span", { "aria-hidden": true, className: cn(
14965
+ // 44px = the title's 24px line + the subtitle's 20px line, so the tile spans both.
14966
+ 'flex size-11 shrink-0 items-center justify-center rounded-lg [&_svg]:size-5', DIALOG_ICON_TONE[tone], className), children: children }));
14967
+ }
14968
+ function DialogHeader({ className, icon, iconTone, children, ...props }) {
14969
+ if (icon) {
14970
+ return (jsxs("div", { "data-slot": "dialog-header",
14971
+ // A lone title centres on the icon; with a subtitle the pair starts at the icon's top.
14972
+ className: cn('flex flex-row items-center gap-3.5 pr-8 text-left has-[[data-slot=dialog-description]]:items-start', className), ...props, children: [jsx(DialogIcon, { tone: iconTone, children: icon }), jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: children })] }));
14973
+ }
14974
+ return (jsx("div", { "data-slot": "dialog-header", className: cn('flex flex-col pr-8 text-left', className), ...props, children: children }));
14885
14975
  }
14886
14976
  // Footer
14977
+ /** Neutral footer buttons get the card surface so they stand out from the tinted footer band. */
14978
+ const DIALOG_FOOTER_BUTTONS = '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:border ' +
14979
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:border-border ' +
14980
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:bg-card ' +
14981
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:shadow-xs ' +
14982
+ '[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:hover:bg-muted ' +
14983
+ // The outline variant forces its own dark fill; keep every footer secondary button on the same card surface.
14984
+ 'dark:[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:!bg-card ' +
14985
+ 'dark:[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:!border-border ' +
14986
+ 'dark:[&_[data-slot=button]:is([data-variant=outline],[data-variant=ghost],[data-variant=secondary])]:hover:!bg-muted';
14887
14987
  function DialogFooter({ className, ...props }) {
14888
- return (jsx("div", { "data-slot": "dialog-footer", className: cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className), ...props }));
14988
+ return (jsx("div", { "data-slot": "dialog-footer",
14989
+ // Bleeds to the dialog's side edges as a tinted band; dialogs that drop the default p-6 reset the margins.
14990
+ className: cn(
14991
+ // Sticky so the actions stay in view while a long body scrolls.
14992
+ 'sticky bottom-0 z-10 -mx-6 mt-1 flex shrink-0 flex-col-reverse gap-2 border-t border-border bg-[color-mix(in_srgb,var(--muted)_40%,var(--card))] px-6 py-4 ' +
14993
+ 'sm:flex-row sm:items-center sm:justify-end', DIALOG_FOOTER_BUTTONS, className), ...props }));
14889
14994
  }
14890
14995
  // Title
14891
- const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(DialogPrimitive.Title, { ref: ref, "data-slot": "dialog-title", className: cn('text-lg font-semibold leading-none', className), ...props })));
14996
+ const DialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(DialogPrimitive.Title, { ref: ref, "data-slot": "dialog-title", className: cn('text-lg font-semibold leading-6 text-foreground', className), ...props })));
14892
14997
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
14893
14998
  // Description
14894
- const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(DialogPrimitive.Description, { ref: ref, "data-slot": "dialog-description", className: cn('text-sm text-muted-foreground', className), ...props })));
14999
+ const DialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(DialogPrimitive.Description, { ref: ref, "data-slot": "dialog-description", className: cn('text-sm leading-5 text-muted-foreground', className), ...props })));
14895
15000
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
14896
15001
 
14897
15002
  // ---------- Command Wrapper ----------
@@ -15311,36 +15416,467 @@ function ApiComboBox({ contactType, selectedItem, onSelect, fetchBusinessContact
15311
15416
  : '', fetchPage: fetchPage, resolveById: resolveById, preSelectedId: customerCode, searchPlaceholder: searchPlaceholder, emptyMessage: "No business contacts found.", disabled: disabled, className: className, align: align, debounceMs: 300, hideTriggerSearchIcon: hideTriggerSearchIcon }));
15312
15417
  }
15313
15418
 
15419
+ const NUMBER = String.raw `(\d+(?:\.\d+)?|\.\d+)`;
15420
+ const COMPARISON_RE = new RegExp(`^(>=|<=|>|<)${NUMBER}$`);
15421
+ const BETWEEN_RE = new RegExp(`^${NUMBER}-${NUMBER}$`);
15422
+ const EXACT_RE = new RegExp(`^${NUMBER}$`);
15423
+ const NUMBER_EXPRESSION_HELP = [
15424
+ { rule: '>1', meaning: 'More than 1' },
15425
+ { rule: '<3', meaning: 'Less than 3' },
15426
+ { rule: '>=1.5', meaning: '1.5 or more' },
15427
+ { rule: '<=3', meaning: '3 or less' },
15428
+ { rule: '1–3', meaning: 'Between 1 and 3, inclusive' },
15429
+ { rule: '1.52', meaning: 'Exactly 1.52' },
15430
+ ];
15431
+ /** Parses the typed rules in `NUMBER_EXPRESSION_HELP`. Accepts `-`, `–` or `—` for ranges and ignores spaces and thousands commas. */
15432
+ function parseNumberExpression(text) {
15433
+ const normalized = text.replace(/[\s,]/g, '').replace(/[–—]/g, '-');
15434
+ if (!normalized)
15435
+ return { ok: true, range: undefined };
15436
+ const comparison = COMPARISON_RE.exec(normalized);
15437
+ if (comparison) {
15438
+ const [, operator, raw] = comparison;
15439
+ const value = Number(raw);
15440
+ if (operator.startsWith('>')) {
15441
+ return {
15442
+ ok: true,
15443
+ range: { min: value, minExclusive: operator === '>' },
15444
+ };
15445
+ }
15446
+ return { ok: true, range: { max: value, maxExclusive: operator === '<' } };
15447
+ }
15448
+ const between = BETWEEN_RE.exec(normalized);
15449
+ if (between) {
15450
+ const min = Number(between[1]);
15451
+ const max = Number(between[2]);
15452
+ return min <= max ? { ok: true, range: { min, max } } : { ok: false };
15453
+ }
15454
+ const exact = EXACT_RE.exec(normalized);
15455
+ if (exact) {
15456
+ const value = Number(exact[1]);
15457
+ return { ok: true, range: { min: value, max: value } };
15458
+ }
15459
+ return { ok: false };
15460
+ }
15461
+ function formatNumberRange(range) {
15462
+ if (!range)
15463
+ return '';
15464
+ const { min, max, minExclusive, maxExclusive } = range;
15465
+ if (min !== undefined && max !== undefined) {
15466
+ return min === max ? String(min) : `${min}–${max}`;
15467
+ }
15468
+ if (min !== undefined)
15469
+ return `${minExclusive ? '>' : '>='}${min}`;
15470
+ if (max !== undefined)
15471
+ return `${maxExclusive ? '<' : '<='}${max}`;
15472
+ return '';
15473
+ }
15474
+ /** Splits a pasted list — commas, semicolons, spaces and new lines all separate IDs. Keeps first-seen order, drops duplicates. */
15475
+ function splitIdList(text) {
15476
+ return Array.from(new Set(text
15477
+ .split(/[\s,;]+/)
15478
+ .map((id) => id.trim())
15479
+ .filter(Boolean)));
15480
+ }
15481
+ function getOptionLabel(options, value) {
15482
+ return options.find((option) => option.value === value)?.label ?? value;
15483
+ }
15484
+ /** Trigger summary for a multi-select: the first selected option (in option order) plus how many more, e.g. `Red +1`. */
15485
+ function summarizeSelection(values, options) {
15486
+ if (values.length === 0)
15487
+ return '';
15488
+ const first = options.find((option) => values.includes(option.value))?.label ?? values[0];
15489
+ return values.length > 1 ? `${first} +${values.length - 1}` : first;
15490
+ }
15491
+ function formatSelectedCount(selected, total) {
15492
+ return `${selected} of ${total} selected`;
15493
+ }
15494
+ function toggleValue(values, value) {
15495
+ return values.includes(value)
15496
+ ? values.filter((v) => v !== value)
15497
+ : [...values, value];
15498
+ }
15499
+ /** Every option between the two ends of the range, inclusive, in scale order. */
15500
+ function expandScaleRange(options, range) {
15501
+ const fromIndex = options.findIndex((option) => option.value === range.from);
15502
+ const toIndex = options.findIndex((option) => option.value === range.to);
15503
+ if (fromIndex < 0 || toIndex < 0)
15504
+ return [];
15505
+ const [start, end] = fromIndex <= toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
15506
+ return options.slice(start, end + 1).map((option) => option.value);
15507
+ }
15508
+ /** `Very Good` → `VG`, `Fair` → `F`. */
15509
+ function toInitials(label) {
15510
+ return label
15511
+ .split(/[\s-]+/)
15512
+ .filter(Boolean)
15513
+ .map((word) => word[0].toUpperCase())
15514
+ .join('');
15515
+ }
15516
+ function formatScaleRange(options, range, short = false) {
15517
+ const values = expandScaleRange(options, range);
15518
+ if (values.length === 0)
15519
+ return '';
15520
+ const labelOf = (value) => {
15521
+ const label = getOptionLabel(options, value);
15522
+ return short ? toInitials(label) : label;
15523
+ };
15524
+ const first = labelOf(values[0]);
15525
+ return values.length === 1
15526
+ ? first
15527
+ : `${first} – ${labelOf(values[values.length - 1])}`;
15528
+ }
15529
+ const DATE_PRESET_OPTIONS = [
15530
+ { value: 'today', label: 'Today' },
15531
+ { value: 'last7Days', label: 'Last 7 days' },
15532
+ { value: 'last30Days', label: 'Last 30 days' },
15533
+ { value: 'thisMonth', label: 'This month' },
15534
+ { value: 'thisFiscalYear', label: 'This fiscal year' },
15535
+ ];
15536
+ function toIsoDate(date) {
15537
+ const month = String(date.getMonth() + 1).padStart(2, '0');
15538
+ const day = String(date.getDate()).padStart(2, '0');
15539
+ return `${date.getFullYear()}-${month}-${day}`;
15540
+ }
15541
+ /** `YYYY-MM-DD` → local date (no timezone shift); empty → undefined. */
15542
+ function fromIsoDate(iso) {
15543
+ if (!iso)
15544
+ return undefined;
15545
+ const [year, month, day] = iso.split('-').map(Number);
15546
+ return new Date(year, month - 1, day);
15547
+ }
15548
+ function daysBefore(today, days) {
15549
+ return new Date(today.getFullYear(), today.getMonth(), today.getDate() - days);
15550
+ }
15551
+ /** `fiscalYearStartMonth` is 1–12 (1 = January, 4 = April). */
15552
+ function resolveDatePreset(preset, today, fiscalYearStartMonth = 1) {
15553
+ const to = toIsoDate(today);
15554
+ switch (preset) {
15555
+ case 'today':
15556
+ return { from: to, to };
15557
+ case 'last7Days':
15558
+ return { from: toIsoDate(daysBefore(today, 6)), to };
15559
+ case 'last30Days':
15560
+ return { from: toIsoDate(daysBefore(today, 29)), to };
15561
+ case 'thisMonth':
15562
+ return {
15563
+ from: toIsoDate(new Date(today.getFullYear(), today.getMonth(), 1)),
15564
+ to,
15565
+ };
15566
+ case 'thisFiscalYear': {
15567
+ const startMonthIndex = fiscalYearStartMonth - 1;
15568
+ const startYear = today.getMonth() >= startMonthIndex
15569
+ ? today.getFullYear()
15570
+ : today.getFullYear() - 1;
15571
+ return { from: toIsoDate(new Date(startYear, startMonthIndex, 1)), to };
15572
+ }
15573
+ }
15574
+ }
15575
+ function resolveDateRange(range, today, fiscalYearStartMonth = 1) {
15576
+ if (range.preset)
15577
+ return resolveDatePreset(range.preset, today, fiscalYearStartMonth);
15578
+ return { from: range.from, to: range.to };
15579
+ }
15580
+ function formatIsoDate(iso) {
15581
+ const [year, month, day] = iso.split('-').map(Number);
15582
+ return new Date(year, month - 1, day).toLocaleDateString('en-GB', {
15583
+ day: 'numeric',
15584
+ month: 'short',
15585
+ year: 'numeric',
15586
+ });
15587
+ }
15588
+ function formatDateRange(range) {
15589
+ if (range.preset)
15590
+ return (DATE_PRESET_OPTIONS.find((option) => option.value === range.preset)
15591
+ ?.label ?? '');
15592
+ if (range.from && range.to)
15593
+ return `${formatIsoDate(range.from)} – ${formatIsoDate(range.to)}`;
15594
+ if (range.from)
15595
+ return `From ${formatIsoDate(range.from)}`;
15596
+ if (range.to)
15597
+ return `Until ${formatIsoDate(range.to)}`;
15598
+ return '';
15599
+ }
15600
+ const TRI_STATE_OPTIONS = [
15601
+ { value: 'any', label: 'Any' },
15602
+ { value: 'yes', label: 'Yes' },
15603
+ { value: 'no', label: 'No' },
15604
+ ];
15605
+ function isFilterValueActive(value) {
15606
+ if (!value)
15607
+ return false;
15608
+ switch (value.type) {
15609
+ case 'list':
15610
+ return value.values.length > 0;
15611
+ case 'ids':
15612
+ return value.ids.length > 0;
15613
+ case 'contains':
15614
+ return value.text.trim().length > 0;
15615
+ case 'number':
15616
+ return value.range.min !== undefined || value.range.max !== undefined;
15617
+ case 'date':
15618
+ return Boolean(value.range.preset || value.range.from || value.range.to);
15619
+ case 'scale':
15620
+ case 'bool':
15621
+ return true;
15622
+ }
15623
+ }
15624
+ const FILTER_FOCUS_RING = 'outline-none focus-visible:ring-2 focus-visible:ring-primary/30';
15625
+ /** Text-link actions such as Clear and "Show all". */
15626
+ const FILTER_LINK_CLASS_NAME = cn('cursor-pointer rounded-sm text-xs font-medium text-primary hover:underline', FILTER_FOCUS_RING);
15627
+ /** A fixed column count, or (when omitted) as many columns as fit at `minWidth` each. */
15628
+ function getGridColumnsStyle(columns, minWidth = '7rem') {
15629
+ return {
15630
+ gridTemplateColumns: columns
15631
+ ? `repeat(${columns}, minmax(0, 1fr))`
15632
+ : `repeat(auto-fill, minmax(${minWidth}, 1fr))`,
15633
+ };
15634
+ }
15635
+ /** 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. */
15636
+ function getSelectableOptionClassName(selected, className) {
15637
+ return cn('cursor-pointer border text-xs transition-colors', FILTER_FOCUS_RING, selected
15638
+ ? 'border-primary bg-primary/5 font-medium text-primary'
15639
+ : 'border-border bg-background text-foreground hover:bg-secondary dark:bg-muted/60 dark:hover:bg-muted', className);
15640
+ }
15641
+ /** Shared look of every filter-row control (trigger buttons and inline inputs). */
15642
+ function getFilterFieldClassName(state, className) {
15643
+ return cn('flex h-7 w-full min-w-0 items-center gap-1 rounded-sm border px-2 text-xs transition-colors outline-none', 'focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-primary/30', state === 'empty' &&
15644
+ 'border-input bg-card text-foreground placeholder:text-placeholder', state === 'applied' &&
15645
+ 'border-primary bg-primary/5 font-medium text-primary', state === 'invalid' && 'border-destructive bg-card text-destructive', state === 'disabled' &&
15646
+ 'pointer-events-none border-dashed border-border bg-transparent', className);
15647
+ }
15648
+
15649
+ function getPanelClassName(variant, active, className) {
15650
+ 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);
15651
+ }
15652
+ function getTitleClassName(variant) {
15653
+ return cn('flex items-center gap-2 text-foreground', variant === 'section'
15654
+ ? 'text-xs font-medium text-label'
15655
+ : 'text-sm font-semibold');
15656
+ }
15657
+
15658
+ /** Shell for one filter: title, selected badge, applied summary, Clear and a hint. Same content in popovers and on full-page surfaces. */
15659
+ function FilterPanel({ title, status, selectedCount, summary, action, onClear, hint, active = false, variant = 'card', className, children, }) {
15660
+ const hasHeader = Boolean(title || status || summary || action || onClear);
15661
+ return (jsxs("section", { className: getPanelClassName(variant, active, className), children: [hasHeader && (jsxs("header", { className: "flex min-h-5 items-center justify-between gap-3", children: [title ? (jsxs("h3", { className: getTitleClassName(variant), children: [title, selectedCount ? (jsx("span", { className: "inline-flex size-5 items-center justify-center rounded-full bg-primary text-xs font-semibold text-primary-foreground", children: selectedCount })) : null] })) : (jsx("span", { className: "text-xs text-muted-foreground", children: status })), jsxs("div", { className: "flex items-center gap-3 text-xs", children: [summary && (jsx("span", { className: "font-medium text-primary", children: summary })), action, onClear && (jsx("button", { type: "button", onClick: onClear, className: FILTER_LINK_CLASS_NAME, children: "Clear" }))] })] })), children, hint && jsx("p", { className: "text-xs text-muted-foreground", children: hint })] }));
15662
+ }
15663
+
15314
15664
  function Checkbox({ className, ...props }) {
15315
15665
  return (jsx(CheckboxPrimitive.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: jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "flex items-center justify-center text-current transition-none", children: jsx(Check, { className: "size-3.5" }) }) }));
15316
15666
  }
15317
15667
 
15668
+ // Sub-pixel rounding leaves scrollTop a hair short of the end.
15669
+ const EDGE_TOLERANCE_PX = 1;
15670
+ function getScrollFadeState(el) {
15671
+ const { scrollTop, scrollHeight, clientHeight } = el;
15672
+ return {
15673
+ top: scrollTop > EDGE_TOLERANCE_PX,
15674
+ bottom: scrollTop + clientHeight < scrollHeight - EDGE_TOLERANCE_PX,
15675
+ };
15676
+ }
15677
+ const FADE_BASE_CLASS_NAME = 'pointer-events-none absolute inset-x-0 h-8 from-card to-transparent';
15678
+
15679
+ function useScrollFade() {
15680
+ const ref = useRef(null);
15681
+ const [state, setState] = useState({
15682
+ top: false,
15683
+ bottom: false,
15684
+ });
15685
+ const update = useCallback(() => {
15686
+ if (!ref.current)
15687
+ return;
15688
+ const next = getScrollFadeState(ref.current);
15689
+ // Skip no-op updates (observers fire often).
15690
+ setState((current) => current.top === next.top && current.bottom === next.bottom
15691
+ ? current
15692
+ : next);
15693
+ }, []);
15694
+ useEffect(() => {
15695
+ const el = ref.current;
15696
+ if (!el)
15697
+ return;
15698
+ update();
15699
+ const resizeObserver = new ResizeObserver(update);
15700
+ resizeObserver.observe(el);
15701
+ const mutationObserver = new MutationObserver(update);
15702
+ mutationObserver.observe(el, { childList: true, subtree: true });
15703
+ return () => {
15704
+ resizeObserver.disconnect();
15705
+ mutationObserver.disconnect();
15706
+ };
15707
+ }, [update]);
15708
+ return { ref, update, ...state };
15709
+ }
15710
+
15711
+ /** Scroll container that fades its top / bottom edge while more content is hidden there, so it reads as scrollable. */
15712
+ function ScrollFade({ className, wrapperClassName, children, ...props }) {
15713
+ const { ref, update, top, bottom } = useScrollFade();
15714
+ return (jsxs("div", { className: cn('relative', wrapperClassName), children: [jsx("div", { ...props, ref: ref, onScroll: update, className: className, children: children }), top && (jsx("div", { "aria-hidden": "true", className: cn(FADE_BASE_CLASS_NAME, 'top-0 bg-gradient-to-b') })), bottom && (jsx("div", { "aria-hidden": "true", className: cn(FADE_BASE_CLASS_NAME, 'bottom-0 bg-gradient-to-t') }))] }));
15715
+ }
15716
+
15717
+ // Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
15718
+ // labels that are not actually clipped.
15719
+ const OVERFLOW_TOLERANCE_PX = 1;
15720
+ function findClippedLabel(root) {
15721
+ const spans = root.querySelectorAll(':scope > span');
15722
+ for (const span of Array.from(spans)) {
15723
+ if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX) {
15724
+ return span;
15725
+ }
15726
+ }
15727
+ return null;
15728
+ }
15729
+ /**
15730
+ * Returns the full text of the first direct-child `<span>` of `ref` that is
15731
+ * clipped by its container (i.e. showing an ellipsis), else `null` — so callers
15732
+ * can surface a tooltip only when the label is actually unreadable.
15733
+ *
15734
+ * Re-measures on element resize (sidebar expand/collapse, window resize) and on
15735
+ * label text changes.
15736
+ */
15737
+ function useTruncatedText(ref) {
15738
+ const [text, setText] = useState(null);
15739
+ useEffect(() => {
15740
+ const el = ref.current;
15741
+ if (!el)
15742
+ return;
15743
+ let frame = 0;
15744
+ const measure = () => {
15745
+ const label = findClippedLabel(el);
15746
+ setText(label?.textContent?.trim() || null);
15747
+ };
15748
+ const schedule = () => {
15749
+ cancelAnimationFrame(frame);
15750
+ frame = requestAnimationFrame(measure);
15751
+ };
15752
+ schedule();
15753
+ const resizeObserver = new ResizeObserver(schedule);
15754
+ resizeObserver.observe(el);
15755
+ const mutationObserver = new MutationObserver(schedule);
15756
+ mutationObserver.observe(el, {
15757
+ characterData: true,
15758
+ childList: true,
15759
+ subtree: true,
15760
+ });
15761
+ return () => {
15762
+ cancelAnimationFrame(frame);
15763
+ resizeObserver.disconnect();
15764
+ mutationObserver.disconnect();
15765
+ };
15766
+ }, [ref]);
15767
+ return text;
15768
+ }
15769
+
15770
+ /** Single-line label that shows its full text in a tooltip, only while it is cut off. */
15771
+ function TruncatedLabel({ text, className, }) {
15772
+ const ref = useRef(null);
15773
+ const clipped = useTruncatedText(ref);
15774
+ return (jsx(TooltipProvider, { delayDuration: 300, children: jsxs(Tooltip, { open: clipped ? undefined : false, children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { ref: ref, className: "block w-full min-w-0", children: jsx("span", { className: cn('block truncate', className), children: text }) }) }), jsx(TooltipContent, { children: text })] }) }));
15775
+ }
15776
+
15777
+ function filterOptionsByQuery(options, query) {
15778
+ const needle = query.trim().toLowerCase();
15779
+ if (!needle)
15780
+ return [...options];
15781
+ return options.filter((option) => option.label.toLowerCase().includes(needle));
15782
+ }
15783
+ function getChipClassName(selected) {
15784
+ return getSelectableOptionClassName(selected, 'inline-flex h-8 items-center gap-1.5 rounded-full px-3');
15785
+ }
15786
+ function getTileClassName(selected) {
15787
+ return getSelectableOptionClassName(selected, 'flex min-h-11 min-w-0 flex-col items-center justify-center gap-0.5 rounded-md px-2 py-1.5 text-center');
15788
+ }
15789
+ /** The list's search box only appears once there are enough options to need it. */
15790
+ const SEARCH_MIN_OPTIONS = 9;
15791
+ /** Long option sets scroll inside the card or popover instead of growing it. */
15792
+ const OPTIONS_SCROLL_CLASS_NAME = 'max-h-48 overflow-y-auto';
15793
+ /** Fills a stretched card: at least the usual height, growing into any space the row gives it (never driving the row height). */
15794
+ const OPTIONS_FILL_CLASS_NAME = 'min-h-48 flex-1 basis-0 overflow-y-auto';
15795
+ const FILL_WRAPPER_CLASS_NAME = 'flex min-h-0 flex-1 flex-col';
15796
+ /** Card lists flow into as many columns as fit; popover lists stay one column. */
15797
+ const LIST_COLUMN_MIN_WIDTH = '10rem';
15798
+ const getOptionsScrollClassName = (fill) => fill ? OPTIONS_FILL_CLASS_NAME : OPTIONS_SCROLL_CLASS_NAME;
15799
+ const LIST_ROW_CLASS_NAME = 'flex w-full cursor-pointer items-center gap-3 rounded-md px-2 py-2 text-sm text-foreground hover:bg-muted/50';
15800
+ /** Outlined (not filled) box until checked; the border is dark enough to read on white. */
15801
+ const LIST_CHECKBOX_CLASS_NAME = 'size-4.5 border-muted-foreground/50 bg-card dark:border-muted-foreground/60 dark:bg-transparent';
15802
+ const SEARCH_BOX_CLASS_NAME = 'flex h-9 items-center gap-2 rounded-lg border border-input bg-card px-3 focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/30';
15803
+
15804
+ function usePickListFilter({ options, value, layout, }) {
15805
+ const [query, setQuery] = useState('');
15806
+ const visibleOptions = useMemo(() => (layout === 'list' ? filterOptionsByQuery(options, query) : options), [layout, options, query]);
15807
+ const selectedCount = useMemo(() => options.filter((option) => value.includes(option.value)).length, [options, value]);
15808
+ return { query, setQuery, visibleOptions, selectedCount };
15809
+ }
15810
+
15811
+ const getSearchInputLabel = (ariaLabel) => `Search ${ariaLabel}`;
15812
+
15813
+ function OptionSwatch({ color, round, }) {
15814
+ if (!color)
15815
+ return null;
15816
+ return (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 } }));
15817
+ }
15818
+ /** Multi-select filter: a searchable checkbox list, or pill / tile toggles. Long sets scroll within a max height. */
15819
+ function PickListFilter({ options, value, onChange, ariaLabel, layout = 'list', searchPlaceholder, alwaysSearchable = false, columns = 5, fill = false, listClassName, }) {
15820
+ const { query, setQuery, visibleOptions, selectedCount } = usePickListFilter({
15821
+ options,
15822
+ value,
15823
+ layout,
15824
+ });
15825
+ const scrollClassName = getOptionsScrollClassName(fill);
15826
+ // Rows with a right-hand hint read best in one column.
15827
+ const multiColumn = fill && !options.some((option) => option.hint);
15828
+ const wrapperClassName = fill ? FILL_WRAPPER_CLASS_NAME : undefined;
15829
+ const toggle = (option) => onChange(toggleValue(value, option.value));
15830
+ if (options.length === 0) {
15831
+ return (jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No options available" }));
15832
+ }
15833
+ if (layout === 'list') {
15834
+ return (jsxs("div", { className: cn('flex flex-col gap-2', fill && FILL_WRAPPER_CLASS_NAME), "aria-label": ariaLabel, role: "group", children: [searchPlaceholder !== undefined &&
15835
+ (alwaysSearchable || options.length >= SEARCH_MIN_OPTIONS) && (jsxs("label", { className: SEARCH_BOX_CLASS_NAME, children: [jsx(Search, { "aria-hidden": "true", className: "size-4 shrink-0 text-muted-foreground" }), 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" })] })), jsxs("div", { className: "flex items-center justify-between px-1 text-xs text-muted-foreground", children: [jsx("span", { children: formatSelectedCount(selectedCount, options.length) }), selectedCount > 0 && (jsx("button", { type: "button", onClick: () => onChange([]), className: FILTER_LINK_CLASS_NAME, children: "Clear" }))] }), jsx(ScrollFade, { className: cn(multiColumn && 'grid content-start gap-x-3', scrollClassName, listClassName), style: multiColumn
15836
+ ? getGridColumnsStyle(undefined, LIST_COLUMN_MIN_WIDTH)
15837
+ : undefined, wrapperClassName: wrapperClassName, children: visibleOptions.map((option) => (jsxs("label", { className: LIST_ROW_CLASS_NAME, children: [jsx(Checkbox, { className: LIST_CHECKBOX_CLASS_NAME, checked: value.includes(option.value), onCheckedChange: () => toggle(option) }), jsx(OptionSwatch, { color: option.swatch }), option.content ? (jsx("span", { className: "min-w-0 flex-1", children: option.content })) : (jsx(TruncatedLabel, { text: option.label, className: "flex-1" })), (option.count ?? option.hint) !== undefined && (jsx("span", { className: "shrink-0 text-muted-foreground tabular-nums", children: option.count ?? option.hint }))] }, option.value))) })] }));
15838
+ }
15839
+ if (layout === 'tiles') {
15840
+ return (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) => (jsxs("button", { type: "button", "aria-pressed": value.includes(option.value), onClick: () => toggle(option), className: getTileClassName(value.includes(option.value)), children: [jsx(TruncatedLabel, { text: option.label }), option.count !== undefined && (jsx("span", { className: "text-xs font-normal text-muted-foreground", children: option.count }))] }, option.value))) }));
15841
+ }
15842
+ return (jsx(ScrollFade, { role: "group", "aria-label": ariaLabel, wrapperClassName: wrapperClassName, className: cn('flex flex-wrap content-start gap-1.5', scrollClassName), children: visibleOptions.map((option) => (jsxs("button", { type: "button", "aria-pressed": value.includes(option.value), onClick: () => toggle(option), className: getChipClassName(value.includes(option.value)), children: [jsx(OptionSwatch, { color: option.swatch, round: true }), jsx("span", { children: option.label }), option.count !== undefined && (jsx("span", { className: "font-normal text-muted-foreground", children: option.count }))] }, option.value))) }));
15843
+ }
15844
+
15318
15845
  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';
15319
15846
  const TRIGGER_ACTIVE = '!border-primary text-primary shadow-[0_0_0_3px_rgba(49,122,81,0.10)]';
15320
15847
  const CONTENT_BASE = 'min-w-[8rem]';
15321
15848
  const isFilterActive = (value, resetValue) => !!value && value !== resetValue;
15849
+ function collectText(node) {
15850
+ if (typeof node === 'string' || typeof node === 'number')
15851
+ return String(node);
15852
+ if (Array.isArray(node))
15853
+ return node.map(collectText).join(' ');
15854
+ if (isValidElement(node))
15855
+ return Children.toArray(node.props.children).map(collectText).join(' ');
15856
+ return '';
15857
+ }
15858
+ /** The visible text inside a label, e.g. a JSX name + description becomes "Name Description". */
15859
+ const getNodeText = (node) => collectText(node).replace(/\s+/g, ' ').trim();
15860
+ /** A JSX label keeps its look as the row's `content`; its text (or the value) is what search and screen readers use. */
15861
+ const toPickListOptions = (options) => options.map((option) => typeof option.label === 'string'
15862
+ ? { value: option.value, label: option.label }
15863
+ : {
15864
+ value: option.value,
15865
+ label: getNodeText(option.label) || option.value,
15866
+ content: option.label,
15867
+ });
15322
15868
 
15323
15869
  /**
15324
- * Multi-select filter dropdown — Popover + checkbox list, matching the
15325
- * `FilterSelect` trigger look (filter icon + count badge when active).
15326
- * Selecting items keeps the popover open; the trigger shows the count.
15870
+ * Multi-select filter dropdown with the `FilterSelect` trigger look (filter icon + count badge when active).
15871
+ * Opens a pick list: a searchable checkbox list with "x of y selected · Clear", or chips/tiles under a
15872
+ * title, count and Clear. Selecting keeps the popover open.
15327
15873
  */
15328
- const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, }) => {
15874
+ const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, pickListLayout = 'list', searchPlaceholder, }) => {
15329
15875
  const active = value.length > 0;
15330
- const toggle = (optValue) => {
15331
- if (value.includes(optValue)) {
15332
- onChange(value.filter((v) => v !== optValue));
15333
- }
15334
- else {
15335
- onChange([...value, optValue]);
15336
- }
15337
- };
15338
- return (jsxs(Popover, { modal: modal, children: [jsx(PopoverTrigger, { className: cn(TRIGGER_BASE, 'inline-flex items-center justify-between', active && TRIGGER_ACTIVE, triggerClassName), children: jsxs("span", { className: "flex items-center gap-2", children: [jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), label, active && (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 }))] }) }), jsx(PopoverContent, { align: "start", className: cn('w-56 p-1', contentClassName), children: jsx("div", { className: cn('max-h-[18rem] overflow-y-auto', listClassName), children: options.map((opt) => {
15339
- const checked = value.includes(opt.value);
15340
- return (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: [jsx(Checkbox, { checked: checked, onCheckedChange: () => toggle(opt.value),
15341
- // Stop the inner checkbox click from double-toggling via the button.
15342
- onClick: (e) => e.stopPropagation() }), jsx("span", { className: "flex-1 truncate", children: opt.label })] }, opt.value));
15343
- }) }) })] }));
15876
+ const isList = pickListLayout === 'list';
15877
+ return (jsxs(Popover, { modal: modal, children: [jsx(PopoverTrigger, { className: cn(TRIGGER_BASE, 'inline-flex items-center justify-between', active && TRIGGER_ACTIVE, triggerClassName), children: jsxs("span", { className: "flex items-center gap-2", children: [jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), label, active && (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 }))] }) }), jsx(PopoverContent, { align: "start", sideOffset: 4, className: cn('w-64 p-0', contentClassName), children: jsx(FilterPanel, { variant: "popover",
15878
+ // A searchable list has its own "x of y selected · Clear" row.
15879
+ title: isList ? undefined : label, selectedCount: isList ? undefined : value.length, onClear: !isList && active ? () => onChange([]) : undefined, children: jsx(PickListFilter, { ariaLabel: label, layout: pickListLayout, options: toPickListOptions(options), value: value, onChange: onChange, searchPlaceholder: isList ? (searchPlaceholder ?? 'Search') : undefined, alwaysSearchable: true, listClassName: listClassName }) }) })] }));
15344
15880
  };
15345
15881
 
15346
15882
  const KYC_STATUS = {
@@ -21211,37 +21747,30 @@ const formatDate$3 = (iso) => {
21211
21747
  }
21212
21748
  };
21213
21749
 
21214
- const InfoCard = ({ info, title, refundToWallet, onRefundChange, }) => {
21750
+ /** The document the dialog acts on: number, customer, total and date, plus paid / outstanding when known. */
21751
+ const InfoCard = ({ info }) => {
21215
21752
  if (!info)
21216
21753
  return null;
21217
21754
  if (React__default.isValidElement(info))
21218
- return jsx("div", { className: "mt-3", children: info });
21755
+ return jsx("div", { children: info });
21219
21756
  const i = info;
21220
- return (jsx("div", { className: "mt-1 rounded-lg border bg-muted p-3 shadow-sm", children: jsxs("div", { className: "flex flex-col gap-1", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Date" }), jsx("div", { children: formatDate$3(i.invoiceDate) })] }), jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Total" }), jsx("div", { className: "font-medium text-foreground", children: formatCurrencyWithTenantSymbol(i.totalAmount) })] }), i.paidAmount !== undefined && (jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Paid" }), jsx("div", { className: "font-medium text-primary", children: formatCurrencyWithTenantSymbol(i.paidAmount) })] })), i.outstandingAmount !== undefined && (jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "w-36 text-sm text-muted-foreground", children: "Outstanding" }), jsx("div", { className: "font-medium text-muted-foreground", children: formatCurrencyWithTenantSymbol(i.outstandingAmount) })] })), title === 'Cancel Invoice' &&
21221
- !React__default.isValidElement(info) &&
21222
- (i?.paidAmount ?? 0) > 0 && (jsxs("div", { className: "flex items-start gap-3", children: [jsx("div", { className: "w-36 whitespace-nowrap text-sm text-muted-foreground", children: "Refund to Wallet" }), jsx(Checkbox, { checked: !!refundToWallet, onCheckedChange: (v) => onRefundChange?.(Boolean(v)), className: "bg-card" })] })), (i.customerName || i.email) && (jsxs("div", { className: "mt-1 rounded bg-card p-2", children: [i.customerName && (jsx("div", { className: "text-sm font-medium", children: i.customerName })), i.email && (jsx("div", { className: "text-sm text-muted-foreground", children: i.email }))] }))] }) }));
21757
+ const party = [i.customerName, i.email].filter(Boolean).join(' · ');
21758
+ const hasBalance = i.paidAmount !== undefined || i.outstandingAmount !== undefined;
21759
+ return (jsxs("div", { className: "rounded-xl border border-border bg-muted/30 p-3.5", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { "aria-hidden": true, className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground", children: jsx(FileText, { className: "size-4" }) }), jsxs("div", { className: "min-w-0 flex-1", children: [i.invoiceNumber && (jsx("p", { className: "m-0 truncate text-sm font-semibold text-foreground", children: i.invoiceNumber })), party && jsx("p", { className: "m-0 truncate text-xs text-muted-foreground", children: party })] }), jsxs("div", { className: "shrink-0 text-right", children: [i.totalAmount !== undefined && (jsx("p", { className: "m-0 text-sm font-semibold tabular-nums text-foreground", children: formatCurrencyWithTenantSymbol(i.totalAmount) })), i.invoiceDate && jsx("p", { className: "m-0 text-xs text-muted-foreground", children: formatDate$3(i.invoiceDate) })] })] }), hasBalance && (jsxs("dl", { className: "m-0 mt-3 grid gap-1.5 border-t border-border pt-3 text-sm", children: [i.paidAmount !== undefined && (jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsx("dt", { className: "text-muted-foreground", children: "Paid" }), jsx("dd", { className: "m-0 font-medium tabular-nums text-amount-paid", children: formatCurrencyWithTenantSymbol(i.paidAmount) })] })), i.outstandingAmount !== undefined && (jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsx("dt", { className: "text-muted-foreground", children: "Outstanding" }), jsx("dd", { className: "m-0 font-medium tabular-nums text-foreground", children: formatCurrencyWithTenantSymbol(i.outstandingAmount) })] }))] }))] }));
21223
21760
  };
21224
21761
 
21225
- function useRefundToWallet(open) {
21226
- const [refundToWallet, setRefundToWallet] = useState(true);
21227
- useEffect(() => {
21228
- if (open)
21229
- setRefundToWallet(true);
21230
- }, [open]);
21231
- return { refundToWallet, setRefundToWallet };
21232
- }
21233
-
21234
- const ConfirmDialog = ({ open, onOpenChange, title, description, info, confirmLabel = 'Yes', cancelLabel = 'Cancel', confirmVariant = 'default', icon: Icon = Trash2, disabled = false, onConfirm, onCancel, }) => {
21235
- const { refundToWallet, setRefundToWallet } = useRefundToWallet(open);
21762
+ const ConfirmDialog = ({ open, onOpenChange, title, description, info, confirmLabel = 'Yes', cancelLabel = 'Cancel', confirmVariant = 'default', icon, disabled = false, onConfirm, onCancel, children, }) => {
21236
21763
  // Opened from a modal menu row, two dismissable layers overlap and Radix
21237
21764
  // restores `pointer-events: none` to <body> on close, freezing the page.
21238
21765
  useOverlayBodyLockRelease(open);
21239
- return (jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxs(DialogContent, { className: "gap-3 p-5", children: [jsxs(DialogHeader, { className: "gap-1.5", children: [jsxs(DialogTitle, { className: "flex items-center gap-2", children: [confirmVariant === 'destructive' && (jsx("span", { className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-destructive/10", children: jsx(Icon, { className: "h-3.5 w-3.5 text-destructive" }) })), jsx("span", { children: title })] }), description && jsx(DialogDescription, { children: description }), info && (jsx(InfoCard, { info: info, title: title, refundToWallet: refundToWallet, onRefundChange: setRefundToWallet }))] }), jsxs(DialogFooter, { className: "mt-1", children: [jsx(Button$1, { variant: "outline", onClick: () => {
21766
+ const destructive = confirmVariant === 'destructive';
21767
+ const Icon = icon ?? (destructive ? Trash2 : undefined);
21768
+ return (jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxs(DialogContent, { children: [jsxs(DialogHeader, { icon: Icon ? jsx(Icon, {}) : undefined, iconTone: destructive ? 'destructive' : 'primary', children: [jsx(DialogTitle, { children: title }), description && jsx(DialogDescription, { children: description })] }), info && jsx(InfoCard, { info: info }), children, jsxs(DialogFooter, { children: [jsx(Button$1, { variant: "outline", onClick: () => {
21240
21769
  onCancel?.();
21241
21770
  onOpenChange(false);
21242
- }, disabled: disabled, children: cancelLabel }), jsxs(Button$1, { variant: confirmVariant, onClick: async () => {
21243
- await onConfirm(title === 'Cancel Invoice' ? refundToWallet : undefined);
21244
- }, disabled: disabled, children: [confirmVariant === 'destructive' && (jsx(Icon, { className: "h-4 w-4", "aria-hidden": true })), disabled ? 'Please wait...' : confirmLabel] })] })] }) }));
21771
+ }, disabled: disabled, children: cancelLabel }), jsx(Button$1, { variant: confirmVariant, onClick: async () => {
21772
+ await onConfirm();
21773
+ }, disabled: disabled, children: disabled ? 'Please wait...' : confirmLabel })] })] }) }));
21245
21774
  };
21246
21775
 
21247
21776
  function matchesSearch(haystack, search) {
@@ -21606,6 +22135,34 @@ function useRowEditing({ saving, onEditChange, onSaveRow, }) {
21606
22135
  handleEditIconClick,
21607
22136
  };
21608
22137
  }
22138
+ /**
22139
+ * Measures the rows area so a loading skeleton can cover exactly the rows it replaces —
22140
+ * the rows stay in the layout (hidden), so column widths and table height never jump.
22141
+ */
22142
+ function useLoadingOverlay(scrollRef, headRef, bodyRef, loading) {
22143
+ const [box, setBox] = useState(null);
22144
+ useLayoutEffect(() => {
22145
+ const scroll = scrollRef.current;
22146
+ const head = headRef.current;
22147
+ const body = bodyRef.current;
22148
+ if (!loading || !scroll || !head || !body) {
22149
+ setBox(null);
22150
+ return;
22151
+ }
22152
+ const measure = () => setBox({
22153
+ top: head.offsetHeight,
22154
+ width: scroll.scrollWidth,
22155
+ height: body.offsetHeight,
22156
+ visibleWidth: scroll.clientWidth,
22157
+ });
22158
+ measure();
22159
+ const observer = new ResizeObserver(measure);
22160
+ observer.observe(scroll);
22161
+ observer.observe(body);
22162
+ return () => observer.disconnect();
22163
+ }, [loading, scrollRef, headRef, bodyRef]);
22164
+ return box;
22165
+ }
21609
22166
 
21610
22167
  function normalizeOptions(options) {
21611
22168
  return options.map((opt) => typeof opt === 'string'
@@ -21636,6 +22193,30 @@ function pinnedHeaderClass() {
21636
22193
  function pinnedCellClass(pinnedBg) {
21637
22194
  return cn('sticky right-0 z-10', PINNED_BEFORE, PINNED_SHADOW, pinnedBg);
21638
22195
  }
22196
+ const PINNED_RIGHT_WIDTH = '72px';
22197
+ /** Width for a header/body/filter cell: the resized width var while resized or dragging, a fixed width for the pinned actions column. */
22198
+ function getColumnWidthStyle(key, isSized, isPinnedRight) {
22199
+ if (isSized) {
22200
+ const width = `var(--col-w-${key})`;
22201
+ return { width, minWidth: width, maxWidth: width };
22202
+ }
22203
+ return isPinnedRight
22204
+ ? {
22205
+ width: PINNED_RIGHT_WIDTH,
22206
+ minWidth: PINNED_RIGHT_WIDTH,
22207
+ maxWidth: PINNED_RIGHT_WIDTH,
22208
+ }
22209
+ : undefined;
22210
+ }
22211
+ function hasFilterRow(columns, filterRowLeading) {
22212
+ return (filterRowLeading != null || columns.some((col) => col.filter !== undefined));
22213
+ }
22214
+ /** `TableRowsSkeleton` bar (52px) plus its gap (8px). */
22215
+ const SKELETON_ROW_PX = 60;
22216
+ /** How many skeleton bars fill a rows area of `height` px (at least one). */
22217
+ function getSkeletonRowCount(height) {
22218
+ return Math.max(1, Math.floor(height / SKELETON_ROW_PX));
22219
+ }
21639
22220
 
21640
22221
  const isValidHex = (v) => /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(v);
21641
22222
  /**
@@ -21727,8 +22308,52 @@ function EditableCellContent({ col, row, value, isEditing, width, onEditValueCha
21727
22308
  }
21728
22309
  return jsx(Fragment$2, { children: clipToWidth(stringValue, width) });
21729
22310
  }
22311
+ const FILTER_CELL = 'px-0.5 py-0.5 font-normal border-b border-solid !border-border';
22312
+ /** Opt-in second header row holding each column's filter control. */
22313
+ function FilterRow({ columns, leading, showEditColumn, showSelectionColumn, isArchiveView, vBorder, localWidths, draggingKey, }) {
22314
+ const leadingCellCount = Number(showEditColumn) + Number(showSelectionColumn);
22315
+ return (jsxs("tr", { children: [Array.from({ length: leadingCellCount }, (_, index) => (jsx("th", { className: cn(FILTER_CELL, 'first:!pl-6 text-left', vBorder), children: index === 0 ? leading : null }, `leading-${index}`))), columns.map((col) => {
22316
+ const isPinnedRight = col.key === 'actions';
22317
+ return (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()));
22318
+ })] }));
22319
+ }
22320
+ /** Keeps the real pagination in the layout (hidden) and lays a placeholder over it, so the footer height never jumps. */
22321
+ function PaginationLoading({ children, }) {
22322
+ return (jsxs("div", { className: "relative", children: [jsx("div", { className: "invisible", children: children }), jsxs("div", { "aria-hidden": "true", className: "absolute inset-0 flex items-center justify-between bg-card px-4", children: [jsx(SquareSkeleton, { height: 14, width: 160, rounded: "sm" }), jsx(SquareSkeleton, { height: 28, width: 220, rounded: "md" })] })] }));
22323
+ }
22324
+
22325
+ /** Label line + input block — mirrors a `Field`. */
22326
+ function FieldSkeleton() {
22327
+ return (jsxs("div", { className: "space-y-2", children: [jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsx(SquareSkeleton, { height: 40, className: "w-full", rounded: "md" })] }));
22328
+ }
22329
+ /**
22330
+ * Loading placeholder that matches a `FormSectionCard` — the tinted header band
22331
+ * (icon square + title + description) above a body of `Field` placeholders and
22332
+ * an optional footer action row.
22333
+ */
22334
+ function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
22335
+ return (jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-xl border border-border bg-card shadow-card", children: [jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsx(SquareSkeleton, { height: 40, width: 40, rounded: "md" }), jsxs("div", { className: "space-y-1.5", children: [jsx(SquareSkeleton, { height: 14, width: 180, rounded: "full" }), description && jsx(SquareSkeleton, { height: 11, width: 260, rounded: "full" })] })] }), jsxs("div", { className: "p-5", children: [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) => (jsx(FieldSkeleton, {}, i))) }), footer !== 'none' && (jsxs("div", { className: cn('mt-8 flex items-center gap-3 pt-4', footer === 'between' ? 'justify-between' : 'justify-end'), children: [footer === 'between' && (jsx(SquareSkeleton, { height: 36, width: 90, rounded: "md" })), jsx(SquareSkeleton, { height: 36, width: 120, rounded: "md" })] }))] })] }));
22336
+ }
22337
+ /** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
22338
+ function TableSkeleton({ rows = 8 }) {
22339
+ return (jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "flex gap-2", children: [jsx(SquareSkeleton, { className: "h-9 flex-1", rounded: "md" }), jsx(SquareSkeleton, { className: "h-9 w-44", rounded: "md" }), jsx(SquareSkeleton, { className: "h-9 w-48", rounded: "md" })] }), Array.from({ length: rows }).map((_, i) => (jsx(SquareSkeleton, { className: "h-12 w-full", rounded: "md" }, i)))] }));
22340
+ }
22341
+ /** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
22342
+ function TableRowsSkeleton({ rows = 10, className }) {
22343
+ return (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) => (
22344
+ // shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
22345
+ jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
22346
+ }
22347
+ /** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
22348
+ function DetailPageSkeleton({ sections = 3, }) {
22349
+ return (jsxs("div", { className: "space-y-5", children: [jsxs("div", { className: "flex items-center justify-between gap-4", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(SquareSkeleton, { height: 32, width: 32, rounded: "md" }), jsxs("div", { className: "space-y-1.5", children: [jsx(SquareSkeleton, { height: 20, width: 192, rounded: "full" }), jsx(SquareSkeleton, { height: 12, width: 128, rounded: "full" })] })] }), jsx(SquareSkeleton, { height: 36, width: 128, rounded: "md" })] }), Array.from({ length: sections }).map((_, s) => (jsxs("div", { className: "overflow-hidden rounded-xl border border-border bg-card", children: [jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsx(SquareSkeleton, { height: 32, width: 32, rounded: "lg" }), jsx(SquareSkeleton, { height: 16, width: 160, rounded: "full" })] }), jsx("div", { className: "grid grid-cols-1 gap-5 p-5 md:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (jsxs("div", { className: "space-y-1.5", children: [jsx(SquareSkeleton, { height: 10, width: 80, rounded: "full" }), jsx(SquareSkeleton, { height: 14, width: 128, rounded: "full" })] }, i))) })] }, s)))] }));
22350
+ }
22351
+ /** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
22352
+ function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
22353
+ return (jsxs("div", { role: "status", "aria-busy": "true", "aria-label": label, className: "space-y-4", children: [jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(SquareSkeleton, { height: 14, width: 80, rounded: "full" }), jsx("span", { className: "h-5 w-px bg-border" }), jsx(SquareSkeleton, { height: 28, width: 200, rounded: "md" }), jsx(SquareSkeleton, { height: 22, width: 72, rounded: "full" })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(SquareSkeleton, { height: 36, width: 112, rounded: "lg" }), jsx(SquareSkeleton, { height: 36, width: 80, rounded: "lg" }), jsx(SquareSkeleton, { height: 36, width: 128, rounded: "lg" }), jsx(SquareSkeleton, { height: 36, width: 36, rounded: "lg" })] })] }), 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: [jsxs("div", { className: "flex flex-col justify-center space-y-3 px-5 py-4 sm:px-7 sm:py-4", children: [jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsx(SquareSkeleton, { height: 40, width: 220, rounded: "md" }), aside !== 'none' && (jsxs("div", { className: "w-full max-w-xl space-y-2 pt-1", children: [jsx(SquareSkeleton, { height: 8, className: "w-full", rounded: "full" }), jsxs("div", { className: "flex justify-between", children: [jsx(SquareSkeleton, { height: 11, width: 88, rounded: "full" }), jsx(SquareSkeleton, { height: 11, width: 40, rounded: "full" })] })] }))] }), 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) => (jsxs("div", { className: "flex min-h-10 items-center gap-3 border-b border-border py-1.5 last:border-b-0", children: [jsx(SquareSkeleton, { height: 24, width: 24, rounded: "md" }), jsx(SquareSkeleton, { height: 12, width: 72, rounded: "full" }), jsx(SquareSkeleton, { height: 12, width: 88, rounded: "full", className: "ml-auto" })] }, i))) })] }), Array.from({ length: sections }).map((_, s) => (jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-2xl border border-border bg-card", children: [jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-3", children: [jsx(SquareSkeleton, { height: 28, width: 28, rounded: "lg" }), jsx(SquareSkeleton, { height: 15, width: 128, rounded: "full" })] }), jsx("div", { className: "space-y-3 p-4", children: Array.from({ length: s === 1 ? 4 : 2 }).map((__, row) => (jsx(SquareSkeleton, { height: s === 1 ? 36 : 14, className: row % 2 ? 'w-3/4' : 'w-full', rounded: "md" }, row))) })] }, s))), jsx("span", { className: "sr-only", children: label })] }));
22354
+ }
21730
22355
 
21731
- 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, }) {
22356
+ 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, }) {
21732
22357
  const showSelectionColumn = enableSelection && (!isArchiveView || selectionInArchiveView);
21733
22358
  const vBorder = showGrid ? 'border-r' : '';
21734
22359
  const { localWidths, draggingKey, tableRef, handleResizeMouseDown } = useColumnResize({
@@ -21741,6 +22366,11 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21741
22366
  onSelectionChange,
21742
22367
  });
21743
22368
  const { editingRow, editValues, savingRow, handleEditValueChange, handleEditIconClick, } = useRowEditing({ saving, onEditChange, onSaveRow });
22369
+ const scrollRef = useRef(null);
22370
+ const headRef = useRef(null);
22371
+ const bodyRef = useRef(null);
22372
+ // Rows stay in the layout while loading; the skeleton covers them so nothing resizes.
22373
+ const overlay = useLoadingOverlay(scrollRef, headRef, bodyRef, loading);
21744
22374
  const handleColumnClick = (columnKey, sortable) => {
21745
22375
  if (!sortable || !setSortBy || !setSortOrder)
21746
22376
  return;
@@ -21752,25 +22382,17 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21752
22382
  setSortOrder('asc');
21753
22383
  }
21754
22384
  };
21755
- return (jsxs("div", { className: "w-full h-full rounded-lg border border-border bg-card flex flex-col overflow-hidden", children: [jsxs("div", { className: "overflow-auto flex-1", children: [jsxs("table", { ref: tableRef, className: "min-w-[70vh] w-full text-xs text-center border-separate", style: { borderSpacing: 0 }, children: [jsx("thead", { className: "sticky top-0 z-20 !bg-table-header border-b border-border text-secondary-foreground text-sm", children: jsxs("tr", { className: "h-[40px]", children: [!isArchiveView && (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 && (jsx("th", { className: cn('px-3 py-1.5 text-center font-semibold first:!pl-6 border-b border-solid !border-border', vBorder), children: jsx(Checkbox, { checked: allSelected
21756
- ? true
21757
- : someSelected
21758
- ? 'indeterminate'
21759
- : false, onCheckedChange: toggleSelectAll }) })), columns.map((col) => {
21760
- const w = localWidths[col.key];
21761
- const isDragging = draggingKey === col.key;
21762
- const isPinnedRight = col.key === 'actions';
21763
- const thStyle = w || isDragging
21764
- ? {
21765
- width: `var(--col-w-${col.key})`,
21766
- minWidth: `var(--col-w-${col.key})`,
21767
- maxWidth: `var(--col-w-${col.key})`,
21768
- }
21769
- : isPinnedRight
21770
- ? { width: '72px', minWidth: '72px', maxWidth: '72px' }
21771
- : undefined;
21772
- return (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: [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' ? (jsx("span", { className: "truncate", title: col.header, children: col.header })) : (col.header), col.sortable && (jsx(SortIcon, { active: sortBy === col.key, order: sortOrder }))] }), 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()));
21773
- })] }) }), jsx("tbody", { children: data.map((row, rowIndex) => {
22385
+ return (jsxs("div", { className: "w-full h-full rounded-lg border border-border bg-card flex flex-col overflow-hidden", children: [jsxs("div", { ref: scrollRef, className: "relative overflow-auto flex-1", children: [jsxs("table", { ref: tableRef, className: "min-w-[70vh] w-full text-xs text-center border-separate", style: { borderSpacing: 0 }, children: [jsxs("thead", { ref: headRef, className: "sticky top-0 z-20 !bg-table-header border-b border-border text-secondary-foreground text-sm", children: [jsxs("tr", { className: "h-[40px]", children: [!isArchiveView && (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 && (jsx("th", { className: cn('px-3 py-1.5 text-center font-semibold first:!pl-6 border-b border-solid !border-border', vBorder), children: jsx(Checkbox, { checked: allSelected
22386
+ ? true
22387
+ : someSelected
22388
+ ? 'indeterminate'
22389
+ : false, onCheckedChange: toggleSelectAll }) })), columns.map((col) => {
22390
+ const w = localWidths[col.key];
22391
+ const isDragging = draggingKey === col.key;
22392
+ const isPinnedRight = col.key === 'actions';
22393
+ const thStyle = getColumnWidthStyle(col.key, Boolean(w) || isDragging, isPinnedRight);
22394
+ return (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: [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' ? (jsx("span", { className: "truncate", title: col.header, children: col.header })) : (col.header), col.filterActive && (jsxs(Fragment$2, { children: [jsx(Funnel, { "aria-hidden": "true", className: "size-3 shrink-0 text-primary" }), jsx("span", { className: "sr-only", children: "Filtered" })] })), col.sortable && (jsx(SortIcon, { active: sortBy === col.key, order: sortOrder }))] }), 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()));
22395
+ })] }), hasFilterRow(columns, filterRowLeading) && (jsx(FilterRow, { columns: columns, leading: filterRowLeading, showEditColumn: !isArchiveView, showSelectionColumn: showSelectionColumn, isArchiveView: isArchiveView, vBorder: vBorder, localWidths: localWidths, draggingKey: draggingKey }))] }), jsx("tbody", { ref: bodyRef, "aria-busy": loading || undefined, className: cn(loading && 'invisible'), children: data.map((row, rowIndex) => {
21774
22396
  const isEditing = editingRow === row.id && editingRow !== null;
21775
22397
  const isSaving = savingRow === row.id;
21776
22398
  const isSelected = selectedSet.has(row.id);
@@ -21790,19 +22412,7 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21790
22412
  : row[col.key];
21791
22413
  const w = localWidths[col.key];
21792
22414
  const isPinnedRight = col.key === 'actions';
21793
- const tdStyle = w || draggingKey === col.key
21794
- ? {
21795
- width: `var(--col-w-${col.key})`,
21796
- minWidth: `var(--col-w-${col.key})`,
21797
- maxWidth: `var(--col-w-${col.key})`,
21798
- }
21799
- : isPinnedRight
21800
- ? {
21801
- width: '72px',
21802
- minWidth: '72px',
21803
- maxWidth: '72px',
21804
- }
21805
- : undefined;
22415
+ const tdStyle = getColumnWidthStyle(col.key, Boolean(w) || draggingKey === col.key, isPinnedRight);
21806
22416
  // Pinned cells need an OPAQUE bg matching the row state so the
21807
22417
  // scrolling content underneath doesn't bleed through — no alpha tints.
21808
22418
  const pinnedBg = isPinnedRight
@@ -21818,7 +22428,13 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
21818
22428
  ? 'text-right'
21819
22429
  : 'text-left', isArchiveView && !isPinnedRight && 'pl-2', columnStyles?.[col.key.toString()] || '', draggingKey === col.key && 'bg-primary/5', isPinnedRight && pinnedCellClass(pinnedBg)), style: tdStyle, children: jsx(EditableCellContent, { col: col, row: row, value: value, isEditing: isEditing, width: w, onEditValueChange: handleEditValueChange, fetchBusinessContacts: fetchBusinessContacts }) }, col.key.toString()));
21820
22430
  })] }, row.id));
21821
- }) })] }), data.length === 0 && (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] }));
22431
+ }) })] }), overlay && overlay.height > 0 ? (
22432
+ // `overflow-clip`, not `hidden`: hidden makes this box the sticky skeleton's scroller, pinning it to scrollLeft 0.
22433
+ jsx("div", { className: "absolute left-0 z-10 overflow-clip bg-card", style: {
22434
+ top: overlay.top,
22435
+ width: overlay.width,
22436
+ height: overlay.height,
22437
+ }, children: jsx("div", { className: "sticky left-0 p-3", style: { width: overlay.visibleWidth }, children: jsx(TableRowsSkeleton, { rows: getSkeletonRowCount(overlay.height) }) }) })) : (loading && (jsx("div", { className: "sticky left-0 w-full p-3", children: jsx(TableRowsSkeleton, { rows: loadingRows }) }))), !loading && data.length === 0 && (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 ? (jsx(PaginationLoading, { children: pagination })) : (pagination)] }));
21822
22438
  }
21823
22439
 
21824
22440
  /**
@@ -37204,7 +37820,11 @@ function DateInput({ value, onChange, onBlur, name, id, className, min, max, dis
37204
37820
 
37205
37821
  /** The permanent-delete confirmation for a document (quotation, memo, proforma…). */
37206
37822
  function DocumentDeleteDialog({ open, onOpenChange, documentLabel, documentNumber, info, busy, onConfirm, }) {
37207
- return (jsx(ConfirmDialog, { open: open, onOpenChange: onOpenChange, title: `Delete ${documentLabel}`, description: jsxs(Fragment$2, { children: [jsxs("span", { children: ["Are you sure you want to permanently delete ", documentLabel, documentNumber ? (jsxs(Fragment$2, { children: [' ', jsx("span", { className: "font-semibold", children: documentNumber })] })) : null, "?"] }), jsx("div", { className: "mt-1", children: "This action cannot be undone." })] }), info: info, confirmLabel: `Yes, Delete ${documentLabel}`, cancelLabel: "No, Keep It", confirmVariant: "destructive", disabled: busy, onConfirm: onConfirm }));
37823
+ const noun = documentLabel.toLowerCase();
37824
+ const summary = info == null || (typeof info === 'object' && !isValidElement(info))
37825
+ ? { invoiceNumber: documentNumber, ...(info ?? {}) }
37826
+ : info;
37827
+ return (jsx(ConfirmDialog, { open: open, onOpenChange: onOpenChange, title: `Delete ${noun}?`, info: summary, confirmLabel: "Delete", cancelLabel: "Cancel", confirmVariant: "destructive", disabled: busy, onConfirm: onConfirm }));
37208
37828
  }
37209
37829
 
37210
37830
  function clampPercent$1(value) {
@@ -37834,6 +38454,487 @@ function fieldTypeIcon(type) {
37834
38454
  return FIELD_TYPE_ICONS[type] ?? Type;
37835
38455
  }
37836
38456
 
38457
+ const getRemoveChipLabel = (label) => `Remove ${label} filter`;
38458
+ const FILTERED_BY_LABEL = 'Filtered by';
38459
+
38460
+ /** Compact badge shape with the filter chip colours. */
38461
+ const CHIP_CLASS = 'inline-flex h-6 max-w-full items-center gap-1 rounded-md border border-primary/30 bg-primary/5 px-2 text-xs text-foreground';
38462
+ 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';
38463
+ const CLEAR_ALL_CLASS = cn(FILTER_LINK_CLASS_NAME, 'underline');
38464
+ function getChipLabelText(label, variant) {
38465
+ return variant === 'inline' ? `${label}:` : label;
38466
+ }
38467
+
38468
+ /** Applied filters as removable chips, with an optional Clear all. */
38469
+ function ActiveFilterChips({ chips, onRemove, onClearAll, variant = 'inline', className, }) {
38470
+ if (chips.length === 0)
38471
+ return null;
38472
+ return (jsxs("div", { className: cn('flex flex-wrap items-center gap-1.5', className), children: [variant === 'inline' && (jsx("span", { className: "mr-0.5 text-xs text-muted-foreground", children: FILTERED_BY_LABEL })), chips.map((chip) => (jsxs("span", { className: CHIP_CLASS, children: [jsx("span", { className: "shrink-0 font-semibold", children: getChipLabelText(chip.label, variant) }), jsx(TruncatedLabel, { text: chip.value }), onRemove && (jsx("button", { type: "button", "aria-label": getRemoveChipLabel(chip.label), onClick: () => onRemove(chip.id), className: REMOVE_BUTTON_CLASS, children: jsx(X$2, { "aria-hidden": "true", className: "size-3" }) }))] }, chip.id))), onClearAll && (jsx("button", { type: "button", onClick: onClearAll, className: CLEAR_ALL_CLASS, children: "Clear all" }))] }));
38473
+ }
38474
+
38475
+ const DEFAULT_CONTAINS_PLACEHOLDER = 'Contains…';
38476
+
38477
+ /**
38478
+ * Local text for a typed filter. It resets to `externalText` only when the applied value
38479
+ * (`externalKey`) changes from outside — e.g. Clear all — not when the change is this field's own commit.
38480
+ */
38481
+ function useFilterDraft(externalKey, externalText) {
38482
+ const [draft, setDraft] = useState(externalText);
38483
+ const [seenKey, setSeenKey] = useState(externalKey);
38484
+ const [committedKey, setCommittedKey] = useState(externalKey);
38485
+ if (seenKey !== externalKey) {
38486
+ setSeenKey(externalKey);
38487
+ if (externalKey !== committedKey) {
38488
+ setCommittedKey(externalKey);
38489
+ setDraft(externalText);
38490
+ }
38491
+ }
38492
+ return { draft, setDraft, markCommitted: setCommittedKey };
38493
+ }
38494
+ /** Debounces `callback`; a call still pending when the field unmounts (e.g. its popover closes) is flushed, not lost. */
38495
+ function useDebouncedCallback(callback, delay) {
38496
+ const callbackRef = useRef(callback);
38497
+ const timerRef = useRef(null);
38498
+ const pendingRef = useRef(null);
38499
+ useEffect(() => {
38500
+ callbackRef.current = callback;
38501
+ }, [callback]);
38502
+ const cancel = useCallback(() => {
38503
+ if (timerRef.current)
38504
+ clearTimeout(timerRef.current);
38505
+ timerRef.current = null;
38506
+ pendingRef.current = null;
38507
+ }, []);
38508
+ const flush = useCallback(() => {
38509
+ const pending = pendingRef.current;
38510
+ cancel();
38511
+ if (pending)
38512
+ callbackRef.current(...pending);
38513
+ }, [cancel]);
38514
+ const schedule = useCallback((...args) => {
38515
+ if (timerRef.current)
38516
+ clearTimeout(timerRef.current);
38517
+ pendingRef.current = args;
38518
+ timerRef.current = setTimeout(flush, delay);
38519
+ }, [delay, flush]);
38520
+ useEffect(() => flush, [flush]);
38521
+ return { schedule, flush, cancel };
38522
+ }
38523
+
38524
+ const COMMIT_DELAY_MS$2 = 400;
38525
+ function useContainsFilter(value, onChange) {
38526
+ const { draft, setDraft, markCommitted } = useFilterDraft(value, value);
38527
+ const commit = useCallback((text) => {
38528
+ const trimmed = text.trim();
38529
+ markCommitted(trimmed);
38530
+ if (trimmed !== value)
38531
+ onChange(trimmed);
38532
+ }, [markCommitted, onChange, value]);
38533
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$2);
38534
+ return {
38535
+ draft,
38536
+ handleChange: (event) => {
38537
+ setDraft(event.target.value);
38538
+ debounced.schedule(event.target.value);
38539
+ },
38540
+ handleKeyDown: (event) => {
38541
+ if (event.key === 'Enter')
38542
+ debounced.flush();
38543
+ },
38544
+ handleBlur: debounced.flush,
38545
+ };
38546
+ }
38547
+
38548
+ function getContainsClassName(size, applied, className) {
38549
+ if (size === 'cell')
38550
+ return getFilterFieldClassName(applied ? 'applied' : 'empty', className);
38551
+ return cn('h-9 text-sm', applied && 'border-primary bg-primary/5', className);
38552
+ }
38553
+
38554
+ /** "Contains…" text filter, as a filter-row cell or a full-size card field. */
38555
+ function ContainsFilter({ value, onChange, ariaLabel, placeholder = DEFAULT_CONTAINS_PLACEHOLDER, size = 'cell', className, }) {
38556
+ const { draft, handleChange, handleKeyDown, handleBlur } = useContainsFilter(value, onChange);
38557
+ const inputProps = {
38558
+ type: 'text',
38559
+ value: draft,
38560
+ placeholder,
38561
+ 'aria-label': ariaLabel,
38562
+ onChange: handleChange,
38563
+ onKeyDown: handleKeyDown,
38564
+ onBlur: handleBlur,
38565
+ className: getContainsClassName(size, value.trim() !== '', className),
38566
+ };
38567
+ return size === 'cell' ? (jsx("input", { ...inputProps })) : (jsx(Input, { ...inputProps }));
38568
+ }
38569
+
38570
+ const getPresetGroupLabel = (ariaLabel) => `${ariaLabel} presets`;
38571
+ const getDateInputLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
38572
+
38573
+ /** Dates shown in the inputs: a preset's resolved range, or the custom range. */
38574
+ function getDisplayedRange(value, today, fiscalYearStartMonth) {
38575
+ if (value?.preset)
38576
+ return resolveDatePreset(value.preset, today, fiscalYearStartMonth);
38577
+ return { from: value?.from ?? '', to: value?.to ?? '' };
38578
+ }
38579
+ function buildCustomRange(from, to) {
38580
+ return from || to
38581
+ ? { from: from || undefined, to: to || undefined }
38582
+ : undefined;
38583
+ }
38584
+ function togglePreset(value, preset) {
38585
+ return value?.preset === preset ? undefined : { preset };
38586
+ }
38587
+ /** Preset row; the picked one gets the primary tint, as in the design. */
38588
+ function getPresetClassName$1(selected) {
38589
+ return cn('w-full cursor-pointer whitespace-nowrap rounded-md px-3 py-2 text-left text-sm text-foreground transition-colors', FILTER_FOCUS_RING, selected ? 'bg-primary/5 font-semibold text-primary' : 'hover:bg-muted/60');
38590
+ }
38591
+
38592
+ const toIsoOrEmpty = (date) => date ? toIsoDate(date) : '';
38593
+ function useDateRangeFilter(value, onChange, today, fiscalYearStartMonth) {
38594
+ const { from, to } = getDisplayedRange(value, today, fiscalYearStartMonth);
38595
+ return {
38596
+ from,
38597
+ to,
38598
+ selectPreset: (preset) => onChange(togglePreset(value, preset)),
38599
+ handleFromChange: (date) => onChange(buildCustomRange(toIsoOrEmpty(date), to)),
38600
+ handleToChange: (date) => onChange(buildCustomRange(from, toIsoOrEmpty(date))),
38601
+ clear: () => onChange(undefined),
38602
+ };
38603
+ }
38604
+
38605
+ /** Date filter body: presets on the left, a From / To range on the right. */
38606
+ function DateRangeFilter({ value, onChange, ariaLabel, fiscalYearStartMonth = 1, today = new Date(), }) {
38607
+ const { from, to, selectPreset, handleFromChange, handleToChange, clear } = useDateRangeFilter(value, onChange, today, fiscalYearStartMonth);
38608
+ return (jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)] divide-x divide-border text-xs", children: [jsx("div", { role: "group", "aria-label": getPresetGroupLabel(ariaLabel), className: "flex flex-col gap-1 pr-3", children: DATE_PRESET_OPTIONS.map((preset) => (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))) }), jsxs("div", { className: "flex min-w-0 flex-col gap-3 pl-3", children: [jsxs("label", { className: "flex min-w-0 flex-col gap-1 text-muted-foreground", children: ["From", jsx(DateInput, { value: fromIsoDate(from), max: to || undefined, ariaLabel: getDateInputLabel(ariaLabel, 'from'), onChange: handleFromChange })] }), jsxs("label", { className: "flex min-w-0 flex-col gap-1 text-muted-foreground", children: ["To", jsx(DateInput, { value: fromIsoDate(to), min: from || undefined, ariaLabel: getDateInputLabel(ariaLabel, 'to'), onChange: handleToChange, align: "end" })] }), value && (jsx("button", { type: "button", onClick: clear, className: cn('self-start', FILTER_LINK_CLASS_NAME), children: "Clear" }))] })] }));
38609
+ }
38610
+
38611
+ const getClearButtonLabel = (ariaLabel) => `Clear ${ariaLabel}`;
38612
+ const NOT_FILTERABLE_LABEL = "This column can't be filtered";
38613
+
38614
+ /** Select-like filter-row control: a compact trigger that opens the filter's panel in a popover. */
38615
+ function FilterCellPopover({ label, placeholder, ariaLabel, state, disabledLabel = NOT_FILTERABLE_LABEL, icon, onClear, showChevron = true, open, onOpenChange, contentClassName, className, children, }) {
38616
+ if (state === 'disabled') {
38617
+ return (jsx(TooltipProvider, { delayDuration: 200, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, "aria-label": disabledLabel, className: "block outline-none", children: jsx("div", { role: "presentation", className: getFilterFieldClassName('disabled', className) }) }) }), jsx(TooltipContent, { side: "top", children: disabledLabel })] }) }));
38618
+ }
38619
+ return (jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [jsx(PopoverAnchor, { asChild: true, children: jsxs("div", { className: getFilterFieldClassName(state, cn('pr-1 focus-within:ring-2 focus-within:ring-primary/30', className)), children: [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 && jsx("span", { className: "shrink-0 [&_svg]:size-3.5", children: icon }), jsx(TruncatedLabel, { text: label || placeholder, className: cn('min-w-0 flex-1', !label && 'font-normal text-placeholder') }), showChevron && (jsx(ChevronDown, { "aria-hidden": "true", className: "size-3.5 shrink-0 text-muted-foreground" }))] }), onClear && label && (jsx("button", { type: "button", "aria-label": getClearButtonLabel(ariaLabel), onClick: onClear, className: "inline-flex size-4 shrink-0 cursor-pointer items-center justify-center rounded-sm outline-none hover:bg-primary/10", children: jsx(X$2, { "aria-hidden": "true", className: "size-3" }) }))] }) }), jsx(PopoverContent, { align: "start",
38620
+ // The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
38621
+ updatePositionStrategy: "always", sideOffset: 4, className: cn('w-72 p-0', contentClassName), children: children })] }));
38622
+ }
38623
+
38624
+ const COUNT_WORDS = [
38625
+ 'One',
38626
+ 'Two',
38627
+ 'Three',
38628
+ 'Four',
38629
+ 'Five',
38630
+ 'Six',
38631
+ 'Seven',
38632
+ 'Eight',
38633
+ 'Nine',
38634
+ 'Ten',
38635
+ ];
38636
+ /** `4` → `Four` for 1–10; any other count stays as digits. */
38637
+ function countToWord(count) {
38638
+ return COUNT_WORDS[count - 1] ?? String(count);
38639
+ }
38640
+ function getEmptyStateTitle(itemNoun) {
38641
+ return `No ${itemNoun}s match these filters`;
38642
+ }
38643
+ function getEmptyStateDescription(itemNoun, activeCount) {
38644
+ const filters = activeCount === 1 ? 'column filter is' : 'column filters are';
38645
+ return `${countToWord(activeCount)} ${filters} active. Loosen one, or clear them all to see every ${itemNoun}.`;
38646
+ }
38647
+
38648
+ /** Shown in place of rows when the applied column filters match nothing. */
38649
+ function FilterEmptyState({ itemNoun, title, description, activeCount, onClearAll, className, }) {
38650
+ return (jsxs("div", { className: cn('flex flex-col items-center py-12 text-center', className), children: [jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-muted text-primary", children: jsx(FunnelX, { "aria-hidden": "true", className: "size-5" }) }), jsx("p", { className: "mt-4 text-base font-semibold text-foreground", children: title ?? getEmptyStateTitle(itemNoun) }), jsx("p", { className: "mt-1.5 max-w-sm text-sm text-muted-foreground", children: description ?? getEmptyStateDescription(itemNoun, activeCount) }), jsx(Button, { appearance: "outline", color: "primary", size: "md", onClick: onClearAll, leftIcon: jsx(RotateCcw, {}), className: "mt-5", children: "Clear all filters" })] }));
38651
+ }
38652
+
38653
+ function getScalePosition(options, value, option) {
38654
+ if (!value)
38655
+ return 'outside';
38656
+ if (option === value.from || option === value.to)
38657
+ return 'end';
38658
+ return expandScaleRange(options, value).includes(option)
38659
+ ? 'between'
38660
+ : 'outside';
38661
+ }
38662
+ /** Next range after clicking `scale`: a fresh single-option range, or the end of the pending one. */
38663
+ function getNextScaleRange(anchor, option) {
38664
+ return anchor === null
38665
+ ? { from: option, to: option }
38666
+ : { from: anchor, to: option };
38667
+ }
38668
+ function getScaleButtonClassName(position, fill = false) {
38669
+ 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,
38670
+ // Unselected options look exactly like unselected pick-list tiles.
38671
+ position === 'outside' && getSelectableOptionClassName(false), position === 'end' &&
38672
+ 'border-primary bg-primary font-medium text-primary-foreground', position === 'between' &&
38673
+ 'border-primary/30 bg-primary/10 font-medium text-primary');
38674
+ }
38675
+
38676
+ /** First click picks the start option, the next click the end option; a click after that starts over. */
38677
+ function useScaleRangeFilter({ value, onChange, }) {
38678
+ const [anchor, setAnchor] = useState(null);
38679
+ // The start point only holds while the value is still that one option; Clear or any outside change drops it.
38680
+ const start = anchor !== null && value?.from === anchor && value.to === anchor
38681
+ ? anchor
38682
+ : null;
38683
+ const selectOption = useCallback((option) => {
38684
+ onChange(getNextScaleRange(start, option));
38685
+ setAnchor(start === null ? option : null);
38686
+ }, [start, onChange]);
38687
+ return { selectOption };
38688
+ }
38689
+
38690
+ /** Ordered-scale filter: click a start option, then an end option. */
38691
+ function ScaleRangeFilter({ options, value, onChange, ariaLabel, columns, fill = false, }) {
38692
+ const { selectOption } = useScaleRangeFilter({ value, onChange });
38693
+ return (jsx("div", { role: "group", "aria-label": ariaLabel, className: fill ? 'grid gap-2' : 'grid gap-1.5', style: getGridColumnsStyle(columns), children: options.map((option) => {
38694
+ const position = getScalePosition(options, value, option.value);
38695
+ return (jsx("button", { type: "button", "aria-pressed": position !== 'outside', "aria-label": option.label, onClick: () => selectOption(option.value), className: getScaleButtonClassName(position, fill), children: jsx("span", { className: "line-clamp-2 leading-tight", children: option.label }) }, option.value));
38696
+ }) }));
38697
+ }
38698
+
38699
+ const getClearIdsLabel = (ariaLabel) => `Clear ${ariaLabel}`;
38700
+
38701
+ const DEFAULT_ID_HELPER_TEXT = 'Paste from Excel or an email. Commas, spaces and new lines all split IDs.';
38702
+ function toIdsKey(ids) {
38703
+ return ids.join('\n');
38704
+ }
38705
+ function formatIdCount(count) {
38706
+ return `${count} ${count === 1 ? 'ID' : 'IDs'}`;
38707
+ }
38708
+
38709
+ const COMMIT_DELAY_MS$1 = 300;
38710
+ function useIdListInput(value, onChange) {
38711
+ const appliedKey = toIdsKey(value);
38712
+ const { draft, setDraft, markCommitted } = useFilterDraft(appliedKey, value.join(', '));
38713
+ const commit = useCallback((text) => {
38714
+ const ids = splitIdList(text);
38715
+ const key = toIdsKey(ids);
38716
+ markCommitted(key);
38717
+ if (key !== appliedKey)
38718
+ onChange(ids);
38719
+ }, [appliedKey, markCommitted, onChange]);
38720
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$1);
38721
+ return {
38722
+ draft,
38723
+ parsedIds: splitIdList(draft),
38724
+ handleChange: (event) => {
38725
+ setDraft(event.target.value);
38726
+ debounced.schedule(event.target.value);
38727
+ },
38728
+ handleBlur: debounced.flush,
38729
+ clear: () => {
38730
+ debounced.cancel();
38731
+ setDraft('');
38732
+ commit('');
38733
+ },
38734
+ };
38735
+ }
38736
+
38737
+ /** Paste-a-list body: a textarea split into IDs on commas, spaces and new lines, with the parsed IDs as chips. */
38738
+ function IdListInput({ value, onChange, ariaLabel, placeholder, helperText = DEFAULT_ID_HELPER_TEXT, showSummary = true, }) {
38739
+ const { draft, parsedIds, handleChange, handleBlur, clear } = useIdListInput(value, onChange);
38740
+ return (jsxs("div", { className: "flex flex-col gap-2", children: [jsx(Textarea, { value: draft, placeholder: placeholder, "aria-label": ariaLabel, onChange: handleChange, onBlur: handleBlur, className: "min-h-20 bg-card" }), helperText && (jsx("p", { className: "text-xs text-muted-foreground", children: helperText })), showSummary && parsedIds.length > 0 && (jsxs(Fragment$2, { children: [jsx("ul", { className: "flex flex-wrap gap-1.5", children: parsedIds.map((id) => (jsx("li", { className: "inline-flex h-6 items-center rounded-full border border-primary/20 bg-primary/5 px-2 text-xs text-primary", children: id }, id))) }), jsxs("div", { className: "flex items-center justify-between text-xs", children: [jsx("span", { className: "text-muted-foreground", children: formatIdCount(parsedIds.length) }), jsx("button", { type: "button", "aria-label": getClearIdsLabel(ariaLabel), onClick: clear, className: FILTER_LINK_CLASS_NAME, children: "Clear" })] })] }))] }));
38741
+ }
38742
+
38743
+ const NUMBER_HELP_HEADING = 'Type a value or a rule';
38744
+ const NUMBER_HELP_SUBTITLE = 'Click a rule to use it.';
38745
+ const getNumberErrorId = (baseId) => `${baseId}-error`;
38746
+ const getUseRuleLabel = (rule, meaning) => `Use ${rule}: ${meaning}`;
38747
+
38748
+ function getNumberFieldState(parsed) {
38749
+ if (!parsed.ok)
38750
+ return 'invalid';
38751
+ return parsed.range ? 'applied' : 'empty';
38752
+ }
38753
+ function getNumberInputClassName(state, className) {
38754
+ return getFilterFieldClassName(state, cn('text-right tabular-nums', className));
38755
+ }
38756
+ /** Cheat-sheet row: the whole row is the click target, highlighted on hover. */
38757
+ const RULE_BUTTON_CLASS_NAME = cn('flex h-8 w-full cursor-pointer items-center gap-3 rounded-md px-2 text-left text-xs transition-colors hover:bg-muted', FILTER_FOCUS_RING);
38758
+ /** Key-cap chip for the rule, fixed width so every meaning lines up. */
38759
+ const RULE_CHIP_CLASS_NAME = 'inline-flex h-6 min-w-12 shrink-0 items-center justify-center rounded border border-border bg-background px-1.5 font-mono text-xs font-semibold text-foreground shadow-xs';
38760
+
38761
+ const COMMIT_DELAY_MS = 400;
38762
+ function useNumberExpressionFilter(value, onChange) {
38763
+ const applied = formatNumberRange(value);
38764
+ const { draft, setDraft, markCommitted } = useFilterDraft(applied, applied);
38765
+ const [helpOpen, setHelpOpen] = useState(false);
38766
+ const errorId = useId$2();
38767
+ const commit = useCallback((text) => {
38768
+ const parsed = parseNumberExpression(text);
38769
+ if (!parsed.ok)
38770
+ return;
38771
+ const key = formatNumberRange(parsed.range);
38772
+ markCommitted(key);
38773
+ if (key !== applied)
38774
+ onChange(parsed.range);
38775
+ }, [applied, markCommitted, onChange]);
38776
+ const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS);
38777
+ const handleChange = (event) => {
38778
+ setDraft(event.target.value);
38779
+ setHelpOpen(true);
38780
+ debounced.schedule(event.target.value);
38781
+ };
38782
+ const handleKeyDown = (event) => {
38783
+ if (event.key === 'Enter')
38784
+ debounced.flush();
38785
+ if (event.key === 'Escape')
38786
+ setHelpOpen(false);
38787
+ };
38788
+ const handleBlur = () => {
38789
+ debounced.flush();
38790
+ setHelpOpen(false);
38791
+ };
38792
+ const applyRule = (rule) => {
38793
+ debounced.cancel();
38794
+ setDraft(rule);
38795
+ commit(rule);
38796
+ setHelpOpen(false);
38797
+ };
38798
+ return {
38799
+ draft,
38800
+ state: getNumberFieldState(parseNumberExpression(draft)),
38801
+ helpOpen,
38802
+ errorId,
38803
+ handleChange,
38804
+ handleKeyDown,
38805
+ handleFocus: () => setHelpOpen(true),
38806
+ handleBlur,
38807
+ applyRule,
38808
+ };
38809
+ }
38810
+
38811
+ /** Filter-row number cell: type a value or a rule (`>1`, `1–3`, `1.52`). Invalid text never reaches the table. */
38812
+ function NumberExpressionFilter({ value, onChange, ariaLabel, placeholder, note, className, }) {
38813
+ const { draft, state, helpOpen, errorId, handleChange, handleKeyDown, handleFocus, handleBlur, applyRule, } = useNumberExpressionFilter(value, onChange);
38814
+ const invalid = state === 'invalid';
38815
+ return (jsxs(Popover, { open: helpOpen, children: [jsx(PopoverAnchor, { asChild: true, children: jsx("input", { type: "text", inputMode: "decimal", value: draft, placeholder: placeholder, "aria-label": ariaLabel, "aria-invalid": invalid || undefined, "aria-describedby": invalid ? getNumberErrorId(errorId) : undefined, onChange: handleChange, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, className: getNumberInputClassName(state, className) }) }), jsxs(PopoverContent, { align: "start",
38816
+ // The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
38817
+ updatePositionStrategy: "always", onOpenAutoFocus: (event) => event.preventDefault(), className: "flex w-72 flex-col gap-2 p-2 text-xs", children: [jsxs("div", { className: "px-2 pt-1", children: [jsx("p", { className: "font-medium text-foreground", children: NUMBER_HELP_HEADING }), jsx("p", { className: "text-muted-foreground", children: NUMBER_HELP_SUBTITLE })] }), jsx("ul", { className: "flex flex-col", children: NUMBER_EXPRESSION_HELP.map(({ rule, meaning }) => (jsx("li", { children: jsxs("button", { type: "button", "aria-label": getUseRuleLabel(rule, meaning),
38818
+ // Keep focus in the field so it doesn't blur and close this help first.
38819
+ onMouseDown: (event) => event.preventDefault(), onClick: () => applyRule(rule), className: RULE_BUTTON_CLASS_NAME, children: [jsx("span", { className: RULE_CHIP_CLASS_NAME, children: rule }), jsx("span", { className: "whitespace-nowrap text-muted-foreground", children: meaning })] }) }, rule))) }), note && (jsxs("div", { className: "flex gap-2 rounded-md bg-muted/50 p-2 text-muted-foreground", children: [jsx(Info, { "aria-hidden": "true", className: "mt-0.5 size-3.5 shrink-0" }), jsx("div", { children: note })] })), invalid && (jsxs("div", { id: getNumberErrorId(errorId), role: "alert", className: "flex gap-2 rounded-md bg-destructive/10 p-2 text-destructive", children: [jsx(CircleAlert, { "aria-hidden": "true", className: "mt-0.5 size-3.5 shrink-0" }), jsxs("p", { children: ["Can't read \u201C", draft, "\u201D. Try ", jsx("strong", { children: "1\u20133" }), ",", ' ', jsx("strong", { children: ">1" }), " or ", jsx("strong", { children: "<=3" }), "."] })] }))] })] }));
38820
+ }
38821
+
38822
+ const REVERSED_RANGE_MESSAGE = 'From must not be more than To.';
38823
+ const getBoundLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
38824
+
38825
+ const DECIMAL_DRAFT_RE = /^\d*\.?\d*$/;
38826
+ /** Allows partial decimals (`1.`) while typing; rejects anything else. */
38827
+ function isDecimalDraft(text) {
38828
+ return DECIMAL_DRAFT_RE.test(text);
38829
+ }
38830
+ function toBound(text) {
38831
+ if (!text || text === '.')
38832
+ return undefined;
38833
+ return Number(text);
38834
+ }
38835
+ function toBoundText(bound) {
38836
+ return bound === undefined ? '' : String(bound);
38837
+ }
38838
+ /** Replaces one bound with a typed (inclusive) number, keeping the other bound and its `>` / `<`. */
38839
+ function withBound(range, bound, next) {
38840
+ const min = bound === 'min' ? next : range?.min;
38841
+ const max = bound === 'max' ? next : range?.max;
38842
+ if (min === undefined && max === undefined)
38843
+ return undefined;
38844
+ const result = { min, max };
38845
+ if (bound === 'max' && range?.minExclusive)
38846
+ result.minExclusive = true;
38847
+ if (bound === 'min' && range?.maxExclusive)
38848
+ result.maxExclusive = true;
38849
+ return result;
38850
+ }
38851
+ function isReversedRange(min, max) {
38852
+ return min !== undefined && max !== undefined && min > max;
38853
+ }
38854
+ function isSameRange(a, b) {
38855
+ return a?.min === b.min && a?.max === b.max;
38856
+ }
38857
+ function getBoundInputClassName(filled) {
38858
+ return cn('h-9 min-w-0 flex-1 text-sm', filled && 'border-primary bg-primary/5');
38859
+ }
38860
+ function getPresetClassName(selected) {
38861
+ return getSelectableOptionClassName(selected, 'inline-flex h-7 items-center rounded-full px-2.5');
38862
+ }
38863
+
38864
+ function useNumberRangeInputs(value, onChange) {
38865
+ const minText = toBoundText(value?.min);
38866
+ const maxText = toBoundText(value?.max);
38867
+ const from = useFilterDraft(minText, minText);
38868
+ const to = useFilterDraft(maxText, maxText);
38869
+ const handleBoundChange = (bound) => (event) => {
38870
+ const text = event.target.value;
38871
+ if (!isDecimalDraft(text))
38872
+ return;
38873
+ const draft = bound === 'min' ? from : to;
38874
+ const parsed = toBound(text);
38875
+ draft.setDraft(text);
38876
+ const next = withBound(value, bound, parsed);
38877
+ if (isReversedRange(next?.min, next?.max))
38878
+ return;
38879
+ draft.markCommitted(toBoundText(parsed));
38880
+ onChange(next);
38881
+ };
38882
+ return {
38883
+ fromDraft: from.draft,
38884
+ toDraft: to.draft,
38885
+ reversed: isReversedRange(toBound(from.draft), toBound(to.draft)),
38886
+ handleFromChange: handleBoundChange('min'),
38887
+ handleToChange: handleBoundChange('max'),
38888
+ isPresetSelected: (preset) => isSameRange(value, preset.range),
38889
+ togglePreset: (preset) => onChange(isSameRange(value, preset.range) ? undefined : preset.range),
38890
+ };
38891
+ }
38892
+
38893
+ /** From – To number inputs for full-page filter cards, with optional quick-pick presets. */
38894
+ function NumberRangeInputs({ value, onChange, ariaLabel, fromPlaceholder = 'From', toPlaceholder = 'To', presets, presetsLabel, }) {
38895
+ const { fromDraft, toDraft, reversed, handleFromChange, handleToChange, isPresetSelected, togglePreset, } = useNumberRangeInputs(value, onChange);
38896
+ return (jsxs("div", { className: "flex flex-col gap-3", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Input, { inputMode: "decimal", value: fromDraft, placeholder: fromPlaceholder, "aria-label": getBoundLabel(ariaLabel, 'from'), "aria-invalid": reversed || undefined, onChange: handleFromChange, className: getBoundInputClassName(fromDraft !== '') }), jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2013" }), jsx(Input, { inputMode: "decimal", value: toDraft, placeholder: toPlaceholder, "aria-label": getBoundLabel(ariaLabel, 'to'), "aria-invalid": reversed || undefined, onChange: handleToChange, className: getBoundInputClassName(toDraft !== '') })] }), reversed && (jsx("p", { role: "alert", className: "text-xs text-destructive", children: REVERSED_RANGE_MESSAGE })), presets && presets.length > 0 && (jsxs("div", { className: "flex flex-col gap-2", children: [presetsLabel && (jsx("p", { className: "text-xs text-muted-foreground", children: presetsLabel })), jsx("div", { className: "flex flex-wrap gap-1.5", children: presets.map((preset) => (jsx("button", { type: "button", "aria-pressed": isPresetSelected(preset), onClick: () => togglePreset(preset), className: getPresetClassName(isPresetSelected(preset)), children: preset.label }, preset.label))) })] }))] }));
38897
+ }
38898
+
38899
+ const NEXT_KEYS = new Set(['ArrowDown', 'ArrowRight']);
38900
+ const PREVIOUS_KEYS = new Set(['ArrowUp', 'ArrowLeft']);
38901
+ /** Arrow keys move and select within the radio group, wrapping at either end. */
38902
+ function getArrowKeyTarget(current, key) {
38903
+ const step = NEXT_KEYS.has(key) ? 1 : PREVIOUS_KEYS.has(key) ? -1 : 0;
38904
+ if (step === 0)
38905
+ return null;
38906
+ const index = TRI_STATE_OPTIONS.findIndex((option) => option.value === current);
38907
+ const nextIndex = (index + step + TRI_STATE_OPTIONS.length) % TRI_STATE_OPTIONS.length;
38908
+ return TRI_STATE_OPTIONS[nextIndex].value;
38909
+ }
38910
+ function createRadioGroupKeyDownHandler(current, onChange) {
38911
+ return (event) => {
38912
+ const target = getArrowKeyTarget(current, event.key);
38913
+ if (!target)
38914
+ return;
38915
+ event.preventDefault();
38916
+ onChange(target);
38917
+ event.currentTarget
38918
+ .querySelector(`[data-value="${target}"]`)
38919
+ ?.focus();
38920
+ };
38921
+ }
38922
+
38923
+ function getRadioRowClassName(checked) {
38924
+ return cn('flex w-full cursor-pointer items-center gap-2.5 rounded-md px-2.5 py-2 text-left text-xs text-foreground transition-colors', FILTER_FOCUS_RING, checked ? 'bg-muted font-medium' : 'hover:bg-muted/50');
38925
+ }
38926
+ function getRadioCircleClassName(checked) {
38927
+ return cn('flex size-4 shrink-0 items-center justify-center rounded-full border', checked ? 'border-primary' : 'border-input-border');
38928
+ }
38929
+
38930
+ /** Any / Yes / No radio group for boolean columns (e.g. Active). */
38931
+ function TriStateFilter({ value, onChange, ariaLabel, }) {
38932
+ return (jsx("div", { role: "radiogroup", "aria-label": ariaLabel, onKeyDown: createRadioGroupKeyDownHandler(value, onChange), className: "flex flex-col gap-0.5", children: TRI_STATE_OPTIONS.map((option) => {
38933
+ const checked = option.value === value;
38934
+ return (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: [jsx("span", { "aria-hidden": "true", className: getRadioCircleClassName(checked), children: checked && jsx("span", { className: "size-2 rounded-full bg-primary" }) }), option.label] }, option.value));
38935
+ }) }));
38936
+ }
38937
+
37837
38938
  /**
37838
38939
  * Compact "time ago" label, e.g. "5m ago". Falls back to a locale date past a
37839
38940
  * week so older entries stay scannable.
@@ -38187,23 +39288,26 @@ function InventoryComboBox({ inventoryType, selectedItem, onSelect, fetchGems, f
38187
39288
  } }), jsx("span", { className: "truncate text-sm font-normal", children: sel.label })] })) : (jsx("span", { className: "truncate text-sm font-normal text-muted-foreground", children: searchPlaceholder })), renderOption: ({ item }) => (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 }));
38188
39289
  }
38189
39290
 
38190
- const OwnershipFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Ownership", options: [
38191
- { value: 'owned', label: 'Owned' },
38192
- { value: 'partner', label: 'Partner' },
38193
- { value: 'memo_in', label: 'Memo In' },
38194
- ] }));
38195
- const StockTypeFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Stock Type", options: [
38196
- { value: 'single', label: 'Single' },
38197
- { value: 'parcel', label: 'Parcel' },
38198
- { value: 'set', label: 'Set' },
38199
- { value: 'pair', label: 'Pair' },
38200
- ] }));
38201
- const StatusFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Status", options: [
38202
- { value: 'in_stock', label: 'In Stock' },
38203
- { value: 'out_of_stock', label: 'Out of Stock' },
38204
- { value: 'sold', label: 'Sold' },
38205
- { value: 'memo_out', label: 'Memo Out' },
38206
- ] }));
39291
+ const OWNERSHIP_STATUS_OPTIONS = [
39292
+ { value: 'owned', label: 'Owned' },
39293
+ { value: 'partner', label: 'Partner' },
39294
+ { value: 'memo_in', label: 'Memo In' },
39295
+ ];
39296
+ const STOCK_TYPE_OPTIONS = [
39297
+ { value: 'single', label: 'Single' },
39298
+ { value: 'parcel', label: 'Parcel' },
39299
+ { value: 'set', label: 'Set' },
39300
+ { value: 'pair', label: 'Pair' },
39301
+ ];
39302
+ const INVENTORY_STATUS_OPTIONS = [
39303
+ { value: 'in_stock', label: 'In Stock' },
39304
+ { value: 'out_of_stock', label: 'Out of Stock' },
39305
+ { value: 'sold', label: 'Sold' },
39306
+ { value: 'memo_out', label: 'Memo Out' },
39307
+ ];
39308
+ const OwnershipFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Ownership", searchPlaceholder: "Search ownership", options: [...OWNERSHIP_STATUS_OPTIONS] }));
39309
+ const StockTypeFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Stock Type", searchPlaceholder: "Search stock types", options: [...STOCK_TYPE_OPTIONS] }));
39310
+ const StatusFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Status", searchPlaceholder: "Search statuses", options: [...INVENTORY_STATUS_OPTIONS] }));
38207
39311
  const WarehouseFilter = ({ getWarehouseList, ...props }) => {
38208
39312
  const [warehouses, setWarehouses] = useState([]);
38209
39313
  useEffect(() => {
@@ -38211,7 +39315,7 @@ const WarehouseFilter = ({ getWarehouseList, ...props }) => {
38211
39315
  .then(setWarehouses)
38212
39316
  .catch(() => { });
38213
39317
  }, [getWarehouseList]);
38214
- return (jsx(FilterMultiSelect, { ...props, label: "Warehouse", contentClassName: "min-w-[250px] w-fit", options: warehouses.map((w) => ({
39318
+ return (jsx(FilterMultiSelect, { ...props, label: "Warehouse", searchPlaceholder: "Search warehouses", options: warehouses.map((w) => ({
38215
39319
  value: w.id,
38216
39320
  label: `${w.warehouseId} · ${w.name}`,
38217
39321
  })) }));
@@ -38443,25 +39547,15 @@ const TONE_ICON_BG = {
38443
39547
  };
38444
39548
  const MetricTile = ({ label, value, sub, icon, tone, className, }) => (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: [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 }), jsxs("div", { className: "flex min-w-0 flex-col", children: [jsx("span", { className: "truncate text-xs text-muted-foreground", children: label }), jsx("span", { className: "truncate text-lg font-semibold text-foreground", children: value }), sub && (jsx("span", { className: "truncate text-xs text-muted-foreground", children: sub }))] })] }));
38445
39549
 
38446
- const SIZE_WIDTH = {
38447
- sm: 480,
38448
- md: 640,
38449
- lg: 760,
38450
- xl: 960,
38451
- };
38452
39550
  /**
38453
39551
  * App-wide modal wrapper with a fixed header / body / footer layout.
38454
39552
  * Built on top of shadcn DialogContent, so it inherits viewport-centered
38455
39553
  * positioning, focus trapping, portal rendering, and overlay handling.
38456
39554
  */
38457
- function Modal({ open, onClose, title, icon, children, footer, size = 'md', hideCloseButton = false, className, bodyClassName, }) {
38458
- const maxWidth = SIZE_WIDTH[size];
39555
+ function Modal({ open, onClose, title, description, icon, children, footer, size = 'default', hideCloseButton = false, className, bodyClassName, }) {
38459
39556
  // See ConfirmDialog: overlapping dismissable layers leak the <body> lock.
38460
39557
  useOverlayBodyLockRelease(open);
38461
- return (jsx(Dialog, { open: open, onOpenChange: (o) => !o && onClose(), children: jsxs(DialogContent, { hideCloseButton: true, style: {
38462
- width: `min(${maxWidth}px, calc(100vw - 2rem))`,
38463
- maxWidth: `${maxWidth}px`,
38464
- }, className: cn('flex max-h-[calc(100vh-2rem)] flex-col gap-0 overflow-hidden p-0 sm:max-w-none', className), children: [jsxs("header", { className: "flex items-center justify-between gap-4 border-b border-border px-6 py-4", children: [jsx(DialogPrimitive.Title, { asChild: true, children: jsxs("div", { className: "flex items-center gap-2 text-base font-medium text-foreground", children: [icon, jsx("span", { children: title })] }) }), !hideCloseButton && (jsx(DialogPrimitive.Close, { "aria-label": "Close", className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-label transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30", children: jsx(X$2, { className: "h-4 w-4" }) }))] }), jsx("div", { className: cn('flex-1 overflow-y-auto', bodyClassName), children: children }), footer && (jsx("footer", { className: "flex items-center justify-end gap-3 border-t border-border px-6 py-4", children: footer }))] }) }));
39558
+ return (jsx(Dialog, { open: open, onOpenChange: (o) => !o && onClose(), children: jsxs(DialogContent, { hideCloseButton: true, size: size === 'wide' ? 'wide' : 'default', className: cn('flex flex-col gap-0 overflow-hidden p-0', className), children: [jsxs("header", { className: "flex shrink-0 items-start justify-between gap-4 px-6 pt-5 pb-4", children: [jsxs("div", { className: cn('flex min-w-0 gap-3.5', description ? 'items-start' : 'items-center'), children: [icon ? jsx(DialogIcon, { children: icon }) : null, jsxs("div", { className: "flex min-w-0 flex-col", children: [jsx(DialogPrimitive.Title, { className: "m-0 text-lg font-semibold leading-6 text-foreground", children: title }), description ? (jsx(DialogPrimitive.Description, { className: "m-0 text-sm leading-5 text-muted-foreground", children: description })) : null] })] }), !hideCloseButton && (jsx(DialogPrimitive.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: jsx(X$2, { className: "h-4 w-4" }) }))] }), jsx("div", { className: cn('flex-1 overflow-y-auto', bodyClassName), children: children }), footer && (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 }))] }) }));
38465
39559
  }
38466
39560
 
38467
39561
  /**
@@ -67169,59 +68263,6 @@ function useIsTablet() {
67169
68263
  return useMediaQuery(`(min-width: ${MOBILE_MAX + 1}px) and (max-width: ${TABLET_MAX}px)`);
67170
68264
  }
67171
68265
 
67172
- // Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
67173
- // labels that are not actually clipped.
67174
- const OVERFLOW_TOLERANCE_PX = 1;
67175
- function findClippedLabel(root) {
67176
- const spans = root.querySelectorAll(':scope > span');
67177
- for (const span of Array.from(spans)) {
67178
- if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX) {
67179
- return span;
67180
- }
67181
- }
67182
- return null;
67183
- }
67184
- /**
67185
- * Returns the full text of the first direct-child `<span>` of `ref` that is
67186
- * clipped by its container (i.e. showing an ellipsis), else `null` — so callers
67187
- * can surface a tooltip only when the label is actually unreadable.
67188
- *
67189
- * Re-measures on element resize (sidebar expand/collapse, window resize) and on
67190
- * label text changes.
67191
- */
67192
- function useTruncatedText(ref) {
67193
- const [text, setText] = useState(null);
67194
- useEffect(() => {
67195
- const el = ref.current;
67196
- if (!el)
67197
- return;
67198
- let frame = 0;
67199
- const measure = () => {
67200
- const label = findClippedLabel(el);
67201
- setText(label?.textContent?.trim() || null);
67202
- };
67203
- const schedule = () => {
67204
- cancelAnimationFrame(frame);
67205
- frame = requestAnimationFrame(measure);
67206
- };
67207
- schedule();
67208
- const resizeObserver = new ResizeObserver(schedule);
67209
- resizeObserver.observe(el);
67210
- const mutationObserver = new MutationObserver(schedule);
67211
- mutationObserver.observe(el, {
67212
- characterData: true,
67213
- childList: true,
67214
- subtree: true,
67215
- });
67216
- return () => {
67217
- cancelAnimationFrame(frame);
67218
- resizeObserver.disconnect();
67219
- mutationObserver.disconnect();
67220
- };
67221
- }, [ref]);
67222
- return text;
67223
- }
67224
-
67225
68266
  const SIDEBAR_COOKIE_NAME = 'sidebar_state';
67226
68267
  const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
67227
68268
  const SIDEBAR_WIDTH = '16rem';
@@ -67460,37 +68501,6 @@ const AppSidebar = ({ brand, navGroups = [], footer, className, }) => {
67460
68501
  return (jsxs(Sidebar, { collapsible: "icon", className: className, children: [brand && (jsx(SidebarHeader, { children: jsx(BrandHeader$1, { brand: brand }) })), jsx(SidebarContent, { children: navGroups.map((group) => (jsx(NavGroupSection, { group: group }, group.label ?? 'nav-group'))) }), footer && jsx(SidebarFooter, { children: footer }), jsx(SidebarRail, {})] }));
67461
68502
  };
67462
68503
 
67463
- /** Label line + input block — mirrors a `Field`. */
67464
- function FieldSkeleton() {
67465
- return (jsxs("div", { className: "space-y-2", children: [jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsx(SquareSkeleton, { height: 40, className: "w-full", rounded: "md" })] }));
67466
- }
67467
- /**
67468
- * Loading placeholder that matches a `FormSectionCard` — the tinted header band
67469
- * (icon square + title + description) above a body of `Field` placeholders and
67470
- * an optional footer action row.
67471
- */
67472
- function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
67473
- return (jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-xl border border-border bg-card shadow-card", children: [jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsx(SquareSkeleton, { height: 40, width: 40, rounded: "md" }), jsxs("div", { className: "space-y-1.5", children: [jsx(SquareSkeleton, { height: 14, width: 180, rounded: "full" }), description && jsx(SquareSkeleton, { height: 11, width: 260, rounded: "full" })] })] }), jsxs("div", { className: "p-5", children: [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) => (jsx(FieldSkeleton, {}, i))) }), footer !== 'none' && (jsxs("div", { className: cn('mt-8 flex items-center gap-3 pt-4', footer === 'between' ? 'justify-between' : 'justify-end'), children: [footer === 'between' && (jsx(SquareSkeleton, { height: 36, width: 90, rounded: "md" })), jsx(SquareSkeleton, { height: 36, width: 120, rounded: "md" })] }))] })] }));
67474
- }
67475
- /** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
67476
- function TableSkeleton({ rows = 8 }) {
67477
- return (jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "flex gap-2", children: [jsx(SquareSkeleton, { className: "h-9 flex-1", rounded: "md" }), jsx(SquareSkeleton, { className: "h-9 w-44", rounded: "md" }), jsx(SquareSkeleton, { className: "h-9 w-48", rounded: "md" })] }), Array.from({ length: rows }).map((_, i) => (jsx(SquareSkeleton, { className: "h-12 w-full", rounded: "md" }, i)))] }));
67478
- }
67479
- /** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
67480
- function TableRowsSkeleton({ rows = 10, className }) {
67481
- return (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) => (
67482
- // shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
67483
- jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
67484
- }
67485
- /** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
67486
- function DetailPageSkeleton({ sections = 3, }) {
67487
- return (jsxs("div", { className: "space-y-5", children: [jsxs("div", { className: "flex items-center justify-between gap-4", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(SquareSkeleton, { height: 32, width: 32, rounded: "md" }), jsxs("div", { className: "space-y-1.5", children: [jsx(SquareSkeleton, { height: 20, width: 192, rounded: "full" }), jsx(SquareSkeleton, { height: 12, width: 128, rounded: "full" })] })] }), jsx(SquareSkeleton, { height: 36, width: 128, rounded: "md" })] }), Array.from({ length: sections }).map((_, s) => (jsxs("div", { className: "overflow-hidden rounded-xl border border-border bg-card", children: [jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-secondary px-5 py-4", children: [jsx(SquareSkeleton, { height: 32, width: 32, rounded: "lg" }), jsx(SquareSkeleton, { height: 16, width: 160, rounded: "full" })] }), jsx("div", { className: "grid grid-cols-1 gap-5 p-5 md:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (jsxs("div", { className: "space-y-1.5", children: [jsx(SquareSkeleton, { height: 10, width: 80, rounded: "full" }), jsx(SquareSkeleton, { height: 14, width: 128, rounded: "full" })] }, i))) })] }, s)))] }));
67488
- }
67489
- /** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
67490
- function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
67491
- return (jsxs("div", { role: "status", "aria-busy": "true", "aria-label": label, className: "space-y-4", children: [jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(SquareSkeleton, { height: 14, width: 80, rounded: "full" }), jsx("span", { className: "h-5 w-px bg-border" }), jsx(SquareSkeleton, { height: 28, width: 200, rounded: "md" }), jsx(SquareSkeleton, { height: 22, width: 72, rounded: "full" })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(SquareSkeleton, { height: 36, width: 112, rounded: "lg" }), jsx(SquareSkeleton, { height: 36, width: 80, rounded: "lg" }), jsx(SquareSkeleton, { height: 36, width: 128, rounded: "lg" }), jsx(SquareSkeleton, { height: 36, width: 36, rounded: "lg" })] })] }), 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: [jsxs("div", { className: "flex flex-col justify-center space-y-3 px-5 py-4 sm:px-7 sm:py-4", children: [jsx(SquareSkeleton, { height: 12, width: 96, rounded: "full" }), jsx(SquareSkeleton, { height: 40, width: 220, rounded: "md" }), aside !== 'none' && (jsxs("div", { className: "w-full max-w-xl space-y-2 pt-1", children: [jsx(SquareSkeleton, { height: 8, className: "w-full", rounded: "full" }), jsxs("div", { className: "flex justify-between", children: [jsx(SquareSkeleton, { height: 11, width: 88, rounded: "full" }), jsx(SquareSkeleton, { height: 11, width: 40, rounded: "full" })] })] }))] }), 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) => (jsxs("div", { className: "flex min-h-10 items-center gap-3 border-b border-border py-1.5 last:border-b-0", children: [jsx(SquareSkeleton, { height: 24, width: 24, rounded: "md" }), jsx(SquareSkeleton, { height: 12, width: 72, rounded: "full" }), jsx(SquareSkeleton, { height: 12, width: 88, rounded: "full", className: "ml-auto" })] }, i))) })] }), Array.from({ length: sections }).map((_, s) => (jsxs("section", { "aria-hidden": "true", className: "overflow-hidden rounded-2xl border border-border bg-card", children: [jsxs("div", { className: "flex items-center gap-2.5 border-b border-border px-4 py-3", children: [jsx(SquareSkeleton, { height: 28, width: 28, rounded: "lg" }), jsx(SquareSkeleton, { height: 15, width: 128, rounded: "full" })] }), jsx("div", { className: "space-y-3 p-4", children: Array.from({ length: s === 1 ? 4 : 2 }).map((__, row) => (jsx(SquareSkeleton, { height: s === 1 ? 36 : 14, className: row % 2 ? 'w-3/4' : 'w-full', rounded: "md" }, row))) })] }, s))), jsx("span", { className: "sr-only", children: label })] }));
67492
- }
67493
-
67494
68504
  const SlideOut = ({ open, onOpenChange, ...props }) => {
67495
68505
  const scheduleLockRelease = useOverlayBodyLockRelease(open);
67496
68506
  return (jsx(DialogPrimitive.Root, { ...props, open: open, onOpenChange: (next) => {
@@ -75302,7 +76312,7 @@ function ImageCropModal({ open, imageUrl, fileType, onCancel, onConfirm, }) {
75302
76312
  const blob = await getCroppedBlob(imgRef.current, completedCrop, fileType);
75303
76313
  onConfirm(blob);
75304
76314
  };
75305
- return (jsxs(Modal, { open: open, onClose: onCancel, size: "lg", icon: jsx(Scissors, { className: "h-5 w-5 text-foreground", strokeWidth: 1.5 }), title: "Crop Image", footer: jsxs(Fragment$2, { children: [jsx(Button$1, { type: "button", variant: "outline", onClick: onCancel, className: "border-border bg-muted text-foreground hover:bg-muted/80", children: "Cancel" }), jsx(Button$1, { type: "button", onClick: handleConfirm, className: "bg-primary text-primary-foreground hover:bg-hover", children: "Crop & Add" })] }), children: [jsxs("div", { className: "space-y-3 px-6 py-4", children: [jsx("p", { className: "text-[13px] text-label", children: "Aspect ratio" }), jsx("div", { className: "grid grid-cols-5 gap-3", children: ASPECTS.map((a) => {
76315
+ return (jsxs(Modal, { open: open, onClose: onCancel, size: "wide", icon: jsx(Scissors, { className: "h-5 w-5 text-foreground", strokeWidth: 1.5 }), title: "Crop Image", footer: jsxs(Fragment$2, { children: [jsx(Button$1, { type: "button", variant: "outline", onClick: onCancel, children: "Cancel" }), jsx(Button$1, { type: "button", onClick: handleConfirm, className: "bg-primary text-primary-foreground hover:bg-hover", children: "Crop & Add" })] }), children: [jsxs("div", { className: "space-y-3 px-6 pb-4", children: [jsx("p", { className: "text-[13px] text-label", children: "Aspect ratio" }), jsx("div", { className: "grid grid-cols-5 gap-3", children: ASPECTS.map((a) => {
75306
76316
  const selected = aspectKey === a.key;
75307
76317
  return (jsxs("button", { type: "button", onClick: () => setAspectKey(a.key), className: cn('flex cursor-pointer flex-col items-center justify-center gap-1 rounded-lg border px-3 py-3 text-xs transition-colors', selected
75308
76318
  ? 'border-primary bg-primary/10 text-primary'
@@ -75438,6 +76448,219 @@ const FileUploader = ({ accept, multiple = true, maxSize = 50, maxFiles = 5, lab
75438
76448
  return (jsxs("div", { className: cn('flex flex-col gap-4', className), children: [label && (jsx("label", { className: "text-sm font-medium text-foreground", children: label })), jsx(DropZone, { uploadSubject: uploadSubject, supportedFormats: supportedFormats, maxSize: maxSize, maxFiles: maxFiles, accept: accept, multiple: multiple, disabled: disabled, onFiles: handlePickerFiles }), files.length > 0 && (jsxs("div", { className: "space-y-2", children: [jsx("p", { className: "text-[13px] text-label", children: "Uploaded File" }), jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: onDragEnd, children: jsx(SortableContext, { items: files.map((f) => f.id), strategy: rectSortingStrategy, children: jsx("div", { className: "flex flex-wrap gap-3", children: files.map((file) => (jsx(FileCard, { file: file, sortable: sortable, disabled: disabled, onRemove: handleRemove, onPreview: previewFile }, file.id))) }) }) })] })), enableUrlInput && (jsxs(Fragment$2, { children: [jsxs("div", { className: "flex items-center gap-3 text-sm font-normal text-label", children: [jsx("span", { className: "h-px flex-1 bg-border" }), jsx("span", { children: "or" }), jsx("span", { className: "h-px flex-1 bg-border" })] }), jsx(UrlImportRow, { disabled: disabled, onAdd: handleAddUrl })] })), cropImages && currentCropFile && cropPreviewUrl && (jsx(ImageCropModal, { open: true, imageUrl: cropPreviewUrl, fileName: currentCropFile.name, fileType: currentCropFile.type, onCancel: handleCropCancel, onConfirm: handleCropConfirm }))] }));
75439
76449
  };
75440
76450
 
76451
+ /** The value narrowed to one control type, or undefined when it holds another (or none). */
76452
+ function valueOfType(value, type) {
76453
+ return value?.type === type ? value : undefined;
76454
+ }
76455
+ /** Each builder returns `undefined` for an empty selection so cleared filters drop out of state. */
76456
+ const toListValue = (values) => values.length ? { type: 'list', values } : undefined;
76457
+ const toScaleValue = (range) => (range ? { type: 'scale', range } : undefined);
76458
+ const toNumberValue = (range) => range && (range.min !== undefined || range.max !== undefined)
76459
+ ? { type: 'number', range }
76460
+ : undefined;
76461
+ const toIdsValue = (ids) => ids.length ? { type: 'ids', ids } : undefined;
76462
+ const toContainsValue = (text) => text.trim() ? { type: 'contains', text: text.trim() } : undefined;
76463
+ const toDateValue = (range) => range && (range.preset || range.from || range.to)
76464
+ ? { type: 'date', range }
76465
+ : undefined;
76466
+ const toBoolValue = (value) => value === 'any' ? undefined : { type: 'bool', value };
76467
+ const DEFAULT_CELL_PLACEHOLDERS = {
76468
+ list: 'All',
76469
+ scale: 'All',
76470
+ number: '',
76471
+ ids: 'Paste IDs…',
76472
+ contains: 'Contains…',
76473
+ date: 'Any date',
76474
+ bool: 'Any',
76475
+ };
76476
+ function getCellState(field, value) {
76477
+ if (field.disabled)
76478
+ return 'disabled';
76479
+ return isFilterValueActive(value) ? 'applied' : 'empty';
76480
+ }
76481
+ /** Human-readable value for chips and card summaries, e.g. `Red, Blue`, `1–3`, `Last 30 days`. */
76482
+ function describeFilterValue(field, value) {
76483
+ if (!value || !isFilterValueActive(value))
76484
+ return '';
76485
+ const options = field.options ?? [];
76486
+ switch (value.type) {
76487
+ case 'list':
76488
+ return options
76489
+ .filter((option) => value.values.includes(option.value))
76490
+ .map((option) => option.label)
76491
+ .concat(value.values.filter((v) => !options.some((option) => option.value === v)))
76492
+ .join(', ');
76493
+ case 'scale':
76494
+ return formatScaleRange(options, value.range);
76495
+ case 'number':
76496
+ return formatNumberRange(value.range);
76497
+ case 'ids':
76498
+ return value.ids.length === 1 ? value.ids[0] : `${value.ids.length} IDs`;
76499
+ case 'contains':
76500
+ return `“${value.text}”`;
76501
+ case 'date':
76502
+ return formatDateRange(value.range);
76503
+ case 'bool':
76504
+ return getOptionLabel([
76505
+ { value: 'yes', label: 'Yes' },
76506
+ { value: 'no', label: 'No' },
76507
+ ], value.value);
76508
+ }
76509
+ }
76510
+ /** Short value shown on the filter-row trigger, e.g. `Red +1`, `VG – F`, `3 IDs`. */
76511
+ function getCellLabel(field, value) {
76512
+ if (!value || !isFilterValueActive(value))
76513
+ return '';
76514
+ if (value.type === 'list')
76515
+ return summarizeSelection(value.values, field.options ?? []);
76516
+ if (value.type === 'scale')
76517
+ return formatScaleRange(field.options ?? [], value.range, field.shortLabels);
76518
+ if (value.type === 'ids')
76519
+ return `${value.ids.length} IDs`;
76520
+ return describeFilterValue(field, value);
76521
+ }
76522
+ /** Filter-row popovers hold the filter's card at a compact, fixed width. */
76523
+ function getPopoverWidthClassName(field) {
76524
+ if (field.type === 'date')
76525
+ return 'w-96';
76526
+ if (field.type === 'bool')
76527
+ return 'w-60';
76528
+ return 'w-64';
76529
+ }
76530
+ const POPOVER_TILE_COLUMNS = 2;
76531
+ /** Above this many options, chips / tiles give way to the searchable checkbox list. */
76532
+ const MAX_PILL_OPTIONS = 10;
76533
+ /** The list layout actually used: the configured one, or the checkbox list once there are too many options for pills. */
76534
+ function resolveListLayout(field) {
76535
+ return (field.options?.length ?? 0) > MAX_PILL_OPTIONS
76536
+ ? 'list'
76537
+ : (field.layout ?? 'chips');
76538
+ }
76539
+ /** Popover variant: tile and option grids drop to two columns; chip lists become the checkbox list. */
76540
+ function toPopoverField(field) {
76541
+ if (field.type === 'scale' ||
76542
+ (field.type === 'list' && resolveListLayout(field) === 'tiles')) {
76543
+ return { ...field, columns: POPOVER_TILE_COLUMNS };
76544
+ }
76545
+ // Chip filters read better as the checkbox list in a narrow popover.
76546
+ return field.type === 'list' ? { ...field, layout: 'list' } : field;
76547
+ }
76548
+ /** ID lists and searchable lists carry their own "x selected · Clear" row, so the card skips its Clear (and, in a popover, its title). */
76549
+ const ownsClearRow = (field) => field.type === 'ids' ||
76550
+ (field.type === 'list' && resolveListLayout(field) === 'list');
76551
+ /** Popover header text in place of the title: `2 of 17 selected`, or the applied value (`VG – F`, `Last 30 days`). */
76552
+ function getPopoverStatus(field, value) {
76553
+ if (ownsClearRow(field))
76554
+ return undefined;
76555
+ if (field.type === 'list') {
76556
+ return formatSelectedCount(valueOfType(value, 'list')?.values.length ?? 0, field.options?.length ?? 0);
76557
+ }
76558
+ return describeFilterValue(field, value) || 'Any';
76559
+ }
76560
+ /** The empty single-select trigger: `inputPlaceholder`, else `Any <label>` (lowercased — set `inputPlaceholder` for acronyms). */
76561
+ const getSingleSelectPlaceholder = (field) => field.inputPlaceholder ?? `Any ${field.label.toLowerCase()}`;
76562
+
76563
+ /** Single-choice list as a searchable dropdown, e.g. "Any vendor". */
76564
+ function SingleSelectFilter({ field, selected, onSelect, }) {
76565
+ const options = field.options ?? [];
76566
+ return (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 }));
76567
+ }
76568
+ /** The control alone — identical in a filter-row popover and on a card, except the list layout. Compose it into custom cards. */
76569
+ function FilterFieldControl({ field, value, onChange, fiscalYearStartMonth, fill, inPopover, }) {
76570
+ const ariaLabel = `${field.label} filter`;
76571
+ switch (field.type) {
76572
+ case 'list': {
76573
+ if (field.single && !inPopover) {
76574
+ return (jsx(SingleSelectFilter, { field: field, selected: valueOfType(value, 'list')?.values[0], onSelect: (next) => onChange(toListValue([next])) }));
76575
+ }
76576
+ const layout = resolveListLayout(field);
76577
+ return (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 }));
76578
+ }
76579
+ case 'scale':
76580
+ return (jsx(ScaleRangeFilter, { ariaLabel: ariaLabel, options: field.options ?? [], value: valueOfType(value, 'scale')?.range, onChange: (range) => onChange(toScaleValue(range)), columns: field.columns, fill: fill }));
76581
+ case 'number':
76582
+ return (jsx(NumberRangeInputs, { ariaLabel: field.label, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), presets: field.presets, presetsLabel: field.presetsLabel }));
76583
+ case 'ids':
76584
+ return (jsx(IdListInput, { ariaLabel: ariaLabel, value: valueOfType(value, 'ids')?.ids ?? [], onChange: (ids) => onChange(toIdsValue(ids)), placeholder: field.inputPlaceholder,
76585
+ // Cards show one shared hint instead of a helper under every box.
76586
+ helperText: inPopover ? field.helperText : '' }));
76587
+ case 'contains':
76588
+ return (jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "field", value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)) }));
76589
+ case 'date':
76590
+ return (jsx(DateRangeFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'date')?.range, onChange: (range) => onChange(toDateValue(range)), fiscalYearStartMonth: fiscalYearStartMonth }));
76591
+ case 'bool':
76592
+ return (jsx(TriStateFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'bool')?.value ?? 'any', onChange: (next) => onChange(toBoolValue(next)) }));
76593
+ }
76594
+ }
76595
+ /** Filter-row cell: inline input for number/contains, otherwise a trigger that opens the control in a popover. */
76596
+ function FilterFieldCell({ field, value, onChange, fiscalYearStartMonth, className, }) {
76597
+ const state = getCellState(field, value);
76598
+ const ariaLabel = `${field.label} filter`;
76599
+ const placeholder = field.placeholder ?? DEFAULT_CELL_PLACEHOLDERS[field.type];
76600
+ const clear = () => onChange(undefined);
76601
+ if (field.type === 'number' && state !== 'disabled') {
76602
+ return (jsx(NumberExpressionFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), placeholder: placeholder, note: field.note, className: className }));
76603
+ }
76604
+ if (field.type === 'contains' && state !== 'disabled') {
76605
+ return (jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "cell", value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)), placeholder: placeholder, className: className }));
76606
+ }
76607
+ return (jsx(FilterCellPopover, { label: getCellLabel(field, value), placeholder: placeholder, ariaLabel: ariaLabel, state: state, disabledLabel: field.disabledLabel, icon: field.type === 'ids' ? jsx(List, {}) : undefined, showChevron: field.type !== 'ids', onClear: field.type === 'ids' ? clear : undefined, contentClassName: getPopoverWidthClassName(field), className: className, children: jsx(FilterFieldCard, { mode: "popover", field: toPopoverField(field), value: value, onChange: onChange, fiscalYearStartMonth: fiscalYearStartMonth }) }));
76608
+ }
76609
+ /** 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`). */
76610
+ function FilterFieldCard({ field, value, onChange, fiscalYearStartMonth, action, className, mode, }) {
76611
+ const active = isFilterValueActive(value);
76612
+ const listCount = valueOfType(value, 'list')?.values.length;
76613
+ // In a filter-row popover the column header already names the filter.
76614
+ const inPopover = mode === 'popover';
76615
+ return (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'
76616
+ ? describeFilterValue(field, value)
76617
+ : undefined, action: action, onClear: active && !ownsClearRow(field)
76618
+ ? () => onChange(undefined)
76619
+ : undefined, hint: field.hint, active: active, className: className, children: jsx(FilterFieldControl, { field: field, value: value, onChange: onChange, fiscalYearStartMonth: fiscalYearStartMonth, fill: mode === 'card', inPopover: mode === 'popover' }) }));
76620
+ }
76621
+ function FilterField(props) {
76622
+ const { mode, ...rest } = props;
76623
+ return mode === 'cell' ? (jsx(FilterFieldCell, { ...rest })) : (jsx(FilterFieldCard, { mode: mode, ...rest }));
76624
+ }
76625
+
76626
+ /** Both leave without applying — the draft is discarded. */
76627
+ const BACK_LABEL = 'Back without applying';
76628
+ const CLOSE_LABEL = 'Close without applying';
76629
+
76630
+ function useCloseOnEscape(onClose) {
76631
+ useEffect(() => {
76632
+ const handleKeyDown = (event) => {
76633
+ if (event.key !== 'Escape' || event.defaultPrevented)
76634
+ return;
76635
+ // Escape inside an open popover only closes that popover (Radix doesn't mark the event handled).
76636
+ if (event.target instanceof Element &&
76637
+ event.target.closest('[data-slot="popover-content"]'))
76638
+ return;
76639
+ onClose();
76640
+ };
76641
+ document.addEventListener('keydown', handleKeyDown);
76642
+ return () => document.removeEventListener('keydown', handleKeyDown);
76643
+ }, [onClose]);
76644
+ }
76645
+ function useFilterSurfaceMore(defaultExpanded = false) {
76646
+ const [expanded, setExpanded] = useState(defaultExpanded);
76647
+ return { expanded, toggle: () => setExpanded((current) => !current) };
76648
+ }
76649
+
76650
+ /** Full-page filter screen (e.g. an advanced search): header, scrolling card grid, sticky apply footer. */
76651
+ function FilterSurface({ title, headerActions, footerChips, footerActions, onClose, children, }) {
76652
+ useCloseOnEscape(onClose);
76653
+ return (jsxs("div", { role: "region", "aria-label": title, className: "flex h-full min-h-0 flex-col bg-background", children: [jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 pt-2 pb-3", children: [jsxs("header", { className: "mb-3 flex flex-wrap items-end justify-between gap-3", children: [jsx("div", { className: "flex flex-col gap-1", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(IconButton, { appearance: "ghost", size: "sm", "aria-label": BACK_LABEL, title: BACK_LABEL, onClick: onClose, children: jsx(ArrowLeft, {}) }), jsx("h1", { className: "text-xl font-semibold text-foreground", children: title })] }) }), jsxs("div", { className: "flex items-center gap-2", children: [headerActions, jsx(IconButton, { appearance: "outline", size: "md", "aria-label": CLOSE_LABEL, title: CLOSE_LABEL, onClick: onClose, children: jsx(X$2, {}) })] })] }), jsx("div", { className: "flex flex-col gap-4", children: children })] }), (footerChips || footerActions) && (jsxs("footer", { className: "flex flex-wrap items-center justify-between gap-3 border-t border-border bg-card px-3 py-2", children: [jsx("div", { className: "min-w-0 flex-1", children: footerChips }), jsx("div", { className: "flex shrink-0 items-center gap-2", children: footerActions })] }))] }));
76654
+ }
76655
+ function FilterSurfaceGroup({ title, className, children, }) {
76656
+ return (jsxs("section", { className: "flex flex-col gap-3", children: [title && (jsx("h2", { className: "text-xs font-semibold uppercase tracking-wide text-label", children: title })), jsx("div", { className: cn('grid grid-cols-1 gap-4 lg:grid-cols-6', className), children: children })] }));
76657
+ }
76658
+ /** Collapsed "More filters" divider that reveals extra cards. */
76659
+ function FilterSurfaceMore({ label, defaultExpanded, children, }) {
76660
+ const { expanded, toggle } = useFilterSurfaceMore(defaultExpanded);
76661
+ return (jsxs("section", { className: "flex flex-col gap-6", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "h-px flex-1 bg-border" }), 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, jsx(ChevronDown, { "aria-hidden": "true", className: cn('size-3.5 transition-transform', expanded && 'rotate-180') })] }), jsx("span", { className: "h-px flex-1 bg-border" })] }), expanded && children] }));
76662
+ }
76663
+
75441
76664
  /** Falls back to counting the current page when the caller has no total. */
75442
76665
  function resolveUnreadCount(notifications, unreadCount) {
75443
76666
  if (typeof unreadCount === 'number')
@@ -78011,5 +79234,5 @@ var RichTextAreaImpl = /*#__PURE__*/Object.freeze({
78011
79234
  RichTextarea: RichTextarea
78012
79235
  });
78013
79236
 
78014
- export { ACTIVITY_CATEGORIES, ACTIVITY_CATEGORY_META, ActionBadge, ActionButtonWithTooltip, ActivityFeed, AdvancedSearchDrawer, Alert, ApiComboBox, AppSidebar, AuditEntryCard, AuditHistoryPanel, AuditTimeline, AuditTimelineShimmer, Badge, BadgeType, BusinessContactStatusFilter, Button, CUSTOMER_AUDIT_CONFIG, CertificateRowList, ChangePill, Collapsible, CollapsibleCard, CollapsibleContent, CollapsibleTrigger, CompanyCard, ConfirmDialog, ContactTypeFilter, CopyButton, CountrySelect, CreateFormPageHeader, CreateFormPageShell, CurrencyDisplayTabs, CurrencyInput, CurrencyToggle, CustomCombobox, CustomFieldInput, CustomFieldValue, CustomTable, CustomizeColumnsDrawer, DIAMOND_AUDIT_CONFIG, DashboardShell, DataEditableTable, DataTable, DateInput, DetailChip, DetailPageLayout, DetailPageSkeleton, DetailSection, DocumentDeleteDialog, DocumentDetailSkeleton, DocumentHero, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyValue, EntityHeader, Field, FieldSkeleton, FileUploader, FilterMultiSelect, FilterSelect, FormSectionCard, FormSectionCardSkeleton, GEM_AUDIT_CONFIG, HistoryEntryCard, HistoryTimeline, HistoryTimelineShimmer, INVOICE_AUDIT_CONFIG, IconButton, IdHyperlinkText, InAppNotificationCard, InAppNotificationsPanel, InfoBanner, InventoryComboBox, InventoryItemCard, InventoryItemRow, InvoiceComboBox, KYCStatusFilter, KeyValueGrid, LAYOUT_AUDIT_CONFIG, LabeledToggle, LineItemsCard, LineProductCell, LineProductThumb, LineProductTypeChip, LineRowActionsMenu, LineTable, LineTableEmpty, MEMO_IN_AUDIT_CONFIG, MEMO_OUT_AUDIT_CONFIG, MediaGallery, MemoInComboBox, MetricCard, MetricRow, MetricTile, Modal, MoreInfoPanel, MoreInfoTrigger, NOT_CAPTURED, Navbar, NavbarActions, NavbarAvatar, NavbarIconButton, NavbarSearch, NavbarTitle, NumberInput, NumberedStepCard, OtpInput, OwnershipFilter, OwnershipSplitCard, PROFORMA_AUDIT_CONFIG, PageHeader, PageTabs, Pagination, PaginationSelect, PartnerShareCard, PriceInput, Protected, PurchaseOrderComboBox, QUOTATION_AUDIT_CONFIG, RadioCardGroup, ReadMoreText, RefreshButton, RichTextarea$1 as RichTextarea, SEARCHABLE_SELECT_PAGE_SIZE, SafeImage, SearchBox, SearchInput, SearchableSelect, SectionCard, SectionIcon, SegmentedControl, ShareDialog, ShareMenu, ShimmerTable, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SlideOut, SlideOutClose, SlideOutContent, SlideOutDescription, SlideOutHeader, SlideOutOverlay, SlideOutPortal, SlideOutTitle, SlideOutTrigger, Slider, SpecList, Spinner, SquareSkeleton, StateSelect, StatusBadge$1 as StatusBadge, StatusFilter, Stepper, StockTypeFilter, TablePagination, TableRowsSkeleton, TableSkeleton, Tabs, TabsContent, TabsList, TabsTrigger, TagsInput, TextHyperlink, TimePicker, ToggleSwitch, TruncateTooltip, WarehouseComboBox, WarehouseFilter, ZoomSplitViewer, asList, asText, badgeVariants, buildBulkShareMessage, buildBulkShareTitle, buildInventoryPublicUrl, buildInventoryRowProps, buildInventoryShareTitle, buildWhatsappUrl, buttonVariants, cn, countries, countryByCode, createVideoMediaItem, dropdownMenuItemDestructiveClass, fieldTypeIcon, findRegion, flagEmoji, formatAddressLocation, formatFileSize, generateActionDescription, generateTitle, getBadgeTypeForStatus, getChangePills, getCountryName, getInitials, getStatesOfCountry, iconButtonVariants, inAppNotificationCardA11y, inAppNotificationsPanelA11y, isBlank, isIndiaCountry, isKnownRegion, isPathActive, isValidAlpha2CountryCode, isValueEmpty, notify, releaseStaleOverlayBodyLock, renderBadge, resolveCountryCode, toAddressFormValues, useAuditShowMore, useBadge, useButton, useDropdownMenu, useInAppNotificationsPanel, useNavbar, useSidebar, videoThumbnailSrc, watchOverlayBodyLock };
79237
+ export { ACTIVITY_CATEGORIES, ACTIVITY_CATEGORY_META, ActionBadge, ActionButtonWithTooltip, ActiveFilterChips, ActivityFeed, AdvancedSearchDrawer, Alert, ApiComboBox, AppSidebar, AuditEntryCard, AuditHistoryPanel, AuditTimeline, AuditTimelineShimmer, Badge, BadgeType, BusinessContactStatusFilter, Button, CUSTOMER_AUDIT_CONFIG, CertificateRowList, ChangePill, Collapsible, CollapsibleCard, CollapsibleContent, CollapsibleTrigger, CompanyCard, ConfirmDialog, ContactTypeFilter, ContainsFilter, CopyButton, CountrySelect, CreateFormPageHeader, CreateFormPageShell, CurrencyDisplayTabs, CurrencyInput, CurrencyToggle, CustomCombobox, CustomFieldInput, CustomFieldValue, CustomTable, CustomizeColumnsDrawer, DATE_PRESET_OPTIONS, DIAMOND_AUDIT_CONFIG, DashboardShell, DataEditableTable, DataTable, DateInput, DateRangeFilter, DetailChip, DetailPageLayout, DetailPageSkeleton, DetailSection, DocumentDeleteDialog, DocumentDetailSkeleton, DocumentHero, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyValue, EntityHeader, Field, FieldSkeleton, FileUploader, FilterCellPopover, FilterEmptyState, FilterField, FilterFieldCard, FilterFieldCell, FilterFieldControl, FilterMultiSelect, FilterPanel, FilterSelect, FilterSurface, FilterSurfaceGroup, FilterSurfaceMore, FormSectionCard, FormSectionCardSkeleton, GEM_AUDIT_CONFIG, HistoryEntryCard, HistoryTimeline, HistoryTimelineShimmer, INVOICE_AUDIT_CONFIG, IconButton, IdHyperlinkText, IdListInput, InAppNotificationCard, InAppNotificationsPanel, InfoBanner, InventoryComboBox, InventoryItemCard, InventoryItemRow, InvoiceComboBox, KYCStatusFilter, KeyValueGrid, LAYOUT_AUDIT_CONFIG, LabeledToggle, LineItemsCard, LineProductCell, LineProductThumb, LineProductTypeChip, LineRowActionsMenu, LineTable, LineTableEmpty, MEMO_IN_AUDIT_CONFIG, MEMO_OUT_AUDIT_CONFIG, MediaGallery, MemoInComboBox, MetricCard, MetricRow, MetricTile, Modal, MoreInfoPanel, MoreInfoTrigger, NOT_CAPTURED, Navbar, NavbarActions, NavbarAvatar, NavbarIconButton, NavbarSearch, NavbarTitle, NumberExpressionFilter, NumberInput, NumberRangeInputs, NumberedStepCard, OtpInput, OwnershipFilter, OwnershipSplitCard, PROFORMA_AUDIT_CONFIG, PageHeader, PageTabs, Pagination, PaginationSelect, PartnerShareCard, PickListFilter, PriceInput, Protected, PurchaseOrderComboBox, QUOTATION_AUDIT_CONFIG, RadioCardGroup, ReadMoreText, RefreshButton, RichTextarea$1 as RichTextarea, SEARCHABLE_SELECT_PAGE_SIZE, SafeImage, ScaleRangeFilter, ScrollFade, SearchBox, SearchInput, SearchableSelect, SectionCard, SectionIcon, SegmentedControl, ShareDialog, ShareMenu, ShimmerTable, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SlideOut, SlideOutClose, SlideOutContent, SlideOutDescription, SlideOutHeader, SlideOutOverlay, SlideOutPortal, SlideOutTitle, SlideOutTrigger, Slider, SpecList, Spinner, SquareSkeleton, StateSelect, StatusBadge$1 as StatusBadge, StatusFilter, Stepper, StockTypeFilter, TablePagination, TableRowsSkeleton, TableSkeleton, Tabs, TabsContent, TabsList, TabsTrigger, TagsInput, TextHyperlink, TimePicker, ToggleSwitch, TriStateFilter, TruncateTooltip, TruncatedLabel, WarehouseComboBox, WarehouseFilter, ZoomSplitViewer, asList, asText, badgeVariants, buildBulkShareMessage, buildBulkShareTitle, buildInventoryPublicUrl, buildInventoryRowProps, buildInventoryShareTitle, buildWhatsappUrl, buttonVariants, cn, countries, countryByCode, createVideoMediaItem, describeFilterValue, dropdownMenuItemDestructiveClass, expandScaleRange, fieldTypeIcon, findRegion, flagEmoji, formatAddressLocation, formatDateRange, formatFileSize, formatNumberRange, formatScaleRange, formatSelectedCount, generateActionDescription, generateTitle, getBadgeTypeForStatus, getChangePills, getCountryName, getInitials, getStatesOfCountry, iconButtonVariants, inAppNotificationCardA11y, inAppNotificationsPanelA11y, isBlank, isFilterValueActive, isIndiaCountry, isKnownRegion, isPathActive, isValidAlpha2CountryCode, isValueEmpty, notify, parseNumberExpression, releaseStaleOverlayBodyLock, renderBadge, resolveCountryCode, resolveDatePreset, resolveDateRange, splitIdList, toAddressFormValues, toBoolValue, toContainsValue, toDateValue, toIdsValue, toListValue, toNumberValue, toScaleValue, useAuditShowMore, useBadge, useButton, useDropdownMenu, useInAppNotificationsPanel, useNavbar, useSidebar, valueOfType, videoThumbnailSrc, watchOverlayBodyLock };
78015
79238
  //# sourceMappingURL=index.esm.js.map