lodash#toPath TypeScript Examples

The following examples show how to use lodash#toPath. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: BrickTable.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function BrickTable(props: BrickTableProps): React.ReactElement {
  if (props.error) {
    throw props.error;
  }

  const {
    configProps,
    columns,
    rowKey,
    expandIconAsCell,
    expandIconColumnIndex,
    childrenColumnName,
    deleteEnabled,
    scroll,
    optimizedColumns,
    onDelete, // 用于 brick form 中,will be deprecated
    ellipsisInfo,
    showHeader,
  } = props;

  const initData = useMemo(() => {
    return (
      props.dataSource &&
      (rowKey
        ? props.dataSource
        : props.dataSource.map((item, index) =>
            isNil(item.key) ? { ...item, key: index } : item
          ))
    );
  }, [props.dataSource, rowKey]);

  const [data, setData] = useState(initData);
  const rowKeyExpandIconMapRef = useRef<Map<unknown, React.ReactNode>>(
    new Map()
  );
  const columnTitleBrickDataMapRef = useRef<
    Map<CustomColumn, { title: unknown }>
  >(new Map());
  const useBrickItemBrickDataMapRef = useRef<
    Map<UseBrickConf, ItemBrickDataMap>
  >(new Map());
  const itemExpandedRowBrickDataMapRef = useRef<Map<unknown, unknown>>(
    new Map()
  );

  useEffect(() => {
    itemExpandedRowBrickDataMapRef.current.clear();
    setData(initData);
  }, [initData]);

  const expandIconColumnIndexOffset = configProps?.rowSelection ? -1 : 0;
  const customColumns = useMemo(() => {
    if (columns) {
      columnTitleBrickDataMapRef.current.clear();
      useBrickItemBrickDataMapRef.current.clear();
      const customColumns = columns.map((column, index) => {
        const {
          useBrick,
          component,
          valueSuffix,
          cellStatus,
          titleUseBrick,
          headerBrick,
          colSpanKey,
          rowSpanKey,
          ...columnConf
        } = column;
        if (headerBrick?.useBrick || titleUseBrick) {
          if (titleUseBrick) {
            // eslint-disable-next-line no-console
            console.warn(
              "`titleUseBrick` of `<presentational-bricks.brick-table>` is deprecated, use `headerBrick` instead."
            );
          }

          const useBrick = headerBrick?.useBrick || titleUseBrick;
          let data = columnTitleBrickDataMapRef.current.get(column);

          if (!data) {
            data = {
              title: columnConf.title,
            };
            columnTitleBrickDataMapRef.current.set(column, data);
          }

          columnConf.title = getCustomHeader(useBrick, data);
        }

        if (useBrick || component) {
          let itemBrickDataMap: ItemBrickDataMap;

          if (useBrick) {
            itemBrickDataMap =
              useBrickItemBrickDataMapRef.current.get(useBrick);

            if (!itemBrickDataMap) {
              itemBrickDataMap = new Map();
              useBrickItemBrickDataMapRef.current.set(
                useBrick,
                itemBrickDataMap
              );
            }
          }

          columnConf.render = getCustomComp(
            useBrick,
            component,
            itemBrickDataMap
          );
          if (optimizedColumns?.includes(column.dataIndex)) {
            // [only update when record changed](https://ant.design/components/table-cn/#%E4%B8%BA%E4%BB%80%E4%B9%88-%E6%9B%B4%E6%96%B0-state-%E4%BC%9A%E5%AF%BC%E8%87%B4%E5%85%A8%E8%A1%A8%E6%B8%B2%E6%9F%93%EF%BC%9F)
            columnConf.shouldCellUpdate = (record, prevRecord) => {
              return !isEqual(record, prevRecord);
            };
          }
        } else if (valueSuffix) {
          columnConf.render = (value) => value + valueSuffix;
        }
        if (
          !expandIconAsCell &&
          index === expandIconColumnIndex + expandIconColumnIndexOffset
        ) {
          const innerRender = columnConf.render;
          columnConf.render = function ExpandIcon(value, record, index) {
            return (
              <>
                {!record[childrenColumnName] &&
                  rowKeyExpandIconMapRef.current.get(
                    rowKey ? record[rowKey] : record
                  )}
                {innerRender ? innerRender(value, record, index) : value}
              </>
            );
          };
        }
        if (cellStatus || colSpanKey || rowSpanKey) {
          const innerRender = columnConf.render;
          columnConf.render = (value, item, index) => {
            return {
              children: innerRender ? innerRender(value, item, index) : value,
              props: {
                colSpan: item[colSpanKey],
                rowSpan: item[rowSpanKey],
                style: cellStatus && getCellStyle(cellStatus, item, value),
              },
            };
          };
        }

        if (typeof columnConf.dataIndex === "string") {
          columnConf.dataIndex = toPath(columnConf.dataIndex);
        }
        if (columnConf.verticalAlign === "top") {
          columnConf.className
            ? (columnConf.className += " alignTop")
            : (columnConf.className = "alignTop");
        }
        if (columnConf.verticalAlign === "bottom") {
          columnConf.className
            ? (columnConf.className += " alignBottom")
            : (columnConf.className = "alignBottom");
        }
        if (ellipsisInfo) {
          columnConf.className = styles.ellipsisInfoCell;
        }
        return columnConf;
      });

      if (deleteEnabled) {
        const render = (value: any, item: any, index: number) => {
          return (
            <Icon
              onClick={() => onDelete?.(index)}
              component={() => <FontAwesomeIcon icon="trash-alt" />}
              style={{ color: "#167be0" }}
            />
          );
        };

        customColumns.push({
          title: "操作",
          render,
        });
      }

      return customColumns;
    }
  }, [
    columns,
    childrenColumnName,
    expandIconAsCell,
    expandIconColumnIndex,
    expandIconColumnIndexOffset,
    rowKey,
    deleteEnabled,
    onDelete,
    ellipsisInfo,
  ]);

  const expandedRowRender = (record: Record<string, any>, index: number) => {
    let data = itemExpandedRowBrickDataMapRef.current.get(record);

    if (!data) {
      data = {
        rowData: record,
        rowIndex: index,
      };
      itemExpandedRowBrickDataMapRef.current.set(record, data);
    }

    return (
      <BrickAsComponent
        useBrick={props.expandedRowBrick.useBrick}
        data={data}
      />
    );
  };

  const components = {
    body: {
      row: DraggableBodyRow,
    },
  };

  const moveRow = (dragIndex: number, hoverIndex: number) => {
    const dragRow = data[dragIndex];
    const newData = update(data, {
      $splice: [
        [dragIndex, 1],
        [hoverIndex, 0, dragRow],
      ],
    });
    setData(newData);
    props.onDrag && props.onDrag(newData);
  };

  const onExpand = (expanded: boolean, record: Record<string, any>) => {
    props.onExpand && props.onExpand(expanded, record);
  };

  const onExpandedRowsChange = (expandedRows: React.Key[]) => {
    props.onExpandedRowsChange && props.onExpandedRowsChange(expandedRows);
  };

  const getCustomExpandIcon = (iconProps: any) => {
    const { record, expandable, expanded, onExpand } = iconProps;
    let icon = props.expandIcon?.collapsedIcon || downMenuIcon;
    let iconNode: React.ReactNode;
    if (expandable) {
      if (!expanded) {
        icon = props.expandIcon?.expandedIcon || rightMenuIcon;
      }
      iconNode = (
        <span
          className={styles.expandIconSpan}
          data-testid="expand-icon"
          onClick={(e) => {
            onExpand(record, e);
          }}
        >
          <GeneralIcon icon={icon} />
        </span>
      );
    } else {
      iconNode = (
        <span className={styles.expandIconSpan} data-testid="expand-icon">
          <span style={{ visibility: "hidden" }}>
            <GeneralIcon icon={icon} />
          </span>
        </span>
      );
    }

    if (iconNode) {
      if (!expandIconAsCell) {
        rowKeyExpandIconMapRef.current.set(
          rowKey ? record[rowKey] : record,
          iconNode
        );
      }
      return iconNode;
    } else {
      return <></>;
    }
  };

  const pickExpandProps = pickBy(
    {
      expandIconColumnIndex,
      expandIconAsCell,
      expandRowByClick: props.expandRowByClick,
      expandedRowKeys: props.expandedRowKeys,
      defaultExpandAllRows: props.defaultExpandAllRows,
    },
    (item) => !isNil(item)
  );

  let table = (
    <Table
      className={classNames(styles.brickTable, {
        [styles.expandIconCellHidden]: !expandIconAsCell,
        [styles.customDropTable]: props.tableDraggable,
        [styles.tableThTransparent]: props.thTransparent,
        [styles.zebraPatternTable]: data?.length >= 2 && props.zebraPattern,
      })}
      dataSource={data}
      {...(props.tableDraggable
        ? {
            components,
            onRow: (record, index) => ({
              index,
              moveRow: moveRow,
            }),
          }
        : {})}
      columns={customColumns}
      onChange={props.onChange}
      {...(props.expandedRowBrick
        ? {
            expandedRowRender,
          }
        : {})}
      {...pickExpandProps}
      onExpand={onExpand}
      onExpandedRowsChange={onExpandedRowsChange}
      rowKey={rowKey}
      childrenColumnName={childrenColumnName}
      rowClassName={(record, index) =>
        props.zebraPattern && index % 2 ? styles.brickTableOddRow : ""
      }
      expandIcon={getCustomExpandIcon}
      scroll={scroll}
      showHeader={showHeader}
      {...configProps}
    />
  );

  if (props.tableDraggable) {
    table = <DndProvider backend={HTML5Backend}>{table}</DndProvider>;
  }

  if (!props.showCard) {
    return table;
  }

  return <Card bordered={false}> {table} </Card>;
}
Example #2
Source File: RankTable.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function RankTable(props: RankTableProps): React.ReactElement {
  const { dataSource, columns, configProps, rowKey, scroll, showHeader } =
    props;
  const columnTitleBrickDataMapRef = useRef<
    Map<CustomColumn, { title: unknown }>
  >(new Map());
  const useBrickItemBrickDataMapRef = useRef<
    Map<UseBrickConf, ItemBrickDataMap>
  >(new Map());

  const initData = useMemo(() => {
    return (
      props.dataSource &&
      (rowKey
        ? props.dataSource
        : props.dataSource.map((item, index) =>
            isNil(item.key) ? { ...item, key: index } : item
          ))
    );
  }, [props.dataSource, rowKey]);
  const [data, setData] = useState(initData);

  useEffect(() => {
    setData(initData);
  }, [initData]);

  const renderAwards = (trend?: number) => (
    <>
      <span
        className={classNames(styles.awards, {
          [styles.medalGold]: trend === 0,
          [styles.medalSilver]: trend === 1,
          [styles.medalBronze]: trend === 2,
          [styles.normalAwards]: trend !== 0 && trend !== 1 && trend !== 2,
          [styles.small]: props?.size === "small",
          [styles.topThree]: [0, 1, 2].includes(trend),
        })}
      >
        {trend + 1}
        {[0, 1, 2].includes(trend) && <span>{getRankNumber(trend)}</span>}
      </span>
      &nbsp;&nbsp;
    </>
  );

  const customColumns = useMemo(() => {
    if (columns) {
      columnTitleBrickDataMapRef.current.clear();
      useBrickItemBrickDataMapRef.current.clear();
      const customColumns = columns.map((column, index) => {
        const {
          useBrick,
          component,
          valueSuffix,
          cellStatus,
          titleUseBrick,
          headerBrick,
          colSpanKey,
          rowSpanKey,
          ...columnConf
        } = column;

        const Awards = index === 0 ? renderAwards : null;
        if (headerBrick?.useBrick || titleUseBrick) {
          if (titleUseBrick) {
            // eslint-disable-next-line no-console
            console.warn(
              "`titleUseBrick` of `<presentational-bricks.rank-table>` is deprecated, use `headerBrick` instead."
            );
          }

          const useBrick = headerBrick?.useBrick || titleUseBrick;
          let data = columnTitleBrickDataMapRef.current.get(column);

          if (!data) {
            data = {
              title: columnConf.title,
            };
            columnTitleBrickDataMapRef.current.set(column, data);
          }

          columnConf.title = getCustomHeader(useBrick, data);
        }

        if (useBrick || component) {
          let itemBrickDataMap: ItemBrickDataMap;

          if (useBrick) {
            itemBrickDataMap =
              useBrickItemBrickDataMapRef.current.get(useBrick);

            if (!itemBrickDataMap) {
              itemBrickDataMap = new Map();
              useBrickItemBrickDataMapRef.current.set(
                useBrick,
                itemBrickDataMap
              );
            }
          }

          columnConf.render = getCustomComp(
            useBrick,
            component,
            itemBrickDataMap,
            Awards,
            props.size
          );
        } else if (valueSuffix) {
          // eslint-disable-next-line react/display-name
          columnConf.render = (value, record, index) => (
            <>
              {Awards?.(index)}
              {value + valueSuffix}
            </>
          );
        }

        if (typeof columnConf.dataIndex === "string") {
          columnConf.dataIndex = toPath(columnConf.dataIndex);
        }
        if (columnConf.verticalAlign === "top") {
          columnConf.className
            ? (columnConf.className += " alignTop")
            : (columnConf.className = "alignTop");
        }
        if (columnConf.verticalAlign === "bottom") {
          columnConf.className
            ? (columnConf.className += " alignBottom")
            : (columnConf.className = "alignBottom");
        }

        if (!columnConf.render) {
          // eslint-disable-next-line react/display-name
          columnConf.render = (text: string, record, trend) => (
            <div style={{ display: "flex", alignItems: "center" }}>
              {Awards?.(trend)}
              <span style={{ flex: 1 }}>{text}</span>
            </div>
          );
        }

        return columnConf;
      });

      return customColumns;
    }
  }, [columns, rowKey]);

  const TrendBar = (
    <div className={styles.trendBar}>
      <span className={styles.yellowBar} />
      <span className={styles.blueBar} />
      <span className={styles.redBar} />
    </div>
  );

  const header = useMemo(() => {
    const { header } = props;
    if (!header || !header?.title) return null;

    return (
      <div
        className={styles.header}
        style={props.size === "small" ? { padding: "0px 0 10px 10px" } : {}}
      >
        <span className={styles.leftCell}>
          {TrendBar}
          {(header.title as UseBrick)?.useBrick ? (
            <BrickAsComponent
              useBrick={(header.title as UseBrick).useBrick}
              data={dataSource}
            />
          ) : (
            (header.title as string)
          )}
        </span>
        <span className={styles.rightCell}>
          {(header?.extra as UseBrick)?.useBrick ? (
            <BrickAsComponent useBrick={(header.extra as UseBrick).useBrick} />
          ) : (
            (header.extra as string)
          )}
        </span>
      </div>
    );
  }, [props.header]);

  const table = () => {
    return (
      <Table
        showHeader={showHeader}
        className={classNames(styles.brickTable)}
        dataSource={data}
        columns={customColumns}
        rowKey={rowKey}
        rowClassName={(record, index) =>
          index % 2 ? styles.brickTableOddRow : ""
        }
        scroll={scroll}
        {...configProps}
        pagination={false}
        onChange={props.onChange}
      />
    );
  };

  return (
    <div>
      {!props.showCard ? (
        <>
          {header}
          {table()}
        </>
      ) : (
        <Card bordered={false}>
          {header}
          {table()}
        </Card>
      )}
    </div>
  );
}