sag_components 2.0.0-beta305 → 2.0.0-beta307

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/index.js CHANGED
@@ -3806,11 +3806,14 @@ const SearchInput$1 = props => {
3806
3806
  position = 'left',
3807
3807
  iconColor = '#212121',
3808
3808
  onTyping = () => {},
3809
+ onClear = () => {},
3810
+ clearTrigger,
3809
3811
  className
3810
3812
  } = props;
3811
3813
 
3812
3814
  // Use internal state for uncontrolled mode
3813
3815
  const [internalValue, setInternalValue] = React$1.useState(defaultValue);
3816
+ const previousValueRef = React$1.useRef(defaultValue);
3814
3817
 
3815
3818
  // Determine if component is controlled
3816
3819
  const isControlled = controlledValue !== undefined;
@@ -3822,12 +3825,33 @@ const SearchInput$1 = props => {
3822
3825
  setInternalValue(defaultValue);
3823
3826
  }
3824
3827
  }, [defaultValue, isControlled]);
3828
+
3829
+ // Clear the input when clearTrigger changes (external clear trigger)
3830
+ React$1.useEffect(() => {
3831
+ if (clearTrigger !== undefined) {
3832
+ setInternalValue('');
3833
+ }
3834
+ }, [clearTrigger]);
3825
3835
  const handleInputChange = e => {
3836
+ const newValue = e.target.value;
3837
+
3838
+ // Detect native clear button click (value was non-empty, now empty, via input event)
3839
+ if (previousValueRef.current && newValue === '') {
3840
+ onClear();
3841
+ }
3842
+ previousValueRef.current = newValue;
3826
3843
  if (!isControlled) {
3827
- setInternalValue(e.target.value);
3844
+ setInternalValue(newValue);
3828
3845
  }
3829
3846
  onTyping(e);
3830
3847
  };
3848
+
3849
+ // Handle the 'search' event which fires when native clear button is clicked
3850
+ const handleSearch = e => {
3851
+ if (e.target.value === '') {
3852
+ onClear();
3853
+ }
3854
+ };
3831
3855
  return /*#__PURE__*/React__default["default"].createElement(TextFieldContainer, {
3832
3856
  className: className,
3833
3857
  width: width
@@ -3842,6 +3866,7 @@ const SearchInput$1 = props => {
3842
3866
  height: height,
3843
3867
  placeholder: placeholder,
3844
3868
  onChange: handleInputChange,
3869
+ onSearch: handleSearch,
3845
3870
  position: position
3846
3871
  }));
3847
3872
  };
@@ -37724,8 +37749,16 @@ const SearchInput = styled__default["default"].input`
37724
37749
  }
37725
37750
  `;
37726
37751
  const ListWrapper = styled__default["default"].div`
37727
- max-height: ${props => props.maxHeight || 'unset'};
37728
- overflow-y: auto;
37752
+ max-height: ${props => {
37753
+ const maxH = parseInt(props.maxHeight) || 400;
37754
+ const actualH = (props.actualHeight || maxH) + 16;
37755
+ return actualH < maxH ? `${actualH}px` : props.maxHeight;
37756
+ }};
37757
+ overflow-y: ${props => {
37758
+ const maxH = parseInt(props.maxHeight) || 400;
37759
+ const actualH = (props.actualHeight || maxH) + 16;
37760
+ return actualH < maxH ? 'hidden' : 'auto';
37761
+ }};
37729
37762
  position: relative;
37730
37763
  `;
37731
37764
  const CheckboxGroup = styled__default["default"].div`
@@ -37770,6 +37803,7 @@ const CheckboxLabel = styled__default["default"].label`
37770
37803
  color: #212121;
37771
37804
  cursor: pointer;
37772
37805
  flex-shrink: 0;
37806
+ box-sizing: border-box;
37773
37807
 
37774
37808
  &:hover {
37775
37809
  background-color: #E6F0F0;
@@ -37842,7 +37876,7 @@ const FilterPop = props => {
37842
37876
  selectedAttributes: propSelectedAttributes = {},
37843
37877
  showSearch = true,
37844
37878
  searchPlaceholder = "Search...",
37845
- itemHeight = 32,
37879
+ itemHeight = 40,
37846
37880
  overscan = 5,
37847
37881
  hasActiveFilter = false // NEW: Indicates if this column has an active filter
37848
37882
  } = props;
@@ -37931,16 +37965,18 @@ const FilterPop = props => {
37931
37965
  offsetY
37932
37966
  } = React$1.useMemo(() => {
37933
37967
  const containerHeight = parseInt(maxHeight) || 400;
37934
- const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
37935
- const endIndex = Math.min(sortedList.length, Math.ceil((scrollTop + containerHeight) / itemHeight) + overscan);
37968
+ const gap = 8;
37969
+ const itemWithGap = itemHeight + gap;
37970
+ const startIndex = Math.max(0, Math.floor(scrollTop / itemWithGap) - overscan);
37971
+ const endIndex = Math.min(sortedList.length, Math.ceil((scrollTop + containerHeight) / itemWithGap) + overscan);
37936
37972
  const visible = sortedList.slice(startIndex, endIndex).map((item, idx) => ({
37937
37973
  ...item,
37938
37974
  index: startIndex + idx
37939
37975
  }));
37940
37976
  return {
37941
37977
  visibleItems: visible,
37942
- totalHeight: (sortedList.length + 1) * (itemHeight + 8),
37943
- offsetY: startIndex * itemHeight
37978
+ totalHeight: sortedList.length * itemHeight + Math.max(0, sortedList.length - 1) * gap,
37979
+ offsetY: startIndex * itemWithGap
37944
37980
  };
37945
37981
  }, [sortedList, scrollTop, itemHeight, overscan, maxHeight]);
37946
37982
  const areAllNonAllItemsSelected = function () {
@@ -38140,7 +38176,8 @@ const FilterPop = props => {
38140
38176
  }), /*#__PURE__*/React__default["default"].createElement(ListWrapper, {
38141
38177
  ref: scrollContainerRef,
38142
38178
  onScroll: handleScroll,
38143
- maxHeight: maxHeight
38179
+ maxHeight: maxHeight,
38180
+ actualHeight: totalHeight
38144
38181
  }, sortedList.length === 1 ? /*#__PURE__*/React__default["default"].createElement(NoResultsMessage, null, "No items match your search") : /*#__PURE__*/React__default["default"].createElement("div", {
38145
38182
  style: {
38146
38183
  height: `${totalHeight}px`,
@@ -40992,10 +41029,12 @@ const TableHeader = ({
40992
41029
  const debouncedFilterState = useDebounce(filterState, debounceDelay);
40993
41030
  const iconRefs = React$1.useRef({});
40994
41031
  const popupRef = React$1.useRef(null);
41032
+ const prevResetKeyRef = React$1.useRef(resetFiltersKey);
40995
41033
 
40996
- // Reset internal state when resetFiltersKey changes
41034
+ // Reset internal state when resetFiltersKey changes (not when columns change)
40997
41035
  React$1.useEffect(() => {
40998
- if (resetFiltersKey > 0) {
41036
+ // Only run reset when resetFiltersKey actually changed
41037
+ if (resetFiltersKey !== prevResetKeyRef.current && resetFiltersKey > 0) {
40999
41038
  const resetSelections = {};
41000
41039
  columns.forEach(column => {
41001
41040
  if (column.filter && column.filterOptions) {
@@ -41017,6 +41056,7 @@ const TableHeader = ({
41017
41056
  setVisibleFilterPopWrapper(null);
41018
41057
  setVisibleSortPopWrapper(null);
41019
41058
  }
41059
+ prevResetKeyRef.current = resetFiltersKey;
41020
41060
  }, [resetFiltersKey, columns]);
41021
41061
 
41022
41062
  // Track if we've already initialized from saved state
@@ -57689,6 +57729,21 @@ function ModalDrawer(_ref) {
57689
57729
  }, "\xD7"), children));
57690
57730
  }
57691
57731
 
57732
+ // Keyframes for rolling/marquee animation
57733
+ const scrollTextAnimation = styled.keyframes`
57734
+ 0% {
57735
+ transform: translateX(0);
57736
+ }
57737
+ 10% {
57738
+ transform: translateX(0);
57739
+ }
57740
+ 90% {
57741
+ transform: translateX(var(--scroll-distance, -30%));
57742
+ }
57743
+ 100% {
57744
+ transform: translateX(var(--scroll-distance, -30%));
57745
+ }
57746
+ `;
57692
57747
  const scrollableStyles = `
57693
57748
  &::-webkit-scrollbar {
57694
57749
  height: 8px;
@@ -57707,6 +57762,9 @@ const scrollableStyles = `
57707
57762
  `;
57708
57763
  const TooltipWrapper = styled__default["default"](Tooltip$2)`
57709
57764
  width: 100%;
57765
+ .tooltip-wrapper {
57766
+ width: 100%;
57767
+ }
57710
57768
  `;
57711
57769
  const DropdownContainer = styled__default["default"].div`
57712
57770
  position: relative;
@@ -57804,6 +57862,41 @@ const Wrapper = styled__default["default"].div`
57804
57862
  align-items: center;
57805
57863
  width: 100%;
57806
57864
  `;
57865
+
57866
+ // Wrapper for scrollable truncated text
57867
+ const ScrollableTextWrapper = styled__default["default"].div`
57868
+ flex: 1;
57869
+ display: flex;
57870
+ align-items: center;
57871
+ min-width: 0;
57872
+ overflow: hidden;
57873
+ position: relative;
57874
+ `;
57875
+
57876
+ // Inner text that scrolls when truncated
57877
+ const ScrollableTextInner = styled__default["default"].span`
57878
+ display: inline-block;
57879
+ white-space: nowrap;
57880
+ line-height: 21px;
57881
+ font-family: "Poppins", sans-serif;
57882
+ font-size: 14px;
57883
+ font-weight: 400;
57884
+ color: ${props => props.color || 'inherit'};
57885
+ max-width: 100%;
57886
+
57887
+ /* Default state: show ellipsis */
57888
+ overflow: hidden;
57889
+ text-overflow: ellipsis;
57890
+
57891
+ ${props => props.$isTruncated && styled.css`
57892
+ ${ScrollableTextWrapper}:hover & {
57893
+ /* On hover: remove ellipsis and start animation */
57894
+ overflow: visible;
57895
+ text-overflow: clip;
57896
+ animation: ${scrollTextAnimation} ${props.$animationDuration || 3}s linear infinite;
57897
+ }
57898
+ `}
57899
+ `;
57807
57900
  const TruncatedText = styled__default["default"].span`
57808
57901
  flex: 1;
57809
57902
  min-width: 0;
@@ -58120,7 +58213,54 @@ OverlayTemplateDialog.propTypes = {
58120
58213
  buttonHoverColor: PropTypes.string
58121
58214
  };
58122
58215
 
58123
- const OverlayDropdown = _ref => {
58216
+ // Component for scrolling truncated text on hover
58217
+ const ScrollingText = _ref => {
58218
+ let {
58219
+ children,
58220
+ color
58221
+ } = _ref;
58222
+ const wrapperRef = React$1.useRef(null);
58223
+ const textRef = React$1.useRef(null);
58224
+ const [isTruncated, setIsTruncated] = React$1.useState(false);
58225
+ const [scrollDistance, setScrollDistance] = React$1.useState(0);
58226
+ const [animationDuration, setAnimationDuration] = React$1.useState(3);
58227
+ const checkTruncation = React$1.useCallback(() => {
58228
+ if (wrapperRef.current && textRef.current) {
58229
+ const wrapperWidth = wrapperRef.current.offsetWidth;
58230
+ const textWidth = textRef.current.scrollWidth;
58231
+ const isOverflowing = textWidth > wrapperWidth;
58232
+ setIsTruncated(isOverflowing);
58233
+ if (isOverflowing) {
58234
+ // Calculate how much we need to scroll (extra width + small padding)
58235
+ const extraWidth = textWidth - wrapperWidth + 20;
58236
+ setScrollDistance(-extraWidth);
58237
+
58238
+ // Calculate animation duration based on text length (roughly 50px per second)
58239
+ const duration = Math.max(2, Math.min(8, extraWidth / 50));
58240
+ setAnimationDuration(duration);
58241
+ }
58242
+ }
58243
+ }, []);
58244
+ React$1.useEffect(() => {
58245
+ checkTruncation();
58246
+
58247
+ // Recheck on window resize
58248
+ window.addEventListener('resize', checkTruncation);
58249
+ return () => window.removeEventListener('resize', checkTruncation);
58250
+ }, [children, checkTruncation]);
58251
+ return /*#__PURE__*/React__default["default"].createElement(ScrollableTextWrapper, {
58252
+ ref: wrapperRef
58253
+ }, /*#__PURE__*/React__default["default"].createElement(ScrollableTextInner, {
58254
+ ref: textRef,
58255
+ color: color,
58256
+ $isTruncated: isTruncated,
58257
+ $animationDuration: animationDuration,
58258
+ style: {
58259
+ '--scroll-distance': `${scrollDistance}px`
58260
+ }
58261
+ }, children));
58262
+ };
58263
+ const OverlayDropdown = _ref2 => {
58124
58264
  let {
58125
58265
  data = [],
58126
58266
  value,
@@ -58146,7 +58286,7 @@ const OverlayDropdown = _ref => {
58146
58286
  height = "auto",
58147
58287
  margin = "8px",
58148
58288
  ...props
58149
- } = _ref;
58289
+ } = _ref2;
58150
58290
  const [open, setOpen] = React$1.useState(false);
58151
58291
  const [hoveredText, setHoveredText] = React$1.useState(null);
58152
58292
  const [templateDialog, setTemplateDialog] = React$1.useState(null);
@@ -58433,9 +58573,8 @@ const OverlayDropdown = _ref => {
58433
58573
  }
58434
58574
  }
58435
58575
  }
58436
- }, /*#__PURE__*/React__default["default"].createElement(TruncatedText, {
58437
- onMouseEnter: () => setHoveredText(displayText),
58438
- onMouseLeave: () => setHoveredText(null)
58576
+ }, /*#__PURE__*/React__default["default"].createElement(ScrollingText, {
58577
+ color: item.value === value ? '#fff' : '#212121'
58439
58578
  }, displayText), iconToShow);
58440
58579
  })))), templateDialog && /*#__PURE__*/React__default["default"].createElement(OverlayTemplateDialog, {
58441
58580
  open: true,