@caratlogic/design-system 0.1.32 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/atoms/ActionButtonWithTooltip/ActionButtonWithTooltip.d.ts.map +1 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts +1 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.d.ts.map +1 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts +16 -0
- package/dist/components/molecules/DataEditableTable/DataEditableTable.hooks.d.ts.map +1 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts +8 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.parts.d.ts.map +1 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts +20 -0
- package/dist/components/molecules/DataEditableTable/DataEditableTable.types.d.ts.map +1 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts +7 -1
- package/dist/components/molecules/DataEditableTable/DataEditableTable.utils.d.ts.map +1 -1
- package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts +8 -3
- package/dist/components/molecules/FilterSelect/FilterMultiSelect.d.ts.map +1 -1
- package/dist/components/molecules/FilterSelect/FilterSelect.d.ts.map +1 -1
- package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts +10 -1
- package/dist/components/molecules/FilterSelect/FilterSelect.utils.d.ts.map +1 -1
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts +3 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts +6 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts +19 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts +7 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/ActiveFilterChips.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts +3 -0
- package/dist/components/molecules/Filters/ActiveFilterChips/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts +2 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts +6 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts +9 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts +11 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts +3 -0
- package/dist/components/molecules/Filters/ContainsFilter/ContainsFilter.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ContainsFilter/index.d.ts +3 -0
- package/dist/components/molecules/Filters/ContainsFilter/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts +3 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts +6 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.d.ts.map +1 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts +11 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts +10 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts +11 -0
- package/dist/components/molecules/Filters/DateRangeFilter/DateRangeFilter.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts +3 -0
- package/dist/components/molecules/Filters/DateRangeFilter/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.d.ts +6 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.types.d.ts +8 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.utils.d.ts +6 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/FilterCardSkeleton.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/index.d.ts +3 -0
- package/dist/components/molecules/Filters/FilterCardSkeleton/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts +3 -0
- package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts +6 -0
- package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts +24 -0
- package/dist/components/molecules/Filters/FilterCellPopover/FilterCellPopover.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts +3 -0
- package/dist/components/molecules/Filters/FilterCellPopover/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts +6 -0
- package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts +14 -0
- package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts +5 -0
- package/dist/components/molecules/Filters/FilterEmptyState/FilterEmptyState.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts +3 -0
- package/dist/components/molecules/Filters/FilterEmptyState/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts +6 -0
- package/dist/components/molecules/Filters/FilterPanel/FilterPanel.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts +28 -0
- package/dist/components/molecules/Filters/FilterPanel/FilterPanel.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts +4 -0
- package/dist/components/molecules/Filters/FilterPanel/FilterPanel.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/FilterPanel/index.d.ts +3 -0
- package/dist/components/molecules/Filters/FilterPanel/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/Filters.hooks.d.ts +20 -0
- package/dist/components/molecules/Filters/Filters.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/Filters.types.d.ts +75 -0
- package/dist/components/molecules/Filters/Filters.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/Filters.utils.d.ts +66 -0
- package/dist/components/molecules/Filters/Filters.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts +2 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts +6 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.d.ts.map +1 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts +10 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts +10 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts +4 -0
- package/dist/components/molecules/Filters/IdListInput/IdListInput.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/IdListInput/index.d.ts +3 -0
- package/dist/components/molecules/Filters/IdListInput/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts +5 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts +6 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts +18 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts +16 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts +19 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/NumberExpressionFilter.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts +3 -0
- package/dist/components/molecules/Filters/NumberExpressionFilter/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts +3 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts +6 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts +15 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts +17 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts +13 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/NumberRangeInputs.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts +3 -0
- package/dist/components/molecules/Filters/NumberRangeInputs/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts +2 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts +6 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.d.ts.map +1 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts +3 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts +34 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts +24 -0
- package/dist/components/molecules/Filters/PickListFilter/PickListFilter.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/PickListFilter/index.d.ts +3 -0
- package/dist/components/molecules/Filters/PickListFilter/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts +6 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts +4 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts +22 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts +7 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/ScaleRangeFilter.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts +3 -0
- package/dist/components/molecules/Filters/ScaleRangeFilter/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts +6 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts +7 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.hooks.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts +15 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts +4 -0
- package/dist/components/molecules/Filters/ScrollFade/ScrollFade.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/ScrollFade/index.d.ts +3 -0
- package/dist/components/molecules/Filters/ScrollFade/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts +6 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts +6 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts +7 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts +3 -0
- package/dist/components/molecules/Filters/TriStateFilter/TriStateFilter.utils.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TriStateFilter/index.d.ts +3 -0
- package/dist/components/molecules/Filters/TriStateFilter/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts +6 -0
- package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts +5 -0
- package/dist/components/molecules/Filters/TruncatedLabel/TruncatedLabel.types.d.ts.map +1 -0
- package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts +3 -0
- package/dist/components/molecules/Filters/TruncatedLabel/index.d.ts.map +1 -0
- package/dist/components/molecules/Filters/index.d.ts +18 -0
- package/dist/components/molecules/Filters/index.d.ts.map +1 -0
- package/dist/components/molecules/InventoryFilterSelects.d.ts.map +1 -1
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.accessibility.d.ts +11 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.d.ts +6 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.hooks.d.ts +9 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.hooks.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.parts.d.ts +5 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.parts.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.types.d.ts +66 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.types.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.utils.d.ts +14 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/SaveSearchDialog.utils.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/index.d.ts +5 -0
- package/dist/components/molecules/SavedSearches/SaveSearchDialog/index.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.d.ts +6 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.hooks.d.ts +7 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.hooks.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.types.d.ts +19 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.types.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.utils.d.ts +5 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/SavedSearchChipList.utils.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/index.d.ts +3 -0
- package/dist/components/molecules/SavedSearches/SavedSearchChipList/index.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.accessibility.d.ts +6 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.d.ts +6 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.hooks.d.ts +3 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.hooks.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.parts.d.ts +7 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.parts.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.types.d.ts +56 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.types.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.utils.d.ts +18 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/SavedSearchesMenu.utils.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/index.d.ts +4 -0
- package/dist/components/molecules/SavedSearches/SavedSearchesMenu/index.d.ts.map +1 -0
- package/dist/components/molecules/SavedSearches/index.d.ts +4 -0
- package/dist/components/molecules/SavedSearches/index.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterField/FilterField.d.ts +11 -0
- package/dist/components/organisms/Filters/FilterField/FilterField.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts +68 -0
- package/dist/components/organisms/Filters/FilterField/FilterField.types.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts +38 -0
- package/dist/components/organisms/Filters/FilterField/FilterField.utils.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterField/index.d.ts +4 -0
- package/dist/components/organisms/Filters/FilterField/index.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts +8 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.accessibility.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts +9 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts +6 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.hooks.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.parts.d.ts +7 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.parts.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts +42 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.types.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.utils.d.ts +4 -0
- package/dist/components/organisms/Filters/FilterSurface/FilterSurface.utils.d.ts.map +1 -0
- package/dist/components/organisms/Filters/FilterSurface/index.d.ts +3 -0
- package/dist/components/organisms/Filters/FilterSurface/index.d.ts.map +1 -0
- package/dist/components/organisms/Filters/index.d.ts +3 -0
- package/dist/components/organisms/Filters/index.d.ts.map +1 -0
- package/dist/hooks/useTruncatedText.d.ts.map +1 -1
- package/dist/index.cjs.js +1979 -320
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1930 -322
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -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,
|
|
5
|
+
import React__default, { forwardRef, createElement, useState, useCallback, useMemo, useEffect, useRef, Fragment as Fragment$3, createContext, useContext, useId as useId$2, isValidElement, Children, useLayoutEffect, cloneElement, createRef, Component, 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$
|
|
2671
|
+
const __iconNode$1x = [
|
|
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$
|
|
2676
|
+
const AlignLeft = createLucideIcon("align-left", __iconNode$1x);
|
|
2677
2677
|
|
|
2678
2678
|
/**
|
|
2679
2679
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2683,12 +2683,12 @@ const AlignLeft = createLucideIcon("align-left", __iconNode$1t);
|
|
|
2683
2683
|
*/
|
|
2684
2684
|
|
|
2685
2685
|
|
|
2686
|
-
const __iconNode$
|
|
2686
|
+
const __iconNode$1w = [
|
|
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$
|
|
2691
|
+
const Archive = createLucideIcon("archive", __iconNode$1w);
|
|
2692
2692
|
|
|
2693
2693
|
/**
|
|
2694
2694
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2698,11 +2698,11 @@ const Archive = createLucideIcon("archive", __iconNode$1s);
|
|
|
2698
2698
|
*/
|
|
2699
2699
|
|
|
2700
2700
|
|
|
2701
|
-
const __iconNode$
|
|
2701
|
+
const __iconNode$1v = [
|
|
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$
|
|
2705
|
+
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1v);
|
|
2706
2706
|
|
|
2707
2707
|
/**
|
|
2708
2708
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2712,11 +2712,11 @@ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$1r);
|
|
|
2712
2712
|
*/
|
|
2713
2713
|
|
|
2714
2714
|
|
|
2715
|
-
const __iconNode$
|
|
2715
|
+
const __iconNode$1u = [
|
|
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$
|
|
2719
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$1u);
|
|
2720
2720
|
|
|
2721
2721
|
/**
|
|
2722
2722
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2726,11 +2726,11 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$1q);
|
|
|
2726
2726
|
*/
|
|
2727
2727
|
|
|
2728
2728
|
|
|
2729
|
-
const __iconNode$
|
|
2729
|
+
const __iconNode$1t = [
|
|
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$
|
|
2733
|
+
const Ban = createLucideIcon("ban", __iconNode$1t);
|
|
2734
2734
|
|
|
2735
2735
|
/**
|
|
2736
2736
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2740,7 +2740,7 @@ const Ban = createLucideIcon("ban", __iconNode$1p);
|
|
|
2740
2740
|
*/
|
|
2741
2741
|
|
|
2742
2742
|
|
|
2743
|
-
const __iconNode$
|
|
2743
|
+
const __iconNode$1s = [
|
|
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$1o = [
|
|
|
2751
2751
|
],
|
|
2752
2752
|
["circle", { cx: "18", cy: "8", r: "3", key: "1g0gzu" }]
|
|
2753
2753
|
];
|
|
2754
|
-
const BellDot = createLucideIcon("bell-dot", __iconNode$
|
|
2754
|
+
const BellDot = createLucideIcon("bell-dot", __iconNode$1s);
|
|
2755
2755
|
|
|
2756
2756
|
/**
|
|
2757
2757
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2761,7 +2761,7 @@ const BellDot = createLucideIcon("bell-dot", __iconNode$1o);
|
|
|
2761
2761
|
*/
|
|
2762
2762
|
|
|
2763
2763
|
|
|
2764
|
-
const __iconNode$
|
|
2764
|
+
const __iconNode$1r = [
|
|
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$1n = [
|
|
|
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$
|
|
2776
|
+
const BellRing = createLucideIcon("bell-ring", __iconNode$1r);
|
|
2777
2777
|
|
|
2778
2778
|
/**
|
|
2779
2779
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2783,7 +2783,7 @@ const BellRing = createLucideIcon("bell-ring", __iconNode$1n);
|
|
|
2783
2783
|
*/
|
|
2784
2784
|
|
|
2785
2785
|
|
|
2786
|
-
const __iconNode$
|
|
2786
|
+
const __iconNode$1q = [
|
|
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$1m = [
|
|
|
2793
2793
|
}
|
|
2794
2794
|
]
|
|
2795
2795
|
];
|
|
2796
|
-
const Bell = createLucideIcon("bell", __iconNode$
|
|
2796
|
+
const Bell = createLucideIcon("bell", __iconNode$1q);
|
|
2797
2797
|
|
|
2798
2798
|
/**
|
|
2799
2799
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2803,13 +2803,13 @@ const Bell = createLucideIcon("bell", __iconNode$1m);
|
|
|
2803
2803
|
*/
|
|
2804
2804
|
|
|
2805
2805
|
|
|
2806
|
-
const __iconNode$
|
|
2806
|
+
const __iconNode$1p = [
|
|
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$
|
|
2812
|
+
const Bold$1 = createLucideIcon("bold", __iconNode$1p);
|
|
2813
2813
|
|
|
2814
2814
|
/**
|
|
2815
2815
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2819,7 +2819,20 @@ const Bold$1 = createLucideIcon("bold", __iconNode$1l);
|
|
|
2819
2819
|
*/
|
|
2820
2820
|
|
|
2821
2821
|
|
|
2822
|
-
const __iconNode$
|
|
2822
|
+
const __iconNode$1o = [
|
|
2823
|
+
["path", { d: "m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z", key: "1fy3hk" }]
|
|
2824
|
+
];
|
|
2825
|
+
const Bookmark = createLucideIcon("bookmark", __iconNode$1o);
|
|
2826
|
+
|
|
2827
|
+
/**
|
|
2828
|
+
* @license lucide-react v0.539.0 - ISC
|
|
2829
|
+
*
|
|
2830
|
+
* This source code is licensed under the ISC license.
|
|
2831
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
2832
|
+
*/
|
|
2833
|
+
|
|
2834
|
+
|
|
2835
|
+
const __iconNode$1n = [
|
|
2823
2836
|
[
|
|
2824
2837
|
"path",
|
|
2825
2838
|
{
|
|
@@ -2830,7 +2843,7 @@ const __iconNode$1k = [
|
|
|
2830
2843
|
["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
|
|
2831
2844
|
["path", { d: "M12 22V12", key: "d0xqtd" }]
|
|
2832
2845
|
];
|
|
2833
|
-
const Box = createLucideIcon("box", __iconNode$
|
|
2846
|
+
const Box = createLucideIcon("box", __iconNode$1n);
|
|
2834
2847
|
|
|
2835
2848
|
/**
|
|
2836
2849
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2840,7 +2853,7 @@ const Box = createLucideIcon("box", __iconNode$1k);
|
|
|
2840
2853
|
*/
|
|
2841
2854
|
|
|
2842
2855
|
|
|
2843
|
-
const __iconNode$
|
|
2856
|
+
const __iconNode$1m = [
|
|
2844
2857
|
["path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z", key: "1b4qmf" }],
|
|
2845
2858
|
["path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2", key: "i71pzd" }],
|
|
2846
2859
|
["path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2", key: "10jefs" }],
|
|
@@ -2849,7 +2862,7 @@ const __iconNode$1j = [
|
|
|
2849
2862
|
["path", { d: "M10 14h4", key: "kelpxr" }],
|
|
2850
2863
|
["path", { d: "M10 18h4", key: "1ulq68" }]
|
|
2851
2864
|
];
|
|
2852
|
-
const Building2 = createLucideIcon("building-2", __iconNode$
|
|
2865
|
+
const Building2 = createLucideIcon("building-2", __iconNode$1m);
|
|
2853
2866
|
|
|
2854
2867
|
/**
|
|
2855
2868
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2859,7 +2872,7 @@ const Building2 = createLucideIcon("building-2", __iconNode$1j);
|
|
|
2859
2872
|
*/
|
|
2860
2873
|
|
|
2861
2874
|
|
|
2862
|
-
const __iconNode$
|
|
2875
|
+
const __iconNode$1l = [
|
|
2863
2876
|
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
2864
2877
|
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
2865
2878
|
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
@@ -2871,7 +2884,7 @@ const __iconNode$1i = [
|
|
|
2871
2884
|
["path", { d: "M12 18h.01", key: "mhygvu" }],
|
|
2872
2885
|
["path", { d: "M16 18h.01", key: "kzsmim" }]
|
|
2873
2886
|
];
|
|
2874
|
-
const CalendarDays = createLucideIcon("calendar-days", __iconNode$
|
|
2887
|
+
const CalendarDays = createLucideIcon("calendar-days", __iconNode$1l);
|
|
2875
2888
|
|
|
2876
2889
|
/**
|
|
2877
2890
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2881,13 +2894,13 @@ const CalendarDays = createLucideIcon("calendar-days", __iconNode$1i);
|
|
|
2881
2894
|
*/
|
|
2882
2895
|
|
|
2883
2896
|
|
|
2884
|
-
const __iconNode$
|
|
2897
|
+
const __iconNode$1k = [
|
|
2885
2898
|
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
2886
2899
|
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
2887
2900
|
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
2888
2901
|
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
2889
2902
|
];
|
|
2890
|
-
const Calendar$1 = createLucideIcon("calendar", __iconNode$
|
|
2903
|
+
const Calendar$1 = createLucideIcon("calendar", __iconNode$1k);
|
|
2891
2904
|
|
|
2892
2905
|
/**
|
|
2893
2906
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2897,11 +2910,11 @@ const Calendar$1 = createLucideIcon("calendar", __iconNode$1h);
|
|
|
2897
2910
|
*/
|
|
2898
2911
|
|
|
2899
2912
|
|
|
2900
|
-
const __iconNode$
|
|
2913
|
+
const __iconNode$1j = [
|
|
2901
2914
|
["path", { d: "M18 6 7 17l-5-5", key: "116fxf" }],
|
|
2902
2915
|
["path", { d: "m22 10-7.5 7.5L13 16", key: "ke71qq" }]
|
|
2903
2916
|
];
|
|
2904
|
-
const CheckCheck = createLucideIcon("check-check", __iconNode$
|
|
2917
|
+
const CheckCheck = createLucideIcon("check-check", __iconNode$1j);
|
|
2905
2918
|
|
|
2906
2919
|
/**
|
|
2907
2920
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2911,8 +2924,8 @@ const CheckCheck = createLucideIcon("check-check", __iconNode$1g);
|
|
|
2911
2924
|
*/
|
|
2912
2925
|
|
|
2913
2926
|
|
|
2914
|
-
const __iconNode$
|
|
2915
|
-
const Check = createLucideIcon("check", __iconNode$
|
|
2927
|
+
const __iconNode$1i = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
2928
|
+
const Check = createLucideIcon("check", __iconNode$1i);
|
|
2916
2929
|
|
|
2917
2930
|
/**
|
|
2918
2931
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2922,8 +2935,8 @@ const Check = createLucideIcon("check", __iconNode$1f);
|
|
|
2922
2935
|
*/
|
|
2923
2936
|
|
|
2924
2937
|
|
|
2925
|
-
const __iconNode$
|
|
2926
|
-
const ChevronDown = createLucideIcon("chevron-down", __iconNode$
|
|
2938
|
+
const __iconNode$1h = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
2939
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$1h);
|
|
2927
2940
|
|
|
2928
2941
|
/**
|
|
2929
2942
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2933,8 +2946,8 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$1e);
|
|
|
2933
2946
|
*/
|
|
2934
2947
|
|
|
2935
2948
|
|
|
2936
|
-
const __iconNode$
|
|
2937
|
-
const ChevronLeft = createLucideIcon("chevron-left", __iconNode$
|
|
2949
|
+
const __iconNode$1g = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
|
|
2950
|
+
const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1g);
|
|
2938
2951
|
|
|
2939
2952
|
/**
|
|
2940
2953
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2944,8 +2957,8 @@ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$1d);
|
|
|
2944
2957
|
*/
|
|
2945
2958
|
|
|
2946
2959
|
|
|
2947
|
-
const __iconNode$
|
|
2948
|
-
const ChevronRight = createLucideIcon("chevron-right", __iconNode$
|
|
2960
|
+
const __iconNode$1f = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
|
|
2961
|
+
const ChevronRight = createLucideIcon("chevron-right", __iconNode$1f);
|
|
2949
2962
|
|
|
2950
2963
|
/**
|
|
2951
2964
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2955,8 +2968,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$1c);
|
|
|
2955
2968
|
*/
|
|
2956
2969
|
|
|
2957
2970
|
|
|
2958
|
-
const __iconNode$
|
|
2959
|
-
const ChevronUp = createLucideIcon("chevron-up", __iconNode$
|
|
2971
|
+
const __iconNode$1e = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
|
|
2972
|
+
const ChevronUp = createLucideIcon("chevron-up", __iconNode$1e);
|
|
2960
2973
|
|
|
2961
2974
|
/**
|
|
2962
2975
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2966,11 +2979,11 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$1b);
|
|
|
2966
2979
|
*/
|
|
2967
2980
|
|
|
2968
2981
|
|
|
2969
|
-
const __iconNode$
|
|
2982
|
+
const __iconNode$1d = [
|
|
2970
2983
|
["path", { d: "m11 17-5-5 5-5", key: "13zhaf" }],
|
|
2971
2984
|
["path", { d: "m18 17-5-5 5-5", key: "h8a8et" }]
|
|
2972
2985
|
];
|
|
2973
|
-
const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$
|
|
2986
|
+
const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1d);
|
|
2974
2987
|
|
|
2975
2988
|
/**
|
|
2976
2989
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2980,11 +2993,11 @@ const ChevronsLeft = createLucideIcon("chevrons-left", __iconNode$1a);
|
|
|
2980
2993
|
*/
|
|
2981
2994
|
|
|
2982
2995
|
|
|
2983
|
-
const __iconNode$
|
|
2996
|
+
const __iconNode$1c = [
|
|
2984
2997
|
["path", { d: "m6 17 5-5-5-5", key: "xnjwq" }],
|
|
2985
2998
|
["path", { d: "m13 17 5-5-5-5", key: "17xmmf" }]
|
|
2986
2999
|
];
|
|
2987
|
-
const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$
|
|
3000
|
+
const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$1c);
|
|
2988
3001
|
|
|
2989
3002
|
/**
|
|
2990
3003
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2994,12 +3007,12 @@ const ChevronsRight = createLucideIcon("chevrons-right", __iconNode$19);
|
|
|
2994
3007
|
*/
|
|
2995
3008
|
|
|
2996
3009
|
|
|
2997
|
-
const __iconNode$
|
|
3010
|
+
const __iconNode$1b = [
|
|
2998
3011
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
2999
3012
|
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
3000
3013
|
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
3001
3014
|
];
|
|
3002
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode$
|
|
3015
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$1b);
|
|
3003
3016
|
|
|
3004
3017
|
/**
|
|
3005
3018
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3009,11 +3022,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$18);
|
|
|
3009
3022
|
*/
|
|
3010
3023
|
|
|
3011
3024
|
|
|
3012
|
-
const __iconNode$
|
|
3025
|
+
const __iconNode$1a = [
|
|
3013
3026
|
["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
|
|
3014
3027
|
["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
|
|
3015
3028
|
];
|
|
3016
|
-
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$
|
|
3029
|
+
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$1a);
|
|
3017
3030
|
|
|
3018
3031
|
/**
|
|
3019
3032
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3023,11 +3036,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$17);
|
|
|
3023
3036
|
*/
|
|
3024
3037
|
|
|
3025
3038
|
|
|
3026
|
-
const __iconNode$
|
|
3039
|
+
const __iconNode$19 = [
|
|
3027
3040
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
3028
3041
|
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
3029
3042
|
];
|
|
3030
|
-
const CircleCheck = createLucideIcon("circle-check", __iconNode$
|
|
3043
|
+
const CircleCheck = createLucideIcon("circle-check", __iconNode$19);
|
|
3031
3044
|
|
|
3032
3045
|
/**
|
|
3033
3046
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3037,11 +3050,11 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$16);
|
|
|
3037
3050
|
*/
|
|
3038
3051
|
|
|
3039
3052
|
|
|
3040
|
-
const __iconNode$
|
|
3053
|
+
const __iconNode$18 = [
|
|
3041
3054
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
3042
3055
|
["path", { d: "m16 10-4 4-4-4", key: "894hmk" }]
|
|
3043
3056
|
];
|
|
3044
|
-
const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$
|
|
3057
|
+
const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$18);
|
|
3045
3058
|
|
|
3046
3059
|
/**
|
|
3047
3060
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3051,11 +3064,11 @@ const CircleChevronDown = createLucideIcon("circle-chevron-down", __iconNode$15)
|
|
|
3051
3064
|
*/
|
|
3052
3065
|
|
|
3053
3066
|
|
|
3054
|
-
const __iconNode$
|
|
3067
|
+
const __iconNode$17 = [
|
|
3055
3068
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
3056
3069
|
["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }]
|
|
3057
3070
|
];
|
|
3058
|
-
const CircleDot = createLucideIcon("circle-dot", __iconNode$
|
|
3071
|
+
const CircleDot = createLucideIcon("circle-dot", __iconNode$17);
|
|
3059
3072
|
|
|
3060
3073
|
/**
|
|
3061
3074
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3065,12 +3078,12 @@ const CircleDot = createLucideIcon("circle-dot", __iconNode$14);
|
|
|
3065
3078
|
*/
|
|
3066
3079
|
|
|
3067
3080
|
|
|
3068
|
-
const __iconNode$
|
|
3081
|
+
const __iconNode$16 = [
|
|
3069
3082
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
3070
3083
|
["path", { d: "m15 9-6 6", key: "1uzhvr" }],
|
|
3071
3084
|
["path", { d: "m9 9 6 6", key: "z0biqf" }]
|
|
3072
3085
|
];
|
|
3073
|
-
const CircleX = createLucideIcon("circle-x", __iconNode$
|
|
3086
|
+
const CircleX = createLucideIcon("circle-x", __iconNode$16);
|
|
3074
3087
|
|
|
3075
3088
|
/**
|
|
3076
3089
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3080,8 +3093,8 @@ const CircleX = createLucideIcon("circle-x", __iconNode$13);
|
|
|
3080
3093
|
*/
|
|
3081
3094
|
|
|
3082
3095
|
|
|
3083
|
-
const __iconNode$
|
|
3084
|
-
const Circle = createLucideIcon("circle", __iconNode$
|
|
3096
|
+
const __iconNode$15 = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
|
|
3097
|
+
const Circle = createLucideIcon("circle", __iconNode$15);
|
|
3085
3098
|
|
|
3086
3099
|
/**
|
|
3087
3100
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3091,11 +3104,11 @@ const Circle = createLucideIcon("circle", __iconNode$12);
|
|
|
3091
3104
|
*/
|
|
3092
3105
|
|
|
3093
3106
|
|
|
3094
|
-
const __iconNode$
|
|
3107
|
+
const __iconNode$14 = [
|
|
3095
3108
|
["path", { d: "M12 6v6l4 2", key: "mmk7yg" }],
|
|
3096
3109
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
|
|
3097
3110
|
];
|
|
3098
|
-
const Clock = createLucideIcon("clock", __iconNode$
|
|
3111
|
+
const Clock = createLucideIcon("clock", __iconNode$14);
|
|
3099
3112
|
|
|
3100
3113
|
/**
|
|
3101
3114
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3105,11 +3118,11 @@ const Clock = createLucideIcon("clock", __iconNode$11);
|
|
|
3105
3118
|
*/
|
|
3106
3119
|
|
|
3107
3120
|
|
|
3108
|
-
const __iconNode$
|
|
3121
|
+
const __iconNode$13 = [
|
|
3109
3122
|
["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
|
|
3110
3123
|
["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
3124
|
];
|
|
3112
|
-
const Copy = createLucideIcon("copy", __iconNode$
|
|
3125
|
+
const Copy = createLucideIcon("copy", __iconNode$13);
|
|
3113
3126
|
|
|
3114
3127
|
/**
|
|
3115
3128
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3119,11 +3132,11 @@ const Copy = createLucideIcon("copy", __iconNode$10);
|
|
|
3119
3132
|
*/
|
|
3120
3133
|
|
|
3121
3134
|
|
|
3122
|
-
const __iconNode
|
|
3135
|
+
const __iconNode$12 = [
|
|
3123
3136
|
["path", { d: "M6 2v14a2 2 0 0 0 2 2h14", key: "ron5a4" }],
|
|
3124
3137
|
["path", { d: "M18 22V8a2 2 0 0 0-2-2H2", key: "7s9ehn" }]
|
|
3125
3138
|
];
|
|
3126
|
-
const Crop = createLucideIcon("crop", __iconNode
|
|
3139
|
+
const Crop = createLucideIcon("crop", __iconNode$12);
|
|
3127
3140
|
|
|
3128
3141
|
/**
|
|
3129
3142
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3133,12 +3146,12 @@ const Crop = createLucideIcon("crop", __iconNode$$);
|
|
|
3133
3146
|
*/
|
|
3134
3147
|
|
|
3135
3148
|
|
|
3136
|
-
const __iconNode$
|
|
3149
|
+
const __iconNode$11 = [
|
|
3137
3150
|
["path", { d: "M12 15V3", key: "m9g1x1" }],
|
|
3138
3151
|
["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
|
|
3139
3152
|
["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
|
|
3140
3153
|
];
|
|
3141
|
-
const Download = createLucideIcon("download", __iconNode$
|
|
3154
|
+
const Download = createLucideIcon("download", __iconNode$11);
|
|
3142
3155
|
|
|
3143
3156
|
/**
|
|
3144
3157
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3148,12 +3161,12 @@ const Download = createLucideIcon("download", __iconNode$_);
|
|
|
3148
3161
|
*/
|
|
3149
3162
|
|
|
3150
3163
|
|
|
3151
|
-
const __iconNode$
|
|
3164
|
+
const __iconNode$10 = [
|
|
3152
3165
|
["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
|
|
3153
3166
|
["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
|
|
3154
3167
|
["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
|
|
3155
3168
|
];
|
|
3156
|
-
const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$
|
|
3169
|
+
const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$10);
|
|
3157
3170
|
|
|
3158
3171
|
/**
|
|
3159
3172
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3163,12 +3176,12 @@ const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$Z);
|
|
|
3163
3176
|
*/
|
|
3164
3177
|
|
|
3165
3178
|
|
|
3166
|
-
const __iconNode
|
|
3179
|
+
const __iconNode$$ = [
|
|
3167
3180
|
["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
|
|
3168
3181
|
["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
|
|
3169
3182
|
["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
|
|
3170
3183
|
];
|
|
3171
|
-
const Ellipsis = createLucideIcon("ellipsis", __iconNode
|
|
3184
|
+
const Ellipsis = createLucideIcon("ellipsis", __iconNode$$);
|
|
3172
3185
|
|
|
3173
3186
|
/**
|
|
3174
3187
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3178,12 +3191,12 @@ const Ellipsis = createLucideIcon("ellipsis", __iconNode$Y);
|
|
|
3178
3191
|
*/
|
|
3179
3192
|
|
|
3180
3193
|
|
|
3181
|
-
const __iconNode$
|
|
3194
|
+
const __iconNode$_ = [
|
|
3182
3195
|
["path", { d: "M15 3h6v6", key: "1q9fwt" }],
|
|
3183
3196
|
["path", { d: "M10 14 21 3", key: "gplh6r" }],
|
|
3184
3197
|
["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
3198
|
];
|
|
3186
|
-
const ExternalLink = createLucideIcon("external-link", __iconNode$
|
|
3199
|
+
const ExternalLink = createLucideIcon("external-link", __iconNode$_);
|
|
3187
3200
|
|
|
3188
3201
|
/**
|
|
3189
3202
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3193,7 +3206,7 @@ const ExternalLink = createLucideIcon("external-link", __iconNode$X);
|
|
|
3193
3206
|
*/
|
|
3194
3207
|
|
|
3195
3208
|
|
|
3196
|
-
const __iconNode$
|
|
3209
|
+
const __iconNode$Z = [
|
|
3197
3210
|
[
|
|
3198
3211
|
"path",
|
|
3199
3212
|
{
|
|
@@ -3203,7 +3216,7 @@ const __iconNode$W = [
|
|
|
3203
3216
|
],
|
|
3204
3217
|
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
3205
3218
|
];
|
|
3206
|
-
const Eye = createLucideIcon("eye", __iconNode$
|
|
3219
|
+
const Eye = createLucideIcon("eye", __iconNode$Z);
|
|
3207
3220
|
|
|
3208
3221
|
/**
|
|
3209
3222
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3213,13 +3226,13 @@ const Eye = createLucideIcon("eye", __iconNode$W);
|
|
|
3213
3226
|
*/
|
|
3214
3227
|
|
|
3215
3228
|
|
|
3216
|
-
const __iconNode$
|
|
3229
|
+
const __iconNode$Y = [
|
|
3217
3230
|
[
|
|
3218
3231
|
"path",
|
|
3219
3232
|
{ d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z", key: "1jg4f8" }
|
|
3220
3233
|
]
|
|
3221
3234
|
];
|
|
3222
|
-
const Facebook = createLucideIcon("facebook", __iconNode$
|
|
3235
|
+
const Facebook = createLucideIcon("facebook", __iconNode$Y);
|
|
3223
3236
|
|
|
3224
3237
|
/**
|
|
3225
3238
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3229,7 +3242,7 @@ const Facebook = createLucideIcon("facebook", __iconNode$V);
|
|
|
3229
3242
|
*/
|
|
3230
3243
|
|
|
3231
3244
|
|
|
3232
|
-
const __iconNode$
|
|
3245
|
+
const __iconNode$X = [
|
|
3233
3246
|
["path", { d: "M12 22h6a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3.072", key: "n6s66f" }],
|
|
3234
3247
|
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
|
|
3235
3248
|
[
|
|
@@ -3241,7 +3254,7 @@ const __iconNode$U = [
|
|
|
3241
3254
|
],
|
|
3242
3255
|
["circle", { cx: "5", cy: "14", r: "3", key: "ufru5t" }]
|
|
3243
3256
|
];
|
|
3244
|
-
const FileBadge = createLucideIcon("file-badge", __iconNode$
|
|
3257
|
+
const FileBadge = createLucideIcon("file-badge", __iconNode$X);
|
|
3245
3258
|
|
|
3246
3259
|
/**
|
|
3247
3260
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3251,12 +3264,12 @@ const FileBadge = createLucideIcon("file-badge", __iconNode$U);
|
|
|
3251
3264
|
*/
|
|
3252
3265
|
|
|
3253
3266
|
|
|
3254
|
-
const __iconNode$
|
|
3267
|
+
const __iconNode$W = [
|
|
3255
3268
|
["path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4", key: "1pf5j1" }],
|
|
3256
3269
|
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
|
|
3257
3270
|
["path", { d: "m3 15 2 2 4-4", key: "1lhrkk" }]
|
|
3258
3271
|
];
|
|
3259
|
-
const FileCheck2 = createLucideIcon("file-check-2", __iconNode$
|
|
3272
|
+
const FileCheck2 = createLucideIcon("file-check-2", __iconNode$W);
|
|
3260
3273
|
|
|
3261
3274
|
/**
|
|
3262
3275
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3266,14 +3279,14 @@ const FileCheck2 = createLucideIcon("file-check-2", __iconNode$T);
|
|
|
3266
3279
|
*/
|
|
3267
3280
|
|
|
3268
3281
|
|
|
3269
|
-
const __iconNode$
|
|
3282
|
+
const __iconNode$V = [
|
|
3270
3283
|
["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
3284
|
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
|
|
3272
3285
|
["path", { d: "M10 9H8", key: "b1mrlr" }],
|
|
3273
3286
|
["path", { d: "M16 13H8", key: "t4e002" }],
|
|
3274
3287
|
["path", { d: "M16 17H8", key: "z1uh3a" }]
|
|
3275
3288
|
];
|
|
3276
|
-
const FileText = createLucideIcon("file-text", __iconNode$
|
|
3289
|
+
const FileText = createLucideIcon("file-text", __iconNode$V);
|
|
3277
3290
|
|
|
3278
3291
|
/**
|
|
3279
3292
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3283,7 +3296,28 @@ const FileText = createLucideIcon("file-text", __iconNode$S);
|
|
|
3283
3296
|
*/
|
|
3284
3297
|
|
|
3285
3298
|
|
|
3286
|
-
const __iconNode$
|
|
3299
|
+
const __iconNode$U = [
|
|
3300
|
+
[
|
|
3301
|
+
"path",
|
|
3302
|
+
{
|
|
3303
|
+
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",
|
|
3304
|
+
key: "ol2ft2"
|
|
3305
|
+
}
|
|
3306
|
+
],
|
|
3307
|
+
["path", { d: "m16.5 3.5 5 5", key: "15e6fa" }],
|
|
3308
|
+
["path", { d: "m21.5 3.5-5 5", key: "m0lwru" }]
|
|
3309
|
+
];
|
|
3310
|
+
const FunnelX = createLucideIcon("funnel-x", __iconNode$U);
|
|
3311
|
+
|
|
3312
|
+
/**
|
|
3313
|
+
* @license lucide-react v0.539.0 - ISC
|
|
3314
|
+
*
|
|
3315
|
+
* This source code is licensed under the ISC license.
|
|
3316
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
3317
|
+
*/
|
|
3318
|
+
|
|
3319
|
+
|
|
3320
|
+
const __iconNode$T = [
|
|
3287
3321
|
[
|
|
3288
3322
|
"path",
|
|
3289
3323
|
{
|
|
@@ -3292,7 +3326,7 @@ const __iconNode$R = [
|
|
|
3292
3326
|
}
|
|
3293
3327
|
]
|
|
3294
3328
|
];
|
|
3295
|
-
const Funnel = createLucideIcon("funnel", __iconNode$
|
|
3329
|
+
const Funnel = createLucideIcon("funnel", __iconNode$T);
|
|
3296
3330
|
|
|
3297
3331
|
/**
|
|
3298
3332
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3302,7 +3336,7 @@ const Funnel = createLucideIcon("funnel", __iconNode$R);
|
|
|
3302
3336
|
*/
|
|
3303
3337
|
|
|
3304
3338
|
|
|
3305
|
-
const __iconNode$
|
|
3339
|
+
const __iconNode$S = [
|
|
3306
3340
|
["path", { d: "M10.5 3 8 9l4 13 4-13-2.5-6", key: "b3dvk1" }],
|
|
3307
3341
|
[
|
|
3308
3342
|
"path",
|
|
@@ -3313,7 +3347,7 @@ const __iconNode$Q = [
|
|
|
3313
3347
|
],
|
|
3314
3348
|
["path", { d: "M2 9h20", key: "16fsjt" }]
|
|
3315
3349
|
];
|
|
3316
|
-
const Gem = createLucideIcon("gem", __iconNode$
|
|
3350
|
+
const Gem = createLucideIcon("gem", __iconNode$S);
|
|
3317
3351
|
|
|
3318
3352
|
/**
|
|
3319
3353
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3323,7 +3357,7 @@ const Gem = createLucideIcon("gem", __iconNode$Q);
|
|
|
3323
3357
|
*/
|
|
3324
3358
|
|
|
3325
3359
|
|
|
3326
|
-
const __iconNode$
|
|
3360
|
+
const __iconNode$R = [
|
|
3327
3361
|
["circle", { cx: "12", cy: "9", r: "1", key: "124mty" }],
|
|
3328
3362
|
["circle", { cx: "19", cy: "9", r: "1", key: "1ruzo2" }],
|
|
3329
3363
|
["circle", { cx: "5", cy: "9", r: "1", key: "1a8b28" }],
|
|
@@ -3331,7 +3365,7 @@ const __iconNode$P = [
|
|
|
3331
3365
|
["circle", { cx: "19", cy: "15", r: "1", key: "1a92ep" }],
|
|
3332
3366
|
["circle", { cx: "5", cy: "15", r: "1", key: "5r1jwy" }]
|
|
3333
3367
|
];
|
|
3334
|
-
const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$
|
|
3368
|
+
const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$R);
|
|
3335
3369
|
|
|
3336
3370
|
/**
|
|
3337
3371
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3341,7 +3375,7 @@ const GripHorizontal = createLucideIcon("grip-horizontal", __iconNode$P);
|
|
|
3341
3375
|
*/
|
|
3342
3376
|
|
|
3343
3377
|
|
|
3344
|
-
const __iconNode$
|
|
3378
|
+
const __iconNode$Q = [
|
|
3345
3379
|
["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
|
|
3346
3380
|
["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
|
|
3347
3381
|
["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
|
|
@@ -3349,7 +3383,7 @@ const __iconNode$O = [
|
|
|
3349
3383
|
["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
|
|
3350
3384
|
["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
|
|
3351
3385
|
];
|
|
3352
|
-
const GripVertical = createLucideIcon("grip-vertical", __iconNode$
|
|
3386
|
+
const GripVertical = createLucideIcon("grip-vertical", __iconNode$Q);
|
|
3353
3387
|
|
|
3354
3388
|
/**
|
|
3355
3389
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3359,13 +3393,13 @@ const GripVertical = createLucideIcon("grip-vertical", __iconNode$O);
|
|
|
3359
3393
|
*/
|
|
3360
3394
|
|
|
3361
3395
|
|
|
3362
|
-
const __iconNode$
|
|
3396
|
+
const __iconNode$P = [
|
|
3363
3397
|
["line", { x1: "4", x2: "20", y1: "9", y2: "9", key: "4lhtct" }],
|
|
3364
3398
|
["line", { x1: "4", x2: "20", y1: "15", y2: "15", key: "vyu0kd" }],
|
|
3365
3399
|
["line", { x1: "10", x2: "8", y1: "3", y2: "21", key: "1ggp8o" }],
|
|
3366
3400
|
["line", { x1: "16", x2: "14", y1: "3", y2: "21", key: "weycgp" }]
|
|
3367
3401
|
];
|
|
3368
|
-
const Hash = createLucideIcon("hash", __iconNode$
|
|
3402
|
+
const Hash = createLucideIcon("hash", __iconNode$P);
|
|
3369
3403
|
|
|
3370
3404
|
/**
|
|
3371
3405
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3375,13 +3409,13 @@ const Hash = createLucideIcon("hash", __iconNode$N);
|
|
|
3375
3409
|
*/
|
|
3376
3410
|
|
|
3377
3411
|
|
|
3378
|
-
const __iconNode$
|
|
3412
|
+
const __iconNode$O = [
|
|
3379
3413
|
["path", { d: "M4 12h8", key: "17cfdx" }],
|
|
3380
3414
|
["path", { d: "M4 18V6", key: "1rz3zl" }],
|
|
3381
3415
|
["path", { d: "M12 18V6", key: "zqpxq5" }],
|
|
3382
3416
|
["path", { d: "m17 12 3-2v8", key: "1hhhft" }]
|
|
3383
3417
|
];
|
|
3384
|
-
const Heading1 = createLucideIcon("heading-1", __iconNode$
|
|
3418
|
+
const Heading1 = createLucideIcon("heading-1", __iconNode$O);
|
|
3385
3419
|
|
|
3386
3420
|
/**
|
|
3387
3421
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3391,13 +3425,13 @@ const Heading1 = createLucideIcon("heading-1", __iconNode$M);
|
|
|
3391
3425
|
*/
|
|
3392
3426
|
|
|
3393
3427
|
|
|
3394
|
-
const __iconNode$
|
|
3428
|
+
const __iconNode$N = [
|
|
3395
3429
|
["path", { d: "M4 12h8", key: "17cfdx" }],
|
|
3396
3430
|
["path", { d: "M4 18V6", key: "1rz3zl" }],
|
|
3397
3431
|
["path", { d: "M12 18V6", key: "zqpxq5" }],
|
|
3398
3432
|
["path", { d: "M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1", key: "9jr5yi" }]
|
|
3399
3433
|
];
|
|
3400
|
-
const Heading2 = createLucideIcon("heading-2", __iconNode$
|
|
3434
|
+
const Heading2 = createLucideIcon("heading-2", __iconNode$N);
|
|
3401
3435
|
|
|
3402
3436
|
/**
|
|
3403
3437
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3407,14 +3441,14 @@ const Heading2 = createLucideIcon("heading-2", __iconNode$L);
|
|
|
3407
3441
|
*/
|
|
3408
3442
|
|
|
3409
3443
|
|
|
3410
|
-
const __iconNode$
|
|
3444
|
+
const __iconNode$M = [
|
|
3411
3445
|
["path", { d: "M4 12h8", key: "17cfdx" }],
|
|
3412
3446
|
["path", { d: "M4 18V6", key: "1rz3zl" }],
|
|
3413
3447
|
["path", { d: "M12 18V6", key: "zqpxq5" }],
|
|
3414
3448
|
["path", { d: "M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2", key: "68ncm8" }],
|
|
3415
3449
|
["path", { d: "M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2", key: "1ejuhz" }]
|
|
3416
3450
|
];
|
|
3417
|
-
const Heading3 = createLucideIcon("heading-3", __iconNode$
|
|
3451
|
+
const Heading3 = createLucideIcon("heading-3", __iconNode$M);
|
|
3418
3452
|
|
|
3419
3453
|
/**
|
|
3420
3454
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3424,12 +3458,12 @@ const Heading3 = createLucideIcon("heading-3", __iconNode$K);
|
|
|
3424
3458
|
*/
|
|
3425
3459
|
|
|
3426
3460
|
|
|
3427
|
-
const __iconNode$
|
|
3461
|
+
const __iconNode$L = [
|
|
3428
3462
|
["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
3463
|
["path", { d: "M3 3v5h5", key: "1xhq8a" }],
|
|
3430
3464
|
["path", { d: "M12 7v5l4 2", key: "1fdv2h" }]
|
|
3431
3465
|
];
|
|
3432
|
-
const History = createLucideIcon("history", __iconNode$
|
|
3466
|
+
const History = createLucideIcon("history", __iconNode$L);
|
|
3433
3467
|
|
|
3434
3468
|
/**
|
|
3435
3469
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3439,12 +3473,12 @@ const History = createLucideIcon("history", __iconNode$J);
|
|
|
3439
3473
|
*/
|
|
3440
3474
|
|
|
3441
3475
|
|
|
3442
|
-
const __iconNode$
|
|
3476
|
+
const __iconNode$K = [
|
|
3443
3477
|
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
|
|
3444
3478
|
["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
|
|
3445
3479
|
["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
|
|
3446
3480
|
];
|
|
3447
|
-
const Image$1 = createLucideIcon("image", __iconNode$
|
|
3481
|
+
const Image$1 = createLucideIcon("image", __iconNode$K);
|
|
3448
3482
|
|
|
3449
3483
|
/**
|
|
3450
3484
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3454,12 +3488,12 @@ const Image$1 = createLucideIcon("image", __iconNode$I);
|
|
|
3454
3488
|
*/
|
|
3455
3489
|
|
|
3456
3490
|
|
|
3457
|
-
const __iconNode$
|
|
3491
|
+
const __iconNode$J = [
|
|
3458
3492
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
3459
3493
|
["path", { d: "M12 16v-4", key: "1dtifu" }],
|
|
3460
3494
|
["path", { d: "M12 8h.01", key: "e9boi3" }]
|
|
3461
3495
|
];
|
|
3462
|
-
const Info = createLucideIcon("info", __iconNode$
|
|
3496
|
+
const Info = createLucideIcon("info", __iconNode$J);
|
|
3463
3497
|
|
|
3464
3498
|
/**
|
|
3465
3499
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3469,12 +3503,12 @@ const Info = createLucideIcon("info", __iconNode$H);
|
|
|
3469
3503
|
*/
|
|
3470
3504
|
|
|
3471
3505
|
|
|
3472
|
-
const __iconNode$
|
|
3506
|
+
const __iconNode$I = [
|
|
3473
3507
|
["line", { x1: "19", x2: "10", y1: "4", y2: "4", key: "15jd3p" }],
|
|
3474
3508
|
["line", { x1: "14", x2: "5", y1: "20", y2: "20", key: "bu0au3" }],
|
|
3475
3509
|
["line", { x1: "15", x2: "9", y1: "4", y2: "20", key: "uljnxc" }]
|
|
3476
3510
|
];
|
|
3477
|
-
const Italic$1 = createLucideIcon("italic", __iconNode$
|
|
3511
|
+
const Italic$1 = createLucideIcon("italic", __iconNode$I);
|
|
3478
3512
|
|
|
3479
3513
|
/**
|
|
3480
3514
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3484,7 +3518,7 @@ const Italic$1 = createLucideIcon("italic", __iconNode$G);
|
|
|
3484
3518
|
*/
|
|
3485
3519
|
|
|
3486
3520
|
|
|
3487
|
-
const __iconNode$
|
|
3521
|
+
const __iconNode$H = [
|
|
3488
3522
|
[
|
|
3489
3523
|
"path",
|
|
3490
3524
|
{
|
|
@@ -3494,7 +3528,7 @@ const __iconNode$F = [
|
|
|
3494
3528
|
],
|
|
3495
3529
|
["circle", { cx: "16.5", cy: "7.5", r: ".5", fill: "currentColor", key: "w0ekpg" }]
|
|
3496
3530
|
];
|
|
3497
|
-
const KeyRound = createLucideIcon("key-round", __iconNode$
|
|
3531
|
+
const KeyRound = createLucideIcon("key-round", __iconNode$H);
|
|
3498
3532
|
|
|
3499
3533
|
/**
|
|
3500
3534
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3504,12 +3538,12 @@ const KeyRound = createLucideIcon("key-round", __iconNode$F);
|
|
|
3504
3538
|
*/
|
|
3505
3539
|
|
|
3506
3540
|
|
|
3507
|
-
const __iconNode$
|
|
3541
|
+
const __iconNode$G = [
|
|
3508
3542
|
["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
|
|
3509
3543
|
["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
|
|
3510
3544
|
["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
|
|
3511
3545
|
];
|
|
3512
|
-
const Link2 = createLucideIcon("link-2", __iconNode$
|
|
3546
|
+
const Link2 = createLucideIcon("link-2", __iconNode$G);
|
|
3513
3547
|
|
|
3514
3548
|
/**
|
|
3515
3549
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3519,14 +3553,14 @@ const Link2 = createLucideIcon("link-2", __iconNode$E);
|
|
|
3519
3553
|
*/
|
|
3520
3554
|
|
|
3521
3555
|
|
|
3522
|
-
const __iconNode$
|
|
3556
|
+
const __iconNode$F = [
|
|
3523
3557
|
["path", { d: "m3 17 2 2 4-4", key: "1jhpwq" }],
|
|
3524
3558
|
["path", { d: "m3 7 2 2 4-4", key: "1obspn" }],
|
|
3525
3559
|
["path", { d: "M13 6h8", key: "15sg57" }],
|
|
3526
3560
|
["path", { d: "M13 12h8", key: "h98zly" }],
|
|
3527
3561
|
["path", { d: "M13 18h8", key: "oe0vm4" }]
|
|
3528
3562
|
];
|
|
3529
|
-
const ListChecks = createLucideIcon("list-checks", __iconNode$
|
|
3563
|
+
const ListChecks = createLucideIcon("list-checks", __iconNode$F);
|
|
3530
3564
|
|
|
3531
3565
|
/**
|
|
3532
3566
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3536,7 +3570,7 @@ const ListChecks = createLucideIcon("list-checks", __iconNode$D);
|
|
|
3536
3570
|
*/
|
|
3537
3571
|
|
|
3538
3572
|
|
|
3539
|
-
const __iconNode$
|
|
3573
|
+
const __iconNode$E = [
|
|
3540
3574
|
["path", { d: "M10 12h11", key: "6m4ad9" }],
|
|
3541
3575
|
["path", { d: "M10 18h11", key: "11hvi2" }],
|
|
3542
3576
|
["path", { d: "M10 6h11", key: "c7qv1k" }],
|
|
@@ -3544,7 +3578,7 @@ const __iconNode$C = [
|
|
|
3544
3578
|
["path", { d: "M4 6h1v4", key: "cnovpq" }],
|
|
3545
3579
|
["path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1", key: "m9a95d" }]
|
|
3546
3580
|
];
|
|
3547
|
-
const ListOrdered = createLucideIcon("list-ordered", __iconNode$
|
|
3581
|
+
const ListOrdered = createLucideIcon("list-ordered", __iconNode$E);
|
|
3548
3582
|
|
|
3549
3583
|
/**
|
|
3550
3584
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3554,7 +3588,7 @@ const ListOrdered = createLucideIcon("list-ordered", __iconNode$C);
|
|
|
3554
3588
|
*/
|
|
3555
3589
|
|
|
3556
3590
|
|
|
3557
|
-
const __iconNode$
|
|
3591
|
+
const __iconNode$D = [
|
|
3558
3592
|
["path", { d: "M3 12h.01", key: "nlz23k" }],
|
|
3559
3593
|
["path", { d: "M3 18h.01", key: "1tta3j" }],
|
|
3560
3594
|
["path", { d: "M3 6h.01", key: "1rqtza" }],
|
|
@@ -3562,7 +3596,7 @@ const __iconNode$B = [
|
|
|
3562
3596
|
["path", { d: "M8 18h13", key: "1lx6n3" }],
|
|
3563
3597
|
["path", { d: "M8 6h13", key: "ik3vkj" }]
|
|
3564
3598
|
];
|
|
3565
|
-
const List = createLucideIcon("list", __iconNode$
|
|
3599
|
+
const List = createLucideIcon("list", __iconNode$D);
|
|
3566
3600
|
|
|
3567
3601
|
/**
|
|
3568
3602
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3572,8 +3606,8 @@ const List = createLucideIcon("list", __iconNode$B);
|
|
|
3572
3606
|
*/
|
|
3573
3607
|
|
|
3574
3608
|
|
|
3575
|
-
const __iconNode$
|
|
3576
|
-
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$
|
|
3609
|
+
const __iconNode$C = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
3610
|
+
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$C);
|
|
3577
3611
|
|
|
3578
3612
|
/**
|
|
3579
3613
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3583,7 +3617,7 @@ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$A);
|
|
|
3583
3617
|
*/
|
|
3584
3618
|
|
|
3585
3619
|
|
|
3586
|
-
const __iconNode$
|
|
3620
|
+
const __iconNode$B = [
|
|
3587
3621
|
["path", { d: "M12 2v4", key: "3427ic" }],
|
|
3588
3622
|
["path", { d: "m16.2 7.8 2.9-2.9", key: "r700ao" }],
|
|
3589
3623
|
["path", { d: "M18 12h4", key: "wj9ykh" }],
|
|
@@ -3593,7 +3627,7 @@ const __iconNode$z = [
|
|
|
3593
3627
|
["path", { d: "M2 12h4", key: "j09sii" }],
|
|
3594
3628
|
["path", { d: "m4.9 4.9 2.9 2.9", key: "giyufr" }]
|
|
3595
3629
|
];
|
|
3596
|
-
const Loader = createLucideIcon("loader", __iconNode$
|
|
3630
|
+
const Loader = createLucideIcon("loader", __iconNode$B);
|
|
3597
3631
|
|
|
3598
3632
|
/**
|
|
3599
3633
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3603,12 +3637,12 @@ const Loader = createLucideIcon("loader", __iconNode$z);
|
|
|
3603
3637
|
*/
|
|
3604
3638
|
|
|
3605
3639
|
|
|
3606
|
-
const __iconNode$
|
|
3640
|
+
const __iconNode$A = [
|
|
3607
3641
|
["path", { d: "m16 17 5-5-5-5", key: "1bji2h" }],
|
|
3608
3642
|
["path", { d: "M21 12H9", key: "dn1m92" }],
|
|
3609
3643
|
["path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4", key: "1uf3rs" }]
|
|
3610
3644
|
];
|
|
3611
|
-
const LogOut = createLucideIcon("log-out", __iconNode$
|
|
3645
|
+
const LogOut = createLucideIcon("log-out", __iconNode$A);
|
|
3612
3646
|
|
|
3613
3647
|
/**
|
|
3614
3648
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3618,11 +3652,11 @@ const LogOut = createLucideIcon("log-out", __iconNode$y);
|
|
|
3618
3652
|
*/
|
|
3619
3653
|
|
|
3620
3654
|
|
|
3621
|
-
const __iconNode$
|
|
3655
|
+
const __iconNode$z = [
|
|
3622
3656
|
["path", { d: "m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7", key: "132q7q" }],
|
|
3623
3657
|
["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }]
|
|
3624
3658
|
];
|
|
3625
|
-
const Mail = createLucideIcon("mail", __iconNode$
|
|
3659
|
+
const Mail = createLucideIcon("mail", __iconNode$z);
|
|
3626
3660
|
|
|
3627
3661
|
/**
|
|
3628
3662
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3632,12 +3666,12 @@ const Mail = createLucideIcon("mail", __iconNode$x);
|
|
|
3632
3666
|
*/
|
|
3633
3667
|
|
|
3634
3668
|
|
|
3635
|
-
const __iconNode$
|
|
3669
|
+
const __iconNode$y = [
|
|
3636
3670
|
["path", { d: "M4 12h16", key: "1lakjw" }],
|
|
3637
3671
|
["path", { d: "M4 18h16", key: "19g7jn" }],
|
|
3638
3672
|
["path", { d: "M4 6h16", key: "1o0s65" }]
|
|
3639
3673
|
];
|
|
3640
|
-
const Menu = createLucideIcon("menu", __iconNode$
|
|
3674
|
+
const Menu = createLucideIcon("menu", __iconNode$y);
|
|
3641
3675
|
|
|
3642
3676
|
/**
|
|
3643
3677
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3647,8 +3681,8 @@ const Menu = createLucideIcon("menu", __iconNode$w);
|
|
|
3647
3681
|
*/
|
|
3648
3682
|
|
|
3649
3683
|
|
|
3650
|
-
const __iconNode$
|
|
3651
|
-
const Minus = createLucideIcon("minus", __iconNode$
|
|
3684
|
+
const __iconNode$x = [["path", { d: "M5 12h14", key: "1ays0h" }]];
|
|
3685
|
+
const Minus = createLucideIcon("minus", __iconNode$x);
|
|
3652
3686
|
|
|
3653
3687
|
/**
|
|
3654
3688
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3658,7 +3692,7 @@ const Minus = createLucideIcon("minus", __iconNode$v);
|
|
|
3658
3692
|
*/
|
|
3659
3693
|
|
|
3660
3694
|
|
|
3661
|
-
const __iconNode$
|
|
3695
|
+
const __iconNode$w = [
|
|
3662
3696
|
[
|
|
3663
3697
|
"path",
|
|
3664
3698
|
{
|
|
@@ -3667,7 +3701,7 @@ const __iconNode$u = [
|
|
|
3667
3701
|
}
|
|
3668
3702
|
]
|
|
3669
3703
|
];
|
|
3670
|
-
const Moon = createLucideIcon("moon", __iconNode$
|
|
3704
|
+
const Moon = createLucideIcon("moon", __iconNode$w);
|
|
3671
3705
|
|
|
3672
3706
|
/**
|
|
3673
3707
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3677,7 +3711,7 @@ const Moon = createLucideIcon("moon", __iconNode$u);
|
|
|
3677
3711
|
*/
|
|
3678
3712
|
|
|
3679
3713
|
|
|
3680
|
-
const __iconNode$
|
|
3714
|
+
const __iconNode$v = [
|
|
3681
3715
|
[
|
|
3682
3716
|
"path",
|
|
3683
3717
|
{
|
|
@@ -3690,7 +3724,7 @@ const __iconNode$t = [
|
|
|
3690
3724
|
["circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor", key: "qy21gx" }],
|
|
3691
3725
|
["circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor", key: "fotxhn" }]
|
|
3692
3726
|
];
|
|
3693
|
-
const Palette = createLucideIcon("palette", __iconNode$
|
|
3727
|
+
const Palette = createLucideIcon("palette", __iconNode$v);
|
|
3694
3728
|
|
|
3695
3729
|
/**
|
|
3696
3730
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3700,12 +3734,12 @@ const Palette = createLucideIcon("palette", __iconNode$t);
|
|
|
3700
3734
|
*/
|
|
3701
3735
|
|
|
3702
3736
|
|
|
3703
|
-
const __iconNode$
|
|
3737
|
+
const __iconNode$u = [
|
|
3704
3738
|
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
|
|
3705
3739
|
["path", { d: "M9 3v18", key: "fh3hqa" }],
|
|
3706
3740
|
["path", { d: "m16 15-3-3 3-3", key: "14y99z" }]
|
|
3707
3741
|
];
|
|
3708
|
-
const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$
|
|
3742
|
+
const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$u);
|
|
3709
3743
|
|
|
3710
3744
|
/**
|
|
3711
3745
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3715,7 +3749,7 @@ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$s);
|
|
|
3715
3749
|
*/
|
|
3716
3750
|
|
|
3717
3751
|
|
|
3718
|
-
const __iconNode$
|
|
3752
|
+
const __iconNode$t = [
|
|
3719
3753
|
[
|
|
3720
3754
|
"path",
|
|
3721
3755
|
{
|
|
@@ -3724,7 +3758,7 @@ const __iconNode$r = [
|
|
|
3724
3758
|
}
|
|
3725
3759
|
]
|
|
3726
3760
|
];
|
|
3727
|
-
const Paperclip = createLucideIcon("paperclip", __iconNode$
|
|
3761
|
+
const Paperclip = createLucideIcon("paperclip", __iconNode$t);
|
|
3728
3762
|
|
|
3729
3763
|
/**
|
|
3730
3764
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3734,7 +3768,7 @@ const Paperclip = createLucideIcon("paperclip", __iconNode$r);
|
|
|
3734
3768
|
*/
|
|
3735
3769
|
|
|
3736
3770
|
|
|
3737
|
-
const __iconNode$
|
|
3771
|
+
const __iconNode$s = [
|
|
3738
3772
|
[
|
|
3739
3773
|
"path",
|
|
3740
3774
|
{
|
|
@@ -3744,7 +3778,7 @@ const __iconNode$q = [
|
|
|
3744
3778
|
],
|
|
3745
3779
|
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
3746
3780
|
];
|
|
3747
|
-
const Pencil = createLucideIcon("pencil", __iconNode$
|
|
3781
|
+
const Pencil = createLucideIcon("pencil", __iconNode$s);
|
|
3748
3782
|
|
|
3749
3783
|
/**
|
|
3750
3784
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3754,7 +3788,7 @@ const Pencil = createLucideIcon("pencil", __iconNode$q);
|
|
|
3754
3788
|
*/
|
|
3755
3789
|
|
|
3756
3790
|
|
|
3757
|
-
const __iconNode$
|
|
3791
|
+
const __iconNode$r = [
|
|
3758
3792
|
[
|
|
3759
3793
|
"path",
|
|
3760
3794
|
{
|
|
@@ -3763,7 +3797,7 @@ const __iconNode$p = [
|
|
|
3763
3797
|
}
|
|
3764
3798
|
]
|
|
3765
3799
|
];
|
|
3766
|
-
const Phone = createLucideIcon("phone", __iconNode$
|
|
3800
|
+
const Phone = createLucideIcon("phone", __iconNode$r);
|
|
3767
3801
|
|
|
3768
3802
|
/**
|
|
3769
3803
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3773,7 +3807,7 @@ const Phone = createLucideIcon("phone", __iconNode$p);
|
|
|
3773
3807
|
*/
|
|
3774
3808
|
|
|
3775
3809
|
|
|
3776
|
-
const __iconNode$
|
|
3810
|
+
const __iconNode$q = [
|
|
3777
3811
|
[
|
|
3778
3812
|
"path",
|
|
3779
3813
|
{
|
|
@@ -3782,7 +3816,7 @@ const __iconNode$o = [
|
|
|
3782
3816
|
}
|
|
3783
3817
|
]
|
|
3784
3818
|
];
|
|
3785
|
-
const Play = createLucideIcon("play", __iconNode$
|
|
3819
|
+
const Play = createLucideIcon("play", __iconNode$q);
|
|
3786
3820
|
|
|
3787
3821
|
/**
|
|
3788
3822
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3792,11 +3826,11 @@ const Play = createLucideIcon("play", __iconNode$o);
|
|
|
3792
3826
|
*/
|
|
3793
3827
|
|
|
3794
3828
|
|
|
3795
|
-
const __iconNode$
|
|
3829
|
+
const __iconNode$p = [
|
|
3796
3830
|
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
3797
3831
|
["path", { d: "M12 5v14", key: "s699le" }]
|
|
3798
3832
|
];
|
|
3799
|
-
const Plus = createLucideIcon("plus", __iconNode$
|
|
3833
|
+
const Plus = createLucideIcon("plus", __iconNode$p);
|
|
3800
3834
|
|
|
3801
3835
|
/**
|
|
3802
3836
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3806,10 +3840,10 @@ const Plus = createLucideIcon("plus", __iconNode$n);
|
|
|
3806
3840
|
*/
|
|
3807
3841
|
|
|
3808
3842
|
|
|
3809
|
-
const __iconNode$
|
|
3843
|
+
const __iconNode$o = [
|
|
3810
3844
|
["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
|
|
3811
3845
|
];
|
|
3812
|
-
const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$
|
|
3846
|
+
const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$o);
|
|
3813
3847
|
|
|
3814
3848
|
/**
|
|
3815
3849
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3819,11 +3853,11 @@ const RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode$
|
|
|
3819
3853
|
*/
|
|
3820
3854
|
|
|
3821
3855
|
|
|
3822
|
-
const __iconNode$
|
|
3856
|
+
const __iconNode$n = [
|
|
3823
3857
|
["path", { d: "M21 7v6h-6", key: "3ptur4" }],
|
|
3824
3858
|
["path", { d: "M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3l3 2.7", key: "1kgawr" }]
|
|
3825
3859
|
];
|
|
3826
|
-
const Redo = createLucideIcon("redo", __iconNode$
|
|
3860
|
+
const Redo = createLucideIcon("redo", __iconNode$n);
|
|
3827
3861
|
|
|
3828
3862
|
/**
|
|
3829
3863
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3833,13 +3867,13 @@ const Redo = createLucideIcon("redo", __iconNode$l);
|
|
|
3833
3867
|
*/
|
|
3834
3868
|
|
|
3835
3869
|
|
|
3836
|
-
const __iconNode$
|
|
3870
|
+
const __iconNode$m = [
|
|
3837
3871
|
["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
|
|
3838
3872
|
["path", { d: "M21 3v5h-5", key: "1q7to0" }],
|
|
3839
3873
|
["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
|
|
3840
3874
|
["path", { d: "M8 16H3v5", key: "1cv678" }]
|
|
3841
3875
|
];
|
|
3842
|
-
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$
|
|
3876
|
+
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$m);
|
|
3843
3877
|
|
|
3844
3878
|
/**
|
|
3845
3879
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3849,14 +3883,14 @@ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$k);
|
|
|
3849
3883
|
*/
|
|
3850
3884
|
|
|
3851
3885
|
|
|
3852
|
-
const __iconNode$
|
|
3886
|
+
const __iconNode$l = [
|
|
3853
3887
|
["path", { d: "M4 7V4h16v3", key: "9msm58" }],
|
|
3854
3888
|
["path", { d: "M5 20h6", key: "1h6pxn" }],
|
|
3855
3889
|
["path", { d: "M13 4 8 20", key: "kqq6aj" }],
|
|
3856
3890
|
["path", { d: "m15 15 5 5", key: "me55sn" }],
|
|
3857
3891
|
["path", { d: "m20 15-5 5", key: "11p7ol" }]
|
|
3858
3892
|
];
|
|
3859
|
-
const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$
|
|
3893
|
+
const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$l);
|
|
3860
3894
|
|
|
3861
3895
|
/**
|
|
3862
3896
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -3866,14 +3900,44 @@ const RemoveFormatting = createLucideIcon("remove-formatting", __iconNode$j);
|
|
|
3866
3900
|
*/
|
|
3867
3901
|
|
|
3868
3902
|
|
|
3869
|
-
const __iconNode$
|
|
3903
|
+
const __iconNode$k = [
|
|
3904
|
+
["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
|
|
3905
|
+
["path", { d: "M3 3v5h5", key: "1xhq8a" }]
|
|
3906
|
+
];
|
|
3907
|
+
const RotateCcw = createLucideIcon("rotate-ccw", __iconNode$k);
|
|
3908
|
+
|
|
3909
|
+
/**
|
|
3910
|
+
* @license lucide-react v0.539.0 - ISC
|
|
3911
|
+
*
|
|
3912
|
+
* This source code is licensed under the ISC license.
|
|
3913
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
3914
|
+
*/
|
|
3915
|
+
|
|
3916
|
+
|
|
3917
|
+
const __iconNode$j = [
|
|
3870
3918
|
["circle", { cx: "6", cy: "6", r: "3", key: "1lh9wr" }],
|
|
3871
3919
|
["path", { d: "M8.12 8.12 12 12", key: "1alkpv" }],
|
|
3872
3920
|
["path", { d: "M20 4 8.12 15.88", key: "xgtan2" }],
|
|
3873
3921
|
["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
|
|
3874
3922
|
["path", { d: "M14.8 14.8 20 20", key: "ptml3r" }]
|
|
3875
3923
|
];
|
|
3876
|
-
const Scissors = createLucideIcon("scissors", __iconNode$
|
|
3924
|
+
const Scissors = createLucideIcon("scissors", __iconNode$j);
|
|
3925
|
+
|
|
3926
|
+
/**
|
|
3927
|
+
* @license lucide-react v0.539.0 - ISC
|
|
3928
|
+
*
|
|
3929
|
+
* This source code is licensed under the ISC license.
|
|
3930
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
3931
|
+
*/
|
|
3932
|
+
|
|
3933
|
+
|
|
3934
|
+
const __iconNode$i = [
|
|
3935
|
+
["path", { d: "m13.5 8.5-5 5", key: "1cs55j" }],
|
|
3936
|
+
["path", { d: "m8.5 8.5 5 5", key: "a8mexj" }],
|
|
3937
|
+
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
|
|
3938
|
+
["path", { d: "m21 21-4.3-4.3", key: "1qie3q" }]
|
|
3939
|
+
];
|
|
3940
|
+
const SearchX = createLucideIcon("search-x", __iconNode$i);
|
|
3877
3941
|
|
|
3878
3942
|
/**
|
|
3879
3943
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -13459,7 +13523,7 @@ collisionPadding = 8, ...props }, ref) {
|
|
|
13459
13523
|
});
|
|
13460
13524
|
|
|
13461
13525
|
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', }) => {
|
|
13462
|
-
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) => {
|
|
13526
|
+
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) => {
|
|
13463
13527
|
e.stopPropagation();
|
|
13464
13528
|
onClick?.(e);
|
|
13465
13529
|
}, disabled: disabled, children: icon }) }) }), jsx(TooltipContent, { children: tooltip })] }) }));
|
|
@@ -15381,36 +15445,537 @@ function ApiComboBox({ contactType, selectedItem, onSelect, fetchBusinessContact
|
|
|
15381
15445
|
: '', fetchPage: fetchPage, resolveById: resolveById, preSelectedId: customerCode, searchPlaceholder: searchPlaceholder, emptyMessage: "No business contacts found.", disabled: disabled, className: className, align: align, debounceMs: 300, hideTriggerSearchIcon: hideTriggerSearchIcon }));
|
|
15382
15446
|
}
|
|
15383
15447
|
|
|
15448
|
+
// A number with an optional `k` (thousand), `M` (million) or `B` (billion), any case, e.g. `1.5`, `2k`, `1.2M`.
|
|
15449
|
+
const NUMBER = String.raw `((?:\d+(?:\.\d+)?|\.\d+)[kKmMbB]?)`;
|
|
15450
|
+
const SUFFIX_MULTIPLIER = {
|
|
15451
|
+
k: 1000,
|
|
15452
|
+
m: 1000000,
|
|
15453
|
+
b: 1000000000,
|
|
15454
|
+
};
|
|
15455
|
+
function toExpressionNumber(raw) {
|
|
15456
|
+
const suffix = raw.slice(-1).toLowerCase();
|
|
15457
|
+
const multiplier = SUFFIX_MULTIPLIER[suffix];
|
|
15458
|
+
return multiplier
|
|
15459
|
+
? Math.round(Number(raw.slice(0, -1)) * multiplier * 1e6) / 1e6
|
|
15460
|
+
: Number(raw);
|
|
15461
|
+
}
|
|
15462
|
+
const COMPARISON_RE = new RegExp(`^(>=|<=|>|<)${NUMBER}$`);
|
|
15463
|
+
const BETWEEN_RE = new RegExp(`^${NUMBER}-${NUMBER}$`);
|
|
15464
|
+
const EXACT_RE = new RegExp(`^${NUMBER}$`);
|
|
15465
|
+
/** Neutral defaults for a number column with no known scale. */
|
|
15466
|
+
const DEFAULT_NUMBER_RULE_EXAMPLES = {
|
|
15467
|
+
low: 1,
|
|
15468
|
+
high: 10,
|
|
15469
|
+
exact: 5,
|
|
15470
|
+
};
|
|
15471
|
+
const SHORT_SCALES = [
|
|
15472
|
+
[1000000000, 'B'],
|
|
15473
|
+
[1000000, 'M'],
|
|
15474
|
+
[1000, 'k'],
|
|
15475
|
+
];
|
|
15476
|
+
/** Rule text for a value: `1k`, `2.5k`, `1M`, `1B` so chips stay short; the parser reads them back. */
|
|
15477
|
+
function formatRuleNumber(value) {
|
|
15478
|
+
const [divisor, suffix] = SHORT_SCALES.find(([scale]) => Math.abs(value) >= scale) ?? [1, ''];
|
|
15479
|
+
const scaled = Math.round((value / divisor) * 100) / 100;
|
|
15480
|
+
return `${scaled}${suffix}`;
|
|
15481
|
+
}
|
|
15482
|
+
function formatRuleValue(value, unit) {
|
|
15483
|
+
const number = value.toLocaleString('en-US', { maximumFractionDigits: 2 });
|
|
15484
|
+
if (!unit)
|
|
15485
|
+
return number;
|
|
15486
|
+
return unit === '%' ? `${number}%` : `${number} ${unit}`;
|
|
15487
|
+
}
|
|
15488
|
+
/** The help popover's rule list for a column's typical range; rules use short numbers (`1k`) that the field accepts as typed. */
|
|
15489
|
+
function buildNumberRuleHelp({ low, high, exact, unit, } = DEFAULT_NUMBER_RULE_EXAMPLES) {
|
|
15490
|
+
const lowText = formatRuleValue(low, unit);
|
|
15491
|
+
const highText = formatRuleValue(high, unit);
|
|
15492
|
+
const lowRule = formatRuleNumber(low);
|
|
15493
|
+
const highRule = formatRuleNumber(high);
|
|
15494
|
+
// Smallest value first: the low bound, the range, a value inside it, then the high bound.
|
|
15495
|
+
return [
|
|
15496
|
+
{ rule: `>${lowRule}`, meaning: `More than ${lowText}` },
|
|
15497
|
+
{ rule: `>=${lowRule}`, meaning: `${lowText} or more` },
|
|
15498
|
+
{ rule: `${lowRule}–${highRule}`, meaning: `${lowText} to ${highText}` },
|
|
15499
|
+
{
|
|
15500
|
+
rule: formatRuleNumber(exact),
|
|
15501
|
+
meaning: `Exactly ${formatRuleValue(exact, unit)}`,
|
|
15502
|
+
},
|
|
15503
|
+
{ rule: `<${highRule}`, meaning: `Less than ${highText}` },
|
|
15504
|
+
{ rule: `<=${highRule}`, meaning: `${highText} or less` },
|
|
15505
|
+
];
|
|
15506
|
+
}
|
|
15507
|
+
/** Parses the typed rules listed by `buildNumberRuleHelp`. Accepts `-`, `–` or `—` for ranges and ignores spaces and thousands commas. */
|
|
15508
|
+
function parseNumberExpression(text) {
|
|
15509
|
+
const normalized = text.replace(/[\s,]/g, '').replace(/[–—]/g, '-');
|
|
15510
|
+
if (!normalized)
|
|
15511
|
+
return { ok: true, range: undefined };
|
|
15512
|
+
const comparison = COMPARISON_RE.exec(normalized);
|
|
15513
|
+
if (comparison) {
|
|
15514
|
+
const [, operator, raw] = comparison;
|
|
15515
|
+
const value = toExpressionNumber(raw);
|
|
15516
|
+
if (operator.startsWith('>')) {
|
|
15517
|
+
return {
|
|
15518
|
+
ok: true,
|
|
15519
|
+
range: { min: value, minExclusive: operator === '>' },
|
|
15520
|
+
};
|
|
15521
|
+
}
|
|
15522
|
+
return { ok: true, range: { max: value, maxExclusive: operator === '<' } };
|
|
15523
|
+
}
|
|
15524
|
+
const between = BETWEEN_RE.exec(normalized);
|
|
15525
|
+
if (between) {
|
|
15526
|
+
const min = toExpressionNumber(between[1]);
|
|
15527
|
+
const max = toExpressionNumber(between[2]);
|
|
15528
|
+
return min <= max ? { ok: true, range: { min, max } } : { ok: false };
|
|
15529
|
+
}
|
|
15530
|
+
const exact = EXACT_RE.exec(normalized);
|
|
15531
|
+
if (exact) {
|
|
15532
|
+
const value = toExpressionNumber(exact[1]);
|
|
15533
|
+
return { ok: true, range: { min: value, max: value } };
|
|
15534
|
+
}
|
|
15535
|
+
return { ok: false };
|
|
15536
|
+
}
|
|
15537
|
+
function formatNumberRange(range) {
|
|
15538
|
+
if (!range)
|
|
15539
|
+
return '';
|
|
15540
|
+
const { min, max, minExclusive, maxExclusive } = range;
|
|
15541
|
+
if (min !== undefined && max !== undefined) {
|
|
15542
|
+
return min === max ? String(min) : `${min}–${max}`;
|
|
15543
|
+
}
|
|
15544
|
+
if (min !== undefined)
|
|
15545
|
+
return `${minExclusive ? '>' : '>='}${min}`;
|
|
15546
|
+
if (max !== undefined)
|
|
15547
|
+
return `${maxExclusive ? '<' : '<='}${max}`;
|
|
15548
|
+
return '';
|
|
15549
|
+
}
|
|
15550
|
+
/** Splits a pasted list — commas, semicolons, spaces and new lines all separate IDs. Keeps first-seen order, drops duplicates. */
|
|
15551
|
+
function splitIdList(text) {
|
|
15552
|
+
return Array.from(new Set(text
|
|
15553
|
+
.split(/[\s,;]+/)
|
|
15554
|
+
.map((id) => id.trim())
|
|
15555
|
+
.filter(Boolean)));
|
|
15556
|
+
}
|
|
15557
|
+
function getOptionLabel(options, value) {
|
|
15558
|
+
return options.find((option) => option.value === value)?.label ?? value;
|
|
15559
|
+
}
|
|
15560
|
+
/** Trigger summary for a multi-select: the first selected option (in option order) plus how many more, e.g. `Red +1`. */
|
|
15561
|
+
function summarizeSelection(values, options) {
|
|
15562
|
+
if (values.length === 0)
|
|
15563
|
+
return '';
|
|
15564
|
+
const first = options.find((option) => values.includes(option.value))?.label ?? values[0];
|
|
15565
|
+
return values.length > 1 ? `${first} +${values.length - 1}` : first;
|
|
15566
|
+
}
|
|
15567
|
+
function formatSelectedCount(selected, total) {
|
|
15568
|
+
return `${selected} of ${total} selected`;
|
|
15569
|
+
}
|
|
15570
|
+
function toggleValue(values, value) {
|
|
15571
|
+
return values.includes(value)
|
|
15572
|
+
? values.filter((v) => v !== value)
|
|
15573
|
+
: [...values, value];
|
|
15574
|
+
}
|
|
15575
|
+
/** Every option between the two ends of the range, inclusive, in scale order. */
|
|
15576
|
+
function expandScaleRange(options, range) {
|
|
15577
|
+
const fromIndex = options.findIndex((option) => option.value === range.from);
|
|
15578
|
+
const toIndex = options.findIndex((option) => option.value === range.to);
|
|
15579
|
+
if (fromIndex < 0 || toIndex < 0)
|
|
15580
|
+
return [];
|
|
15581
|
+
const [start, end] = fromIndex <= toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
|
|
15582
|
+
return options.slice(start, end + 1).map((option) => option.value);
|
|
15583
|
+
}
|
|
15584
|
+
/** `Very Good` → `VG`, `Fair` → `F`. */
|
|
15585
|
+
function toInitials(label) {
|
|
15586
|
+
return label
|
|
15587
|
+
.split(/[\s-]+/)
|
|
15588
|
+
.filter(Boolean)
|
|
15589
|
+
.map((word) => word[0].toUpperCase())
|
|
15590
|
+
.join('');
|
|
15591
|
+
}
|
|
15592
|
+
function formatScaleRange(options, range, short = false) {
|
|
15593
|
+
const values = expandScaleRange(options, range);
|
|
15594
|
+
if (values.length === 0)
|
|
15595
|
+
return '';
|
|
15596
|
+
const labelOf = (value) => {
|
|
15597
|
+
const label = getOptionLabel(options, value);
|
|
15598
|
+
return short ? toInitials(label) : label;
|
|
15599
|
+
};
|
|
15600
|
+
const first = labelOf(values[0]);
|
|
15601
|
+
return values.length === 1
|
|
15602
|
+
? first
|
|
15603
|
+
: `${first} – ${labelOf(values[values.length - 1])}`;
|
|
15604
|
+
}
|
|
15605
|
+
const DATE_PRESET_OPTIONS = [
|
|
15606
|
+
{ value: 'today', label: 'Today' },
|
|
15607
|
+
{ value: 'last7Days', label: 'Last 7 days' },
|
|
15608
|
+
{ value: 'last30Days', label: 'Last 30 days' },
|
|
15609
|
+
{ value: 'thisMonth', label: 'This month' },
|
|
15610
|
+
{ value: 'thisFiscalYear', label: 'This fiscal year' },
|
|
15611
|
+
];
|
|
15612
|
+
function toIsoDate(date) {
|
|
15613
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
15614
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
15615
|
+
return `${date.getFullYear()}-${month}-${day}`;
|
|
15616
|
+
}
|
|
15617
|
+
/** `YYYY-MM-DD` → local date (no timezone shift); empty → undefined. */
|
|
15618
|
+
function fromIsoDate(iso) {
|
|
15619
|
+
if (!iso)
|
|
15620
|
+
return undefined;
|
|
15621
|
+
const [year, month, day] = iso.split('-').map(Number);
|
|
15622
|
+
return new Date(year, month - 1, day);
|
|
15623
|
+
}
|
|
15624
|
+
function daysBefore(today, days) {
|
|
15625
|
+
return new Date(today.getFullYear(), today.getMonth(), today.getDate() - days);
|
|
15626
|
+
}
|
|
15627
|
+
/** `fiscalYearStartMonth` is 1–12 (1 = January, 4 = April). */
|
|
15628
|
+
function resolveDatePreset(preset, today, fiscalYearStartMonth = 1) {
|
|
15629
|
+
const to = toIsoDate(today);
|
|
15630
|
+
switch (preset) {
|
|
15631
|
+
case 'today':
|
|
15632
|
+
return { from: to, to };
|
|
15633
|
+
case 'last7Days':
|
|
15634
|
+
return { from: toIsoDate(daysBefore(today, 6)), to };
|
|
15635
|
+
case 'last30Days':
|
|
15636
|
+
return { from: toIsoDate(daysBefore(today, 29)), to };
|
|
15637
|
+
case 'thisMonth':
|
|
15638
|
+
return {
|
|
15639
|
+
from: toIsoDate(new Date(today.getFullYear(), today.getMonth(), 1)),
|
|
15640
|
+
to,
|
|
15641
|
+
};
|
|
15642
|
+
case 'thisFiscalYear': {
|
|
15643
|
+
const startMonthIndex = fiscalYearStartMonth - 1;
|
|
15644
|
+
const startYear = today.getMonth() >= startMonthIndex
|
|
15645
|
+
? today.getFullYear()
|
|
15646
|
+
: today.getFullYear() - 1;
|
|
15647
|
+
return { from: toIsoDate(new Date(startYear, startMonthIndex, 1)), to };
|
|
15648
|
+
}
|
|
15649
|
+
}
|
|
15650
|
+
}
|
|
15651
|
+
function resolveDateRange(range, today, fiscalYearStartMonth = 1) {
|
|
15652
|
+
if (range.preset)
|
|
15653
|
+
return resolveDatePreset(range.preset, today, fiscalYearStartMonth);
|
|
15654
|
+
return { from: range.from, to: range.to };
|
|
15655
|
+
}
|
|
15656
|
+
function formatIsoDate(iso) {
|
|
15657
|
+
const [year, month, day] = iso.split('-').map(Number);
|
|
15658
|
+
return new Date(year, month - 1, day).toLocaleDateString('en-GB', {
|
|
15659
|
+
day: 'numeric',
|
|
15660
|
+
month: 'short',
|
|
15661
|
+
year: 'numeric',
|
|
15662
|
+
});
|
|
15663
|
+
}
|
|
15664
|
+
function formatDateRange(range) {
|
|
15665
|
+
if (range.preset)
|
|
15666
|
+
return (DATE_PRESET_OPTIONS.find((option) => option.value === range.preset)
|
|
15667
|
+
?.label ?? '');
|
|
15668
|
+
if (range.from && range.to)
|
|
15669
|
+
return `${formatIsoDate(range.from)} – ${formatIsoDate(range.to)}`;
|
|
15670
|
+
if (range.from)
|
|
15671
|
+
return `From ${formatIsoDate(range.from)}`;
|
|
15672
|
+
if (range.to)
|
|
15673
|
+
return `Until ${formatIsoDate(range.to)}`;
|
|
15674
|
+
return '';
|
|
15675
|
+
}
|
|
15676
|
+
const TRI_STATE_OPTIONS = [
|
|
15677
|
+
{ value: 'any', label: 'Any' },
|
|
15678
|
+
{ value: 'yes', label: 'Yes' },
|
|
15679
|
+
{ value: 'no', label: 'No' },
|
|
15680
|
+
];
|
|
15681
|
+
function isFilterValueActive(value) {
|
|
15682
|
+
if (!value)
|
|
15683
|
+
return false;
|
|
15684
|
+
switch (value.type) {
|
|
15685
|
+
case 'list':
|
|
15686
|
+
return value.values.length > 0;
|
|
15687
|
+
case 'ids':
|
|
15688
|
+
return value.ids.length > 0;
|
|
15689
|
+
case 'contains':
|
|
15690
|
+
return value.text.trim().length > 0;
|
|
15691
|
+
case 'number':
|
|
15692
|
+
return value.range.min !== undefined || value.range.max !== undefined;
|
|
15693
|
+
case 'date':
|
|
15694
|
+
return Boolean(value.range.preset || value.range.from || value.range.to);
|
|
15695
|
+
case 'scale':
|
|
15696
|
+
case 'bool':
|
|
15697
|
+
return true;
|
|
15698
|
+
}
|
|
15699
|
+
}
|
|
15700
|
+
const FILTER_FOCUS_RING = 'outline-none focus-visible:ring-2 focus-visible:ring-primary/30';
|
|
15701
|
+
/** Text-link actions such as Clear and "Show all". */
|
|
15702
|
+
const FILTER_LINK_CLASS_NAME = cn('cursor-pointer rounded-sm text-xs font-medium text-primary hover:underline', FILTER_FOCUS_RING);
|
|
15703
|
+
/** One look for every pickable row in a filter (list rows, Yes/No, date presets, number rules). */
|
|
15704
|
+
function getOptionRowClassName(selected = false, className) {
|
|
15705
|
+
return cn('flex w-full cursor-pointer items-center gap-3 rounded-md px-2 py-2 text-left text-sm text-foreground transition-colors', FILTER_FOCUS_RING, selected ? 'bg-primary/5 font-medium text-primary' : 'hover:bg-muted/60', className);
|
|
15706
|
+
}
|
|
15707
|
+
/** A selectable pill (chip options, range presets); one height and shape everywhere. */
|
|
15708
|
+
function getPillClassName(selected) {
|
|
15709
|
+
return getSelectableOptionClassName(selected, 'inline-flex h-8 items-center gap-1.5 rounded-full px-3');
|
|
15710
|
+
}
|
|
15711
|
+
/** Search box above a list (pick lists, saved searches); matches the inputs' height and corners. */
|
|
15712
|
+
const FILTER_SEARCH_BOX_CLASS_NAME = 'flex h-9 items-center gap-2 rounded-md border border-input bg-card px-3 focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/30';
|
|
15713
|
+
/** Solid count bubble, e.g. a filter button's or card title's selected count. */
|
|
15714
|
+
const FILTER_COUNT_BADGE_CLASS_NAME = 'inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-primary px-1.5 text-xs font-semibold leading-none text-primary-foreground';
|
|
15715
|
+
/** A fixed column count, or (when omitted) as many columns as fit at `minWidth` each. */
|
|
15716
|
+
function getGridColumnsStyle(columns, minWidth = '7rem') {
|
|
15717
|
+
return {
|
|
15718
|
+
gridTemplateColumns: columns
|
|
15719
|
+
? `repeat(${columns}, minmax(0, 1fr))`
|
|
15720
|
+
: `repeat(auto-fill, minmax(${minWidth}, 1fr))`,
|
|
15721
|
+
};
|
|
15722
|
+
}
|
|
15723
|
+
/** 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. */
|
|
15724
|
+
function getSelectableOptionClassName(selected, className) {
|
|
15725
|
+
return cn('cursor-pointer border text-xs transition-colors', FILTER_FOCUS_RING, selected
|
|
15726
|
+
? 'border-primary bg-primary/5 font-medium text-primary'
|
|
15727
|
+
: 'border-border bg-background text-foreground hover:bg-secondary dark:bg-muted/60 dark:hover:bg-muted', className);
|
|
15728
|
+
}
|
|
15729
|
+
/** Shared look of every filter-row control (trigger buttons and inline inputs). */
|
|
15730
|
+
function getFilterFieldClassName(state, className) {
|
|
15731
|
+
return cn('flex h-7 w-full min-w-0 items-center gap-1 rounded-md border px-2 text-xs transition-colors outline-none', 'focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-primary/30', state === 'empty' &&
|
|
15732
|
+
'border-input bg-card text-foreground placeholder:text-placeholder', state === 'applied' &&
|
|
15733
|
+
'border-primary bg-primary/5 font-medium text-primary', state === 'invalid' && 'border-destructive bg-card text-destructive', state === 'disabled' &&
|
|
15734
|
+
'pointer-events-none border-dashed border-border bg-transparent', className);
|
|
15735
|
+
}
|
|
15736
|
+
|
|
15737
|
+
function getPanelClassName(variant, active, className) {
|
|
15738
|
+
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);
|
|
15739
|
+
}
|
|
15740
|
+
function getTitleClassName(variant) {
|
|
15741
|
+
return cn('flex items-center gap-2 text-foreground', variant === 'section'
|
|
15742
|
+
? 'text-xs font-medium text-label'
|
|
15743
|
+
: 'text-sm font-semibold');
|
|
15744
|
+
}
|
|
15745
|
+
|
|
15746
|
+
/** Shell for one filter: title, selected badge, applied summary, Clear and a hint. Same content in popovers and on full-page surfaces. */
|
|
15747
|
+
function FilterPanel({ title, status, selectedCount, summary, action, onClear, hint, active = false, variant = 'card', className, children, }) {
|
|
15748
|
+
const hasHeader = Boolean(title || status || summary || action || onClear);
|
|
15749
|
+
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: FILTER_COUNT_BADGE_CLASS_NAME, 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 })] }));
|
|
15750
|
+
}
|
|
15751
|
+
|
|
15384
15752
|
function Checkbox({ className, ...props }) {
|
|
15385
15753
|
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" }) }) }));
|
|
15386
15754
|
}
|
|
15387
15755
|
|
|
15756
|
+
// Sub-pixel rounding leaves scrollTop a hair short of the end.
|
|
15757
|
+
const EDGE_TOLERANCE_PX = 1;
|
|
15758
|
+
function getScrollFadeState(el) {
|
|
15759
|
+
const { scrollTop, scrollHeight, clientHeight } = el;
|
|
15760
|
+
return {
|
|
15761
|
+
top: scrollTop > EDGE_TOLERANCE_PX,
|
|
15762
|
+
bottom: scrollTop + clientHeight < scrollHeight - EDGE_TOLERANCE_PX,
|
|
15763
|
+
};
|
|
15764
|
+
}
|
|
15765
|
+
const FADE_BASE_CLASS_NAME = 'pointer-events-none absolute inset-x-0 h-8 from-card to-transparent';
|
|
15766
|
+
|
|
15767
|
+
function useScrollFade() {
|
|
15768
|
+
const ref = useRef(null);
|
|
15769
|
+
const [state, setState] = useState({
|
|
15770
|
+
top: false,
|
|
15771
|
+
bottom: false,
|
|
15772
|
+
});
|
|
15773
|
+
const update = useCallback(() => {
|
|
15774
|
+
if (!ref.current)
|
|
15775
|
+
return;
|
|
15776
|
+
const next = getScrollFadeState(ref.current);
|
|
15777
|
+
// Skip no-op updates (observers fire often).
|
|
15778
|
+
setState((current) => current.top === next.top && current.bottom === next.bottom
|
|
15779
|
+
? current
|
|
15780
|
+
: next);
|
|
15781
|
+
}, []);
|
|
15782
|
+
useEffect(() => {
|
|
15783
|
+
const el = ref.current;
|
|
15784
|
+
if (!el)
|
|
15785
|
+
return;
|
|
15786
|
+
update();
|
|
15787
|
+
const resizeObserver = new ResizeObserver(update);
|
|
15788
|
+
resizeObserver.observe(el);
|
|
15789
|
+
const mutationObserver = new MutationObserver(update);
|
|
15790
|
+
mutationObserver.observe(el, { childList: true, subtree: true });
|
|
15791
|
+
return () => {
|
|
15792
|
+
resizeObserver.disconnect();
|
|
15793
|
+
mutationObserver.disconnect();
|
|
15794
|
+
};
|
|
15795
|
+
}, [update]);
|
|
15796
|
+
return { ref, update, ...state };
|
|
15797
|
+
}
|
|
15798
|
+
|
|
15799
|
+
/** Scroll container that fades its top / bottom edge while more content is hidden there, so it reads as scrollable. */
|
|
15800
|
+
function ScrollFade({ className, wrapperClassName, children, ...props }) {
|
|
15801
|
+
const { ref, update, top, bottom } = useScrollFade();
|
|
15802
|
+
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') }))] }));
|
|
15803
|
+
}
|
|
15804
|
+
|
|
15805
|
+
// Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
|
|
15806
|
+
// labels that are not actually clipped.
|
|
15807
|
+
const OVERFLOW_TOLERANCE_PX = 1;
|
|
15808
|
+
function findClippedLabel(root) {
|
|
15809
|
+
const spans = root.querySelectorAll(':scope > span');
|
|
15810
|
+
for (const span of Array.from(spans)) {
|
|
15811
|
+
// Width for a single-line ellipsis; height for a multi-line clamp.
|
|
15812
|
+
if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX ||
|
|
15813
|
+
span.scrollHeight > span.clientHeight + OVERFLOW_TOLERANCE_PX) {
|
|
15814
|
+
return span;
|
|
15815
|
+
}
|
|
15816
|
+
}
|
|
15817
|
+
return null;
|
|
15818
|
+
}
|
|
15819
|
+
/**
|
|
15820
|
+
* Returns the full text of the first direct-child `<span>` of `ref` that is
|
|
15821
|
+
* clipped by its container (i.e. showing an ellipsis), else `null` — so callers
|
|
15822
|
+
* can surface a tooltip only when the label is actually unreadable.
|
|
15823
|
+
*
|
|
15824
|
+
* Re-measures on element resize (sidebar expand/collapse, window resize) and on
|
|
15825
|
+
* label text changes.
|
|
15826
|
+
*/
|
|
15827
|
+
function useTruncatedText(ref) {
|
|
15828
|
+
const [text, setText] = useState(null);
|
|
15829
|
+
useEffect(() => {
|
|
15830
|
+
const el = ref.current;
|
|
15831
|
+
if (!el)
|
|
15832
|
+
return;
|
|
15833
|
+
let frame = 0;
|
|
15834
|
+
const measure = () => {
|
|
15835
|
+
const label = findClippedLabel(el);
|
|
15836
|
+
setText(label?.textContent?.trim() || null);
|
|
15837
|
+
};
|
|
15838
|
+
const schedule = () => {
|
|
15839
|
+
cancelAnimationFrame(frame);
|
|
15840
|
+
frame = requestAnimationFrame(measure);
|
|
15841
|
+
};
|
|
15842
|
+
schedule();
|
|
15843
|
+
const resizeObserver = new ResizeObserver(schedule);
|
|
15844
|
+
resizeObserver.observe(el);
|
|
15845
|
+
const mutationObserver = new MutationObserver(schedule);
|
|
15846
|
+
mutationObserver.observe(el, {
|
|
15847
|
+
characterData: true,
|
|
15848
|
+
childList: true,
|
|
15849
|
+
subtree: true,
|
|
15850
|
+
});
|
|
15851
|
+
return () => {
|
|
15852
|
+
cancelAnimationFrame(frame);
|
|
15853
|
+
resizeObserver.disconnect();
|
|
15854
|
+
mutationObserver.disconnect();
|
|
15855
|
+
};
|
|
15856
|
+
}, [ref]);
|
|
15857
|
+
return text;
|
|
15858
|
+
}
|
|
15859
|
+
|
|
15860
|
+
/** Single-line label that shows its full text in a tooltip, only while it is cut off. */
|
|
15861
|
+
function TruncatedLabel({ text, className, }) {
|
|
15862
|
+
const ref = useRef(null);
|
|
15863
|
+
const clipped = useTruncatedText(ref);
|
|
15864
|
+
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 })] }) }));
|
|
15865
|
+
}
|
|
15866
|
+
|
|
15867
|
+
function filterOptionsByQuery(options, query) {
|
|
15868
|
+
const needle = query.trim().toLowerCase();
|
|
15869
|
+
if (!needle)
|
|
15870
|
+
return [...options];
|
|
15871
|
+
return options.filter((option) => option.label.toLowerCase().includes(needle));
|
|
15872
|
+
}
|
|
15873
|
+
const getChipClassName = getPillClassName;
|
|
15874
|
+
function getTileClassName(selected) {
|
|
15875
|
+
return getSelectableOptionClassName(selected, 'flex min-h-12 min-w-0 flex-col items-center justify-center gap-0.5 rounded-md px-2 py-1.5 text-center');
|
|
15876
|
+
}
|
|
15877
|
+
/** The list's search box only appears once there are enough options to need it. */
|
|
15878
|
+
const SEARCH_MIN_OPTIONS = 9;
|
|
15879
|
+
/** Long option sets scroll inside the card or popover instead of growing it. */
|
|
15880
|
+
const OPTIONS_SCROLL_CLASS_NAME = 'max-h-48 overflow-y-auto';
|
|
15881
|
+
/** Fills a stretched card: at least the usual height, growing into any space the row gives it (never driving the row height). */
|
|
15882
|
+
const OPTIONS_FILL_CLASS_NAME = 'min-h-48 flex-1 basis-0 overflow-y-auto';
|
|
15883
|
+
const FILL_WRAPPER_CLASS_NAME = 'flex min-h-0 flex-1 flex-col';
|
|
15884
|
+
/** Card lists flow into as many columns as fit; popover lists stay one column. */
|
|
15885
|
+
const LIST_COLUMN_MIN_WIDTH = '10rem';
|
|
15886
|
+
const getOptionsScrollClassName = (fill) => fill ? OPTIONS_FILL_CLASS_NAME : OPTIONS_SCROLL_CLASS_NAME;
|
|
15887
|
+
const LIST_ROW_CLASS_NAME = getOptionRowClassName();
|
|
15888
|
+
/** Picking a value: a single-choice list replaces (or clears) it, a multi-choice list toggles it. */
|
|
15889
|
+
const pickValue = (values, value, single) => {
|
|
15890
|
+
if (!single)
|
|
15891
|
+
return toggleValue(values, value);
|
|
15892
|
+
return values.includes(value) ? [] : [value];
|
|
15893
|
+
};
|
|
15894
|
+
/** The single-choice counterpart of the checkbox: same size, primary dot when picked. */
|
|
15895
|
+
const LIST_RADIO_CLASS_NAME = 'size-4.5 shrink-0 cursor-pointer accent-primary';
|
|
15896
|
+
/** Outlined (not filled) box until checked; the border is dark enough to read on white. */
|
|
15897
|
+
const LIST_CHECKBOX_CLASS_NAME = 'size-4.5 border-muted-foreground/50 bg-card dark:border-muted-foreground/60 dark:bg-transparent';
|
|
15898
|
+
const SEARCH_BOX_CLASS_NAME = FILTER_SEARCH_BOX_CLASS_NAME;
|
|
15899
|
+
|
|
15900
|
+
function usePickListFilter({ options, value, layout, }) {
|
|
15901
|
+
const [query, setQuery] = useState('');
|
|
15902
|
+
const visibleOptions = useMemo(() => (layout === 'list' ? filterOptionsByQuery(options, query) : options), [layout, options, query]);
|
|
15903
|
+
const selectedCount = useMemo(() => options.filter((option) => value.includes(option.value)).length, [options, value]);
|
|
15904
|
+
return { query, setQuery, visibleOptions, selectedCount };
|
|
15905
|
+
}
|
|
15906
|
+
|
|
15907
|
+
const getSearchInputLabel = (ariaLabel) => `Search ${ariaLabel}`;
|
|
15908
|
+
|
|
15909
|
+
function OptionSwatch({ color, round, }) {
|
|
15910
|
+
if (!color)
|
|
15911
|
+
return null;
|
|
15912
|
+
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 } }));
|
|
15913
|
+
}
|
|
15914
|
+
/** Multi-select filter: a searchable checkbox list, or pill / tile toggles. Long sets scroll within a max height. */
|
|
15915
|
+
function PickListFilter({ options, value, onChange, ariaLabel, layout = 'list', searchPlaceholder, alwaysSearchable = false, columns = 5, fill = false, listClassName, single = false, }) {
|
|
15916
|
+
const { query, setQuery, visibleOptions, selectedCount } = usePickListFilter({
|
|
15917
|
+
options,
|
|
15918
|
+
value,
|
|
15919
|
+
layout,
|
|
15920
|
+
});
|
|
15921
|
+
const radioName = useId$2();
|
|
15922
|
+
const scrollClassName = getOptionsScrollClassName(fill);
|
|
15923
|
+
// Rows with a right-hand hint read best in one column.
|
|
15924
|
+
const multiColumn = fill && !options.some((option) => option.hint);
|
|
15925
|
+
const wrapperClassName = fill ? FILL_WRAPPER_CLASS_NAME : undefined;
|
|
15926
|
+
const toggle = (option) => onChange(pickValue(value, option.value, single));
|
|
15927
|
+
if (options.length === 0) {
|
|
15928
|
+
return (jsx("p", { className: "px-1 py-2 text-xs text-muted-foreground", children: "No options available" }));
|
|
15929
|
+
}
|
|
15930
|
+
if (layout === 'list') {
|
|
15931
|
+
return (jsxs("div", { className: cn('flex flex-col gap-2', fill && FILL_WRAPPER_CLASS_NAME), "aria-label": ariaLabel, role: "group", children: [searchPlaceholder !== undefined &&
|
|
15932
|
+
(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
|
|
15933
|
+
? getGridColumnsStyle(undefined, LIST_COLUMN_MIN_WIDTH)
|
|
15934
|
+
: undefined, wrapperClassName: wrapperClassName, children: visibleOptions.map((option) => (jsxs("label", { className: LIST_ROW_CLASS_NAME, children: [single ? (jsx("input", { type: "radio", name: radioName, checked: value.includes(option.value),
|
|
15935
|
+
// A click on the picked row clears it (radios can't be unticked natively).
|
|
15936
|
+
onClick: () => toggle(option), onChange: () => undefined, className: LIST_RADIO_CLASS_NAME })) : (jsx(Checkbox, { className: LIST_CHECKBOX_CLASS_NAME, checked: value.includes(option.value), onCheckedChange: () => toggle(option) })), 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 })), jsx(OptionSwatch, { color: option.swatch })] }, option.value))) })] }));
|
|
15937
|
+
}
|
|
15938
|
+
if (layout === 'tiles') {
|
|
15939
|
+
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))) }));
|
|
15940
|
+
}
|
|
15941
|
+
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))) }));
|
|
15942
|
+
}
|
|
15943
|
+
|
|
15388
15944
|
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';
|
|
15389
|
-
const TRIGGER_ACTIVE = '!border-primary
|
|
15945
|
+
const TRIGGER_ACTIVE = '!border-primary bg-primary/5 text-primary';
|
|
15390
15946
|
const CONTENT_BASE = 'min-w-[8rem]';
|
|
15391
15947
|
const isFilterActive = (value, resetValue) => !!value && value !== resetValue;
|
|
15948
|
+
function collectText(node) {
|
|
15949
|
+
if (typeof node === 'string' || typeof node === 'number')
|
|
15950
|
+
return String(node);
|
|
15951
|
+
if (Array.isArray(node))
|
|
15952
|
+
return node.map(collectText).join(' ');
|
|
15953
|
+
if (isValidElement(node))
|
|
15954
|
+
return Children.toArray(node.props.children).map(collectText).join(' ');
|
|
15955
|
+
return '';
|
|
15956
|
+
}
|
|
15957
|
+
/** The visible text inside a label, e.g. a JSX name + description becomes "Name Description". */
|
|
15958
|
+
const getNodeText = (node) => collectText(node).replace(/\s+/g, ' ').trim();
|
|
15959
|
+
/** A JSX label keeps its look as the row's `content`; its text (or the value) is what search and screen readers use. */
|
|
15960
|
+
const toPickListOptions = (options) => options.map((option) => typeof option.label === 'string'
|
|
15961
|
+
? { value: option.value, label: option.label }
|
|
15962
|
+
: {
|
|
15963
|
+
value: option.value,
|
|
15964
|
+
label: getNodeText(option.label) || option.value,
|
|
15965
|
+
content: option.label,
|
|
15966
|
+
});
|
|
15392
15967
|
|
|
15393
15968
|
/**
|
|
15394
|
-
* Multi-select filter dropdown
|
|
15395
|
-
*
|
|
15396
|
-
* Selecting
|
|
15969
|
+
* Multi-select filter dropdown with the `FilterSelect` trigger look (filter icon + count badge when active).
|
|
15970
|
+
* Opens a pick list: a searchable checkbox list with "x of y selected · Clear", or chips/tiles under a
|
|
15971
|
+
* title, count and Clear. Selecting keeps the popover open.
|
|
15397
15972
|
*/
|
|
15398
|
-
const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, }) => {
|
|
15973
|
+
const FilterMultiSelect = ({ label, value, onChange, options, triggerClassName, contentClassName, listClassName, modal = false, pickListLayout = 'list', searchPlaceholder, }) => {
|
|
15399
15974
|
const active = value.length > 0;
|
|
15400
|
-
const
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
else {
|
|
15405
|
-
onChange([...value, optValue]);
|
|
15406
|
-
}
|
|
15407
|
-
};
|
|
15408
|
-
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) => {
|
|
15409
|
-
const checked = value.includes(opt.value);
|
|
15410
|
-
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),
|
|
15411
|
-
// Stop the inner checkbox click from double-toggling via the button.
|
|
15412
|
-
onClick: (e) => e.stopPropagation() }), jsx("span", { className: "flex-1 truncate", children: opt.label })] }, opt.value));
|
|
15413
|
-
}) }) })] }));
|
|
15975
|
+
const isList = pickListLayout === 'list';
|
|
15976
|
+
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: cn('ml-1', FILTER_COUNT_BADGE_CLASS_NAME), children: value.length }))] }) }), jsx(PopoverContent, { align: "start", sideOffset: 4, className: cn('w-64 p-0', contentClassName), children: jsx(FilterPanel, { variant: "popover",
|
|
15977
|
+
// A searchable list has its own "x of y selected · Clear" row.
|
|
15978
|
+
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 }) }) })] }));
|
|
15414
15979
|
};
|
|
15415
15980
|
|
|
15416
15981
|
const KYC_STATUS = {
|
|
@@ -21669,6 +22234,34 @@ function useRowEditing({ saving, onEditChange, onSaveRow, }) {
|
|
|
21669
22234
|
handleEditIconClick,
|
|
21670
22235
|
};
|
|
21671
22236
|
}
|
|
22237
|
+
/**
|
|
22238
|
+
* Measures the rows area so a loading skeleton can cover exactly the rows it replaces —
|
|
22239
|
+
* the rows stay in the layout (hidden), so column widths and table height never jump.
|
|
22240
|
+
*/
|
|
22241
|
+
function useLoadingOverlay(scrollRef, headRef, bodyRef, loading) {
|
|
22242
|
+
const [box, setBox] = useState(null);
|
|
22243
|
+
useLayoutEffect(() => {
|
|
22244
|
+
const scroll = scrollRef.current;
|
|
22245
|
+
const head = headRef.current;
|
|
22246
|
+
const body = bodyRef.current;
|
|
22247
|
+
if (!loading || !scroll || !head || !body) {
|
|
22248
|
+
setBox(null);
|
|
22249
|
+
return;
|
|
22250
|
+
}
|
|
22251
|
+
const measure = () => setBox({
|
|
22252
|
+
top: head.offsetHeight,
|
|
22253
|
+
width: scroll.scrollWidth,
|
|
22254
|
+
height: body.offsetHeight,
|
|
22255
|
+
visibleWidth: scroll.clientWidth,
|
|
22256
|
+
});
|
|
22257
|
+
measure();
|
|
22258
|
+
const observer = new ResizeObserver(measure);
|
|
22259
|
+
observer.observe(scroll);
|
|
22260
|
+
observer.observe(body);
|
|
22261
|
+
return () => observer.disconnect();
|
|
22262
|
+
}, [loading, scrollRef, headRef, bodyRef]);
|
|
22263
|
+
return box;
|
|
22264
|
+
}
|
|
21672
22265
|
|
|
21673
22266
|
function normalizeOptions(options) {
|
|
21674
22267
|
return options.map((opt) => typeof opt === 'string'
|
|
@@ -21699,6 +22292,30 @@ function pinnedHeaderClass() {
|
|
|
21699
22292
|
function pinnedCellClass(pinnedBg) {
|
|
21700
22293
|
return cn('sticky right-0 z-10', PINNED_BEFORE, PINNED_SHADOW, pinnedBg);
|
|
21701
22294
|
}
|
|
22295
|
+
const PINNED_RIGHT_WIDTH = '72px';
|
|
22296
|
+
/** Width for a header/body/filter cell: the resized width var while resized or dragging, a fixed width for the pinned actions column. */
|
|
22297
|
+
function getColumnWidthStyle(key, isSized, isPinnedRight) {
|
|
22298
|
+
if (isSized) {
|
|
22299
|
+
const width = `var(--col-w-${key})`;
|
|
22300
|
+
return { width, minWidth: width, maxWidth: width };
|
|
22301
|
+
}
|
|
22302
|
+
return isPinnedRight
|
|
22303
|
+
? {
|
|
22304
|
+
width: PINNED_RIGHT_WIDTH,
|
|
22305
|
+
minWidth: PINNED_RIGHT_WIDTH,
|
|
22306
|
+
maxWidth: PINNED_RIGHT_WIDTH,
|
|
22307
|
+
}
|
|
22308
|
+
: undefined;
|
|
22309
|
+
}
|
|
22310
|
+
function hasFilterRow(columns, filterRowLeading) {
|
|
22311
|
+
return (filterRowLeading != null || columns.some((col) => col.filter !== undefined));
|
|
22312
|
+
}
|
|
22313
|
+
/** `TableRowsSkeleton` bar (52px) plus its gap (8px). */
|
|
22314
|
+
const SKELETON_ROW_PX = 60;
|
|
22315
|
+
/** How many skeleton bars fill a rows area of `height` px (at least one). */
|
|
22316
|
+
function getSkeletonRowCount(height) {
|
|
22317
|
+
return Math.max(1, Math.floor(height / SKELETON_ROW_PX));
|
|
22318
|
+
}
|
|
21702
22319
|
|
|
21703
22320
|
const isValidHex = (v) => /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(v);
|
|
21704
22321
|
/**
|
|
@@ -21790,8 +22407,52 @@ function EditableCellContent({ col, row, value, isEditing, width, onEditValueCha
|
|
|
21790
22407
|
}
|
|
21791
22408
|
return jsx(Fragment$2, { children: clipToWidth(stringValue, width) });
|
|
21792
22409
|
}
|
|
22410
|
+
const FILTER_CELL = 'px-0.5 py-0.5 font-normal border-b border-solid !border-border';
|
|
22411
|
+
/** Opt-in second header row holding each column's filter control. */
|
|
22412
|
+
function FilterRow({ columns, leading, showEditColumn, showSelectionColumn, isArchiveView, vBorder, localWidths, draggingKey, }) {
|
|
22413
|
+
const leadingCellCount = Number(showEditColumn) + Number(showSelectionColumn);
|
|
22414
|
+
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) => {
|
|
22415
|
+
const isPinnedRight = col.key === 'actions';
|
|
22416
|
+
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()));
|
|
22417
|
+
})] }));
|
|
22418
|
+
}
|
|
22419
|
+
/** Keeps the real pagination in the layout (hidden) and lays a placeholder over it, so the footer height never jumps. */
|
|
22420
|
+
function PaginationLoading({ children, }) {
|
|
22421
|
+
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" })] })] }));
|
|
22422
|
+
}
|
|
21793
22423
|
|
|
21794
|
-
|
|
22424
|
+
/** Label line + input block — mirrors a `Field`. */
|
|
22425
|
+
function FieldSkeleton() {
|
|
22426
|
+
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" })] }));
|
|
22427
|
+
}
|
|
22428
|
+
/**
|
|
22429
|
+
* Loading placeholder that matches a `FormSectionCard` — the tinted header band
|
|
22430
|
+
* (icon square + title + description) above a body of `Field` placeholders and
|
|
22431
|
+
* an optional footer action row.
|
|
22432
|
+
*/
|
|
22433
|
+
function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
|
|
22434
|
+
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" })] }))] })] }));
|
|
22435
|
+
}
|
|
22436
|
+
/** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
|
|
22437
|
+
function TableSkeleton({ rows = 8 }) {
|
|
22438
|
+
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)))] }));
|
|
22439
|
+
}
|
|
22440
|
+
/** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
|
|
22441
|
+
function TableRowsSkeleton({ rows = 10, className }) {
|
|
22442
|
+
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) => (
|
|
22443
|
+
// shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
|
|
22444
|
+
jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
|
|
22445
|
+
}
|
|
22446
|
+
/** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
|
|
22447
|
+
function DetailPageSkeleton({ sections = 3, }) {
|
|
22448
|
+
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)))] }));
|
|
22449
|
+
}
|
|
22450
|
+
/** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
|
|
22451
|
+
function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
|
|
22452
|
+
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 })] }));
|
|
22453
|
+
}
|
|
22454
|
+
|
|
22455
|
+
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, }) {
|
|
21795
22456
|
const showSelectionColumn = enableSelection && (!isArchiveView || selectionInArchiveView);
|
|
21796
22457
|
const vBorder = showGrid ? 'border-r' : '';
|
|
21797
22458
|
const { localWidths, draggingKey, tableRef, handleResizeMouseDown } = useColumnResize({
|
|
@@ -21804,6 +22465,11 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
|
|
|
21804
22465
|
onSelectionChange,
|
|
21805
22466
|
});
|
|
21806
22467
|
const { editingRow, editValues, savingRow, handleEditValueChange, handleEditIconClick, } = useRowEditing({ saving, onEditChange, onSaveRow });
|
|
22468
|
+
const scrollRef = useRef(null);
|
|
22469
|
+
const headRef = useRef(null);
|
|
22470
|
+
const bodyRef = useRef(null);
|
|
22471
|
+
// Rows stay in the layout while loading; the skeleton covers them so nothing resizes.
|
|
22472
|
+
const overlay = useLoadingOverlay(scrollRef, headRef, bodyRef, loading);
|
|
21807
22473
|
const handleColumnClick = (columnKey, sortable) => {
|
|
21808
22474
|
if (!sortable || !setSortBy || !setSortOrder)
|
|
21809
22475
|
return;
|
|
@@ -21815,25 +22481,17 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
|
|
|
21815
22481
|
setSortOrder('asc');
|
|
21816
22482
|
}
|
|
21817
22483
|
};
|
|
21818
|
-
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: [
|
|
21819
|
-
|
|
21820
|
-
|
|
21821
|
-
|
|
21822
|
-
|
|
21823
|
-
|
|
21824
|
-
|
|
21825
|
-
|
|
21826
|
-
|
|
21827
|
-
? {
|
|
21828
|
-
|
|
21829
|
-
minWidth: `var(--col-w-${col.key})`,
|
|
21830
|
-
maxWidth: `var(--col-w-${col.key})`,
|
|
21831
|
-
}
|
|
21832
|
-
: isPinnedRight
|
|
21833
|
-
? { width: '72px', minWidth: '72px', maxWidth: '72px' }
|
|
21834
|
-
: undefined;
|
|
21835
|
-
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()));
|
|
21836
|
-
})] }) }), jsx("tbody", { children: data.map((row, rowIndex) => {
|
|
22484
|
+
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
|
|
22485
|
+
? true
|
|
22486
|
+
: someSelected
|
|
22487
|
+
? 'indeterminate'
|
|
22488
|
+
: false, onCheckedChange: toggleSelectAll }) })), columns.map((col) => {
|
|
22489
|
+
const w = localWidths[col.key];
|
|
22490
|
+
const isDragging = draggingKey === col.key;
|
|
22491
|
+
const isPinnedRight = col.key === 'actions';
|
|
22492
|
+
const thStyle = getColumnWidthStyle(col.key, Boolean(w) || isDragging, isPinnedRight);
|
|
22493
|
+
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()));
|
|
22494
|
+
})] }), 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) => {
|
|
21837
22495
|
const isEditing = editingRow === row.id && editingRow !== null;
|
|
21838
22496
|
const isSaving = savingRow === row.id;
|
|
21839
22497
|
const isSelected = selectedSet.has(row.id);
|
|
@@ -21853,19 +22511,7 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
|
|
|
21853
22511
|
: row[col.key];
|
|
21854
22512
|
const w = localWidths[col.key];
|
|
21855
22513
|
const isPinnedRight = col.key === 'actions';
|
|
21856
|
-
const tdStyle = w || draggingKey === col.key
|
|
21857
|
-
? {
|
|
21858
|
-
width: `var(--col-w-${col.key})`,
|
|
21859
|
-
minWidth: `var(--col-w-${col.key})`,
|
|
21860
|
-
maxWidth: `var(--col-w-${col.key})`,
|
|
21861
|
-
}
|
|
21862
|
-
: isPinnedRight
|
|
21863
|
-
? {
|
|
21864
|
-
width: '72px',
|
|
21865
|
-
minWidth: '72px',
|
|
21866
|
-
maxWidth: '72px',
|
|
21867
|
-
}
|
|
21868
|
-
: undefined;
|
|
22514
|
+
const tdStyle = getColumnWidthStyle(col.key, Boolean(w) || draggingKey === col.key, isPinnedRight);
|
|
21869
22515
|
// Pinned cells need an OPAQUE bg matching the row state so the
|
|
21870
22516
|
// scrolling content underneath doesn't bleed through — no alpha tints.
|
|
21871
22517
|
const pinnedBg = isPinnedRight
|
|
@@ -21881,7 +22527,13 @@ function DataEditableTable({ data, columns, onRowClick, enableSelection = false,
|
|
|
21881
22527
|
? 'text-right'
|
|
21882
22528
|
: '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()));
|
|
21883
22529
|
})] }, row.id));
|
|
21884
|
-
}) })] }),
|
|
22530
|
+
}) })] }), overlay && overlay.height > 0 ? (
|
|
22531
|
+
// `overflow-clip`, not `hidden`: hidden makes this box the sticky skeleton's scroller, pinning it to scrollLeft 0.
|
|
22532
|
+
jsx("div", { className: "absolute left-0 z-10 overflow-clip bg-card", style: {
|
|
22533
|
+
top: overlay.top,
|
|
22534
|
+
width: overlay.width,
|
|
22535
|
+
height: overlay.height,
|
|
22536
|
+
}, 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)] }));
|
|
21885
22537
|
}
|
|
21886
22538
|
|
|
21887
22539
|
/**
|
|
@@ -37556,7 +38208,7 @@ function SelectScrollDownButton({ className, ...props }) {
|
|
|
37556
38208
|
|
|
37557
38209
|
const FilterSelect = ({ label, value, onValueChange, options, resetValue = 'all', activeCount = 1, searchable, triggerClassName, contentClassName, }) => {
|
|
37558
38210
|
const active = isFilterActive(value, resetValue);
|
|
37559
|
-
return (jsxs(Select, { value: value, onValueChange: onValueChange, keepOpenOnSelect: true, children: [jsxs(SelectTrigger, { className: cn(TRIGGER_BASE, active && TRIGGER_ACTIVE, triggerClassName), children: [jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), jsxs("span", { className: "flex items-center gap-1", children: [jsx(SelectValue, { placeholder: label }), active && (jsx("span", { className:
|
|
38211
|
+
return (jsxs(Select, { value: value, onValueChange: onValueChange, keepOpenOnSelect: true, children: [jsxs(SelectTrigger, { className: cn(TRIGGER_BASE, active && TRIGGER_ACTIVE, triggerClassName), children: [jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), jsxs("span", { className: "flex items-center gap-1", children: [jsx(SelectValue, { placeholder: label }), active && (jsx("span", { className: cn('ml-1', FILTER_COUNT_BADGE_CLASS_NAME), children: activeCount }))] })] }), jsxs(SelectContent, { className: cn(CONTENT_BASE, contentClassName), searchable: searchable, children: [jsx(SelectItem, { value: resetValue, withCheckbox: true, children: label }), options.map((opt) => (jsx(SelectItem, { value: opt.value, searchValue: opt.searchValue, withCheckbox: true, children: opt.label }, opt.value)))] })] }));
|
|
37560
38212
|
};
|
|
37561
38213
|
|
|
37562
38214
|
/**
|
|
@@ -37901,6 +38553,824 @@ function fieldTypeIcon(type) {
|
|
|
37901
38553
|
return FIELD_TYPE_ICONS[type] ?? Type;
|
|
37902
38554
|
}
|
|
37903
38555
|
|
|
38556
|
+
const getRemoveChipLabel = (label) => `Remove ${label} filter`;
|
|
38557
|
+
const FILTERED_BY_LABEL = 'Filtered by';
|
|
38558
|
+
|
|
38559
|
+
/** Compact badge shape with the filter chip colours. */
|
|
38560
|
+
const CHIP_CLASS = 'inline-flex h-7 max-w-full items-center gap-1 rounded-md border border-primary/30 bg-primary/5 px-2.5 text-xs text-foreground';
|
|
38561
|
+
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';
|
|
38562
|
+
const CLEAR_ALL_CLASS = cn(FILTER_LINK_CLASS_NAME, 'underline');
|
|
38563
|
+
function getChipLabelText(label, variant) {
|
|
38564
|
+
return variant === 'inline' ? `${label}:` : label;
|
|
38565
|
+
}
|
|
38566
|
+
|
|
38567
|
+
/** Applied filters as removable chips, with an optional Clear all. */
|
|
38568
|
+
function ActiveFilterChips({ chips, onRemove, onClearAll, variant = 'inline', actions, className, }) {
|
|
38569
|
+
if (chips.length === 0)
|
|
38570
|
+
return null;
|
|
38571
|
+
const clearAll = onClearAll && (jsx("button", { type: "button", onClick: onClearAll, className: CLEAR_ALL_CLASS, children: "Clear all" }));
|
|
38572
|
+
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))), actions ? (
|
|
38573
|
+
// With actions, Clear all joins them at the row's right end.
|
|
38574
|
+
jsxs("div", { className: "ml-auto flex items-center gap-3 pl-3", children: [clearAll, actions] })) : (clearAll)] }));
|
|
38575
|
+
}
|
|
38576
|
+
|
|
38577
|
+
const DEFAULT_CONTAINS_PLACEHOLDER = 'Contains…';
|
|
38578
|
+
|
|
38579
|
+
/**
|
|
38580
|
+
* Local text for a typed filter. It resets to `externalText` only when the applied value
|
|
38581
|
+
* (`externalKey`) changes from outside — e.g. Clear all — not when the change is this field's own commit.
|
|
38582
|
+
*/
|
|
38583
|
+
function useFilterDraft(externalKey, externalText) {
|
|
38584
|
+
const [draft, setDraft] = useState(externalText);
|
|
38585
|
+
const [seenKey, setSeenKey] = useState(externalKey);
|
|
38586
|
+
const [committedKey, setCommittedKey] = useState(externalKey);
|
|
38587
|
+
if (seenKey !== externalKey) {
|
|
38588
|
+
setSeenKey(externalKey);
|
|
38589
|
+
if (externalKey !== committedKey) {
|
|
38590
|
+
setCommittedKey(externalKey);
|
|
38591
|
+
setDraft(externalText);
|
|
38592
|
+
}
|
|
38593
|
+
}
|
|
38594
|
+
return { draft, setDraft, markCommitted: setCommittedKey };
|
|
38595
|
+
}
|
|
38596
|
+
/** Debounces `callback`; a call still pending when the field unmounts (e.g. its popover closes) is flushed, not lost. */
|
|
38597
|
+
function useDebouncedCallback(callback, delay) {
|
|
38598
|
+
const callbackRef = useRef(callback);
|
|
38599
|
+
const timerRef = useRef(null);
|
|
38600
|
+
const pendingRef = useRef(null);
|
|
38601
|
+
useEffect(() => {
|
|
38602
|
+
callbackRef.current = callback;
|
|
38603
|
+
}, [callback]);
|
|
38604
|
+
const cancel = useCallback(() => {
|
|
38605
|
+
if (timerRef.current)
|
|
38606
|
+
clearTimeout(timerRef.current);
|
|
38607
|
+
timerRef.current = null;
|
|
38608
|
+
pendingRef.current = null;
|
|
38609
|
+
}, []);
|
|
38610
|
+
const flush = useCallback(() => {
|
|
38611
|
+
const pending = pendingRef.current;
|
|
38612
|
+
cancel();
|
|
38613
|
+
if (pending)
|
|
38614
|
+
callbackRef.current(...pending);
|
|
38615
|
+
}, [cancel]);
|
|
38616
|
+
const schedule = useCallback((...args) => {
|
|
38617
|
+
if (timerRef.current)
|
|
38618
|
+
clearTimeout(timerRef.current);
|
|
38619
|
+
pendingRef.current = args;
|
|
38620
|
+
timerRef.current = setTimeout(flush, delay);
|
|
38621
|
+
}, [delay, flush]);
|
|
38622
|
+
useEffect(() => flush, [flush]);
|
|
38623
|
+
return { schedule, flush, cancel };
|
|
38624
|
+
}
|
|
38625
|
+
|
|
38626
|
+
const COMMIT_DELAY_MS$2 = 400;
|
|
38627
|
+
function useContainsFilter(value, onChange) {
|
|
38628
|
+
const { draft, setDraft, markCommitted } = useFilterDraft(value, value);
|
|
38629
|
+
const commit = useCallback((text) => {
|
|
38630
|
+
const trimmed = text.trim();
|
|
38631
|
+
markCommitted(trimmed);
|
|
38632
|
+
if (trimmed !== value)
|
|
38633
|
+
onChange(trimmed);
|
|
38634
|
+
}, [markCommitted, onChange, value]);
|
|
38635
|
+
const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$2);
|
|
38636
|
+
return {
|
|
38637
|
+
draft,
|
|
38638
|
+
handleChange: (event) => {
|
|
38639
|
+
setDraft(event.target.value);
|
|
38640
|
+
debounced.schedule(event.target.value);
|
|
38641
|
+
},
|
|
38642
|
+
handleKeyDown: (event) => {
|
|
38643
|
+
if (event.key === 'Enter')
|
|
38644
|
+
debounced.flush();
|
|
38645
|
+
},
|
|
38646
|
+
handleBlur: debounced.flush,
|
|
38647
|
+
};
|
|
38648
|
+
}
|
|
38649
|
+
|
|
38650
|
+
function getContainsClassName(size, applied, className) {
|
|
38651
|
+
if (size === 'cell')
|
|
38652
|
+
return getFilterFieldClassName(applied ? 'applied' : 'empty', className);
|
|
38653
|
+
return cn('h-9 text-sm', applied && 'border-primary bg-primary/5', className);
|
|
38654
|
+
}
|
|
38655
|
+
|
|
38656
|
+
/** "Contains…" text filter, as a filter-row cell or a full-size card field. */
|
|
38657
|
+
function ContainsFilter({ value, onChange, ariaLabel, placeholder = DEFAULT_CONTAINS_PLACEHOLDER, size = 'cell', className, }) {
|
|
38658
|
+
const { draft, handleChange, handleKeyDown, handleBlur } = useContainsFilter(value, onChange);
|
|
38659
|
+
const inputProps = {
|
|
38660
|
+
type: 'text',
|
|
38661
|
+
value: draft,
|
|
38662
|
+
placeholder,
|
|
38663
|
+
'aria-label': ariaLabel,
|
|
38664
|
+
onChange: handleChange,
|
|
38665
|
+
onKeyDown: handleKeyDown,
|
|
38666
|
+
onBlur: handleBlur,
|
|
38667
|
+
className: getContainsClassName(size, value.trim() !== '', className),
|
|
38668
|
+
};
|
|
38669
|
+
return size === 'cell' ? (jsx("input", { ...inputProps })) : (jsx(Input, { ...inputProps }));
|
|
38670
|
+
}
|
|
38671
|
+
|
|
38672
|
+
const getPresetGroupLabel = (ariaLabel) => `${ariaLabel} presets`;
|
|
38673
|
+
const getDateInputLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
|
|
38674
|
+
|
|
38675
|
+
/** Dates shown in the inputs: a preset's resolved range, or the custom range. */
|
|
38676
|
+
function getDisplayedRange(value, today, fiscalYearStartMonth) {
|
|
38677
|
+
if (value?.preset)
|
|
38678
|
+
return resolveDatePreset(value.preset, today, fiscalYearStartMonth);
|
|
38679
|
+
return { from: value?.from ?? '', to: value?.to ?? '' };
|
|
38680
|
+
}
|
|
38681
|
+
function buildCustomRange(from, to) {
|
|
38682
|
+
return from || to
|
|
38683
|
+
? { from: from || undefined, to: to || undefined }
|
|
38684
|
+
: undefined;
|
|
38685
|
+
}
|
|
38686
|
+
function togglePreset(value, preset) {
|
|
38687
|
+
return value?.preset === preset ? undefined : { preset };
|
|
38688
|
+
}
|
|
38689
|
+
/** Preset row; the picked one gets the primary tint, as in the design. */
|
|
38690
|
+
const getPresetClassName$1 = (selected) => getOptionRowClassName(selected, 'whitespace-nowrap');
|
|
38691
|
+
|
|
38692
|
+
const toIsoOrEmpty = (date) => date ? toIsoDate(date) : '';
|
|
38693
|
+
function useDateRangeFilter(value, onChange, today, fiscalYearStartMonth) {
|
|
38694
|
+
const { from, to } = getDisplayedRange(value, today, fiscalYearStartMonth);
|
|
38695
|
+
return {
|
|
38696
|
+
from,
|
|
38697
|
+
to,
|
|
38698
|
+
selectPreset: (preset) => onChange(togglePreset(value, preset)),
|
|
38699
|
+
handleFromChange: (date) => onChange(buildCustomRange(toIsoOrEmpty(date), to)),
|
|
38700
|
+
handleToChange: (date) => onChange(buildCustomRange(from, toIsoOrEmpty(date))),
|
|
38701
|
+
clear: () => onChange(undefined),
|
|
38702
|
+
};
|
|
38703
|
+
}
|
|
38704
|
+
|
|
38705
|
+
/** Date filter body: presets on the left, a From / To range on the right. */
|
|
38706
|
+
function DateRangeFilter({ value, onChange, ariaLabel, fiscalYearStartMonth = 1, today = new Date(), }) {
|
|
38707
|
+
const { from, to, selectPreset, handleFromChange, handleToChange, clear } = useDateRangeFilter(value, onChange, today, fiscalYearStartMonth);
|
|
38708
|
+
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
|
|
38709
|
+
// The inputs sit on the card's right; an end-aligned calendar stays under them.
|
|
38710
|
+
, {
|
|
38711
|
+
// The inputs sit on the card's right; an end-aligned calendar stays under them.
|
|
38712
|
+
align: "end", 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" }))] })] }));
|
|
38713
|
+
}
|
|
38714
|
+
|
|
38715
|
+
const getClearButtonLabel = (ariaLabel) => `Clear ${ariaLabel}`;
|
|
38716
|
+
const NOT_FILTERABLE_LABEL = "This column can't be filtered";
|
|
38717
|
+
|
|
38718
|
+
/** Select-like filter-row control: a compact trigger that opens the filter's panel in a popover. */
|
|
38719
|
+
function FilterCellPopover({ label, placeholder, ariaLabel, state, disabledLabel = NOT_FILTERABLE_LABEL, icon, onClear, showChevron = true, open, onOpenChange, contentClassName, className, children, }) {
|
|
38720
|
+
if (state === 'disabled') {
|
|
38721
|
+
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 })] }) }));
|
|
38722
|
+
}
|
|
38723
|
+
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-full outline-none hover:bg-primary/10", children: jsx(X$2, { "aria-hidden": "true", className: "size-3" }) }))] }) }), jsx(PopoverContent, { align: "start",
|
|
38724
|
+
// The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
|
|
38725
|
+
updatePositionStrategy: "always", sideOffset: 4, className: cn('w-72 p-0', contentClassName), children: children })] }));
|
|
38726
|
+
}
|
|
38727
|
+
|
|
38728
|
+
const COUNT_WORDS = [
|
|
38729
|
+
'One',
|
|
38730
|
+
'Two',
|
|
38731
|
+
'Three',
|
|
38732
|
+
'Four',
|
|
38733
|
+
'Five',
|
|
38734
|
+
'Six',
|
|
38735
|
+
'Seven',
|
|
38736
|
+
'Eight',
|
|
38737
|
+
'Nine',
|
|
38738
|
+
'Ten',
|
|
38739
|
+
];
|
|
38740
|
+
/** `4` → `Four` for 1–10; any other count stays as digits. */
|
|
38741
|
+
function countToWord(count) {
|
|
38742
|
+
return COUNT_WORDS[count - 1] ?? String(count);
|
|
38743
|
+
}
|
|
38744
|
+
function getEmptyStateTitle(itemNoun) {
|
|
38745
|
+
return `No ${itemNoun}s match these filters`;
|
|
38746
|
+
}
|
|
38747
|
+
function getEmptyStateDescription(itemNoun, activeCount) {
|
|
38748
|
+
const filters = activeCount === 1 ? 'column filter is' : 'column filters are';
|
|
38749
|
+
return `${countToWord(activeCount)} ${filters} active. Loosen one, or clear them all to see every ${itemNoun}.`;
|
|
38750
|
+
}
|
|
38751
|
+
|
|
38752
|
+
/** Shown in place of rows when the applied column filters match nothing. */
|
|
38753
|
+
function FilterEmptyState({ itemNoun, title, description, activeCount, onClearAll, className, }) {
|
|
38754
|
+
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" })] }));
|
|
38755
|
+
}
|
|
38756
|
+
|
|
38757
|
+
function getScalePosition(options, value, option) {
|
|
38758
|
+
if (!value)
|
|
38759
|
+
return 'outside';
|
|
38760
|
+
if (option === value.from || option === value.to)
|
|
38761
|
+
return 'end';
|
|
38762
|
+
return expandScaleRange(options, value).includes(option)
|
|
38763
|
+
? 'between'
|
|
38764
|
+
: 'outside';
|
|
38765
|
+
}
|
|
38766
|
+
/** Next range after clicking `scale`: a fresh single-option range, or the end of the pending one. */
|
|
38767
|
+
function getNextScaleRange(anchor, option) {
|
|
38768
|
+
return anchor === null
|
|
38769
|
+
? { from: option, to: option }
|
|
38770
|
+
: { from: anchor, to: option };
|
|
38771
|
+
}
|
|
38772
|
+
function getScaleButtonClassName(position, fill = false) {
|
|
38773
|
+
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,
|
|
38774
|
+
// Unselected options look exactly like unselected pick-list tiles.
|
|
38775
|
+
position === 'outside' && getSelectableOptionClassName(false), position === 'end' &&
|
|
38776
|
+
'border-primary bg-primary font-medium text-primary-foreground', position === 'between' &&
|
|
38777
|
+
'border-primary/30 bg-primary/10 font-medium text-primary');
|
|
38778
|
+
}
|
|
38779
|
+
|
|
38780
|
+
/** First click picks the start option, the next click the end option; a click after that starts over. */
|
|
38781
|
+
function useScaleRangeFilter({ value, onChange, }) {
|
|
38782
|
+
const [anchor, setAnchor] = useState(null);
|
|
38783
|
+
// The start point only holds while the value is still that one option; Clear or any outside change drops it.
|
|
38784
|
+
const start = anchor !== null && value?.from === anchor && value.to === anchor
|
|
38785
|
+
? anchor
|
|
38786
|
+
: null;
|
|
38787
|
+
const selectOption = useCallback((option) => {
|
|
38788
|
+
onChange(getNextScaleRange(start, option));
|
|
38789
|
+
setAnchor(start === null ? option : null);
|
|
38790
|
+
}, [start, onChange]);
|
|
38791
|
+
return { selectOption };
|
|
38792
|
+
}
|
|
38793
|
+
|
|
38794
|
+
/** Ordered-scale filter: click a start option, then an end option. */
|
|
38795
|
+
function ScaleRangeFilter({ options, value, onChange, ariaLabel, columns, fill = false, }) {
|
|
38796
|
+
const { selectOption } = useScaleRangeFilter({ value, onChange });
|
|
38797
|
+
return (jsx("div", { role: "group", "aria-label": ariaLabel, className: fill ? 'grid gap-2' : 'grid gap-1.5', style: getGridColumnsStyle(columns), children: options.map((option) => {
|
|
38798
|
+
const position = getScalePosition(options, value, option.value);
|
|
38799
|
+
return (jsx("button", { type: "button", "aria-pressed": position !== 'outside', "aria-label": option.label, onClick: () => selectOption(option.value), className: getScaleButtonClassName(position, fill), children: jsx(TruncatedLabel, { text: option.label }) }, option.value));
|
|
38800
|
+
}) }));
|
|
38801
|
+
}
|
|
38802
|
+
|
|
38803
|
+
/** Varied widths so placeholder rows and pills read as text, not a block. */
|
|
38804
|
+
const LIST_ROW_WIDTHS = ['55%', '40%', '62%', '48%', '35%'];
|
|
38805
|
+
const PILL_WIDTHS = [72, 88, 64, 96, 76, 84];
|
|
38806
|
+
const TILE_KEYS = ['a', 'b', 'c', 'd'];
|
|
38807
|
+
const CARD_CLASS_NAME = 'flex h-full min-w-0 flex-col gap-3 rounded-xl border border-border bg-card p-4';
|
|
38808
|
+
|
|
38809
|
+
function Pills({ count }) {
|
|
38810
|
+
return (jsx("div", { className: "flex flex-wrap gap-1.5", children: PILL_WIDTHS.slice(0, count).map((width) => (jsx(SquareSkeleton, { height: 32, width: width, rounded: "full" }, width))) }));
|
|
38811
|
+
}
|
|
38812
|
+
function Body({ variant, }) {
|
|
38813
|
+
switch (variant) {
|
|
38814
|
+
case 'list':
|
|
38815
|
+
return (jsxs(Fragment$2, { children: [jsx(SquareSkeleton, { height: 36, rounded: "md" }), jsx(SquareSkeleton, { height: 12, width: 96, rounded: "sm" }), jsx("div", { className: "flex flex-col gap-3 px-2 pt-1", children: LIST_ROW_WIDTHS.map((width) => (jsxs("div", { className: "flex items-center gap-3", children: [jsx(SquareSkeleton, { height: 18, width: 18, rounded: "sm" }), jsx(SquareSkeleton, { height: 14, width: width, rounded: "sm" })] }, width))) })] }));
|
|
38816
|
+
case 'chips':
|
|
38817
|
+
return (jsxs(Fragment$2, { children: [jsx(SquareSkeleton, { height: 12, width: 64, rounded: "sm" }), jsx(Pills, { count: 3 }), jsx(SquareSkeleton, { height: 12, width: 80, rounded: "sm" }), jsx(Pills, { count: 4 })] }));
|
|
38818
|
+
case 'tiles':
|
|
38819
|
+
return (jsx("div", { className: "grid grid-cols-2 gap-2", children: TILE_KEYS.map((key) => (jsx(SquareSkeleton, { height: 48, rounded: "md" }, key))) }));
|
|
38820
|
+
case 'range':
|
|
38821
|
+
return (jsxs(Fragment$2, { children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(SquareSkeleton, { height: 36, rounded: "md" }), jsx(SquareSkeleton, { height: 2, width: 8, rounded: "full" }), jsx(SquareSkeleton, { height: 36, rounded: "md" })] }), jsx(SquareSkeleton, { height: 12, width: 88, rounded: "sm" }), jsx(Pills, { count: 6 })] }));
|
|
38822
|
+
case 'ids':
|
|
38823
|
+
return (jsxs(Fragment$2, { children: [jsx(SquareSkeleton, { height: 12, width: 64, rounded: "sm" }), jsx(SquareSkeleton, { height: 80, rounded: "md" }), jsx(SquareSkeleton, { height: 12, width: "75%", rounded: "sm" }), jsx(SquareSkeleton, { height: 12, width: 56, rounded: "sm" }), jsx(SquareSkeleton, { height: 36, rounded: "md" })] }));
|
|
38824
|
+
case 'select':
|
|
38825
|
+
return (jsxs(Fragment$2, { children: [jsx(SquareSkeleton, { height: 12, width: 64, rounded: "sm" }), jsx(SquareSkeleton, { height: 36, rounded: "md" })] }));
|
|
38826
|
+
}
|
|
38827
|
+
}
|
|
38828
|
+
/** Placeholder for one filter card while the filters load, shaped like the control it will hold. */
|
|
38829
|
+
function FilterCardSkeleton({ variant = 'list', className, }) {
|
|
38830
|
+
return (jsxs("div", { "aria-hidden": "true", className: cn(CARD_CLASS_NAME, className), children: [jsx(SquareSkeleton, { height: 16, width: 96, rounded: "sm" }), jsx(Body, { variant: variant })] }));
|
|
38831
|
+
}
|
|
38832
|
+
|
|
38833
|
+
const getClearIdsLabel = (ariaLabel) => `Clear ${ariaLabel}`;
|
|
38834
|
+
|
|
38835
|
+
const DEFAULT_ID_HELPER_TEXT = 'Paste from Excel or an email. Commas, spaces and new lines all split IDs.';
|
|
38836
|
+
function toIdsKey(ids) {
|
|
38837
|
+
return ids.join('\n');
|
|
38838
|
+
}
|
|
38839
|
+
function formatIdCount(count) {
|
|
38840
|
+
return `${count} ${count === 1 ? 'ID' : 'IDs'}`;
|
|
38841
|
+
}
|
|
38842
|
+
|
|
38843
|
+
const COMMIT_DELAY_MS$1 = 300;
|
|
38844
|
+
function useIdListInput(value, onChange) {
|
|
38845
|
+
const appliedKey = toIdsKey(value);
|
|
38846
|
+
const { draft, setDraft, markCommitted } = useFilterDraft(appliedKey, value.join(', '));
|
|
38847
|
+
const commit = useCallback((text) => {
|
|
38848
|
+
const ids = splitIdList(text);
|
|
38849
|
+
const key = toIdsKey(ids);
|
|
38850
|
+
markCommitted(key);
|
|
38851
|
+
if (key !== appliedKey)
|
|
38852
|
+
onChange(ids);
|
|
38853
|
+
}, [appliedKey, markCommitted, onChange]);
|
|
38854
|
+
const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS$1);
|
|
38855
|
+
return {
|
|
38856
|
+
draft,
|
|
38857
|
+
parsedIds: splitIdList(draft),
|
|
38858
|
+
handleChange: (event) => {
|
|
38859
|
+
setDraft(event.target.value);
|
|
38860
|
+
debounced.schedule(event.target.value);
|
|
38861
|
+
},
|
|
38862
|
+
handleBlur: debounced.flush,
|
|
38863
|
+
clear: () => {
|
|
38864
|
+
debounced.cancel();
|
|
38865
|
+
setDraft('');
|
|
38866
|
+
commit('');
|
|
38867
|
+
},
|
|
38868
|
+
};
|
|
38869
|
+
}
|
|
38870
|
+
|
|
38871
|
+
/** Paste-a-list body: a textarea split into IDs on commas, spaces and new lines, with the parsed IDs as chips. */
|
|
38872
|
+
function IdListInput({ value, onChange, ariaLabel, placeholder, helperText = DEFAULT_ID_HELPER_TEXT, showSummary = true, }) {
|
|
38873
|
+
const { draft, parsedIds, handleChange, handleBlur, clear } = useIdListInput(value, onChange);
|
|
38874
|
+
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/30 bg-primary/5 px-2 text-xs text-foreground", 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" })] })] }))] }));
|
|
38875
|
+
}
|
|
38876
|
+
|
|
38877
|
+
const NUMBER_HELP_HEADING = 'Type a value or a rule';
|
|
38878
|
+
const NUMBER_HELP_SUBTITLE = 'Click a rule to use it.';
|
|
38879
|
+
const getNumberErrorId = (baseId) => `${baseId}-error`;
|
|
38880
|
+
const getUseRuleLabel = (rule, meaning) => `Use ${rule}: ${meaning}`;
|
|
38881
|
+
|
|
38882
|
+
function getNumberFieldState(parsed) {
|
|
38883
|
+
if (!parsed.ok)
|
|
38884
|
+
return 'invalid';
|
|
38885
|
+
return parsed.range ? 'applied' : 'empty';
|
|
38886
|
+
}
|
|
38887
|
+
function getNumberInputClassName(state, className) {
|
|
38888
|
+
return getFilterFieldClassName(state, cn('text-right tabular-nums', className));
|
|
38889
|
+
}
|
|
38890
|
+
/** Cheat-sheet row: the whole row is the click target, highlighted on hover. */
|
|
38891
|
+
const RULE_BUTTON_CLASS_NAME = getOptionRowClassName(false, 'py-1.5');
|
|
38892
|
+
/** Key-cap chip for the rule, fixed width so every meaning lines up. */
|
|
38893
|
+
// Every chip is as wide as the longest rule, so the meanings start at the same x.
|
|
38894
|
+
const RULE_CHIP_CLASS_NAME = 'inline-flex h-6 w-[calc(var(--rule-width)+1.25rem)] min-w-14 shrink-0 whitespace-nowrap items-center justify-center rounded-full border border-border bg-background px-2 text-xs font-semibold tabular-nums text-foreground';
|
|
38895
|
+
/** Note / error box in the help popover; text on a fixed 16px line. */
|
|
38896
|
+
const MESSAGE_CLASS_NAME = 'flex gap-2 rounded-md p-2 leading-4';
|
|
38897
|
+
/** One text line tall, so the icon centres on the first line however the text wraps. */
|
|
38898
|
+
const MESSAGE_ICON_SLOT_CLASS_NAME = 'flex h-4 shrink-0 items-center';
|
|
38899
|
+
/** Sets `--rule-width` to the longest rule, which sizes every chip in the list. */
|
|
38900
|
+
function getRuleListStyle(rules) {
|
|
38901
|
+
const longest = Math.max(...rules.map(({ rule }) => rule.length));
|
|
38902
|
+
return { '--rule-width': `${longest}ch` };
|
|
38903
|
+
}
|
|
38904
|
+
|
|
38905
|
+
const COMMIT_DELAY_MS = 400;
|
|
38906
|
+
function useNumberExpressionFilter(value, onChange) {
|
|
38907
|
+
const applied = formatNumberRange(value);
|
|
38908
|
+
const { draft, setDraft, markCommitted } = useFilterDraft(applied, applied);
|
|
38909
|
+
const [helpOpen, setHelpOpen] = useState(false);
|
|
38910
|
+
const errorId = useId$2();
|
|
38911
|
+
const commit = useCallback((text) => {
|
|
38912
|
+
const parsed = parseNumberExpression(text);
|
|
38913
|
+
if (!parsed.ok)
|
|
38914
|
+
return;
|
|
38915
|
+
const key = formatNumberRange(parsed.range);
|
|
38916
|
+
markCommitted(key);
|
|
38917
|
+
if (key !== applied)
|
|
38918
|
+
onChange(parsed.range);
|
|
38919
|
+
}, [applied, markCommitted, onChange]);
|
|
38920
|
+
const debounced = useDebouncedCallback(commit, COMMIT_DELAY_MS);
|
|
38921
|
+
const handleChange = (event) => {
|
|
38922
|
+
setDraft(event.target.value);
|
|
38923
|
+
setHelpOpen(true);
|
|
38924
|
+
debounced.schedule(event.target.value);
|
|
38925
|
+
};
|
|
38926
|
+
const handleKeyDown = (event) => {
|
|
38927
|
+
if (event.key === 'Enter')
|
|
38928
|
+
debounced.flush();
|
|
38929
|
+
if (event.key === 'Escape')
|
|
38930
|
+
setHelpOpen(false);
|
|
38931
|
+
};
|
|
38932
|
+
const handleBlur = () => {
|
|
38933
|
+
debounced.flush();
|
|
38934
|
+
setHelpOpen(false);
|
|
38935
|
+
};
|
|
38936
|
+
const applyRule = (rule) => {
|
|
38937
|
+
debounced.cancel();
|
|
38938
|
+
setDraft(rule);
|
|
38939
|
+
commit(rule);
|
|
38940
|
+
setHelpOpen(false);
|
|
38941
|
+
};
|
|
38942
|
+
return {
|
|
38943
|
+
draft,
|
|
38944
|
+
state: getNumberFieldState(parseNumberExpression(draft)),
|
|
38945
|
+
helpOpen,
|
|
38946
|
+
errorId,
|
|
38947
|
+
handleChange,
|
|
38948
|
+
handleKeyDown,
|
|
38949
|
+
handleFocus: () => setHelpOpen(true),
|
|
38950
|
+
handleClick: () => setHelpOpen(true),
|
|
38951
|
+
handleBlur,
|
|
38952
|
+
applyRule,
|
|
38953
|
+
};
|
|
38954
|
+
}
|
|
38955
|
+
|
|
38956
|
+
/** Filter-row number cell: type a value or a rule (`>1`, `1–3`, `1.52`). Invalid text never reaches the table. */
|
|
38957
|
+
function NumberExpressionFilter({ value, onChange, ariaLabel, placeholder, note, ruleExamples, className, }) {
|
|
38958
|
+
const { draft, state, helpOpen, errorId, handleChange, handleKeyDown, handleFocus, handleClick, handleBlur, applyRule, } = useNumberExpressionFilter(value, onChange);
|
|
38959
|
+
const invalid = state === 'invalid';
|
|
38960
|
+
const rules = buildNumberRuleHelp(ruleExamples);
|
|
38961
|
+
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, onClick: handleClick, onBlur: handleBlur, className: getNumberInputClassName(state, className) }) }), jsxs(PopoverContent, { align: "start",
|
|
38962
|
+
// The filter row moves when the "Filtered by" row appears; track it every frame so the popover never lags behind.
|
|
38963
|
+
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", style: getRuleListStyle(rules), children: rules.map(({ rule, meaning }) => (jsx("li", { children: jsxs("button", { type: "button", "aria-label": getUseRuleLabel(rule, meaning),
|
|
38964
|
+
// Keep focus in the field so it doesn't blur and close this help first.
|
|
38965
|
+
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: cn(MESSAGE_CLASS_NAME, 'bg-muted/50 text-muted-foreground'), children: [jsx("span", { className: MESSAGE_ICON_SLOT_CLASS_NAME, children: jsx(Info, { "aria-hidden": "true", className: "size-3.5" }) }), jsx("div", { children: note })] })), invalid && (jsxs("div", { id: getNumberErrorId(errorId), role: "alert", className: cn(MESSAGE_CLASS_NAME, 'bg-destructive/10 text-destructive'), children: [jsx("span", { className: MESSAGE_ICON_SLOT_CLASS_NAME, children: jsx(CircleAlert, { "aria-hidden": "true", className: "size-3.5" }) }), jsxs("p", { children: ["Can't read \u201C", draft, "\u201D. Try ", jsx("strong", { children: "1\u20133" }), ",", ' ', jsx("strong", { children: ">1" }), " or ", jsx("strong", { children: "<=3" }), "."] })] }))] })] }));
|
|
38966
|
+
}
|
|
38967
|
+
|
|
38968
|
+
const REVERSED_RANGE_MESSAGE = 'From must not be more than To.';
|
|
38969
|
+
const getBoundLabel = (ariaLabel, bound) => `${ariaLabel} ${bound}`;
|
|
38970
|
+
|
|
38971
|
+
const DECIMAL_DRAFT_RE = /^\d*\.?\d*$/;
|
|
38972
|
+
/** Allows partial decimals (`1.`) while typing; rejects anything else. */
|
|
38973
|
+
function isDecimalDraft(text) {
|
|
38974
|
+
return DECIMAL_DRAFT_RE.test(text);
|
|
38975
|
+
}
|
|
38976
|
+
function toBound(text) {
|
|
38977
|
+
if (!text || text === '.')
|
|
38978
|
+
return undefined;
|
|
38979
|
+
return Number(text);
|
|
38980
|
+
}
|
|
38981
|
+
function toBoundText(bound) {
|
|
38982
|
+
return bound === undefined ? '' : String(bound);
|
|
38983
|
+
}
|
|
38984
|
+
/** Replaces one bound with a typed (inclusive) number, keeping the other bound and its `>` / `<`. */
|
|
38985
|
+
function withBound(range, bound, next) {
|
|
38986
|
+
const min = bound === 'min' ? next : range?.min;
|
|
38987
|
+
const max = bound === 'max' ? next : range?.max;
|
|
38988
|
+
if (min === undefined && max === undefined)
|
|
38989
|
+
return undefined;
|
|
38990
|
+
const result = { min, max };
|
|
38991
|
+
if (bound === 'max' && range?.minExclusive)
|
|
38992
|
+
result.minExclusive = true;
|
|
38993
|
+
if (bound === 'min' && range?.maxExclusive)
|
|
38994
|
+
result.maxExclusive = true;
|
|
38995
|
+
return result;
|
|
38996
|
+
}
|
|
38997
|
+
function isReversedRange(min, max) {
|
|
38998
|
+
return min !== undefined && max !== undefined && min > max;
|
|
38999
|
+
}
|
|
39000
|
+
function isSameRange(a, b) {
|
|
39001
|
+
return a?.min === b.min && a?.max === b.max;
|
|
39002
|
+
}
|
|
39003
|
+
function getBoundInputClassName(filled) {
|
|
39004
|
+
return cn('h-9 min-w-0 flex-1 text-sm', filled && 'border-primary bg-primary/5');
|
|
39005
|
+
}
|
|
39006
|
+
const getPresetClassName = getPillClassName;
|
|
39007
|
+
|
|
39008
|
+
function useNumberRangeInputs(value, onChange) {
|
|
39009
|
+
const minText = toBoundText(value?.min);
|
|
39010
|
+
const maxText = toBoundText(value?.max);
|
|
39011
|
+
const from = useFilterDraft(minText, minText);
|
|
39012
|
+
const to = useFilterDraft(maxText, maxText);
|
|
39013
|
+
const handleBoundChange = (bound) => (event) => {
|
|
39014
|
+
const text = event.target.value;
|
|
39015
|
+
if (!isDecimalDraft(text))
|
|
39016
|
+
return;
|
|
39017
|
+
const draft = bound === 'min' ? from : to;
|
|
39018
|
+
const parsed = toBound(text);
|
|
39019
|
+
draft.setDraft(text);
|
|
39020
|
+
const next = withBound(value, bound, parsed);
|
|
39021
|
+
if (isReversedRange(next?.min, next?.max))
|
|
39022
|
+
return;
|
|
39023
|
+
draft.markCommitted(toBoundText(parsed));
|
|
39024
|
+
onChange(next);
|
|
39025
|
+
};
|
|
39026
|
+
return {
|
|
39027
|
+
fromDraft: from.draft,
|
|
39028
|
+
toDraft: to.draft,
|
|
39029
|
+
reversed: isReversedRange(toBound(from.draft), toBound(to.draft)),
|
|
39030
|
+
handleFromChange: handleBoundChange('min'),
|
|
39031
|
+
handleToChange: handleBoundChange('max'),
|
|
39032
|
+
isPresetSelected: (preset) => isSameRange(value, preset.range),
|
|
39033
|
+
togglePreset: (preset) => onChange(isSameRange(value, preset.range) ? undefined : preset.range),
|
|
39034
|
+
};
|
|
39035
|
+
}
|
|
39036
|
+
|
|
39037
|
+
/** From – To number inputs for full-page filter cards, with optional quick-pick presets. */
|
|
39038
|
+
function NumberRangeInputs({ value, onChange, ariaLabel, fromPlaceholder = 'From', toPlaceholder = 'To', presets, presetsLabel, }) {
|
|
39039
|
+
const { fromDraft, toDraft, reversed, handleFromChange, handleToChange, isPresetSelected, togglePreset, } = useNumberRangeInputs(value, onChange);
|
|
39040
|
+
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))) })] }))] }));
|
|
39041
|
+
}
|
|
39042
|
+
|
|
39043
|
+
const NEXT_KEYS = new Set(['ArrowDown', 'ArrowRight']);
|
|
39044
|
+
const PREVIOUS_KEYS = new Set(['ArrowUp', 'ArrowLeft']);
|
|
39045
|
+
/** Arrow keys move and select within the radio group, wrapping at either end. */
|
|
39046
|
+
function getArrowKeyTarget(current, key) {
|
|
39047
|
+
const step = NEXT_KEYS.has(key) ? 1 : PREVIOUS_KEYS.has(key) ? -1 : 0;
|
|
39048
|
+
if (step === 0)
|
|
39049
|
+
return null;
|
|
39050
|
+
const index = TRI_STATE_OPTIONS.findIndex((option) => option.value === current);
|
|
39051
|
+
const nextIndex = (index + step + TRI_STATE_OPTIONS.length) % TRI_STATE_OPTIONS.length;
|
|
39052
|
+
return TRI_STATE_OPTIONS[nextIndex].value;
|
|
39053
|
+
}
|
|
39054
|
+
function createRadioGroupKeyDownHandler(current, onChange) {
|
|
39055
|
+
return (event) => {
|
|
39056
|
+
const target = getArrowKeyTarget(current, event.key);
|
|
39057
|
+
if (!target)
|
|
39058
|
+
return;
|
|
39059
|
+
event.preventDefault();
|
|
39060
|
+
onChange(target);
|
|
39061
|
+
event.currentTarget
|
|
39062
|
+
.querySelector(`[data-value="${target}"]`)
|
|
39063
|
+
?.focus();
|
|
39064
|
+
};
|
|
39065
|
+
}
|
|
39066
|
+
|
|
39067
|
+
const getRadioRowClassName = (checked) => getOptionRowClassName(checked);
|
|
39068
|
+
function getRadioCircleClassName(checked) {
|
|
39069
|
+
return cn('flex size-4 shrink-0 items-center justify-center rounded-full border', checked ? 'border-primary' : 'border-input-border');
|
|
39070
|
+
}
|
|
39071
|
+
|
|
39072
|
+
/** Any / Yes / No radio group for boolean columns (e.g. Active). */
|
|
39073
|
+
function TriStateFilter({ value, onChange, ariaLabel, }) {
|
|
39074
|
+
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) => {
|
|
39075
|
+
const checked = option.value === value;
|
|
39076
|
+
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));
|
|
39077
|
+
}) }));
|
|
39078
|
+
}
|
|
39079
|
+
|
|
39080
|
+
const SAVED_SEARCH_CHIP_CLASS_NAME = 'inline-flex h-6 min-w-0 max-w-full items-center rounded-full border border-primary/30 bg-primary/5 px-2 text-xs text-foreground';
|
|
39081
|
+
/** Children laid out below the first one's line. */
|
|
39082
|
+
function countWrapped(items) {
|
|
39083
|
+
if (items.length === 0)
|
|
39084
|
+
return 0;
|
|
39085
|
+
const firstTop = items[0].offsetTop;
|
|
39086
|
+
return items.filter((item) => item.offsetTop > firstTop).length;
|
|
39087
|
+
}
|
|
39088
|
+
const getShowMoreLabel = (hiddenCount) => `+${hiddenCount} more`;
|
|
39089
|
+
|
|
39090
|
+
/**
|
|
39091
|
+
* Fits chips on one line with the "+N more" link right after the last one. Renders every chip, counts
|
|
39092
|
+
* how many wrap, then drops chips until the link itself fits; a resize starts the measurement over.
|
|
39093
|
+
*/
|
|
39094
|
+
function useChipOverflow(chips, enabled) {
|
|
39095
|
+
const [list, setList] = useState(null);
|
|
39096
|
+
const [expanded, setExpanded] = useState(false);
|
|
39097
|
+
const [visibleCount, setVisibleCount] = useState(chips.length);
|
|
39098
|
+
const collapsed = enabled && !expanded;
|
|
39099
|
+
const [measuredLength, setMeasuredLength] = useState(chips.length);
|
|
39100
|
+
if (measuredLength !== chips.length) {
|
|
39101
|
+
setMeasuredLength(chips.length);
|
|
39102
|
+
setVisibleCount(chips.length);
|
|
39103
|
+
}
|
|
39104
|
+
useLayoutEffect(() => {
|
|
39105
|
+
if (!collapsed || !list)
|
|
39106
|
+
return;
|
|
39107
|
+
const items = Array.from(list.children);
|
|
39108
|
+
if (visibleCount >= chips.length) {
|
|
39109
|
+
const wrapped = countWrapped(items);
|
|
39110
|
+
if (wrapped > 0)
|
|
39111
|
+
setVisibleCount(chips.length - wrapped);
|
|
39112
|
+
return;
|
|
39113
|
+
}
|
|
39114
|
+
// The last child is the "+N more" link; if it wrapped, give it one more chip's room.
|
|
39115
|
+
if (countWrapped(items) > 0 && visibleCount > 1)
|
|
39116
|
+
setVisibleCount(visibleCount - 1);
|
|
39117
|
+
}, [collapsed, list, visibleCount, chips.length]);
|
|
39118
|
+
useEffect(() => {
|
|
39119
|
+
if (!collapsed || !list)
|
|
39120
|
+
return;
|
|
39121
|
+
let width = list.clientWidth;
|
|
39122
|
+
const observer = new ResizeObserver(() => {
|
|
39123
|
+
if (list.clientWidth === width)
|
|
39124
|
+
return;
|
|
39125
|
+
width = list.clientWidth;
|
|
39126
|
+
setVisibleCount(chips.length);
|
|
39127
|
+
});
|
|
39128
|
+
observer.observe(list);
|
|
39129
|
+
return () => observer.disconnect();
|
|
39130
|
+
}, [collapsed, list, chips.length]);
|
|
39131
|
+
const shown = collapsed ? Math.min(visibleCount, chips.length) : chips.length;
|
|
39132
|
+
return {
|
|
39133
|
+
listRef: useCallback((node) => setList(node), []),
|
|
39134
|
+
expanded,
|
|
39135
|
+
toggle: () => {
|
|
39136
|
+
setExpanded((current) => !current);
|
|
39137
|
+
setVisibleCount(chips.length);
|
|
39138
|
+
},
|
|
39139
|
+
visibleChips: chips.slice(0, shown),
|
|
39140
|
+
hiddenCount: chips.length - shown,
|
|
39141
|
+
};
|
|
39142
|
+
}
|
|
39143
|
+
|
|
39144
|
+
/** Read-only filter summaries of a saved search, as pills; optionally one line ending in "+N more". */
|
|
39145
|
+
function SavedSearchChipList({ chips, emptyText = 'No filters', collapsible = false, className, }) {
|
|
39146
|
+
const { listRef, expanded, toggle, visibleChips, hiddenCount } = useChipOverflow(chips, collapsible);
|
|
39147
|
+
if (chips.length === 0) {
|
|
39148
|
+
return (jsx("p", { className: cn('text-xs text-muted-foreground', className), children: emptyText }));
|
|
39149
|
+
}
|
|
39150
|
+
const showToggle = collapsible && (expanded || hiddenCount > 0);
|
|
39151
|
+
return (jsxs("ul", { ref: listRef, className: cn('flex min-w-0 flex-wrap items-center gap-1.5', className), children: [visibleChips.map((chip) => (jsx("li", { className: SAVED_SEARCH_CHIP_CLASS_NAME, children: jsx(TruncatedLabel, { text: chip }) }, chip))), showToggle && (jsx("li", { className: "flex h-6 shrink-0 items-center", children: jsx("button", { type: "button", "aria-expanded": expanded, onClick: toggle,
|
|
39152
|
+
// Above a parent's stretched click area (e.g. a saved-search row).
|
|
39153
|
+
className: cn(FILTER_LINK_CLASS_NAME, 'relative z-10 whitespace-nowrap px-1 underline underline-offset-2'), children: expanded ? 'Show less' : getShowMoreLabel(hiddenCount) }) }))] }));
|
|
39154
|
+
}
|
|
39155
|
+
|
|
39156
|
+
const SEARCH_INPUT_LABEL = 'Find a saved search';
|
|
39157
|
+
const getRenameLabel = (name) => `Rename ${name}`;
|
|
39158
|
+
const getDeleteLabel = (name) => `Delete ${name}`;
|
|
39159
|
+
const NO_MATCH_TITLE = 'No matches';
|
|
39160
|
+
const getNoMatchText = (query) => `No saved searches match “${query.trim()}”.`;
|
|
39161
|
+
|
|
39162
|
+
/** Matches the name or any filter summary, ignoring case. */
|
|
39163
|
+
function filterSavedSearches(items, query) {
|
|
39164
|
+
const needle = query.trim().toLowerCase();
|
|
39165
|
+
if (!needle)
|
|
39166
|
+
return [...items];
|
|
39167
|
+
return items.filter((item) => [item.name, ...item.chips].some((text) => text.toLowerCase().includes(needle)));
|
|
39168
|
+
}
|
|
39169
|
+
const ROW_CLASS_NAME = 'relative flex items-center gap-4 rounded-md px-2 py-2.5 transition-colors hover:bg-muted/60';
|
|
39170
|
+
/** The name is the row's button; its `::after` stretches over the whole row so the row is the click target. */
|
|
39171
|
+
const ROW_BUTTON_CLASS_NAME = "block min-w-0 max-w-full cursor-pointer text-left text-sm font-semibold text-foreground outline-none after:absolute after:inset-0 after:rounded-md after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-primary/30";
|
|
39172
|
+
/** Lifts the name above the button's stretched area so its overflow tooltip gets the hover; clicks still reach the button. */
|
|
39173
|
+
const ROW_NAME_CLASS_NAME = 'relative z-10 block min-w-0';
|
|
39174
|
+
/** Rename / Delete as one outlined, button-shaped group with a divider between them. */
|
|
39175
|
+
const ROW_ACTIONS_CLASS_NAME = 'flex shrink-0 items-center divide-x divide-border overflow-hidden rounded-md border border-border bg-card shadow-xs';
|
|
39176
|
+
/** A cell of the actions group; Delete turns destructive on hover. */
|
|
39177
|
+
function getRowActionClassName(destructive) {
|
|
39178
|
+
return cn('size-7 rounded-none text-foreground/70 [&_svg]:size-3.5', destructive
|
|
39179
|
+
? 'hover:bg-destructive/10 hover:text-destructive'
|
|
39180
|
+
: 'hover:bg-muted hover:text-foreground');
|
|
39181
|
+
}
|
|
39182
|
+
/** Controls inside the row that sit above the stretched button. */
|
|
39183
|
+
const ROW_CONTROL_CLASS_NAME = 'relative z-10';
|
|
39184
|
+
/** About three rows (name line + one pill line each) before the list scrolls. */
|
|
39185
|
+
const LIST_SCROLL_CLASS_NAME = 'max-h-54 overflow-y-auto';
|
|
39186
|
+
|
|
39187
|
+
function useSavedSearchesMenu(items, onOpenChange) {
|
|
39188
|
+
const [open, setOpenState] = useState(false);
|
|
39189
|
+
const [query, setQuery] = useState('');
|
|
39190
|
+
const setOpen = (next) => {
|
|
39191
|
+
setOpenState(next);
|
|
39192
|
+
if (!next)
|
|
39193
|
+
setQuery('');
|
|
39194
|
+
onOpenChange?.(next);
|
|
39195
|
+
};
|
|
39196
|
+
const visibleItems = useMemo(() => filterSavedSearches(items, query), [items, query]);
|
|
39197
|
+
const closeThen = (action, item) => () => {
|
|
39198
|
+
setOpen(false);
|
|
39199
|
+
action(item);
|
|
39200
|
+
};
|
|
39201
|
+
return { open, setOpen, query, setQuery, visibleItems, closeThen };
|
|
39202
|
+
}
|
|
39203
|
+
|
|
39204
|
+
/** Small icon button on a row, named by its tooltip. */
|
|
39205
|
+
function RowActionButton({ label, onClick, destructive = false, children, }) {
|
|
39206
|
+
return (jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(IconButton, { appearance: "ghost", size: "xs", "aria-label": label, onClick: onClick, className: getRowActionClassName(destructive), children: children }) }), jsx(TooltipContent, { side: "top", children: label })] }));
|
|
39207
|
+
}
|
|
39208
|
+
/** One saved search: name, filter pills, when it was saved, and Rename / Delete buttons. */
|
|
39209
|
+
function SavedSearchRow({ item, onSelect, onRename, onDelete, }) {
|
|
39210
|
+
const hasCount = item.countLoading || item.count !== undefined;
|
|
39211
|
+
return (jsxs("li", { className: ROW_CLASS_NAME, children: [jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [jsxs("div", { className: "flex min-w-0 items-baseline gap-2", children: [jsx("button", { type: "button", onClick: onSelect, className: ROW_BUTTON_CLASS_NAME, children: jsx("span", { className: ROW_NAME_CLASS_NAME, children: jsx(TruncatedLabel, { text: item.name }) }) }), hasCount &&
|
|
39212
|
+
(item.countLoading ? (jsx(SquareSkeleton, { height: 12, width: 40, rounded: "sm" })) : (jsx("span", { className: "shrink-0 text-xs font-medium tabular-nums text-foreground", children: item.countLabel ?? item.count }))), item.meta && (jsx("span", { className: "shrink-0 text-xs text-muted-foreground before:mr-2 before:content-['\u00B7']", children: item.meta }))] }), jsx(SavedSearchChipList, { chips: item.chips, collapsible: true })] }), (onRename || onDelete) && (jsxs("div", { className: cn(ROW_CONTROL_CLASS_NAME, ROW_ACTIONS_CLASS_NAME), children: [onRename && (jsx(RowActionButton, { label: getRenameLabel(item.name), onClick: onRename, children: jsx(Pencil, {}) })), onDelete && (jsx(RowActionButton, { label: getDeleteLabel(item.name), onClick: onDelete, destructive: true, children: jsx(Trash2, {}) }))] }))] }));
|
|
39213
|
+
}
|
|
39214
|
+
/** Centered empty / no-match state inside the dropdown. */
|
|
39215
|
+
function SavedSearchesEmpty({ icon, title, description, }) {
|
|
39216
|
+
return (jsxs("div", { className: "flex flex-col items-center gap-1 px-4 py-6 text-center", children: [jsx("span", { className: "mb-2 flex size-10 items-center justify-center rounded-full bg-muted text-primary [&>svg]:size-5", children: icon }), jsx("p", { className: "text-sm font-semibold text-foreground", children: title }), jsx("p", { className: "max-w-xs text-xs text-muted-foreground", children: description })] }));
|
|
39217
|
+
}
|
|
39218
|
+
|
|
39219
|
+
/** "Saved searches" dropdown: find, pick, rename or delete a saved filter set. */
|
|
39220
|
+
function SavedSearchesMenu({ items, onSelect, onRename, onDelete, loading = false, onOpenChange, label = 'Saved searches', footnote, emptyTitle = 'No saved searches yet', emptyDescription = 'Apply some filters, then choose Save search to keep them here.', align = 'start', triggerClassName, }) {
|
|
39221
|
+
const { open, setOpen, query, setQuery, visibleItems, closeThen } = useSavedSearchesMenu(items, onOpenChange);
|
|
39222
|
+
const hasNone = !loading && items.length === 0;
|
|
39223
|
+
return (jsxs(Popover, { open: open, onOpenChange: setOpen, children: [jsx(PopoverTrigger, { asChild: true, children: jsx(Button, { appearance: "outline", color: open ? 'primary' : 'secondary', size: "md", leftIcon: jsx(Bookmark, {}), rightIcon: open ? jsx(ChevronUp, {}) : jsx(ChevronDown, {}), className: triggerClassName, children: label }) }), jsxs(PopoverContent, { align: align, sideOffset: 4, className: "flex w-120 max-w-[calc(100vw-2rem)] flex-col gap-2 p-2", children: [!hasNone && (jsxs("label", { className: FILTER_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: SEARCH_INPUT_LABEL, "aria-label": SEARCH_INPUT_LABEL, className: "min-w-0 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-placeholder" })] })), loading ? (jsxs("div", { className: "flex flex-col gap-2 p-2", "aria-busy": "true", children: [jsx(SquareSkeleton, { height: 44, rounded: "md" }), jsx(SquareSkeleton, { height: 44, rounded: "md" })] })) : hasNone ? (jsx(SavedSearchesEmpty, { icon: jsx(Bookmark, {}), title: emptyTitle, description: emptyDescription })) : visibleItems.length === 0 ? (jsx(SavedSearchesEmpty, { icon: jsx(SearchX, {}), title: NO_MATCH_TITLE, description: getNoMatchText(query) })) : (jsx(ScrollFade, { className: LIST_SCROLL_CLASS_NAME, children: jsx(TooltipProvider, { delayDuration: 300, children: jsx("ul", { className: "flex flex-col", children: visibleItems.map((item) => (jsx(SavedSearchRow, { item: item, onSelect: closeThen(onSelect, item), onRename: onRename && closeThen(onRename, item), onDelete: onDelete && closeThen(onDelete, item) }, item.id))) }) }) })), footnote && !hasNone && (jsx("p", { className: "border-t border-border px-2 pt-2 text-xs text-muted-foreground", children: footnote }))] })] }));
|
|
39224
|
+
}
|
|
39225
|
+
|
|
39226
|
+
/**
|
|
39227
|
+
* App-wide modal wrapper with a fixed header / body / footer layout.
|
|
39228
|
+
* Built on top of shadcn DialogContent, so it inherits viewport-centered
|
|
39229
|
+
* positioning, focus trapping, portal rendering, and overlay handling.
|
|
39230
|
+
*/
|
|
39231
|
+
function Modal({ open, onClose, title, description, icon, children, footer, size = 'default', hideCloseButton = false, className, bodyClassName, }) {
|
|
39232
|
+
// See ConfirmDialog: overlapping dismissable layers leak the <body> lock.
|
|
39233
|
+
useOverlayBodyLockRelease(open);
|
|
39234
|
+
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 }))] }) }));
|
|
39235
|
+
}
|
|
39236
|
+
|
|
39237
|
+
const NAME_LABEL = 'Name';
|
|
39238
|
+
const FILTERS_LABEL = 'Filters saved';
|
|
39239
|
+
const NAME_REQUIRED_ERROR = 'Enter a name for this search.';
|
|
39240
|
+
const DUPLICATE_TITLE = 'Name already in use';
|
|
39241
|
+
const DUPLICATE_DESCRIPTION = 'Save another search with this name?';
|
|
39242
|
+
const DUPLICATE_DETAIL_LABEL = 'Existing saved search';
|
|
39243
|
+
const SAVE_ANYWAY_LABEL = 'Save anyway';
|
|
39244
|
+
const CHANGE_NAME_LABEL = 'Change name';
|
|
39245
|
+
const GO_BACK_LABEL = 'Go back';
|
|
39246
|
+
const CANCEL_LABEL = 'Cancel';
|
|
39247
|
+
|
|
39248
|
+
const SAVED_SEARCH_NAME_MAX_LENGTH = 100;
|
|
39249
|
+
const isValidSearchName = (name) => {
|
|
39250
|
+
const trimmed = name.trim();
|
|
39251
|
+
return trimmed.length > 0 && trimmed.length <= SAVED_SEARCH_NAME_MAX_LENGTH;
|
|
39252
|
+
};
|
|
39253
|
+
const isDuplicateSearchName = (name, existingNames) => {
|
|
39254
|
+
const needle = name.trim().toLowerCase();
|
|
39255
|
+
return existingNames.some((taken) => taken.trim().toLowerCase() === needle);
|
|
39256
|
+
};
|
|
39257
|
+
const FILTERS_PANEL_CLASS_NAME = 'rounded-lg border border-border bg-muted/40 p-3';
|
|
39258
|
+
/** The warning for a step: the caller's for the limit and already-saved steps, built-in copy for a reused name. */
|
|
39259
|
+
function getStepWarning(step, name, warnings) {
|
|
39260
|
+
if (step === 'limit')
|
|
39261
|
+
return warnings.limitWarning;
|
|
39262
|
+
if (step === 'existing')
|
|
39263
|
+
return warnings.existingWarning;
|
|
39264
|
+
if (step === 'duplicate') {
|
|
39265
|
+
return {
|
|
39266
|
+
title: DUPLICATE_TITLE,
|
|
39267
|
+
description: DUPLICATE_DESCRIPTION,
|
|
39268
|
+
detail: { label: DUPLICATE_DETAIL_LABEL, value: name.trim() },
|
|
39269
|
+
};
|
|
39270
|
+
}
|
|
39271
|
+
return undefined;
|
|
39272
|
+
}
|
|
39273
|
+
/** Cancel closes before the form; later warnings go back to it. */
|
|
39274
|
+
function getWarningCancelLabel(step) {
|
|
39275
|
+
if (step === 'existing')
|
|
39276
|
+
return CANCEL_LABEL;
|
|
39277
|
+
if (step === 'limit')
|
|
39278
|
+
return GO_BACK_LABEL;
|
|
39279
|
+
return CHANGE_NAME_LABEL;
|
|
39280
|
+
}
|
|
39281
|
+
const WARNING_DETAIL_CLASS_NAME = 'flex min-w-0 flex-col gap-0.5 rounded-xl border border-border bg-muted/30 px-3.5 py-3';
|
|
39282
|
+
|
|
39283
|
+
/**
|
|
39284
|
+
* The name field restarts from `defaultName` every time the dialog opens. Save stays enabled and reports a
|
|
39285
|
+
* missing name; an optional warning can come before the form (e.g. already saved), and a reused name, then the
|
|
39286
|
+
* saved-search limit, each get a follow-up warning that replaces the
|
|
39287
|
+
* form until the user confirms (the last one stays up, showing progress, until the caller closes on success).
|
|
39288
|
+
*/
|
|
39289
|
+
function useSaveSearchDialog({ open, defaultName, onSave, saving, existingNames, hasLimitWarning, hasExistingWarning, onClose, }) {
|
|
39290
|
+
const formId = useId$2();
|
|
39291
|
+
const inputId = useId$2();
|
|
39292
|
+
const [name, setNameState] = useState(defaultName);
|
|
39293
|
+
const [error, setError] = useState();
|
|
39294
|
+
const firstStep = hasExistingWarning ? 'existing' : 'form';
|
|
39295
|
+
const [step, setStep] = useState(firstStep);
|
|
39296
|
+
const [wasOpen, setWasOpen] = useState(open);
|
|
39297
|
+
if (open !== wasOpen) {
|
|
39298
|
+
setWasOpen(open);
|
|
39299
|
+
if (open) {
|
|
39300
|
+
setNameState(defaultName);
|
|
39301
|
+
setError(undefined);
|
|
39302
|
+
setStep(firstStep);
|
|
39303
|
+
}
|
|
39304
|
+
}
|
|
39305
|
+
const save = () => onSave(name.trim());
|
|
39306
|
+
const afterDuplicate = () => hasLimitWarning ? setStep('limit') : save();
|
|
39307
|
+
return {
|
|
39308
|
+
formId,
|
|
39309
|
+
inputId,
|
|
39310
|
+
name,
|
|
39311
|
+
setName: (next) => {
|
|
39312
|
+
setNameState(next);
|
|
39313
|
+
if (error)
|
|
39314
|
+
setError(undefined);
|
|
39315
|
+
},
|
|
39316
|
+
error,
|
|
39317
|
+
submit: () => {
|
|
39318
|
+
if (saving)
|
|
39319
|
+
return;
|
|
39320
|
+
if (!isValidSearchName(name)) {
|
|
39321
|
+
setError(NAME_REQUIRED_ERROR);
|
|
39322
|
+
return;
|
|
39323
|
+
}
|
|
39324
|
+
if (isDuplicateSearchName(name, existingNames)) {
|
|
39325
|
+
setStep('duplicate');
|
|
39326
|
+
return;
|
|
39327
|
+
}
|
|
39328
|
+
afterDuplicate();
|
|
39329
|
+
},
|
|
39330
|
+
step,
|
|
39331
|
+
confirmWarning: () => {
|
|
39332
|
+
if (step === 'existing')
|
|
39333
|
+
setStep('form');
|
|
39334
|
+
else if (step === 'duplicate')
|
|
39335
|
+
afterDuplicate();
|
|
39336
|
+
else
|
|
39337
|
+
save();
|
|
39338
|
+
},
|
|
39339
|
+
cancelWarning: () => step === 'existing' ? onClose() : setStep('form'),
|
|
39340
|
+
};
|
|
39341
|
+
}
|
|
39342
|
+
|
|
39343
|
+
/** The search a warning is about, in the dialog body (long names stay on one line, full text on hover). */
|
|
39344
|
+
function WarningDetail({ label, value, }) {
|
|
39345
|
+
return (jsxs("div", { className: WARNING_DETAIL_CLASS_NAME, children: [jsx("span", { className: "text-xs text-muted-foreground", children: label }), jsx(TruncatedLabel, { text: value, className: "text-sm font-semibold text-foreground" })] }));
|
|
39346
|
+
}
|
|
39347
|
+
|
|
39348
|
+
/** Names the current filters and saves them; also used to rename a saved search. */
|
|
39349
|
+
function SaveSearchDialog({ open, onClose, onSave, defaultName = '', chips, title = 'Save search', icon = jsx(Bookmark, { className: "size-5" }), submitLabel = 'Save search', note, existingNames, limitWarning, existingWarning, saving = false, }) {
|
|
39350
|
+
const { formId, inputId, name, setName, error, submit, step, confirmWarning, cancelWarning, } = useSaveSearchDialog({
|
|
39351
|
+
open,
|
|
39352
|
+
defaultName,
|
|
39353
|
+
onSave,
|
|
39354
|
+
saving,
|
|
39355
|
+
existingNames: existingNames ?? [],
|
|
39356
|
+
hasLimitWarning: Boolean(limitWarning),
|
|
39357
|
+
hasExistingWarning: Boolean(existingWarning),
|
|
39358
|
+
onClose,
|
|
39359
|
+
});
|
|
39360
|
+
const warning = getStepWarning(step, name, {
|
|
39361
|
+
limitWarning,
|
|
39362
|
+
existingWarning,
|
|
39363
|
+
});
|
|
39364
|
+
return (jsxs(Fragment$2, { children: [jsx(Modal
|
|
39365
|
+
// One dialog at a time: the duplicate-name warning replaces this one and hands back to it.
|
|
39366
|
+
, {
|
|
39367
|
+
// One dialog at a time: the duplicate-name warning replaces this one and hands back to it.
|
|
39368
|
+
open: open && step === 'form', onClose: onClose, title: title, icon: icon, footer: jsxs(Fragment$2, { children: [jsx(Button, { appearance: "outline", color: "secondary", size: "md", onClick: onClose, children: "Cancel" }), jsx(Button, { appearance: "solid", color: "primary", size: "md", type: "submit", form: formId, loading: saving, children: submitLabel })] }), children: jsxs("form", { id: formId, noValidate: true, className: "flex flex-col gap-4 px-6 pb-5", onSubmit: (event) => {
|
|
39369
|
+
event.preventDefault();
|
|
39370
|
+
submit();
|
|
39371
|
+
}, children: [jsx(Field, { label: NAME_LABEL, required: true, error: error, input: jsx(Input, { id: inputId, "aria-label": NAME_LABEL, "aria-invalid": Boolean(error) || undefined, value: name, maxLength: SAVED_SEARCH_NAME_MAX_LENGTH, onChange: (event) => setName(event.target.value), autoFocus: true }) }), chips && (jsxs("div", { className: "flex flex-col gap-1", children: [jsx("span", { className: "text-[13px] text-label", children: FILTERS_LABEL }), jsx(SavedSearchChipList, { chips: chips, className: FILTERS_PANEL_CLASS_NAME })] })), note && (jsxs("p", { className: "flex items-start gap-1.5 text-xs text-muted-foreground", children: [jsx(Info, { "aria-hidden": "true", className: "mt-px size-3.5 shrink-0" }), jsx("span", { children: note })] }))] }) }), jsx(ConfirmDialog, { open: open && step !== 'form', onOpenChange: (next) => !next && !saving && cancelWarning(), icon: TriangleAlert, title: warning?.title ?? '', description: warning?.description, cancelLabel: getWarningCancelLabel(step), confirmLabel: warning?.confirmLabel ?? SAVE_ANYWAY_LABEL, confirmVariant: "default", disabled: saving, onConfirm: confirmWarning, children: warning?.detail && jsx(WarningDetail, { ...warning.detail }) })] }));
|
|
39372
|
+
}
|
|
39373
|
+
|
|
37904
39374
|
/**
|
|
37905
39375
|
* Compact "time ago" label, e.g. "5m ago". Falls back to a locale date past a
|
|
37906
39376
|
* week so older entries stay scannable.
|
|
@@ -38254,23 +39724,26 @@ function InventoryComboBox({ inventoryType, selectedItem, onSelect, fetchGems, f
|
|
|
38254
39724
|
} }), 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 }));
|
|
38255
39725
|
}
|
|
38256
39726
|
|
|
38257
|
-
const
|
|
38258
|
-
|
|
38259
|
-
|
|
38260
|
-
|
|
38261
|
-
|
|
38262
|
-
const
|
|
38263
|
-
|
|
38264
|
-
|
|
38265
|
-
|
|
38266
|
-
|
|
38267
|
-
|
|
38268
|
-
const
|
|
38269
|
-
|
|
38270
|
-
|
|
38271
|
-
|
|
38272
|
-
|
|
38273
|
-
|
|
39727
|
+
const OWNERSHIP_STATUS_OPTIONS = [
|
|
39728
|
+
{ value: 'owned', label: 'Owned' },
|
|
39729
|
+
{ value: 'partner', label: 'Partner' },
|
|
39730
|
+
{ value: 'memo_in', label: 'Memo In' },
|
|
39731
|
+
];
|
|
39732
|
+
const STOCK_TYPE_OPTIONS = [
|
|
39733
|
+
{ value: 'single', label: 'Single' },
|
|
39734
|
+
{ value: 'parcel', label: 'Parcel' },
|
|
39735
|
+
{ value: 'set', label: 'Set' },
|
|
39736
|
+
{ value: 'pair', label: 'Pair' },
|
|
39737
|
+
];
|
|
39738
|
+
const INVENTORY_STATUS_OPTIONS = [
|
|
39739
|
+
{ value: 'in_stock', label: 'In Stock' },
|
|
39740
|
+
{ value: 'out_of_stock', label: 'Out of Stock' },
|
|
39741
|
+
{ value: 'sold', label: 'Sold' },
|
|
39742
|
+
{ value: 'memo_out', label: 'Memo Out' },
|
|
39743
|
+
];
|
|
39744
|
+
const OwnershipFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Ownership", searchPlaceholder: "Search ownership", options: [...OWNERSHIP_STATUS_OPTIONS] }));
|
|
39745
|
+
const StockTypeFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Stock Type", searchPlaceholder: "Search stock types", options: [...STOCK_TYPE_OPTIONS] }));
|
|
39746
|
+
const StatusFilter = (props) => (jsx(FilterMultiSelect, { ...props, label: "Status", searchPlaceholder: "Search statuses", options: [...INVENTORY_STATUS_OPTIONS] }));
|
|
38274
39747
|
const WarehouseFilter = ({ getWarehouseList, ...props }) => {
|
|
38275
39748
|
const [warehouses, setWarehouses] = useState([]);
|
|
38276
39749
|
useEffect(() => {
|
|
@@ -38278,7 +39751,7 @@ const WarehouseFilter = ({ getWarehouseList, ...props }) => {
|
|
|
38278
39751
|
.then(setWarehouses)
|
|
38279
39752
|
.catch(() => { });
|
|
38280
39753
|
}, [getWarehouseList]);
|
|
38281
|
-
return (jsx(FilterMultiSelect, { ...props, label: "Warehouse",
|
|
39754
|
+
return (jsx(FilterMultiSelect, { ...props, label: "Warehouse", searchPlaceholder: "Search warehouses", options: warehouses.map((w) => ({
|
|
38282
39755
|
value: w.id,
|
|
38283
39756
|
label: `${w.warehouseId} · ${w.name}`,
|
|
38284
39757
|
})) }));
|
|
@@ -38510,17 +39983,6 @@ const TONE_ICON_BG = {
|
|
|
38510
39983
|
};
|
|
38511
39984
|
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 }))] })] }));
|
|
38512
39985
|
|
|
38513
|
-
/**
|
|
38514
|
-
* App-wide modal wrapper with a fixed header / body / footer layout.
|
|
38515
|
-
* Built on top of shadcn DialogContent, so it inherits viewport-centered
|
|
38516
|
-
* positioning, focus trapping, portal rendering, and overlay handling.
|
|
38517
|
-
*/
|
|
38518
|
-
function Modal({ open, onClose, title, description, icon, children, footer, size = 'default', hideCloseButton = false, className, bodyClassName, }) {
|
|
38519
|
-
// See ConfirmDialog: overlapping dismissable layers leak the <body> lock.
|
|
38520
|
-
useOverlayBodyLockRelease(open);
|
|
38521
|
-
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 }))] }) }));
|
|
38522
|
-
}
|
|
38523
|
-
|
|
38524
39986
|
/**
|
|
38525
39987
|
* Side info panel that sits adjacent to the form content (not a modal/drawer).
|
|
38526
39988
|
* The parent page is responsible for layout: render this inside a flex row
|
|
@@ -67226,59 +68688,6 @@ function useIsTablet() {
|
|
|
67226
68688
|
return useMediaQuery(`(min-width: ${MOBILE_MAX + 1}px) and (max-width: ${TABLET_MAX}px)`);
|
|
67227
68689
|
}
|
|
67228
68690
|
|
|
67229
|
-
// Sub-pixel layout rounding makes scrollWidth exceed clientWidth by a hair on
|
|
67230
|
-
// labels that are not actually clipped.
|
|
67231
|
-
const OVERFLOW_TOLERANCE_PX = 1;
|
|
67232
|
-
function findClippedLabel(root) {
|
|
67233
|
-
const spans = root.querySelectorAll(':scope > span');
|
|
67234
|
-
for (const span of Array.from(spans)) {
|
|
67235
|
-
if (span.scrollWidth > span.clientWidth + OVERFLOW_TOLERANCE_PX) {
|
|
67236
|
-
return span;
|
|
67237
|
-
}
|
|
67238
|
-
}
|
|
67239
|
-
return null;
|
|
67240
|
-
}
|
|
67241
|
-
/**
|
|
67242
|
-
* Returns the full text of the first direct-child `<span>` of `ref` that is
|
|
67243
|
-
* clipped by its container (i.e. showing an ellipsis), else `null` — so callers
|
|
67244
|
-
* can surface a tooltip only when the label is actually unreadable.
|
|
67245
|
-
*
|
|
67246
|
-
* Re-measures on element resize (sidebar expand/collapse, window resize) and on
|
|
67247
|
-
* label text changes.
|
|
67248
|
-
*/
|
|
67249
|
-
function useTruncatedText(ref) {
|
|
67250
|
-
const [text, setText] = useState(null);
|
|
67251
|
-
useEffect(() => {
|
|
67252
|
-
const el = ref.current;
|
|
67253
|
-
if (!el)
|
|
67254
|
-
return;
|
|
67255
|
-
let frame = 0;
|
|
67256
|
-
const measure = () => {
|
|
67257
|
-
const label = findClippedLabel(el);
|
|
67258
|
-
setText(label?.textContent?.trim() || null);
|
|
67259
|
-
};
|
|
67260
|
-
const schedule = () => {
|
|
67261
|
-
cancelAnimationFrame(frame);
|
|
67262
|
-
frame = requestAnimationFrame(measure);
|
|
67263
|
-
};
|
|
67264
|
-
schedule();
|
|
67265
|
-
const resizeObserver = new ResizeObserver(schedule);
|
|
67266
|
-
resizeObserver.observe(el);
|
|
67267
|
-
const mutationObserver = new MutationObserver(schedule);
|
|
67268
|
-
mutationObserver.observe(el, {
|
|
67269
|
-
characterData: true,
|
|
67270
|
-
childList: true,
|
|
67271
|
-
subtree: true,
|
|
67272
|
-
});
|
|
67273
|
-
return () => {
|
|
67274
|
-
cancelAnimationFrame(frame);
|
|
67275
|
-
resizeObserver.disconnect();
|
|
67276
|
-
mutationObserver.disconnect();
|
|
67277
|
-
};
|
|
67278
|
-
}, [ref]);
|
|
67279
|
-
return text;
|
|
67280
|
-
}
|
|
67281
|
-
|
|
67282
68691
|
const SIDEBAR_COOKIE_NAME = 'sidebar_state';
|
|
67283
68692
|
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
67284
68693
|
const SIDEBAR_WIDTH = '16rem';
|
|
@@ -67517,37 +68926,6 @@ const AppSidebar = ({ brand, navGroups = [], footer, className, }) => {
|
|
|
67517
68926
|
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, {})] }));
|
|
67518
68927
|
};
|
|
67519
68928
|
|
|
67520
|
-
/** Label line + input block — mirrors a `Field`. */
|
|
67521
|
-
function FieldSkeleton() {
|
|
67522
|
-
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" })] }));
|
|
67523
|
-
}
|
|
67524
|
-
/**
|
|
67525
|
-
* Loading placeholder that matches a `FormSectionCard` — the tinted header band
|
|
67526
|
-
* (icon square + title + description) above a body of `Field` placeholders and
|
|
67527
|
-
* an optional footer action row.
|
|
67528
|
-
*/
|
|
67529
|
-
function FormSectionCardSkeleton({ fields = 4, columns = 2, footer = 'end', description = true, }) {
|
|
67530
|
-
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" })] }))] })] }));
|
|
67531
|
-
}
|
|
67532
|
-
/** Table placeholder: toolbar (search + filters) + rows. Mirrors a data grid. */
|
|
67533
|
-
function TableSkeleton({ rows = 8 }) {
|
|
67534
|
-
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)))] }));
|
|
67535
|
-
}
|
|
67536
|
-
/** Listing table while it loads: one full-width bar per row, like the gem and diamond inventory tables. */
|
|
67537
|
-
function TableRowsSkeleton({ rows = 10, className }) {
|
|
67538
|
-
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) => (
|
|
67539
|
-
// shrink-0: in a height-capped flex parent the bars would otherwise squash below 52px.
|
|
67540
|
-
jsx(SquareSkeleton, { height: 52, className: "w-full shrink-0" }, i))) }));
|
|
67541
|
-
}
|
|
67542
|
-
/** Detail page: header row + key-value section cards. Mirrors `DetailPageLayout`. */
|
|
67543
|
-
function DetailPageSkeleton({ sections = 3, }) {
|
|
67544
|
-
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)))] }));
|
|
67545
|
-
}
|
|
67546
|
-
/** Document detail page (invoice, memo…): header, `DocumentHero` and `DetailSection` placeholders. */
|
|
67547
|
-
function DocumentDetailSkeleton({ aside = 'payment', sections = 3, label = 'Loading document', }) {
|
|
67548
|
-
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 })] }));
|
|
67549
|
-
}
|
|
67550
|
-
|
|
67551
68929
|
const SlideOut = ({ open, onOpenChange, ...props }) => {
|
|
67552
68930
|
const scheduleLockRelease = useOverlayBodyLockRelease(open);
|
|
67553
68931
|
return (jsx(DialogPrimitive.Root, { ...props, open: open, onOpenChange: (next) => {
|
|
@@ -75495,6 +76873,236 @@ const FileUploader = ({ accept, multiple = true, maxSize = 50, maxFiles = 5, lab
|
|
|
75495
76873
|
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 }))] }));
|
|
75496
76874
|
};
|
|
75497
76875
|
|
|
76876
|
+
/** The value narrowed to one control type, or undefined when it holds another (or none). */
|
|
76877
|
+
function valueOfType(value, type) {
|
|
76878
|
+
return value?.type === type ? value : undefined;
|
|
76879
|
+
}
|
|
76880
|
+
/** Each builder returns `undefined` for an empty selection so cleared filters drop out of state. */
|
|
76881
|
+
const toListValue = (values) => values.length ? { type: 'list', values } : undefined;
|
|
76882
|
+
const toScaleValue = (range) => (range ? { type: 'scale', range } : undefined);
|
|
76883
|
+
const toNumberValue = (range) => range && (range.min !== undefined || range.max !== undefined)
|
|
76884
|
+
? { type: 'number', range }
|
|
76885
|
+
: undefined;
|
|
76886
|
+
const toIdsValue = (ids) => ids.length ? { type: 'ids', ids } : undefined;
|
|
76887
|
+
const toContainsValue = (text) => text.trim() ? { type: 'contains', text: text.trim() } : undefined;
|
|
76888
|
+
const toDateValue = (range) => range && (range.preset || range.from || range.to)
|
|
76889
|
+
? { type: 'date', range }
|
|
76890
|
+
: undefined;
|
|
76891
|
+
const toBoolValue = (value) => value === 'any' ? undefined : { type: 'bool', value };
|
|
76892
|
+
const DEFAULT_CELL_PLACEHOLDERS = {
|
|
76893
|
+
list: 'All',
|
|
76894
|
+
scale: 'All',
|
|
76895
|
+
number: '',
|
|
76896
|
+
ids: 'Paste IDs…',
|
|
76897
|
+
contains: 'Contains…',
|
|
76898
|
+
date: 'Any date',
|
|
76899
|
+
bool: 'Any',
|
|
76900
|
+
};
|
|
76901
|
+
function getCellState(field, value) {
|
|
76902
|
+
if (field.disabled)
|
|
76903
|
+
return 'disabled';
|
|
76904
|
+
return isFilterValueActive(value) ? 'applied' : 'empty';
|
|
76905
|
+
}
|
|
76906
|
+
/** Human-readable value for chips and card summaries, e.g. `Red, Blue`, `1–3`, `Last 30 days`. */
|
|
76907
|
+
function describeFilterValue(field, value) {
|
|
76908
|
+
if (!value || !isFilterValueActive(value))
|
|
76909
|
+
return '';
|
|
76910
|
+
const options = field.options ?? [];
|
|
76911
|
+
switch (value.type) {
|
|
76912
|
+
case 'list':
|
|
76913
|
+
return options
|
|
76914
|
+
.filter((option) => value.values.includes(option.value))
|
|
76915
|
+
.map((option) => option.label)
|
|
76916
|
+
.concat(value.values.filter((v) => !options.some((option) => option.value === v)))
|
|
76917
|
+
.join(', ');
|
|
76918
|
+
case 'scale':
|
|
76919
|
+
return formatScaleRange(options, value.range);
|
|
76920
|
+
case 'number':
|
|
76921
|
+
return formatNumberRange(value.range);
|
|
76922
|
+
case 'ids':
|
|
76923
|
+
return value.ids.length === 1 ? value.ids[0] : `${value.ids.length} IDs`;
|
|
76924
|
+
case 'contains':
|
|
76925
|
+
return `“${value.text}”`;
|
|
76926
|
+
case 'date':
|
|
76927
|
+
return formatDateRange(value.range);
|
|
76928
|
+
case 'bool':
|
|
76929
|
+
return getOptionLabel([
|
|
76930
|
+
{ value: 'yes', label: 'Yes' },
|
|
76931
|
+
{ value: 'no', label: 'No' },
|
|
76932
|
+
], value.value);
|
|
76933
|
+
}
|
|
76934
|
+
}
|
|
76935
|
+
/** Short value shown on the filter-row trigger, e.g. `Red +1`, `VG – F`, `A-102`, `3 IDs`. */
|
|
76936
|
+
function getCellLabel(field, value) {
|
|
76937
|
+
if (!value || !isFilterValueActive(value))
|
|
76938
|
+
return '';
|
|
76939
|
+
if (value.type === 'list')
|
|
76940
|
+
return summarizeSelection(value.values, field.options ?? []);
|
|
76941
|
+
if (value.type === 'scale')
|
|
76942
|
+
return formatScaleRange(field.options ?? [], value.range, field.shortLabels);
|
|
76943
|
+
return describeFilterValue(field, value);
|
|
76944
|
+
}
|
|
76945
|
+
/** Filter-row popovers hold the filter's card at a compact, fixed width. */
|
|
76946
|
+
function getPopoverWidthClassName(field) {
|
|
76947
|
+
if (field.type === 'date')
|
|
76948
|
+
return 'w-96';
|
|
76949
|
+
if (field.type === 'bool')
|
|
76950
|
+
return 'w-60';
|
|
76951
|
+
return 'w-64';
|
|
76952
|
+
}
|
|
76953
|
+
const POPOVER_TILE_COLUMNS = 2;
|
|
76954
|
+
/** Above this many options, chips / tiles give way to the searchable checkbox list. */
|
|
76955
|
+
const MAX_PILL_OPTIONS = 10;
|
|
76956
|
+
/** The list layout actually used: the configured one, or the checkbox list once there are too many options for pills. */
|
|
76957
|
+
function resolveListLayout(field) {
|
|
76958
|
+
return (field.options?.length ?? 0) > MAX_PILL_OPTIONS
|
|
76959
|
+
? 'list'
|
|
76960
|
+
: (field.layout ?? 'chips');
|
|
76961
|
+
}
|
|
76962
|
+
/** The empty single-select dropdown on a card: `inputPlaceholder`, else `Any <label>` (set `inputPlaceholder` for acronyms). */
|
|
76963
|
+
const getSingleSelectPlaceholder = (field) => field.inputPlaceholder ?? `Any ${field.label.toLowerCase()}`;
|
|
76964
|
+
/** Popover variant: the same control and layout as the card (pills up to 10 options, then the list); tile grids drop to two columns. */
|
|
76965
|
+
function toPopoverField(field) {
|
|
76966
|
+
if (field.type === 'scale' ||
|
|
76967
|
+
(field.type === 'list' && resolveListLayout(field) === 'tiles')) {
|
|
76968
|
+
return { ...field, columns: POPOVER_TILE_COLUMNS };
|
|
76969
|
+
}
|
|
76970
|
+
return field;
|
|
76971
|
+
}
|
|
76972
|
+
/** ID lists and searchable lists carry their own "x selected · Clear" row, so the card skips its Clear (and, in a popover, its title). */
|
|
76973
|
+
const ownsClearRow = (field) => field.type === 'ids' ||
|
|
76974
|
+
(field.type === 'list' && resolveListLayout(field) === 'list');
|
|
76975
|
+
/** Popover header text in place of the title: `2 of 17 selected`, or the applied value (`VG – F`, `Last 30 days`); none when nothing is applied. */
|
|
76976
|
+
function getPopoverStatus(field, value) {
|
|
76977
|
+
if (ownsClearRow(field))
|
|
76978
|
+
return undefined;
|
|
76979
|
+
if (field.type === 'list') {
|
|
76980
|
+
return formatSelectedCount(valueOfType(value, 'list')?.values.length ?? 0, field.options?.length ?? 0);
|
|
76981
|
+
}
|
|
76982
|
+
// Nothing applied: the trigger already reads "Any", so the popover skips the header.
|
|
76983
|
+
return describeFilterValue(field, value) || undefined;
|
|
76984
|
+
}
|
|
76985
|
+
|
|
76986
|
+
/** Single-choice list on a card, as the design's dropdown ("Any supplier"); the filter row lists the same options as a pick-one list. */
|
|
76987
|
+
function SingleSelectFilter({ field, selected, onSelect, }) {
|
|
76988
|
+
const options = field.options ?? [];
|
|
76989
|
+
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 }));
|
|
76990
|
+
}
|
|
76991
|
+
/** The control alone — identical in a filter-row popover and on a card, except the list layout. Compose it into custom cards. */
|
|
76992
|
+
function FilterFieldControl({ field, value, onChange, fiscalYearStartMonth, fill, inPopover, }) {
|
|
76993
|
+
const ariaLabel = `${field.label} filter`;
|
|
76994
|
+
switch (field.type) {
|
|
76995
|
+
case 'list': {
|
|
76996
|
+
if (field.single && !inPopover) {
|
|
76997
|
+
return (jsx(SingleSelectFilter, { field: field, selected: valueOfType(value, 'list')?.values[0], onSelect: (next) => onChange(toListValue([next])) }));
|
|
76998
|
+
}
|
|
76999
|
+
const layout = resolveListLayout(field);
|
|
77000
|
+
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, single: field.single }));
|
|
77001
|
+
}
|
|
77002
|
+
case 'scale':
|
|
77003
|
+
return (jsx(ScaleRangeFilter, { ariaLabel: ariaLabel, options: field.options ?? [], value: valueOfType(value, 'scale')?.range, onChange: (range) => onChange(toScaleValue(range)), columns: field.columns, fill: fill }));
|
|
77004
|
+
case 'number':
|
|
77005
|
+
return (jsx(NumberRangeInputs, { ariaLabel: field.label, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), presets: field.presets, presetsLabel: field.presetsLabel }));
|
|
77006
|
+
case 'ids':
|
|
77007
|
+
return (jsx(IdListInput, { ariaLabel: ariaLabel, value: valueOfType(value, 'ids')?.ids ?? [], onChange: (ids) => onChange(toIdsValue(ids)), placeholder: field.inputPlaceholder,
|
|
77008
|
+
// Cards show one shared hint instead of a helper under every box.
|
|
77009
|
+
helperText: inPopover ? field.helperText : '' }));
|
|
77010
|
+
case 'contains':
|
|
77011
|
+
return (jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "field", placeholder: field.inputPlaceholder, value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)) }));
|
|
77012
|
+
case 'date':
|
|
77013
|
+
return (jsx(DateRangeFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'date')?.range, onChange: (range) => onChange(toDateValue(range)), fiscalYearStartMonth: fiscalYearStartMonth }));
|
|
77014
|
+
case 'bool':
|
|
77015
|
+
return (jsx(TriStateFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'bool')?.value ?? 'any', onChange: (next) => onChange(toBoolValue(next)) }));
|
|
77016
|
+
}
|
|
77017
|
+
}
|
|
77018
|
+
/** Filter-row cell: inline input for number/contains, otherwise a trigger that opens the control in a popover. */
|
|
77019
|
+
function FilterFieldCell({ field, value, onChange, fiscalYearStartMonth, className, }) {
|
|
77020
|
+
const state = getCellState(field, value);
|
|
77021
|
+
const ariaLabel = `${field.label} filter`;
|
|
77022
|
+
const placeholder = field.placeholder ?? DEFAULT_CELL_PLACEHOLDERS[field.type];
|
|
77023
|
+
const clear = () => onChange(undefined);
|
|
77024
|
+
if (field.type === 'number' && state !== 'disabled') {
|
|
77025
|
+
return (jsx(NumberExpressionFilter, { ariaLabel: ariaLabel, value: valueOfType(value, 'number')?.range, onChange: (range) => onChange(toNumberValue(range)), placeholder: placeholder, note: field.note, ruleExamples: field.ruleExamples, className: className }));
|
|
77026
|
+
}
|
|
77027
|
+
if (field.type === 'contains' && state !== 'disabled') {
|
|
77028
|
+
return (jsx(ContainsFilter, { ariaLabel: ariaLabel, size: "cell", value: valueOfType(value, 'contains')?.text ?? '', onChange: (text) => onChange(toContainsValue(text)), placeholder: placeholder, className: className }));
|
|
77029
|
+
}
|
|
77030
|
+
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 }) }));
|
|
77031
|
+
}
|
|
77032
|
+
/** 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`). */
|
|
77033
|
+
function FilterFieldCard({ field, value, onChange, fiscalYearStartMonth, action, className, mode, }) {
|
|
77034
|
+
const active = isFilterValueActive(value);
|
|
77035
|
+
const listCount = valueOfType(value, 'list')?.values.length;
|
|
77036
|
+
// In a filter-row popover the column header already names the filter.
|
|
77037
|
+
const inPopover = mode === 'popover';
|
|
77038
|
+
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'
|
|
77039
|
+
? describeFilterValue(field, value)
|
|
77040
|
+
: undefined, action: action, onClear: active && !ownsClearRow(field)
|
|
77041
|
+
? () => onChange(undefined)
|
|
77042
|
+
: 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' }) }));
|
|
77043
|
+
}
|
|
77044
|
+
function FilterField(props) {
|
|
77045
|
+
const { mode, ...rest } = props;
|
|
77046
|
+
return mode === 'cell' ? (jsx(FilterFieldCell, { ...rest })) : (jsx(FilterFieldCard, { mode: mode, ...rest }));
|
|
77047
|
+
}
|
|
77048
|
+
|
|
77049
|
+
/** Both leave without applying — the draft is discarded. */
|
|
77050
|
+
const BACK_LABEL = 'Back without applying';
|
|
77051
|
+
const CLOSE_LABEL = 'Close without applying';
|
|
77052
|
+
const LOADING_LABEL = 'Loading filters';
|
|
77053
|
+
const ERROR_TITLE = "Couldn't load filters";
|
|
77054
|
+
const DEFAULT_ERROR_MESSAGE = 'Something went wrong while loading the filters. Check your connection and try again.';
|
|
77055
|
+
const RETRY_LABEL = 'Try again';
|
|
77056
|
+
|
|
77057
|
+
/** Placeholder cards while the filters load; roughly the first rows of a card grid. */
|
|
77058
|
+
const SKELETON_CARD_COUNT = 8;
|
|
77059
|
+
const SKELETON_GRID_CLASS_NAME = 'grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4';
|
|
77060
|
+
|
|
77061
|
+
const DEFAULT_SKELETON_CARDS = Array.from({ length: SKELETON_CARD_COUNT }, (_, index) => `card-${index}`);
|
|
77062
|
+
/** Loading placeholder: the page's own skeleton, or generic list cards. */
|
|
77063
|
+
function FilterSurfaceSkeleton({ children, }) {
|
|
77064
|
+
return (jsx("div", { role: "status", "aria-label": LOADING_LABEL, children: children ?? (jsx("div", { className: SKELETON_GRID_CLASS_NAME, children: DEFAULT_SKELETON_CARDS.map((id) => (jsx(FilterCardSkeleton, {}, id))) })) }));
|
|
77065
|
+
}
|
|
77066
|
+
/** Shown in place of the cards when the filters couldn't load. */
|
|
77067
|
+
function FilterSurfaceError({ message, onRetry, }) {
|
|
77068
|
+
return (jsxs("div", { role: "alert", className: "flex flex-col items-center rounded-xl border border-border bg-card px-6 py-12 text-center", children: [jsx("span", { className: "flex size-10 items-center justify-center rounded-full bg-destructive/10 text-destructive", children: jsx(TriangleAlert, { "aria-hidden": "true", className: "size-5" }) }), jsx("p", { className: "mt-4 text-base font-semibold text-foreground", children: ERROR_TITLE }), jsx("p", { className: "mt-1.5 max-w-sm text-sm text-muted-foreground", children: message }), onRetry && (jsx(Button, { appearance: "outline", color: "secondary", size: "md", leftIcon: jsx(RotateCcw, {}), onClick: onRetry, className: "mt-5", children: RETRY_LABEL }))] }));
|
|
77069
|
+
}
|
|
77070
|
+
|
|
77071
|
+
const NESTED_LAYER_SELECTOR = '[data-slot="popover-content"], [role="dialog"], [role="menu"], [role="listbox"]';
|
|
77072
|
+
function useCloseOnEscape(onClose) {
|
|
77073
|
+
useEffect(() => {
|
|
77074
|
+
const handleKeyDown = (event) => {
|
|
77075
|
+
if (event.key !== 'Escape' || event.defaultPrevented)
|
|
77076
|
+
return;
|
|
77077
|
+
// Escape inside an open popover, dialog or menu only closes that layer (Radix doesn't mark the event handled).
|
|
77078
|
+
if (event.target instanceof Element &&
|
|
77079
|
+
event.target.closest(NESTED_LAYER_SELECTOR))
|
|
77080
|
+
return;
|
|
77081
|
+
onClose();
|
|
77082
|
+
};
|
|
77083
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
77084
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
77085
|
+
}, [onClose]);
|
|
77086
|
+
}
|
|
77087
|
+
function useFilterSurfaceMore(defaultExpanded = false) {
|
|
77088
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
77089
|
+
return { expanded, toggle: () => setExpanded((current) => !current) };
|
|
77090
|
+
}
|
|
77091
|
+
|
|
77092
|
+
/** Full-page filter screen (e.g. an advanced search): header, scrolling card grid, sticky apply footer. */
|
|
77093
|
+
function FilterSurface({ title, headerActions, footerChips, footerActions, onClose, status = 'ready', errorMessage, onRetry, skeleton, children, }) {
|
|
77094
|
+
useCloseOnEscape(onClose);
|
|
77095
|
+
return (jsxs("div", { role: "region", "aria-label": title, className: "flex h-full min-h-0 flex-col bg-background", children: [jsxs("header", { className: "sticky top-0 z-20 flex shrink-0 flex-wrap items-end justify-between gap-3 bg-background px-3 pt-2 pb-3", children: [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: "min-h-0 flex-1 overflow-y-auto px-3 pb-3", children: status === 'loading' ? (jsx(FilterSurfaceSkeleton, { children: skeleton })) : status === 'error' ? (jsx(FilterSurfaceError, { message: errorMessage ?? DEFAULT_ERROR_MESSAGE, onRetry: onRetry })) : (jsx("div", { className: "flex flex-col gap-3", children: children })) }), status === 'ready' && (footerChips || footerActions) && (jsxs("footer", { className: "sticky bottom-0 z-20 flex flex-wrap items-center justify-between gap-3 border-t border-border bg-card px-3 py-2", children: [jsx("div", { className: "min-w-0 flex-1", children: footerChips }), jsx("div", { className: "flex shrink-0 items-center gap-2", children: footerActions })] }))] }));
|
|
77096
|
+
}
|
|
77097
|
+
function FilterSurfaceGroup({ title, className, children, }) {
|
|
77098
|
+
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-3 lg:grid-cols-6', className), children: children })] }));
|
|
77099
|
+
}
|
|
77100
|
+
/** Collapsed "More filters" divider that reveals extra cards. */
|
|
77101
|
+
function FilterSurfaceMore({ label, defaultExpanded, children, }) {
|
|
77102
|
+
const { expanded, toggle } = useFilterSurfaceMore(defaultExpanded);
|
|
77103
|
+
return (jsxs("section", { className: "flex flex-col gap-3", 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] }));
|
|
77104
|
+
}
|
|
77105
|
+
|
|
75498
77106
|
/** Falls back to counting the current page when the caller has no total. */
|
|
75499
77107
|
function resolveUnreadCount(notifications, unreadCount) {
|
|
75500
77108
|
if (typeof unreadCount === 'number')
|
|
@@ -78068,5 +79676,5 @@ var RichTextAreaImpl = /*#__PURE__*/Object.freeze({
|
|
|
78068
79676
|
RichTextarea: RichTextarea
|
|
78069
79677
|
});
|
|
78070
79678
|
|
|
78071
|
-
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 };
|
|
79679
|
+
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, FILTER_COUNT_BADGE_CLASS_NAME, Field, FieldSkeleton, FileUploader, FilterCardSkeleton, 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, SAVED_SEARCH_NAME_MAX_LENGTH, SEARCHABLE_SELECT_PAGE_SIZE, SafeImage, SaveSearchDialog, SavedSearchChipList, SavedSearchesMenu, 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, buildNumberRuleHelp, buildWhatsappUrl, buttonVariants, cn, countries, countryByCode, createVideoMediaItem, describeFilterValue, dropdownMenuItemDestructiveClass, expandScaleRange, fieldTypeIcon, filterSavedSearches, findRegion, flagEmoji, formatAddressLocation, formatDateRange, formatFileSize, formatNumberRange, formatScaleRange, formatSelectedCount, generateActionDescription, generateTitle, getBadgeTypeForStatus, getChangePills, getCountryName, getInitials, getStatesOfCountry, iconButtonVariants, inAppNotificationCardA11y, inAppNotificationsPanelA11y, isBlank, isDuplicateSearchName, isFilterValueActive, isIndiaCountry, isKnownRegion, isPathActive, isValidAlpha2CountryCode, isValidSearchName, 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 };
|
|
78072
79680
|
//# sourceMappingURL=index.esm.js.map
|