funda-ui 4.7.730 → 4.7.740
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/EventCalendarTimeline/index.css +3 -0
- package/EventCalendarTimeline/index.js +316 -197
- package/lib/cjs/EventCalendarTimeline/index.js +316 -197
- package/lib/css/EventCalendarTimeline/index.css +3 -0
- package/lib/esm/EventCalendarTimeline/index.scss +3 -0
- package/lib/esm/EventCalendarTimeline/index.tsx +343 -200
- package/lib/esm/ModalDialog/index.tsx +1 -0
- package/package.json +1 -1
|
@@ -247,10 +247,12 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
247
247
|
//
|
|
248
248
|
const now = useMemo(() => new Date(), []);
|
|
249
249
|
const [date, setDate] = useState<Date>(now);
|
|
250
|
+
const prevDateRef = useRef<Date | null>(null);
|
|
250
251
|
const [day, setDay] = useState<number>(date.getDate());
|
|
251
252
|
const [month, setMonth] = useState<number>(date.getMonth());
|
|
252
253
|
const [year, setYear] = useState<number>(date.getFullYear());
|
|
253
254
|
const [startDay, setStartDay] = useState<number>(getStartDayOfMonth(date));
|
|
255
|
+
|
|
254
256
|
|
|
255
257
|
|
|
256
258
|
// selection tab
|
|
@@ -291,6 +293,10 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
291
293
|
const [tempDate, setTempDate] = useState<string>('');
|
|
292
294
|
|
|
293
295
|
|
|
296
|
+
// Track all pending requestAnimationFrame IDs for cleanup on unmount
|
|
297
|
+
const rafIdsRef = useRef<Set<number>>(new Set());
|
|
298
|
+
|
|
299
|
+
|
|
294
300
|
|
|
295
301
|
// Open temporary storage for pop-ups
|
|
296
302
|
const [tableRowNum, setTableRowNum] = useState<number>(-1);
|
|
@@ -901,6 +907,7 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
901
907
|
let mouseDown: boolean = false;
|
|
902
908
|
let startX: any = 0;
|
|
903
909
|
let scrollLeft: any = 0;
|
|
910
|
+
const tableDragRafIdRef = useRef<number | null>(null);
|
|
904
911
|
|
|
905
912
|
const handleTableDragStart = useCallback((e: any) => {
|
|
906
913
|
draggedObj = e.currentTarget;
|
|
@@ -920,14 +927,29 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
920
927
|
|
|
921
928
|
mouseDown = false;
|
|
922
929
|
draggedObj.classList.remove('dragging');
|
|
930
|
+
|
|
931
|
+
// Cancel any pending animation frame
|
|
932
|
+
if (tableDragRafIdRef.current !== null) {
|
|
933
|
+
cancelAnimationFrame(tableDragRafIdRef.current);
|
|
934
|
+
tableDragRafIdRef.current = null;
|
|
935
|
+
}
|
|
936
|
+
|
|
923
937
|
}, []);
|
|
924
938
|
|
|
925
939
|
const handleTableMove = useCallback((e: any) => {
|
|
926
940
|
e.preventDefault();
|
|
927
941
|
if (!mouseDown) { return; }
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
// Use requestAnimationFrame to throttle scroll updates for better performance
|
|
945
|
+
if (tableDragRafIdRef.current === null) {
|
|
946
|
+
tableDragRafIdRef.current = requestAnimationFrame(() => {
|
|
947
|
+
const x = e.pageX - draggedObj.offsetLeft;
|
|
948
|
+
const scroll = x - startX;
|
|
949
|
+
draggedObj.scrollLeft = scrollLeft - scroll;
|
|
950
|
+
tableDragRafIdRef.current = null;
|
|
951
|
+
});
|
|
952
|
+
}
|
|
931
953
|
}, []);
|
|
932
954
|
|
|
933
955
|
|
|
@@ -1019,25 +1041,37 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
1019
1041
|
// ================================================================
|
|
1020
1042
|
// Calendar
|
|
1021
1043
|
// ================================================================
|
|
1022
|
-
function updateTodayDate(inputDate: Date) {
|
|
1044
|
+
function updateTodayDate(inputDate: Date, prevDate?: Date | null) {
|
|
1045
|
+
const previous = prevDate ?? prevDateRef.current;
|
|
1046
|
+
const hasMonthOrYearChanged =
|
|
1047
|
+
!previous ||
|
|
1048
|
+
previous.getMonth() !== inputDate.getMonth() ||
|
|
1049
|
+
previous.getFullYear() !== inputDate.getFullYear();
|
|
1050
|
+
|
|
1051
|
+
// Always sync the active day value
|
|
1023
1052
|
setDay(inputDate.getDate());
|
|
1024
|
-
setMonth(inputDate.getMonth());
|
|
1025
|
-
setYear(inputDate.getFullYear());
|
|
1026
|
-
setStartDay(getStartDayOfMonth(inputDate));
|
|
1027
1053
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1054
|
+
if (hasMonthOrYearChanged) {
|
|
1055
|
+
// Only update month/year related state when it actually changes;
|
|
1056
|
+
// this prevents expensive table re-inits for simple day clicks.
|
|
1057
|
+
setMonth(inputDate.getMonth());
|
|
1058
|
+
setYear(inputDate.getFullYear());
|
|
1059
|
+
setStartDay(getStartDayOfMonth(inputDate));
|
|
1031
1060
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
tableGridInit();
|
|
1061
|
+
// update selector
|
|
1062
|
+
setSelectedMonth(inputDate.getMonth());
|
|
1063
|
+
setSelectedYear(inputDate.getFullYear());
|
|
1036
1064
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1065
|
+
setTimeout(() => {
|
|
1066
|
+
// initialize table grid
|
|
1067
|
+
tableGridInit();
|
|
1040
1068
|
|
|
1069
|
+
// The scrollbar position is horizontal
|
|
1070
|
+
bodyScrollbarInit();
|
|
1071
|
+
}, 500);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
prevDateRef.current = inputDate;
|
|
1041
1075
|
}
|
|
1042
1076
|
|
|
1043
1077
|
|
|
@@ -1136,6 +1170,29 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
1136
1170
|
|
|
1137
1171
|
}
|
|
1138
1172
|
function handleDayChange(e: React.MouseEvent, currentDay: number) {
|
|
1173
|
+
// Avoid triggering a full table re-render when the clicked cell is already
|
|
1174
|
+
// the active day; this becomes expensive with large datasets.
|
|
1175
|
+
if (
|
|
1176
|
+
date.getDate() === currentDay &&
|
|
1177
|
+
date.getMonth() === month &&
|
|
1178
|
+
date.getFullYear() === year
|
|
1179
|
+
) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
// !!! Important, performance optimization for large data renderings
|
|
1184
|
+
/*
|
|
1185
|
+
- Previously, every time I clicked on the date, 'setDate' would be called in 'useEffect([date])',
|
|
1186
|
+
and 'tableGridInit + bodyScrollbarInit' would be run regardless of whether it was across months/years,
|
|
1187
|
+
and these recalculations and DOM operations were very time-consuming when 1000+ pieces of data, causing lag.
|
|
1188
|
+
|
|
1189
|
+
- Now remember the last date with 'prevDateRef', reset the month/year related state only when the month or year
|
|
1190
|
+
changes and execute 'tableGridInit/scrollbarInit'. Only 'day' is updated when the date is changed, avoiding
|
|
1191
|
+
the relayout of the entire table and the initialization of the scrollbar.
|
|
1192
|
+
|
|
1193
|
+
-'handleDayChange' still updates 'date', but since the month/year has not changed, it no longer triggers heavy
|
|
1194
|
+
initialization, significantly reducing stuttering when clicking, while the month/year switch triggers a full recount as usual.
|
|
1195
|
+
*/
|
|
1139
1196
|
setDate(new Date(year, month, currentDay));
|
|
1140
1197
|
}
|
|
1141
1198
|
|
|
@@ -1866,30 +1923,44 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
1866
1923
|
|
|
1867
1924
|
|
|
1868
1925
|
function tableGridInitHeadertitle() {
|
|
1926
|
+
|
|
1869
1927
|
//
|
|
1870
1928
|
if (tableGridRef.current === null) return;
|
|
1871
1929
|
|
|
1872
1930
|
const tableGridEl: any = tableGridRef.current;
|
|
1873
1931
|
|
|
1874
|
-
//
|
|
1875
|
-
const
|
|
1876
|
-
|
|
1877
|
-
if (!headerTitleTbody || !contentTbody) return;
|
|
1932
|
+
// Use requestAnimationFrame to batch DOM operations
|
|
1933
|
+
const rafId = requestAnimationFrame(() => {
|
|
1934
|
+
|
|
1878
1935
|
|
|
1879
|
-
|
|
1880
|
-
|
|
1936
|
+
// initialize cell height
|
|
1937
|
+
const headerTitleTbody = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__title tbody');
|
|
1938
|
+
const contentTbody = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content tbody');
|
|
1939
|
+
if (!headerTitleTbody || !contentTbody) return;
|
|
1940
|
+
|
|
1941
|
+
const headerTitleTrElements = headerTitleTbody.getElementsByTagName('tr');
|
|
1942
|
+
const trElements = contentTbody.getElementsByTagName('tr');
|
|
1943
|
+
|
|
1944
|
+
// Reset any previously set inline heights so we measure natural heights.
|
|
1945
|
+
for (let i = 0; i < headerTitleTrElements.length; i++) {
|
|
1946
|
+
// set to 'auto' (or remove inline style) to allow shrink
|
|
1947
|
+
headerTitleTrElements[i].style.height = 'auto';
|
|
1948
|
+
if (trElements[i]) trElements[i].style.height = 'auto';
|
|
1949
|
+
|
|
1950
|
+
const targetElement = headerTitleTrElements[i].offsetHeight > trElements[i].offsetHeight ? headerTitleTrElements[i] : trElements[i];
|
|
1951
|
+
const tdOHeight = window.getComputedStyle(targetElement).height;
|
|
1952
|
+
headerTitleTrElements[i].style.height = tdOHeight;
|
|
1953
|
+
trElements[i].style.height = tdOHeight;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
|
|
1957
|
+
// Remove from tracking set after execution
|
|
1958
|
+
rafIdsRef.current.delete(rafId);
|
|
1959
|
+
});
|
|
1960
|
+
|
|
1961
|
+
// Track this requestAnimationFrame ID for cleanup
|
|
1962
|
+
rafIdsRef.current.add(rafId);
|
|
1881
1963
|
|
|
1882
|
-
// Reset any previously set inline heights so we measure natural heights.
|
|
1883
|
-
for (let i = 0; i < headerTitleTrElements.length; i++) {
|
|
1884
|
-
// set to 'auto' (or remove inline style) to allow shrink
|
|
1885
|
-
headerTitleTrElements[i].style.height = 'auto';
|
|
1886
|
-
if (trElements[i]) trElements[i].style.height = 'auto';
|
|
1887
|
-
|
|
1888
|
-
const targetElement = headerTitleTrElements[i].offsetHeight > trElements[i].offsetHeight ? headerTitleTrElements[i] : trElements[i];
|
|
1889
|
-
const tdOHeight = window.getComputedStyle(targetElement).height;
|
|
1890
|
-
headerTitleTrElements[i].style.height = tdOHeight;
|
|
1891
|
-
trElements[i].style.height = tdOHeight;
|
|
1892
|
-
}
|
|
1893
1964
|
|
|
1894
1965
|
|
|
1895
1966
|
}
|
|
@@ -1909,223 +1980,234 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
1909
1980
|
_curColCount = 7;
|
|
1910
1981
|
}
|
|
1911
1982
|
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
// calculate min width (MODE: WEEK)
|
|
1916
|
-
//--------------
|
|
1917
|
-
if (appearanceMode === 'week') {
|
|
1918
|
-
const tableMaxWidth = tableGridEl.clientWidth;
|
|
1919
|
-
const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
|
|
1920
|
-
const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
|
|
1921
|
-
const tableBorderWidth = 4;
|
|
1922
|
-
const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
|
|
1983
|
+
// Use requestAnimationFrame to batch DOM operations
|
|
1984
|
+
const rafId = requestAnimationFrame(() => {
|
|
1985
|
+
|
|
1923
1986
|
|
|
1924
|
-
|
|
1925
|
-
|
|
1987
|
+
//****************
|
|
1988
|
+
// STEP 1-1:
|
|
1989
|
+
//****************
|
|
1990
|
+
// calculate min width (MODE: WEEK)
|
|
1991
|
+
//--------------
|
|
1992
|
+
if (appearanceMode === 'week') {
|
|
1993
|
+
const tableMaxWidth = tableGridEl.clientWidth;
|
|
1994
|
+
const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
|
|
1995
|
+
const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
|
|
1996
|
+
const tableBorderWidth = 4;
|
|
1997
|
+
const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
|
|
1926
1998
|
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
node.style.width = _curCellMinWidth + 'px';
|
|
1930
|
-
});
|
|
1999
|
+
_curCellMinWidth = scrollMaxWidth / 7;
|
|
2000
|
+
_curColCount = 7;
|
|
1931
2001
|
|
|
2002
|
+
// header
|
|
2003
|
+
tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-headercontent__container, .custom-event-tl-table__cell-cushion-content').forEach((node: HTMLDivElement) => {
|
|
2004
|
+
node.style.width = _curCellMinWidth + 'px';
|
|
2005
|
+
});
|
|
1932
2006
|
|
|
1933
|
-
}
|
|
1934
2007
|
|
|
2008
|
+
}
|
|
1935
2009
|
|
|
1936
2010
|
|
|
1937
|
-
//****************
|
|
1938
|
-
// STEP 1-2:
|
|
1939
|
-
//****************
|
|
1940
|
-
// calculate min width (MODE: MONTH)
|
|
1941
|
-
//--------------
|
|
1942
|
-
const cellMinWidth = _curCellMinWidth;
|
|
1943
|
-
const colCount = _curColCount;
|
|
1944
|
-
const scrollableMinWidth = cellMinWidth * colCount;
|
|
1945
2011
|
|
|
2012
|
+
//****************
|
|
2013
|
+
// STEP 1-2:
|
|
2014
|
+
//****************
|
|
2015
|
+
// calculate min width (MODE: MONTH)
|
|
2016
|
+
//--------------
|
|
2017
|
+
const cellMinWidth = _curCellMinWidth;
|
|
2018
|
+
const colCount = _curColCount;
|
|
2019
|
+
const scrollableMinWidth = cellMinWidth * colCount;
|
|
1946
2020
|
|
|
1947
|
-
//****************
|
|
1948
|
-
// STEP 1-3:
|
|
1949
|
-
//****************
|
|
1950
|
-
// initialize "header & main" cells
|
|
1951
|
-
//--------------
|
|
1952
|
-
const headerThContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-header__content tbody').getElementsByTagName('th');
|
|
1953
|
-
for (let i = 0; i < headerThContentContainers.length; i++) {
|
|
1954
|
-
const curHeaderThContent = headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent');
|
|
1955
|
-
if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
|
|
1956
|
-
}
|
|
1957
2021
|
|
|
2022
|
+
//****************
|
|
2023
|
+
// STEP 1-3:
|
|
2024
|
+
//****************
|
|
2025
|
+
// initialize "header & main" cells
|
|
2026
|
+
//--------------
|
|
2027
|
+
const headerThContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-header__content tbody').getElementsByTagName('th');
|
|
2028
|
+
for (let i = 0; i < headerThContentContainers.length; i++) {
|
|
2029
|
+
const curHeaderThContent = headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent');
|
|
2030
|
+
if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
|
|
2031
|
+
}
|
|
1958
2032
|
|
|
1959
|
-
const mainTdContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content tbody').getElementsByTagName('td');
|
|
1960
|
-
for (let i = 0; i < mainTdContentContainers.length; i++) {
|
|
1961
|
-
const curHeaderThContent = mainTdContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-content');
|
|
1962
|
-
if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
|
|
1963
|
-
}
|
|
1964
2033
|
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2034
|
+
const mainTdContentContainers: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content tbody').getElementsByTagName('td');
|
|
2035
|
+
for (let i = 0; i < mainTdContentContainers.length; i++) {
|
|
2036
|
+
const curHeaderThContent = mainTdContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-content');
|
|
2037
|
+
if (curHeaderThContent !== null) curHeaderThContent.style.width = _curCellMinWidth + 'px';
|
|
2038
|
+
}
|
|
1969
2039
|
|
|
2040
|
+
const mainTdContentCols: any = tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content colgroup').getElementsByTagName('col')
|
|
2041
|
+
for (let i = 0; i < mainTdContentCols.length; i++) {
|
|
2042
|
+
mainTdContentCols[i].style.minWidth = _curCellMinWidth + 'px';
|
|
2043
|
+
}
|
|
1970
2044
|
|
|
1971
|
-
//****************
|
|
1972
|
-
// STEP 2:
|
|
1973
|
-
//****************
|
|
1974
|
-
// initialize scrollable wrapper (width)
|
|
1975
|
-
//--------------
|
|
1976
|
-
const _scrollableWrapper: HTMLElement[] = tableGridEl.querySelectorAll('.custom-event-tl-table__scroller-harness');
|
|
1977
|
-
[].slice.call(_scrollableWrapper).forEach((el: any) => {
|
|
1978
|
-
const scrollType = el.dataset.scroll;
|
|
1979
2045
|
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
2046
|
+
//****************
|
|
2047
|
+
// STEP 2:
|
|
2048
|
+
//****************
|
|
2049
|
+
// initialize scrollable wrapper (width)
|
|
2050
|
+
//--------------
|
|
2051
|
+
const _scrollableWrapper: HTMLElement[] = tableGridEl.querySelectorAll('.custom-event-tl-table__scroller-harness');
|
|
2052
|
+
[].slice.call(_scrollableWrapper).forEach((el: any) => {
|
|
2053
|
+
const scrollType = el.dataset.scroll;
|
|
1986
2054
|
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
|
|
2055
|
+
if (appearanceMode === 'week') {
|
|
2056
|
+
el.classList.add('custom-event-tl-table__scroller-harness--hideX');
|
|
2057
|
+
}
|
|
2058
|
+
if (appearanceMode === 'month') {
|
|
2059
|
+
el.classList.remove('custom-event-tl-table__scroller-harness--hideX');
|
|
2060
|
+
}
|
|
1994
2061
|
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
2062
|
+
if (scrollType !== 'list') {
|
|
2063
|
+
const _content = el.querySelector('.custom-event-tl-table__scroller');
|
|
2064
|
+
const tableMaxWidth = tableGridEl.clientWidth;
|
|
2065
|
+
const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
|
|
2066
|
+
const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
|
|
2067
|
+
const tableBorderWidth = 4;
|
|
2068
|
+
const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
|
|
1998
2069
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2070
|
+
el.dataset.width = scrollMaxWidth;
|
|
2071
|
+
el.style.maxWidth = el.dataset.width + 'px';
|
|
2072
|
+
_content.style.minWidth = scrollableMinWidth + 'px';
|
|
2073
|
+
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2001
2076
|
|
|
2002
2077
|
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2078
|
+
//****************
|
|
2079
|
+
// STEP 3:
|
|
2080
|
+
//****************
|
|
2081
|
+
// initialize cell width
|
|
2082
|
+
//--------------
|
|
2083
|
+
const tdElementMaxWidth: number = typeof mainTdContentContainers[0] === 'undefined' ? 0 : parseFloat(window.getComputedStyle(mainTdContentContainers[0].querySelector('.custom-event-tl-table__cell-cushion-content')).maxWidth);
|
|
2009
2084
|
|
|
2010
2085
|
|
|
2011
|
-
|
|
2086
|
+
if (Array.isArray(eventsValue) && eventsValue.length > 0) {
|
|
2012
2087
|
|
|
2013
|
-
|
|
2088
|
+
for (let i = 0; i < headerThContentContainers.length; i++) {
|
|
2014
2089
|
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2090
|
+
const curHeaderThContent = headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent');
|
|
2091
|
+
const curHeaderThContentMaxWidth = parseFloat(window.getComputedStyle(curHeaderThContent).width);
|
|
2092
|
+
const targetElement = headerThContentContainers[i].offsetWidth > mainTdContentContainers[i].offsetWidth ? headerThContentContainers[i] : mainTdContentContainers[i];
|
|
2093
|
+
let tdOwidth = parseFloat(window.getComputedStyle(targetElement).width);
|
|
2019
2094
|
|
|
2020
2095
|
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2096
|
+
// check td max width
|
|
2097
|
+
if (tdElementMaxWidth > 0 && tdOwidth > tdElementMaxWidth) {
|
|
2098
|
+
tdOwidth = tdElementMaxWidth;
|
|
2099
|
+
}
|
|
2025
2100
|
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2101
|
+
// check header th max width
|
|
2102
|
+
if (tdElementMaxWidth > 0 && tdElementMaxWidth < curHeaderThContentMaxWidth) {
|
|
2103
|
+
tdOwidth = curHeaderThContentMaxWidth;
|
|
2104
|
+
}
|
|
2030
2105
|
|
|
2031
|
-
|
|
2032
|
-
|
|
2106
|
+
// Prevent the width from being +1 each time it is initialized
|
|
2107
|
+
tdOwidth = tdOwidth - 1;
|
|
2033
2108
|
|
|
2034
2109
|
|
|
2035
|
-
|
|
2036
|
-
|
|
2110
|
+
headerThContentContainers[i].querySelector('.custom-event-tl-table__cell-cushion-headercontent').style.width = tdOwidth + 'px';
|
|
2111
|
+
mainTdContentCols[i].style.minWidth = tdOwidth + 'px';
|
|
2037
2112
|
|
|
2038
2113
|
|
|
2114
|
+
}
|
|
2039
2115
|
}
|
|
2040
|
-
}
|
|
2041
2116
|
|
|
2042
2117
|
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2118
|
+
//****************
|
|
2119
|
+
// STEP 4:
|
|
2120
|
+
//****************
|
|
2121
|
+
// initialize max width of table content
|
|
2122
|
+
//--------------
|
|
2123
|
+
if (scrollBodyRef.current !== null && scrollHeaderRef.current !== null) {
|
|
2124
|
+
const tableContentWidth = window.getComputedStyle(tableGridEl.querySelector('.custom-event-tl-table__datagrid-body__content')).width;
|
|
2125
|
+
const scrollBodyEl: any = scrollBodyRef.current;
|
|
2126
|
+
const scrollHeaderEl: any = scrollHeaderRef.current;
|
|
2052
2127
|
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2128
|
+
scrollBodyEl.style.width = tableContentWidth;
|
|
2129
|
+
scrollHeaderEl.style.width = tableContentWidth;
|
|
2130
|
+
scrollBodyEl.dataset.width = parseFloat(tableContentWidth);
|
|
2131
|
+
scrollHeaderEl.dataset.width = parseFloat(tableContentWidth);
|
|
2057
2132
|
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2133
|
+
//
|
|
2134
|
+
const tableWrapperMaxWidthLatest = tableGridEl.clientWidth;
|
|
2135
|
+
if (tableWrapperMaxWidthLatest > parseFloat(tableContentWidth)) {
|
|
2136
|
+
tableGridEl.querySelector('.custom-event-tl-table__timeline-table').style.width = tableContentWidth;
|
|
2137
|
+
}
|
|
2063
2138
|
|
|
2064
2139
|
|
|
2065
|
-
|
|
2140
|
+
}
|
|
2066
2141
|
|
|
2067
2142
|
|
|
2068
2143
|
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2144
|
+
//****************
|
|
2145
|
+
// STEP 5:
|
|
2146
|
+
//****************
|
|
2147
|
+
// initialize cell height
|
|
2148
|
+
//--------------
|
|
2149
|
+
tableGridInitHeadertitle();
|
|
2075
2150
|
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2151
|
+
//****************
|
|
2152
|
+
// STEP 6:
|
|
2153
|
+
//****************
|
|
2154
|
+
//initialize scrollable wrapper (height)
|
|
2155
|
+
//--------------
|
|
2156
|
+
[].slice.call(_scrollableWrapper).forEach((el: any) => {
|
|
2157
|
+
const scrollType = el.dataset.scroll;
|
|
2158
|
+
const oldHeight = el.clientHeight;
|
|
2084
2159
|
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2160
|
+
if (scrollType !== 'header') {
|
|
2161
|
+
const tableWrapperMaxHeight = window.getComputedStyle(tableGridEl as HTMLElement).height;
|
|
2162
|
+
if (oldHeight > parseFloat(tableWrapperMaxHeight)) {
|
|
2163
|
+
el.style.height = tableWrapperMaxHeight;
|
|
2164
|
+
}
|
|
2089
2165
|
}
|
|
2090
|
-
}
|
|
2091
2166
|
|
|
2092
|
-
|
|
2167
|
+
});
|
|
2093
2168
|
|
|
2094
2169
|
|
|
2095
2170
|
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2171
|
+
//****************
|
|
2172
|
+
// STEP 7:
|
|
2173
|
+
//****************
|
|
2174
|
+
// display wrapper
|
|
2175
|
+
//--------------
|
|
2176
|
+
setGridReady(true);
|
|
2102
2177
|
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2178
|
+
//****************
|
|
2179
|
+
// STEP 7-1:
|
|
2180
|
+
//****************
|
|
2181
|
+
// calculate min width (MODE: WEEK)
|
|
2182
|
+
//--------------
|
|
2183
|
+
if (appearanceMode === 'week') {
|
|
2184
|
+
const tableMaxWidth = tableGridEl.clientWidth;
|
|
2185
|
+
const tableHeaderTitleWidth = tableGridEl.querySelector('.custom-event-tl-table__cell-cushion-headertitle').clientWidth;
|
|
2186
|
+
const tableDividerWidth = tableGridEl.querySelector('.custom-event-tl-table__timeline-divider').clientWidth;
|
|
2187
|
+
const tableBorderWidth = 4;
|
|
2188
|
+
const scrollMaxWidth = tableMaxWidth - tableHeaderTitleWidth - tableDividerWidth - tableBorderWidth;
|
|
2114
2189
|
|
|
2115
|
-
|
|
2116
|
-
|
|
2190
|
+
_curCellMinWidth = scrollMaxWidth / 7;
|
|
2191
|
+
_curColCount = 7;
|
|
2117
2192
|
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2193
|
+
// header content
|
|
2194
|
+
tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-headercontent__container, .custom-event-tl-table__cell-cushion-headercontent').forEach((node: HTMLDivElement) => {
|
|
2195
|
+
node.style.width = _curCellMinWidth + 'px';
|
|
2196
|
+
});
|
|
2122
2197
|
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2198
|
+
// main content
|
|
2199
|
+
tableGridEl.querySelectorAll('.custom-event-tl-table__cell-cushion-content').forEach((node: HTMLDivElement) => {
|
|
2200
|
+
node.style.width = _curCellMinWidth + 'px';
|
|
2201
|
+
});
|
|
2127
2202
|
|
|
2128
|
-
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
// Remove from tracking set after execution
|
|
2206
|
+
rafIdsRef.current.delete(rafId);
|
|
2207
|
+
});
|
|
2208
|
+
|
|
2209
|
+
// Track this requestAnimationFrame ID for cleanup
|
|
2210
|
+
rafIdsRef.current.add(rafId);
|
|
2129
2211
|
|
|
2130
2212
|
}
|
|
2131
2213
|
|
|
@@ -2160,6 +2242,52 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2160
2242
|
|
|
2161
2243
|
}
|
|
2162
2244
|
|
|
2245
|
+
// Dual RAF survival test
|
|
2246
|
+
/*
|
|
2247
|
+
A single RAF only guarantees "moving to the next frame."
|
|
2248
|
+
Only dual RAFs can guarantee "DOM is mounted + layout is stable."
|
|
2249
|
+
*/
|
|
2250
|
+
const [gridReady, setGridReady] = useState<boolean>(false);
|
|
2251
|
+
const rafRef = useRef<{ r1?: number; r2?: number }>({});
|
|
2252
|
+
|
|
2253
|
+
function safeShowGrid() {
|
|
2254
|
+
//
|
|
2255
|
+
setGridReady(false);
|
|
2256
|
+
|
|
2257
|
+
rafRef.current.r1 = requestAnimationFrame(() => {
|
|
2258
|
+
rafRef.current.r2 = requestAnimationFrame(() => {
|
|
2259
|
+
const el = tableGridRef.current;
|
|
2260
|
+
if (!el) return;
|
|
2261
|
+
|
|
2262
|
+
//
|
|
2263
|
+
tableGridInit();
|
|
2264
|
+
|
|
2265
|
+
// Do only one thing: notify React that it’s ready to be displayed.
|
|
2266
|
+
setGridReady(true);
|
|
2267
|
+
});
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
useEffect(() => {
|
|
2272
|
+
safeShowGrid();
|
|
2273
|
+
|
|
2274
|
+
return () => {
|
|
2275
|
+
if (rafRef.current.r1) {
|
|
2276
|
+
cancelAnimationFrame(rafRef.current.r1);
|
|
2277
|
+
}
|
|
2278
|
+
if (rafRef.current.r2) {
|
|
2279
|
+
cancelAnimationFrame(rafRef.current.r2);
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2282
|
+
}, [appearanceMode]);
|
|
2283
|
+
|
|
2284
|
+
|
|
2285
|
+
// Make sure the left side is highly synchronized with the right side.
|
|
2286
|
+
useEffect(() => {
|
|
2287
|
+
tableGridInitHeadertitle();
|
|
2288
|
+
}, [orginalData, appearanceMode]);
|
|
2289
|
+
|
|
2290
|
+
|
|
2163
2291
|
// if user change the selectedYear, then udate the years array that is displayed on year tab view
|
|
2164
2292
|
useEffect(() => {
|
|
2165
2293
|
const years: number[] = [];
|
|
@@ -2172,7 +2300,7 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2172
2300
|
|
|
2173
2301
|
|
|
2174
2302
|
useEffect(() => {
|
|
2175
|
-
updateTodayDate(date);
|
|
2303
|
+
updateTodayDate(date, prevDateRef.current);
|
|
2176
2304
|
}, [date]);
|
|
2177
2305
|
|
|
2178
2306
|
|
|
@@ -2222,6 +2350,18 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2222
2350
|
//--------------
|
|
2223
2351
|
return () => {
|
|
2224
2352
|
|
|
2353
|
+
// Cancel all pending requestAnimationFrame callbacks to prevent memory leaks
|
|
2354
|
+
rafIdsRef.current.forEach((rafId) => {
|
|
2355
|
+
cancelAnimationFrame(rafId);
|
|
2356
|
+
});
|
|
2357
|
+
rafIdsRef.current.clear();
|
|
2358
|
+
|
|
2359
|
+
// Cancel table drag animation frame if pending
|
|
2360
|
+
if (tableDragRafIdRef.current !== null) {
|
|
2361
|
+
cancelAnimationFrame(tableDragRafIdRef.current);
|
|
2362
|
+
tableDragRafIdRef.current = null;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2225
2365
|
// reset table grid
|
|
2226
2366
|
tableGridReset();
|
|
2227
2367
|
|
|
@@ -2475,8 +2615,11 @@ const EventCalendarTimeline = (props: EventCalendarTimelineProps) => {
|
|
|
2475
2615
|
<div
|
|
2476
2616
|
ref={tableGridRef}
|
|
2477
2617
|
className={combinedCls(
|
|
2478
|
-
`custom-event-tl-table__timeline-table__wrapper custom-event-tl-table__timeline-table__wrapper--${appearanceMode}
|
|
2479
|
-
tableWrapperClassName
|
|
2618
|
+
`custom-event-tl-table__timeline-table__wrapper custom-event-tl-table__timeline-table__wrapper--${appearanceMode}`,
|
|
2619
|
+
tableWrapperClassName,
|
|
2620
|
+
{
|
|
2621
|
+
'invisible': !gridReady
|
|
2622
|
+
}
|
|
2480
2623
|
)}
|
|
2481
2624
|
onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
2482
2625
|
onKeyPressed?.(e, selectedCells);
|