@axinom/mosaic-ui 0.66.0-rc.0 → 0.66.0-rc.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-ui",
3
- "version": "0.66.0-rc.0",
3
+ "version": "0.66.0-rc.2",
4
4
  "description": "UI components for building Axinom Mosaic applications",
5
5
  "author": "Axinom",
6
6
  "license": "PROPRIETARY",
@@ -112,5 +112,5 @@
112
112
  "publishConfig": {
113
113
  "access": "public"
114
114
  },
115
- "gitHead": "33d1874b89d5afbcab34421ddef28e2ee6838d00"
115
+ "gitHead": "8367444991c09b4d3c680988cbb1d8feabefbb62"
116
116
  }
@@ -3,18 +3,18 @@ import classes from './TagsRenderer.scss';
3
3
 
4
4
  export const TagsRenderer = (val: unknown): JSX.Element => {
5
5
  const containerRef = useRef<HTMLDivElement>(null);
6
- const tagRefs = useRef<(HTMLDivElement | null)[]>([]);
7
- const [visibleItems, setVisibleItems] = useState<string[]>([]);
8
- const [hiddenItems, setHiddenItems] = useState<string[]>([]);
6
+ const resizeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
7
+ const [visibleCount, setVisibleCount] = useState<number>(0);
9
8
 
10
9
  useEffect(() => {
11
10
  if (!Array.isArray(val) || !containerRef.current || val.length === 0) {
11
+ setVisibleCount(0);
12
12
  return;
13
13
  }
14
14
 
15
15
  const calculateVisibleItems = (): void => {
16
16
  const container = containerRef.current;
17
- if (!container || tagRefs.current.length === 0) {
17
+ if (!container) {
18
18
  return;
19
19
  }
20
20
 
@@ -22,17 +22,30 @@ export const TagsRenderer = (val: unknown): JSX.Element => {
22
22
  const gap = 5; // Gap between items from SCSS
23
23
  const overflowIndicatorWidth = 60; // Approximate width for "... +X"
24
24
 
25
- // Measure actual tag widths using refs
25
+ // Measure actual tag widths using hidden temporary elements in the actual container
26
26
  const tagWidths: number[] = [];
27
- tagRefs.current.forEach((tagRef) => {
28
- if (tagRef) {
29
- tagWidths.push(tagRef.offsetWidth);
30
- }
31
- });
27
+ const tempElements: HTMLDivElement[] = [];
28
+
29
+ try {
30
+ (val as string[]).forEach((item) => {
31
+ const tempTag = document.createElement('div');
32
+ tempTag.className = classes.tag;
33
+ tempTag.textContent = item;
34
+ tempTag.style.position = 'absolute';
35
+ tempTag.style.visibility = 'hidden';
36
+ tempTag.style.pointerEvents = 'none';
37
+ container.appendChild(tempTag);
38
+ tempElements.push(tempTag);
39
+ tagWidths.push(tempTag.offsetWidth);
40
+ });
41
+ } finally {
42
+ // Clean up temporary elements
43
+ tempElements.forEach((el) => container.removeChild(el));
44
+ }
32
45
 
33
46
  // Calculate how many items can fit
34
47
  let totalWidth = 0;
35
- let visibleCount = 0;
48
+ let newVisibleCount = 0;
36
49
 
37
50
  for (let i = 0; i < val.length; i++) {
38
51
  const itemWidth = tagWidths[i] + (i > 0 ? gap : 0);
@@ -44,17 +57,17 @@ export const TagsRenderer = (val: unknown): JSX.Element => {
44
57
 
45
58
  if (requiredWidth <= containerWidth) {
46
59
  totalWidth += itemWidth;
47
- visibleCount++;
60
+ newVisibleCount++;
48
61
  } else {
49
62
  break;
50
63
  }
51
64
  }
52
65
 
53
66
  // If we can't fit all items, reserve space for overflow indicator
54
- if (visibleCount < val.length && visibleCount > 0) {
67
+ if (newVisibleCount < val.length && newVisibleCount > 0) {
55
68
  // Re-calculate with overflow indicator space reserved
56
69
  totalWidth = 0;
57
- visibleCount = 0;
70
+ newVisibleCount = 0;
58
71
 
59
72
  for (let i = 0; i < val.length; i++) {
60
73
  const itemWidth = tagWidths[i] + (i > 0 ? gap : 0);
@@ -63,27 +76,37 @@ export const TagsRenderer = (val: unknown): JSX.Element => {
63
76
 
64
77
  if (requiredWidth <= containerWidth && i < val.length - 1) {
65
78
  totalWidth += itemWidth;
66
- visibleCount++;
79
+ newVisibleCount++;
67
80
  } else {
68
81
  break;
69
82
  }
70
83
  }
71
84
  }
72
85
 
73
- setVisibleItems(val.slice(0, visibleCount));
74
- setHiddenItems(val.slice(visibleCount));
86
+ // Update state with the new visible count
87
+ setVisibleCount(newVisibleCount);
75
88
  };
76
89
 
77
- // Initial calculation after render
78
- const timer = setTimeout(() => {
79
- calculateVisibleItems();
80
- }, 0);
90
+ // Initial calculation
91
+ calculateVisibleItems();
81
92
 
82
- const resizeObserver = new ResizeObserver(calculateVisibleItems);
93
+ // Debounced resize handler
94
+ const debouncedCalculate = (): void => {
95
+ if (resizeTimeoutRef.current) {
96
+ clearTimeout(resizeTimeoutRef.current);
97
+ }
98
+ resizeTimeoutRef.current = setTimeout(() => {
99
+ calculateVisibleItems();
100
+ }, 100);
101
+ };
102
+
103
+ const resizeObserver = new ResizeObserver(debouncedCalculate);
83
104
  resizeObserver.observe(containerRef.current);
84
105
 
85
106
  return () => {
86
- clearTimeout(timer);
107
+ if (resizeTimeoutRef.current) {
108
+ clearTimeout(resizeTimeoutRef.current);
109
+ }
87
110
  resizeObserver.disconnect();
88
111
  };
89
112
  }, [val]);
@@ -93,6 +116,8 @@ export const TagsRenderer = (val: unknown): JSX.Element => {
93
116
  }
94
117
 
95
118
  const stringArray = val as string[];
119
+ const visibleItems = stringArray.slice(0, visibleCount);
120
+ const hiddenItems = stringArray.slice(visibleCount);
96
121
 
97
122
  // Create tooltip text for hidden items
98
123
  const tooltipText = hiddenItems.length > 0 ? hiddenItems.join(', ') : '';
@@ -104,25 +129,11 @@ export const TagsRenderer = (val: unknown): JSX.Element => {
104
129
  data-testid="tags-container"
105
130
  title={stringArray.join(', ')}
106
131
  >
107
- {stringArray.map((item, index) => {
108
- const isVisible = visibleItems.includes(item);
109
-
110
- return (
111
- <div
112
- key={`${item}-${index}`}
113
- ref={(el) => {
114
- tagRefs.current[index] = el;
115
- }}
116
- className={classes.tag}
117
- style={{
118
- visibility: isVisible ? 'visible' : 'hidden',
119
- position: isVisible ? 'static' : 'absolute',
120
- }}
121
- >
122
- {item}
123
- </div>
124
- );
125
- })}
132
+ {visibleItems.map((item, index) => (
133
+ <div key={`${item}-${index}`} className={classes.tag}>
134
+ {item}
135
+ </div>
136
+ ))}
126
137
  {hiddenItems.length > 0 && (
127
138
  <div className={classes.overflowIndicator} title={tooltipText}>
128
139
  {`+${hiddenItems.length}`}