فهرست منبع

update: table实现左右fixed

xyh 2 سال پیش
والد
کامیت
01b650761c

+ 5 - 2
packages/app/src/components/table/BodyTr.tsx

@@ -1,6 +1,6 @@
 import {Cell, flexRender} from '@tanstack/react-table';
 import classNames from 'classnames';
-import {FC} from 'react';
+import {CSSProperties, FC} from 'react';
 
 type Props = {
   getVisibleCells: () => Cell<Record<string, any>, unknown>[]
@@ -16,19 +16,22 @@ const BodyTr: FC<Props> = function({getVisibleCells}) {
         column,
         getContext,
       }) {
-        const {align, fixed} = column.columnDef.meta as {
+        const {align, fixed, fixedStyle} = column.columnDef.meta as {
           align?: 'left' | 'center' | 'right';
           fixed?: 'right' | 'left';
+          fixedStyle: CSSProperties,
         };
         return (
           <td
             key={id}
             className={classNames({
               'ld-table-fixed-right ld-table-right-fixed-shadow': fixed === 'right',
+              'ld-table-fixed-left ld-table-left-fixed-shadow': fixed === 'left',
             })}
             style={{
               width: column.getSize(),
               textAlign: align ?? 'left',
+              ...fixedStyle,
             }}
           >
             {flexRender(

+ 4 - 2
packages/app/src/components/table/HeaderTh.tsx

@@ -10,9 +10,10 @@ type Props = {
 };
 
 const HeaderTh: FC<Props> = function({header, useDiv, isSecondLevel}) {
-  const {fixed, disabledSort} = header.column.columnDef.meta as {
+  const {fixed, disabledSort, fixedStyle} = header.column.columnDef.meta as {
     fixed?: 'left' | 'right';
     disabledSort: boolean;
+    fixedStyle: CSSProperties,
   };
 
   const {setNodeRef, attributes, listeners} = useSortable({
@@ -53,12 +54,13 @@ const HeaderTh: FC<Props> = function({header, useDiv, isSecondLevel}) {
   return (
     <th
       key={header.id}
-      style={style}
+      style={{...style, ...fixedStyle}}
       ref={setNodeRef}
       {...attributes}
       {...listeners}
       className={classNames('ld-table-head-th', {
         'ld-table-fixed-right ld-table-right-fixed-shadow': fixed === 'right',
+        'ld-table-fixed-left ld-table-left-fixed-shadow': fixed === 'left',
       })}
     >
       {flexRender(header.column.columnDef.header, header.getContext())}

+ 40 - 19
packages/app/src/components/table/hooks.tsx

@@ -6,6 +6,7 @@ import {
   RowSelectionState,
 } from '@tanstack/react-table';
 import {
+  CSSProperties,
   Dispatch,
   SetStateAction,
   useEffect,
@@ -18,6 +19,7 @@ import {arrayMove} from '@dnd-kit/sortable';
 import {createTableSettingContext, useContextSection} from '@hooks';
 import TableCheck from './Check';
 import {LDColumnsType} from '.';
+import {TABLE_CELL_WIDTH} from '@utils';
 
 function parseColumn<T extends Record<string, unknown>>(
   columns: LDColumnsType<T>[],
@@ -25,18 +27,51 @@ function parseColumn<T extends Record<string, unknown>>(
 ) {
   const helper = createColumnHelper<Record<string, any>>();
 
-  const tableColumns = columns.map(function(val) {
-    const {dataIndex, title, render, align, fixed} = val;
+  const parseColumns: LDColumnsType<T>[] = [
+    {
+      title: '序号',
+      dataIndex: 'no',
+      align: 'center',
+      width: TABLE_CELL_WIDTH.no,
+      render(_, index) {
+        return index + 1;
+      },
+    },
+    ...columns,
+  ];
+
+  let leftPosition = 0;
+  let rightPosition = parseColumns.reduce(function(prev, next) {
+    if (next.fixed !== 'right') return prev;
+
+    return prev + next.width;
+  }, 0);
+
+  const tableColumns = parseColumns.map(function(val) {
+    const {dataIndex, title, render, align, fixed, width} = val;
+    let fixedStyle: CSSProperties = {};
+
+    if (fixed === 'left') {
+      fixedStyle = {left: leftPosition};
+      leftPosition += width;
+    }
+
+    if (fixed === 'right') {
+      rightPosition -= width;
+      fixedStyle = {right: rightPosition};
+    }
+
     const meta = {
       align,
       fixed,
+      fixedStyle,
       disabledSort: Boolean(fixed) || dataIndex === 'no',
     };
 
     if (render) {
       return helper.display({
         id: dataIndex.toString(),
-        header: title?.toString(),
+        header: title.toString(),
         cell(props) {
           return render(
             props.row.original as T,
@@ -80,21 +115,7 @@ function parseColumn<T extends Record<string, unknown>>(
         align: 'center',
         fixed: false,
         disabledSort: true,
-      },
-    }),
-  );
-
-  tableColumns.unshift(
-    helper.display({
-      header: '序号',
-      id: 'no',
-      cell({row}) {
-        return row.index + 1;
-      },
-      meta: {
-        align: 'center',
-        fixed: false,
-        disabledSort: true,
+        fixedStyle: {},
       },
     }),
   );
@@ -225,7 +246,7 @@ export function useTableShadow(tableSize: number) {
 
         setScrollProgess(function() {
           if (scrollLeft + elWidth === scrollWidth) return 'end';
-          if (scrollLeft + elWidth === 0) return 'start';
+          if (scrollLeft === 0) return 'start';
 
           return 'process';
         });

+ 46 - 8
packages/app/src/components/table/index.css

@@ -1,11 +1,14 @@
 .ld-table-wrapper {
   width: 100%;
+  overflow: hidden;
   border-inline-start: 1px solid var(--border-color-light);
   border-start-start-radius: var(--border-radius);
   border-start-end-radius: var(--border-radius);
 }
 
 .ld-table {
+  --animate-duration: 200ms;
+
   min-width: 100%;
   padding: 0;
   margin: 0;
@@ -26,26 +29,49 @@
     background-color: var(--layout-background-color);
   }
 
-  & .ld-table-right-fixed-shadow {
+  & .ld-table-right-fixed-shadow,
+  & .ld-table-left-fixed-shadow {
     &::before {
       position: absolute;
       top: 0;
       bottom: -1px;
-      left: 0;
       width: 30px;
       pointer-events: none;
       content: '';
-      box-shadow: -10px 0 8px -8px rgb(0 0 0 / 0%) inset;
-      transition: box-shadow 0.3s;
+    }
+  }
+
+  & .ld-table-right-fixed-shadow {
+    &::before {
+      left: 0;
       transform: translateX(-100%);
     }
   }
+
+  & .ld-table-left-fixed-shadow {
+    &::before {
+      right: 0;
+      transform: translateX(100%);
+    }
+  }
+
+  & .ld-table-right-fixed-shadow ~ .ld-table-right-fixed-shadow {
+    &::before {
+      display: none;
+    }
+  }
+
+  & .ld-table-left-fixed-shadow:has(~ .ld-table-left-fixed-shadow) {
+    &::before {
+      display: none;
+    }
+  }
 }
 
 .ld-table-header-sticky {
   position: sticky;
   top: 0;
-  z-index: 1;
+  z-index: 5;
   width: 100%;
   overflow: hidden;
 }
@@ -67,10 +93,22 @@
   }
 }
 
-.ld-table-fixed-right {
+.ld-table-enabled-left-fixed-shadow {
+  & .ld-table-left-fixed-shadow:not(:has(+ .ld-table-left-fixed-shadow)) {
+    border-inline-end-color: transparent;
+  }
+
+  & .ld-table-left-fixed-shadow {
+    &::before {
+      box-shadow: 10px 0 8px -6px rgb(0 0 0 / 10%) inset;
+    }
+  }
+}
+
+.ld-table-fixed-right,
+.ld-table-fixed-left {
   position: sticky !important;
-  right: 0;
-  border-top-left-radius: 0 !important;
+  z-index: 4;
 }
 
 .ld-table-head {

+ 3 - 1
packages/app/src/components/table/index.tsx

@@ -30,10 +30,10 @@ import BodyTr from './BodyTr';
 export type LDColumnsType<T extends Record<string, unknown>> = {
   dataIndex: keyof T,
   title: string,
+  width: number,
   render?: (info: T, index: number) => ReactNode,
   align?: 'left' | 'right' | 'center',
   fixed?: 'left' | 'right',
-  width?: number,
 };
 
 type Props<T extends Record<string, unknown>> = {
@@ -103,6 +103,7 @@ function LDTable<T extends Record<string, any>>(props: Props<T>): ReactElement {
               <table
                 className={classNames('ld-table', {
                   'ld-table-enabled-right-fixed-shadow': scrollProgess !== 'end',
+                  'ld-table-enabled-left-fixed-shadow': scrollProgess !== 'start',
                 })}
                 style={{width: getCenterTotalSize()}}
               >
@@ -134,6 +135,7 @@ function LDTable<T extends Record<string, any>>(props: Props<T>): ReactElement {
           <table
             className={classNames('ld-table', {
               'ld-table-enabled-right-fixed-shadow': scrollProgess !== 'end',
+              'ld-table-enabled-left-fixed-shadow': scrollProgess !== 'start',
             })}
             style={{width: getCenterTotalSize()}}
           >