utils.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import { merge, clone as lodashClone, find, map } from 'lodash';
  2. import Logger from '@douyinfe/semi-foundation/utils/Logger';
  3. import { numbers } from '@douyinfe/semi-foundation/table/constants';
  4. import { cloneDeep } from '../_utils';
  5. import { TableComponents, Virtualized } from './interface';
  6. import { getColumnKey } from '@douyinfe/semi-foundation/table/utils';
  7. let scrollbarVerticalSize: number,
  8. scrollbarHorizontalSize: number;
  9. // Measure scrollbar width for padding body during modal show/hide
  10. const scrollbarMeasure = {
  11. position: 'absolute',
  12. top: '-9999px',
  13. width: '50px',
  14. height: '50px',
  15. };
  16. /**
  17. * @param {'vertical'|'horizontal'} [direction]
  18. * @returns {number}
  19. */
  20. export function measureScrollbar(direction = 'vertical') {
  21. if (typeof document === 'undefined' || typeof window === 'undefined') {
  22. return 0;
  23. }
  24. const isVertical = direction === 'vertical';
  25. if (isVertical && scrollbarVerticalSize) {
  26. return scrollbarVerticalSize;
  27. } else if (!isVertical && scrollbarHorizontalSize) {
  28. return scrollbarHorizontalSize;
  29. }
  30. const scrollDiv = document.createElement('div');
  31. Object.keys(scrollbarMeasure).forEach(scrollProp => {
  32. scrollDiv.style[scrollProp] = scrollbarMeasure[scrollProp];
  33. });
  34. // Append related overflow style
  35. if (isVertical) {
  36. scrollDiv.style.overflowY = 'scroll';
  37. } else {
  38. scrollDiv.style.overflowX = 'scroll';
  39. }
  40. document.body.appendChild(scrollDiv);
  41. let size = 0;
  42. if (isVertical) {
  43. // clientWidth is the inner width (excluding borders and scrollbars)
  44. // offsetWidth is the outer width (including padding and borders)
  45. size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  46. scrollbarVerticalSize = size;
  47. } else {
  48. size = scrollDiv.offsetHeight - scrollDiv.clientHeight;
  49. scrollbarHorizontalSize = size;
  50. }
  51. document.body.removeChild(scrollDiv);
  52. // console.log(size);
  53. return size;
  54. }
  55. export function amendTableWidth(tableWidth: number) {
  56. return typeof tableWidth === 'number' ?
  57. tableWidth -
  58. numbers.DEFAULT_CELL_PADDING_LEFT -
  59. numbers.DEFAULT_CELL_PADDING_RIGHT -
  60. numbers.DEFAULT_CELL_BORDER_WIDTH_LEFT -
  61. numbers.DEFAULT_CELL_BORDER_WIDTH_RIGHT -
  62. measureScrollbar('vertical') :
  63. undefined;
  64. }
  65. /**
  66. * The user can pass a component to define the rendering method of each level of the table
  67. * This function merges the components passed in by the user with the default components
  68. * @param {Object} components
  69. * @param {Boolean|Object} virtualized
  70. * @returns
  71. */
  72. export function mergeComponents(components: TableComponents, virtualized: Virtualized) {
  73. return merge(
  74. {},
  75. {
  76. table: 'table',
  77. header: {
  78. outer: 'table',
  79. wrapper: 'thead',
  80. row: 'tr',
  81. cell: 'th',
  82. },
  83. body: virtualized ?
  84. {
  85. outer: 'div',
  86. wrapper: 'div',
  87. row: 'div',
  88. cell: 'div',
  89. colgroup: {
  90. wrapper: 'div',
  91. col: 'div',
  92. },
  93. } :
  94. {
  95. outer: 'table',
  96. wrapper: 'tbody',
  97. row: 'tr',
  98. cell: 'td',
  99. colgroup: {
  100. wrapper: 'colgroup',
  101. col: 'col',
  102. },
  103. },
  104. footer: {
  105. wrapper: 'tfoot',
  106. row: 'tr',
  107. cell: 'td',
  108. },
  109. },
  110. components
  111. );
  112. }
  113. export const logger = new Logger('[@douyinfe/semi-ui Table]');
  114. export function mergeColumns(oldColumns: any[] = [], newColumns: any[] = [], keyPropNames: any[] = null, deep = true) {
  115. const finalColumns: any[] = [];
  116. const clone = deep ? cloneDeep : lodashClone;
  117. map(newColumns, newColumn => {
  118. newColumn = { ...newColumn };
  119. const key = getColumnKey(newColumn, keyPropNames);
  120. const oldColumn = key != null && find(oldColumns, item => getColumnKey(item, keyPropNames) === key);
  121. if (oldColumn) {
  122. finalColumns.push(
  123. clone({
  124. ...oldColumn,
  125. ...newColumn,
  126. })
  127. );
  128. } else {
  129. finalColumns.push(clone(newColumn));
  130. }
  131. });
  132. return finalColumns;
  133. }
  134. export { cloneDeep };