diff --git a/app/client/packages/design-system/widgets/src/components/Menu/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Menu/src/styles.module.css index 4a8f1e143b..777b5edead 100644 --- a/app/client/packages/design-system/widgets/src/components/Menu/src/styles.module.css +++ b/app/client/packages/design-system/widgets/src/components/Menu/src/styles.module.css @@ -81,6 +81,11 @@ padding: 0; } +/* this is required so that separator ( ) if passed with a text as children, the text is hidden */ +.menuList li[data-separator] > * { + display: none; +} + /* making sure the first and last child are not displayed when they have the data-separator attribute */ .menuList li:is(:first-child, :last-child):is([data-separator]) { display: none; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx index c934918b0b..3fb405f0f2 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/StaticTable.tsx @@ -85,7 +85,6 @@ const StaticTable = (props: StaticTableProps) => { selectTableRow={props.selectTableRow} selectedRowIndex={props.selectedRowIndex} selectedRowIndices={props.selectedRowIndices} - tableSizes={props.tableSizes} useVirtual={props.useVirtual} width={props.width - TABLE_SCROLLBAR_WIDTH / 2} /> diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx index 66a5db739f..e001febd98 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/Table.tsx @@ -19,17 +19,11 @@ import type { AddNewRowActions, StickyType, } from "./Constants"; -import { - TABLE_SIZES, - CompactModeTypes, - TABLE_SCROLLBAR_HEIGHT, -} from "./Constants"; +import { TABLE_SIZES, CompactModeTypes } from "./Constants"; import { Colors } from "constants/Colors"; import type { EventType } from "constants/AppsmithActionConstants/ActionConstants"; import type { EditableCell, TableVariant } from "../constants"; import "simplebar-react/dist/simplebar.min.css"; -import { createGlobalStyle } from "styled-components"; -import { Classes as PopOver2Classes } from "@blueprintjs/popover2"; import StaticTable from "./StaticTable"; import VirtualTable from "./VirtualTable"; import { ConnectDataOverlay } from "widgets/ConnectDataOverlay"; @@ -38,25 +32,7 @@ import { createMessage, CONNECT_BUTTON_TEXT, } from "@appsmith/constants/messages"; - -const SCROLL_BAR_OFFSET = 2; -const HEADER_MENU_PORTAL_CLASS = ".header-menu-portal"; - -const PopoverStyles = createGlobalStyle<{ - widgetId: string; - borderRadius: string; -}>` - ${HEADER_MENU_PORTAL_CLASS}-${({ widgetId }) => widgetId} { - font-family: var(--wds-font-family) !important; - - & .${PopOver2Classes.POPOVER2}, - .${PopOver2Classes.POPOVER2_CONTENT}, - .bp3-menu { - border-radius: ${({ borderRadius }) => - borderRadius >= `1.5rem` ? `0.375rem` : borderRadius} !important; - } - } -`; +import styles from "./styles.module.css"; export interface TableProps { width: number; @@ -286,21 +262,18 @@ export function Table(props: TableProps) { props.isVisiblePagination || props.allowAddNewRow; - const scrollContainerStyles = useMemo(() => { - return { - height: isHeaderVisible - ? props.height - - tableSizes.TABLE_HEADER_HEIGHT - - TABLE_SCROLLBAR_HEIGHT - - SCROLL_BAR_OFFSET - : props.height - TABLE_SCROLLBAR_HEIGHT - SCROLL_BAR_OFFSET, - }; - }, [isHeaderVisible, props.height, tableSizes.TABLE_HEADER_HEIGHT]); - const shouldUseVirtual = props.serverSidePaginationEnabled && !props.columns.some((column) => column.columnProperties.allowCellWrapping); + const variant = (() => { + if (props.variant === "DEFAULT") return "default"; + if (props.variant === "VARIANT2") return "no-borders"; + if (props.variant === "VARIANT3") return "horizontal-borders"; + + return "default"; + })(); + return ( <> {showConnectDataOverlay && ( @@ -317,21 +290,20 @@ export function Table(props: TableProps) { borderRadius={props.borderRadius} borderWidth={props.borderWidth} boxShadow={props.boxShadow} + className={styles.table} + data-status={props.isAddRowInProgress ? "add-row-in-progress" : ""} + data-type={shouldUseVirtual ? "virtualized" : "static"} + data-variant={variant} height={props.height} id={`table${props.widgetId}`} isAddRowInProgress={props.isAddRowInProgress} isHeaderVisible={isHeaderVisible} isResizingColumn={isResizingColumn.current} - multiRowSelection={props.multiRowSelection} tableSizes={tableSizes} triggerRowSelection={props.triggerRowSelection} variant={props.variant} width={props.width} > - {isHeaderVisible && (
{!shouldUseVirtual && ( @@ -435,7 +408,6 @@ export function Table(props: TableProps) { prepareRow={prepareRow} primaryColumnId={props.primaryColumnId} rowSelectionState={rowSelectionState} - scrollContainerStyles={scrollContainerStyles} selectTableRow={props.selectTableRow} selectedRowIndex={props.selectedRowIndex} selectedRowIndices={props.selectedRowIndices} diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableActionIcon.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableActionIcon.tsx deleted file mode 100644 index 44f10d7e79..0000000000 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableActionIcon.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from "react"; -import { Tooltip } from "@blueprintjs/core"; -import { IconWrapper } from "constants/IconConstants"; -import { Colors } from "constants/Colors"; -import { TableIconWrapper } from "./TableStyledWrappers"; - -interface TableActionIconProps { - tooltip: string; - selected: boolean; - selectMenu: (selected: boolean) => void; - className: string; - children: React.ReactNode; - icon?: React.ReactNode; -} - -function TableActionIcon(props: TableActionIconProps) { - return ( - - { - props.selectMenu(!props.selected); - e.stopPropagation(); - }} - selected={props.selected} - > - - {props.children} - - - - ); -} - -export default TableActionIcon; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx index fd2a87dce9..804b98ae01 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/Row.tsx @@ -44,28 +44,29 @@ export function Row(props: RowType) { (primaryColumnId && (props.row.original[primaryColumnId] as Key)) || props.index; - if (!isAddRowInProgress) { - rowProps["role"] = "button"; - } + const onClickRow = (e: React.MouseEvent) => { + props.row.toggleRowSelected(); + selectTableRow?.(props.row); + e.stopPropagation(); + }; return (
{ - props.row.toggleRowSelected(); - selectTableRow?.(props.row); - e.stopPropagation(); - }} + onClick={onClickRow} > {multiRowSelection && renderBodyCheckBoxCell(isRowSelected, accentColor, borderRadius)} {props.row.cells.map((cell, cellIndex) => { const cellProperties = cell.getCellProps(); + cellProperties["style"] = { ...cellProperties.style, left: @@ -76,6 +77,7 @@ export function Row(props: RowType) { return (
{ + return ( +
+ {props.rows.map((row, index) => { + return ; + })} + {props.pageSize > props.rows.length && ( + + )} +
+ ); +}; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/VirtualTableBody.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/VirtualTableBody.tsx new file mode 100644 index 0000000000..4aae1d2892 --- /dev/null +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/VirtualTableBody.tsx @@ -0,0 +1,107 @@ +import React, { useCallback } from "react"; +import { useLayoutEffect, useRef } from "react"; +import type { VirtualTableBodyProps } from "./types"; + +import { FixedSizeList, areEqual } from "react-window"; +import type { ListChildComponentProps } from "react-window"; +import { Row, EmptyRow } from "./Row"; +import { useResizeObserver } from "@react-aria/utils"; + +export const VirtualTableBody = (props: VirtualTableBodyProps) => { + const ref = useRef(null); + const [horizontalScrollbarHeight, setHorizontalScrollbarHeight] = + React.useState(0); + const [itemHeight, setItemHeight] = React.useState("0px"); + const [headerHeight, setHeaderHeight] = React.useState("0px"); + + useLayoutEffect(() => { + if (ref.current) { + const horizontalScrollbar = ref.current; + if (horizontalScrollbar) { + setHorizontalScrollbarHeight( + horizontalScrollbar.offsetHeight - horizontalScrollbar.clientHeight, + ); + } + } + }, [ref.current]); + + useLayoutEffect(() => { + if (ref.current) { + const table = ref.current.closest("[role='table']"); + + if (table && table instanceof HTMLElement) { + const style = window.getComputedStyle(table); + + const thHeight = style.getPropertyValue("background-position-x"); + const trHeight = style.getPropertyValue("background-position-y"); + + setHeaderHeight(thHeight); + setItemHeight(trHeight); + } + } + }, [props.pageSize, ref.current]); + + const onSizeChange = useCallback(() => { + if (ref.current) { + const table = ref.current.closest("[role='table']"); + + if (table && table instanceof HTMLElement) { + const style = window.getComputedStyle(table); + + const thHeight = style.getPropertyValue("background-position-x"); + const trHeight = style.getPropertyValue("background-position-y"); + + setHeaderHeight(thHeight); + setItemHeight(trHeight); + } + } + }, [props.pageSize, ref.current]); + + useResizeObserver({ + ref: ref, + onResize: onSizeChange, + }); + + return ( + + {rowRenderer} + + ); +}; + +const rowRenderer = React.memo((rowProps: ListChildComponentProps) => { + const { data, index, style } = rowProps; + + if (index < data.length) { + const row = data[index]; + + return ( + + ); + } else { + return ; + } +}, areEqual); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx index 9ccda579a4..ee33c93a8f 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/index.tsx @@ -1,14 +1,14 @@ -import React, { useLayoutEffect } from "react"; +import React from "react"; import type { Row as ReactTableRowType, TableBodyPropGetter, TableBodyProps, } from "react-table"; -import type { ListChildComponentProps, ReactElementType } from "react-window"; -import { FixedSizeList, areEqual } from "react-window"; -import { EmptyRows, EmptyRow, Row } from "./Row"; -import type { ReactTableColumnProps, TableSizes } from "../Constants"; +import type { ReactTableColumnProps } from "../Constants"; import type { HeaderComponentProps } from "../Table"; +import { StaticTableBody } from "./StaticTableBody"; +import { VirtualTableBody } from "./VirtualTableBody"; +import type { VirtualTableBodyProps } from "./types"; export type BodyContextType = { accentColor: string; @@ -46,97 +46,8 @@ export const BodyContext = React.createContext({ totalColumnsWidth: 0, }); -const rowRenderer = React.memo((rowProps: ListChildComponentProps) => { - const { data, index, style } = rowProps; - - if (index < data.length) { - const row = data[index]; - - return ( - - ); - } else { - return ; - } -}, areEqual); - -interface BodyPropsType { - getTableBodyProps( - propGetter?: TableBodyPropGetter> | undefined, - ): TableBodyProps; - pageSize: number; - rows: ReactTableRowType>[]; - height: number; - width?: number; - tableSizes: TableSizes; - innerElementType?: ReactElementType; -} - -const TableVirtualBodyComponent = (props: BodyPropsType) => { - const ref = React.useRef(null); - const [horizontalScrollbarHeight, setHorizontalScrollbarHeight] = - React.useState(0); - - useLayoutEffect(() => { - if (ref.current) { - const horizontalScrollbar = ref.current; - if (horizontalScrollbar) { - setHorizontalScrollbarHeight( - horizontalScrollbar.offsetHeight - horizontalScrollbar.clientHeight, - ); - } - } - }, [ref.current]); - - return ( - - {rowRenderer} - - ); -}; - -const TableBodyComponent = (props: BodyPropsType) => { - return ( -
- {props.rows.map((row, index) => { - return ; - })} - {props.pageSize > props.rows.length && ( - - )} -
- ); -}; - export const TableBody = ( - props: BodyPropsType & BodyContextType & { useVirtual: boolean }, + props: VirtualTableBodyProps & BodyContextType & { useVirtual: boolean }, ) => { const { accentColor, @@ -203,9 +114,9 @@ export const TableBody = ( }} > {useVirtual ? ( - + ) : ( - + )} ); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/types.ts b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/types.ts new file mode 100644 index 0000000000..e169839193 --- /dev/null +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableBody/types.ts @@ -0,0 +1,20 @@ +import type { + TableBodyProps, + TableBodyPropGetter, + Row as ReactTableRowType, +} from "react-table"; +import type { ReactElementType } from "react-window"; + +export interface StaticTableProps { + getTableBodyProps( + propGetter?: TableBodyPropGetter> | undefined, + ): TableBodyProps; + pageSize: number; + rows: ReactTableRowType>[]; + height: number; + width?: number; +} + +export interface VirtualTableBodyProps extends StaticTableProps { + innerElementType?: ReactElementType; +} diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/Pagination.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/Pagination.tsx index 00a91671df..c8d2398e85 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/Pagination.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableHeader/Pagination.tsx @@ -51,11 +51,11 @@ export const Pagination = (props: PaginationProps) => { props.isVisiblePagination && props.serverSidePaginationEnabled && (
- {props.totalRecordsCount && ( + {props.totalRecordsCount ? ( {props.totalRecordsCount} Records - )} + ) : null} void; @@ -34,12 +33,6 @@ export interface TableColumnHeaderProps { widgetId: string; } -const StyledHeaderGroup = styled.div<{ - headerWidth: number; -}>` - display: flex; - width: ${(props) => props.headerWidth}px !important; -`; const TableColumnHeader = (props: TableColumnHeaderProps) => { const currentDraggedColumn = React.useRef(""); const columnOrder = props.columns.map((col) => col.alias); @@ -59,22 +52,17 @@ const TableColumnHeader = (props: TableColumnHeaderProps) => { ); return ( -
+ {props.headerGroups.map((headerGroup: any, index: number) => { const headerRowProps = { ...headerGroup.getHeaderGroupProps(), }; return ( - {props.multiRowSelection && renderHeaderCheckBoxCell( @@ -123,7 +111,7 @@ const TableColumnHeader = (props: TableColumnHeaderProps) => { /> ); })} - + ); })} @@ -139,7 +127,7 @@ const TableColumnHeader = (props: TableColumnHeaderProps) => { {}, props.prepareRow, )} -
+ ); }; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/TableStyledWrappers.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/TableStyledWrappers.tsx index e81b9af377..a95fa83737 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/TableStyledWrappers.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/TableStyledWrappers.tsx @@ -23,7 +23,6 @@ import { lightenColor, darkenColor } from "widgets/WidgetUtils"; import { FontStyleTypes } from "constants/WidgetConstants"; import { Classes } from "@blueprintjs/core"; import type { TableVariant } from "../constants"; -import { TableVariantTypes } from "../constants"; import { Layers } from "constants/Layers"; const BORDER_RADIUS = "border-radius: 4px;"; @@ -44,271 +43,8 @@ export const TableWrapper = styled.div<{ isResizingColumn?: boolean; variant?: TableVariant; isAddRowInProgress: boolean; - multiRowSelection?: boolean; }>` - width: 100%; - height: 100%; - background: var(--color-bg-secondary); - border-style: solid; - border-width: ${({ borderWidth }) => `${borderWidth}px`}; - border-color: ${({ borderColor }) => borderColor}; - border-radius: var(--border-radius-elevation-3); - box-shadow: ${({ boxShadow }) => `${boxShadow}`} !important; - box-sizing: border-box; - display: flex; - justify-content: space-between; - flex-direction: column; - overflow: hidden; - - /* wriiten exclusively for safari */ - position: sticky; - } - .tableWrap { - height: 100%; - display: block; - position: relative; - width: 100%; - overflow: auto hidden; - scrollbar-color: initial; - container-type: inline-size; - - &.virtual { - overflow: hidden; - } - } - .table { - border-spacing: 0; - color: ${Colors.THUNDER}; - position: relative; - display: table; - width: 100%; - tab .tbody { - height: fit-content; - width: fit-content; - } - .tr { - cursor: ${(props) => props.triggerRowSelection && "pointer"}; - background: ${Colors.WHITE}; - &.selected-row { - background: ${({ accentColor }) => - `${lightenColor(accentColor)}`} !important; - - &:hover { - background: ${({ accentColor }) => - `${lightenColor(accentColor, "0.9")}`} !important; - } - } - - ${(props) => { - if (!props.isAddRowInProgress) { - return `&:hover { - background: var(--wds-color-bg-hover) !important; - }`; - } - }} - &.new-row { - background: ${({ accentColor }) => - `${lightenColor(accentColor)}`} !important; - } - } - .th, - .td { - margin: 0; - border-bottom: ${(props) => - props.variant === TableVariantTypes.DEFAULT || - props.variant === undefined || - props.variant === TableVariantTypes.VARIANT3 - ? "1px solid var(--wds-color-border-onaccent)" - : "none"}; - border-right: ${(props) => - props.variant === TableVariantTypes.DEFAULT || - props.variant === undefined || - props.isResizingColumn - ? "1px solid var(--wds-color-border-onaccent)" - : "none"}; - position: relative; - font-size: ${(props) => props.tableSizes.ROW_FONT_SIZE}px; - line-height: ${(props) => props.tableSizes.ROW_FONT_SIZE}px; - :last-child { - border-right: 0; - .resizer { - right: 5px; - } - } - .resizer { - display: inline-block; - width: 10px; - height: 100%; - position: absolute; - right: 0; - top: 0; - transform: translateX(50%); - z-index: 1; - ${"" /* prevents from scrolling while dragging on touch devices */} - touch-action:none; - &.isResizing { - cursor: isResizing; - } - } - } - - .th { - font-size: 14px; - } - - .th { - padding: 0 10px 0 0; - height: ${(props) => - props.isHeaderVisible ? props.tableSizes.COLUMN_HEADER_HEIGHT : 40}px; - line-height: ${(props) => - props.isHeaderVisible ? props.tableSizes.COLUMN_HEADER_HEIGHT : 40}px; - background: var(--wds-color-bg); - font-weight: bold; - } - .td { - min-height: ${(props) => props.tableSizes.ROW_HEIGHT}px; - padding: 0; - } - .thead { - position: sticky; - top: 0; - z-index: 1; - width: fit-content; - } - } - .column-freeze { - .body { - position: relative; - z-index: 0; - } - - [role="columnheader"] { - background-color: var(--wds-color-bg) !important; - } - - [data-sticky-td] { - position: sticky; - position: -webkit-sticky; - background-color: inherit; - border-bottom: ${(props) => - props.variant === TableVariantTypes.VARIANT2 - ? "none" - : "1px solid var(--wds-color-border-onaccent)"}; - & .draggable-header { - cursor: pointer; - } - &.hidden-cell, - &:has(> .hidden-header) { - z-index: 0; - position: unset !important; - } - - &:has(> .hidden-header) .resizer { - position: relative; - } - } - - [data-sticky-last-left-td] { - left: 0px; - border-right: 3px solid var(--wds-color-border); - &.hidden-cell, - &:has(> .hidden-header) { - border-right: 0.5px solid var(--wds-color-border); - } - } - - [data-sticky-first-right-td] { - right: 0px; - border-left: 3px solid var(--wds-color-border); - &.hidden-cell, - &:has(> .hidden-header) { - border-left: none; - } - } - - & .sticky-right-modifier { - border-left: 3px solid var(--wds-color-border); - } - } - - .draggable-header, - .hidden-header { - width: 100%; - text-overflow: ellipsis; - overflow: hidden; - color: ${Colors.OXFORD_BLUE}; - padding-left: 10px; - &.sorted { - padding-left: 5px; - } - } - .draggable-header { - cursor: grab; - display: inline-block; - width: 100%; - height: ${(props) => props.tableSizes.COLUMN_HEADER_HEIGHT}; - &.reorder-line { - width: 1px; - height: 100%; - } - } - .hidden-header { - opacity: 0.6; - - ${invisible}; - } - .header-menu { - cursor: pointer; - width: 24px; - display: flex; - align-items: center; - .bp3-popover2-target { - display: block; - } - - &.hide-menu { - display: none; - } - - &.hide { - &:hover { - .bp3-popover2-target { - display: block; - } - } - .bp3-popover2-target { - display: none; - } - } - } - .column-menu { - cursor: pointer; - height: ${(props) => props.tableSizes.COLUMN_HEADER_HEIGHT}px; - line-height: ${(props) => props.tableSizes.COLUMN_HEADER_HEIGHT}px; - } - .th { - display: flex !important; - justify-content: space-between; - &.highlight-left { - border-left: 2px solid ${Colors.GREEN}; - } - &.highlight-right { - border-right: 2px solid ${Colors.GREEN}; - } - & .draggable-header--dragging { - background: #efefef; - border-radius: 4px; - z-index: 100; - width: 100%; - text-overflow: none; - overflow: none; - } - } - .input-group { - height: ${(props) => props.tableSizes.COLUMN_HEADER_HEIGHT}px; - line-height: ${(props) => props.tableSizes.COLUMN_HEADER_HEIGHT}px; - padding: 0 5px; } `; @@ -352,51 +88,6 @@ export const OptionWrapper = styled.div<{ } `; -export const PaginationItemWrapper = styled.div<{ - disabled?: boolean; - selected?: boolean; - borderRadius: string; - accentColor: string; -}>` - background: ${(props) => - props.disabled ? `var(--wds-color-bg-disabled)` : `var(--wds-color-bg)`}; - border: 1px solid - ${(props) => - props.disabled - ? `var(--wds-color-border-disabled)` - : `var(--wds-color-border)`}; - box-sizing: border-box; - width: 24px; - height: 24px; - display: flex; - justify-content: center; - align-items: center; - margin: 0 4px; - cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")}; - border-radius: ${({ borderRadius }) => borderRadius}; - - & > * { - pointer-events: ${(props) => props.disabled && "none"}; - display: flex; - align-items: center; - justify-content: center; - position: relative; - } - - & svg { - fill: ${(props) => - props.disabled - ? `var(--wds-color-icon-disabled)` - : `var(--wds-color-icon)`}; - } - ${({ disabled }) => - !disabled && - `&:hover { - border-color: var(--wds-color-border-hover); - background-color: var(--wds-color-bg-hover); - }`} -`; - export const MenuColumnWrapper = styled.div<{ selected: boolean }>` display: flex; justify-content: flex-start; diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/VirtualTable.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/VirtualTable.tsx index 342309dd99..fa0c39c138 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/VirtualTable.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/VirtualTable.tsx @@ -31,7 +31,6 @@ type VirtualTableProps = TableColumnHeaderProps & { primaryColumnId?: string; isAddRowInProgress: boolean; totalColumnsWidth?: number; - scrollContainerStyles: any; useVirtual: boolean; }; @@ -65,7 +64,6 @@ const VirtualTable = (props: VirtualTableProps) => { selectedRowIndex={props.selectedRowIndex} selectedRowIndices={props.selectedRowIndices} sortTableColumn={props.sortTableColumn} - tableSizes={props.tableSizes} totalColumnsWidth={props?.totalColumnsWidth} useVirtual={props.useVirtual} widgetId={props.widgetId} diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/EmptyCell.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/EmptyCell.tsx index f3755a5dd8..e68a002787 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/EmptyCell.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/EmptyCell.tsx @@ -99,7 +99,7 @@ export const renderEmptyRows = ( return rows.map((row: string, index: number) => { return ( - + {multiRowSelection && renderBodyCheckBoxCell(false, accentColor, borderRadius)} {tableColumns.map((column: any, colIndex: number) => { @@ -155,6 +155,7 @@ export const renderEmptyRows = ( ? "td hidden-cell" : `td${addStickyModifierClass(columns, colIndex)}` } + role="cell" {...stickyAttributes} key={colIndex} sticky={column?.sticky ?? StickyType.NONE} diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/HeaderCell.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/HeaderCell.tsx index 56809cb60a..1b6ef81fea 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/HeaderCell.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/HeaderCell.tsx @@ -1,131 +1,17 @@ -import React, { - createRef, - useCallback, - useEffect, - useState, - memo, -} from "react"; -import { MenuItem, Tooltip, Menu } from "@blueprintjs/core"; +import type { Key } from "react"; +import React, { useCallback, memo } from "react"; -import { Colors } from "constants/Colors"; -import styled from "styled-components"; -import { ControlIcons } from "icons/ControlIcons"; -import type { CellAlignment } from "../Constants"; -import { - HEADER_MENU_PORTAL_CLASS, - JUSTIFY_CONTENT, - MENU_CONTENT_CLASS, - MULTISELECT_CHECKBOX_WIDTH, - POPOVER_ITEMS_TEXT_MAP, - StickyType, -} from "../Constants"; -import { TooltipContentWrapper } from "../TableStyledWrappers"; +import { MULTISELECT_CHECKBOX_WIDTH, StickyType } from "../Constants"; import { isColumnTypeEditable } from "widgets/wds/WDSTableWidget/widget/utilities"; -import { Popover2 } from "@blueprintjs/popover2"; -import { MenuDivider } from "@design-system/widgets-old"; -import { importRemixIcon, importSvg } from "@design-system/widgets-old"; -import { CANVAS_ART_BOARD } from "constants/componentClassNameConstants"; - -const Check = importRemixIcon( - async () => import("remixicon-react/CheckFillIcon"), -); -const ArrowDownIcon = importRemixIcon( - async () => import("remixicon-react/ArrowDownSLineIcon"), -); -const EditIcon = importSvg( - async () => import("assets/icons/control/edit-variant1.svg"), -); - -const AscendingIcon = styled(ControlIcons.SORT_CONTROL)` - padding: 0; - position: relative; - top: 3px; - cursor: pointer; - transform: rotate(180deg); - && svg { - path { - fill: ${Colors.LIGHT_GREYISH_BLUE}; - } - } -`; - -const DescendingIcon = styled(ControlIcons.SORT_CONTROL)` - padding: 0; - position: relative; - top: 3px; - cursor: pointer; - && svg { - path { - fill: ${Colors.LIGHT_GREYISH_BLUE}; - } - } -`; - -const ColumnNameContainer = styled.div<{ - horizontalAlignment: CellAlignment; -}>` - display: flex; - align-items: center; - justify-content: ${(props) => - props?.horizontalAlignment && JUSTIFY_CONTENT[props.horizontalAlignment]}; -`; - -const StyledEditIcon = styled(EditIcon)` - width: 14px; - min-width: 14px; - margin-right: 3px; -`; - -const TitleWrapper = styled.div` - &, - span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -`; - -interface TitleProps { - children: React.ReactNode; - tableWidth?: number; - width?: number; -} - -function Title(props: TitleProps) { - const ref = createRef(); - const [useToolTip, updateToolTip] = useState(false); - useEffect(() => { - const element = ref.current; - if (element && element.offsetWidth < element.scrollWidth) { - updateToolTip(true); - } else { - updateToolTip(false); - } - }, [ref.current, props.width, props.children]); - - return ( - - {useToolTip && props.children ? ( - - {props.children} - - } - hoverOpenDelay={1000} - position="top" - > - {props.children} - - ) : ( - props.children - )} - - ); -} - -const ICON_SIZE = 16; +import { + Flex, + Icon, + IconButton, + Item, + Menu, + MenuList, + Text, +} from "@design-system/widgets"; interface HeaderProps { canFreezeColumn?: boolean; @@ -162,11 +48,11 @@ interface HeaderProps { const HeaderCellComponent = (props: HeaderProps) => { const { column, editMode, isSortable } = props; - const [isMenuOpen, setIsMenuOpen] = useState(false); const headerProps = { ...column.getHeaderProps() }; headerProps["style"] = { ...headerProps.style, + display: "flex", left: column.sticky === StickyType.LEFT && props.multiRowSelection ? MULTISELECT_CHECKBOX_WIDTH + column.totalLeft @@ -239,14 +125,35 @@ const HeaderCellComponent = (props: HeaderProps) => { [props.onDrop, props.columnIndex], ); + const onActionOnMenu = (key: Key) => { + switch (key) { + case "sort-asc": + props.sortTableColumn(props.columnIndex, true); + break; + case "sort-desc": + props.sortTableColumn(props.columnIndex, false); + break; + case "freeze-left": + toggleColumnFreeze(StickyType.LEFT); + break; + case "freeze-right": + toggleColumnFreeze(StickyType.RIGHT); + break; + default: + break; + } + }; + return ( -
{ onDragOver={onDragOver} onDragStart={onDragStart} onDrop={onDrop} + style={ + { + "--padding-inline-end": props.isAscOrder + ? "calc((var(--outer-spacing-2) * 2) + (2 *var(--sizing-7)))" + : "calc((var(--outer-spacing-2) * 2) + var(--sizing-7))", + } as React.CSSProperties + } > - - {isColumnEditable && } - + {isColumnEditable && <Icon name="edit" size="small" />} + <Text + lineClamp={1} + title={props.columnName.replace(/\s/g, "\u00a0")} + variant="caption" + > {props.columnName.replace(/\s/g, "\u00a0")} - - + +
-
- - : undefined} - onClick={() => { - props.sortTableColumn(props.columnIndex, true); - }} - text={POPOVER_ITEMS_TEXT_MAP.SORT_ASC} - /> - : undefined - } - onClick={() => { - props.sortTableColumn(props.columnIndex, false); - }} - text={POPOVER_ITEMS_TEXT_MAP.SORT_DSC} - /> - - : undefined - } - onClick={() => { - toggleColumnFreeze(StickyType.LEFT); - }} - text={POPOVER_ITEMS_TEXT_MAP.FREEZE_LEFT} - /> - : undefined - } - onClick={() => { - toggleColumnFreeze(StickyType.RIGHT); - }} - text={POPOVER_ITEMS_TEXT_MAP.FREEZE_RIGHT} - /> - - } - interactionKind="hover" - isOpen={isMenuOpen} - minimal - onInteraction={setIsMenuOpen} - placement="bottom-end" - portalClassName={`${HEADER_MENU_PORTAL_CLASS}-${props.widgetId}`} - portalContainer={ - document.getElementById(CANVAS_ART_BOARD) || undefined - } - > - - -
- {props.isAscOrder !== undefined ? ( -
- {props.isAscOrder ? ( - - ) : ( - - )} -
- ) : null} + + {props.isAscOrder !== undefined && ( + + )} + + + + Sort column ascending + Sort column descending + + Separator + + Freeze column left + Freeze column right + + +
) => { e.preventDefault(); e.stopPropagation(); }} /> -
+ ); }; export const HeaderCell = memo(HeaderCellComponent); diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/SelectionCheckboxCell.tsx b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/SelectionCheckboxCell.tsx index cff08bd3a5..cc03ff6e89 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/SelectionCheckboxCell.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/component/cellComponents/SelectionCheckboxCell.tsx @@ -23,6 +23,7 @@ export const renderBodyCheckBoxCell = ( data-sticky-td="true" isCellVisible isChecked={isChecked} + role="cell" > {isChecked && } diff --git a/app/client/src/widgets/wds/WDSTableWidget/component/styles.module.css b/app/client/src/widgets/wds/WDSTableWidget/component/styles.module.css new file mode 100644 index 0000000000..f2c7da2127 --- /dev/null +++ b/app/client/src/widgets/wds/WDSTableWidget/component/styles.module.css @@ -0,0 +1,224 @@ +.table { + --th-height: calc( + var(--caption-line-height) + var(--caption-margin-end) + + var(--caption-margin-start) + (2 * var(--outer-spacing-3)) + ); + --tr-height: calc( + var(--body-line-height) + var(--body-margin-end) + var(--body-margin-start) + + (2 * var(--outer-spacing-4)) + ); + + display: flex; + justify-content: space-between; + flex-direction: column; + flex-grow: 1; + background: var(--color-bg-elevation-3); + border-style: solid; + border-width: var(--border-width-1); + border-color: var(--color-bd); + border-radius: var(--border-radius-elevation-3); + box-sizing: border-box; + /* adding overflow hidden so that the scollbar at the bottom does not flow out */ + overflow: hidden; + + & [aria-hidden] { + opacity: 0.6; + } + + /* -------------------------------------------------------------------------- + * WRAPPER + *-------------------------------------------------------------------------- */ + [data-table-wrapper] { + display: block; + position: relative; + overflow: auto hidden; + scrollbar-color: initial; + container-type: inline-size; + } + + &[data-type="virtualized"] [data-table-wrapper] { + overflow: hidden; + } + + /* -------------------------------------------------------------------------- + * TABLE + *-------------------------------------------------------------------------- */ + & [role="table"] { + background-position-x: var(--th-height); + background-position-y: var(--tr-height); + + border-spacing: 0; + display: table; + } + + /* -------------------------------------------------------------------------- + * THEAD + *-------------------------------------------------------------------------- */ + & thead { + position: sticky; + top: 0; + z-index: 1; + width: fit-content; + } + + /* -------------------------------------------------------------------------- + * ROWGROUP + *-------------------------------------------------------------------------- */ + & [role="rowgroup"] { + position: relative; + } + + /* -------------------------------------------------------------------------- + * TH + *-------------------------------------------------------------------------- */ + & thead [role="columnheader"] { + padding-inline: var(--outer-spacing-1); + padding-block: var(--outer-spacing-1); + background: var(--color-bg-elevation-3); + font-weight: bold; + align-items: center; + justify-content: flex-end; + border-block-end: var(--border-width-1) solid var(--color-bd); + } + + &[data-variant="default"] thead [role="columnheader"] { + border-inline-end: var(--border-width-1) solid var(--color-bd); + } + + & thead [role="columnheader"]:last-child { + border-inline-end: none; + } + + & thead [role="columnheader"][data-sticky-td] { + position: sticky; + left: 0; + } + + & thead [role="columnheader"][data-highlight-position="start"] { + border-inline-start: 2px solid var(--color-bd-positive); + } + + & thead [role="columnheader"][data-highlight-position="end"] { + border-inline-end: 2px solid var(--color-bd-positive); + } + + & thead [role="columnheader"] [data-draggable-header] { + position: absolute; + inset: 0; + display: flex; + align-items: items; + padding-inline: var(--outer-spacing-2); + padding-inline-end: var(--padding-inline-end); + } + + & + thead + [role="columnheader"]:has([data-status="dragging"]) + [data-draggable-header] { + background: var(--color-bg); + border-radius: 4px; + z-index: 100; + width: 100%; + text-overflow: none; + overflow: none; + } + + & thead [role="columnheader"][data-sticky-last-left-td]:not([aria-hidden]) { + /*important is added below because the useSticky hooks adds left as inline css */ + left: 0px !important; + border-right: 3px solid var(--color-bd); + } + + & thead [role="columnheader"][data-sticky-first-right-td]:not([aria-hidden]) { + /*important is added below because the useSticky hooks adds left as inline css */ + right: 0px !important; + border-left: 3px solid var(--color-bd); + } + + /* -------------------------------------------------------------------------- + * TR + *-------------------------------------------------------------------------- */ + & [role="row"] { + display: flex; + block-size: var(--tr-height); + } + + & [role="row"]:has([role="columnheader"]) { + block-size: var(--th-height); + } + + /*------------------------------------------------------------------------- + * Cell ( td ) + *-------------------------------------------------------------------------- */ + & [role="cell"] { + background-color: var(--color-bg-elevation-3); + } + + & [role="row"][aria-checked="true"] [role="cell"] { + background-color: var(--color-bg-accent-subtle); + } + + &[data-status="add-row-in-progress"] [role="cell"] { + background: var(--color-bg); + } + + & [role="row"][data-is-new] [role="cell"] { + background: var(--color-bg-accent-subtle); + } + + &[data-variant="default"] [role="cell"]:not(:last-child) { + border-inline-end: var(--border-width-1) solid var(--color-bd); + } + + &:is([data-variant="horizontal-borders"], [data-variant="default"]) + [role="cell"] { + border-block-end: var(--border-width-1) solid var(--color-bd); + } + + & [role="cell"][data-sticky-td] { + position: sticky; + position: -webkit-sticky; + } + + & [role="cell"][data-sticky-last-left-td]:not([aria-hidden]) { + /*important is added below because the useSticky hooks adds left as inline css */ + left: 0px !important; + border-right: 3px solid var(--color-bd); + } + + & [role="cell"][data-sticky-first-right-td]:not([aria-hidden]) { + /*important is below here because the useSticky hooks adds left as inline css */ + right: 0px !important; + border-left: 3px solid var(--color-bd); + } + + /*important is added below because the useSticky hooks adds styles as inline css */ + & :is([role="cell"], th)[data-sticky-td][aria-hidden] { + position: relative !important; + left: unset !important; + right: unset !important; + } + /* -------------------------------------------------------------------------- + * Resizor + *-------------------------------------------------------------------------- */ + & [data-resizor] { + display: inline-block; + width: 10px; + height: 100%; + position: absolute; + right: 0; + top: 0; + transform: translateX(50%); + z-index: 1; + /* prevents from scrolling while dragging on touch devices */ + touch-action: none; + } + + & [data-resizor][data-status="resizing"] { + cursor: isResizing; + } + + & thead th:last-child [data-resizor] { + right: 5px; + } +} diff --git a/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/PanelConfig/Data.ts b/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/PanelConfig/Data.ts index 244f9f0fa0..2ccb5be0b5 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/PanelConfig/Data.ts +++ b/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/PanelConfig/Data.ts @@ -13,7 +13,6 @@ import { updateCurrencyDefaultValues, updateMenuItemsSource, updateNumberColumnTypeTextAlignment, - updateThemeStylesheetsInColumns, } from "../../../widget/propertyUtils"; import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType"; import { composePropertyUpdateHook } from "widgets/WidgetUtils"; @@ -84,7 +83,6 @@ export default { ], updateHook: composePropertyUpdateHook([ updateNumberColumnTypeTextAlignment, - updateThemeStylesheetsInColumns, updateMenuItemsSource, updateCurrencyDefaultValues, ]), diff --git a/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/styleConfig.ts b/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/styleConfig.ts index 38bfab12f8..84ac34ccbb 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/styleConfig.ts +++ b/app/client/src/widgets/wds/WDSTableWidget/config/propertyPaneConfig/styleConfig.ts @@ -194,47 +194,6 @@ export const styleConfig = [ }, ], }, - { - propertyName: "borderRadius", - label: "Border radius", - helpText: "Rounds the corners of the icon button's outer border edge", - controlType: "BORDER_RADIUS_OPTIONS", - isJSConvertible: true, - isBindProperty: true, - isTriggerProperty: false, - validation: { type: ValidationTypes.TEXT }, - }, - { - propertyName: "boxShadow", - label: "Box shadow", - helpText: - "Enables you to cast a drop shadow from the frame of the widget", - controlType: "BOX_SHADOW_OPTIONS", - isJSConvertible: true, - isBindProperty: true, - isTriggerProperty: false, - validation: { type: ValidationTypes.TEXT }, - }, - { - helpText: "Use a html color name, HEX, RGB or RGBA value", - placeholderText: "#FFFFFF / Gray / rgb(255, 99, 71)", - propertyName: "borderColor", - label: "Border color", - controlType: "COLOR_PICKER", - isBindProperty: true, - isTriggerProperty: false, - validation: { type: ValidationTypes.TEXT }, - }, - { - helpText: "Enter value for border width", - propertyName: "borderWidth", - label: "Border width", - placeholderText: "Enter value in px", - controlType: "INPUT_TEXT", - isBindProperty: true, - isTriggerProperty: false, - validation: { type: ValidationTypes.NUMBER }, - }, ], }, ]; diff --git a/app/client/src/widgets/wds/WDSTableWidget/widget/index.tsx b/app/client/src/widgets/wds/WDSTableWidget/widget/index.tsx index 4d2d0666fc..eac642cd0b 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/widget/index.tsx +++ b/app/client/src/widgets/wds/WDSTableWidget/widget/index.tsx @@ -20,7 +20,7 @@ import _, { import type { WidgetState } from "widgets/BaseWidget"; import BaseWidget from "widgets/BaseWidget"; -import { RenderModes, WIDGET_PADDING } from "constants/WidgetConstants"; +import { RenderModes } from "constants/WidgetConstants"; import { EventType } from "constants/AppsmithActionConstants/ActionConstants"; import Skeleton from "components/utils/Skeleton"; import { noop, retryPromise } from "utils/AppsmithUtils"; @@ -910,8 +910,7 @@ export class WDSTableWidget extends BaseWidget { document .getElementById(getAnvilWidgetDOMId(this.props.widgetId)) ?.getBoundingClientRect().width || this.props.componentWidth; - // (2 * WIDGET_PADDING) gives the total horizontal padding (i.e. paddingLeft + paddingRight) - componentWidth = componentWidth - 2 * WIDGET_PADDING; + componentWidth = componentWidth; return { componentHeight: 300, componentWidth }; }; diff --git a/app/client/src/widgets/wds/WDSTableWidget/widget/propertyUtils.ts b/app/client/src/widgets/wds/WDSTableWidget/widget/propertyUtils.ts index 9a5d4ba9c0..a56da2c945 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/widget/propertyUtils.ts +++ b/app/client/src/widgets/wds/WDSTableWidget/widget/propertyUtils.ts @@ -6,10 +6,6 @@ import type { TableWidgetProps } from "../constants"; import { ColumnTypes, InlineEditingSaveOptions } from "../constants"; import _, { findIndex, get, isBoolean } from "lodash"; import { Colors } from "constants/Colors"; -import { - combineDynamicBindings, - getDynamicBindings, -} from "utils/DynamicBindingUtils"; import { createEditActionColumn, generateNewColumnOrderFromStickyValue, @@ -559,72 +555,6 @@ export const updateNumberColumnTypeTextAlignment = ( return; }; -/** - * updates theme stylesheets - * - * @param props - * @param propertyPath - * @param propertyValue - */ -export function updateThemeStylesheetsInColumns( - props: TableWidgetProps, - propertyPath: string, - propertyValue: any, -): Array | undefined { - const regex = /^primaryColumns\.(\w+)\.(.*)$/; - const matches = propertyPath.match(regex); - const columnId = matches?.[1]; - const columnProperty = matches?.[2]; - - if (columnProperty === "columnType") { - const propertiesToUpdate: Array = []; - const oldColumnType = get(props, `primaryColumns.${columnId}.columnType`); - const newColumnType = propertyValue; - - const propertiesToRemove = Object.keys( - props.childStylesheet[oldColumnType] || {}, - ); - - const propertiesToAdd = Object.keys( - props.childStylesheet[newColumnType] || {}, - ); - - propertiesToRemove.forEach((propertyKey) => { - propertiesToUpdate.push({ - propertyPath: `primaryColumns.${columnId}.${propertyKey}`, - shouldDeleteProperty: true, - }); - }); - - propertiesToAdd.forEach((propertyKey) => { - const { jsSnippets, stringSegments } = getDynamicBindings( - props.childStylesheet[newColumnType][propertyKey], - ); - - const js = combineDynamicBindings(jsSnippets, stringSegments); - - propertiesToUpdate.push({ - propertyPath: `primaryColumns.${columnId}.${propertyKey}`, - propertyValue: `{{${props.widgetName}.processedTableData.map((currentRow, currentIndex) => ( ${js}))}}`, - }); - }); - - if (propertiesToUpdate.length) { - /* - * Temporary patch to make evaluations to compute inverseDependencyMap when - * column type is changed. - * TODO(Balaji): remove once https://github.com/appsmithorg/appsmith/issues/14436 gets fixed - */ - propertiesToUpdate.push({ - propertyPath: `primaryColumns.${columnId}.customAlias`, - propertyValue: "", - }); - - return propertiesToUpdate; - } - } -} - /** * A function for updateHook to remove the boxShadowColor property post migration. * @param props diff --git a/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.test.ts b/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.test.ts index f8a36f503f..996bc5cf72 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.test.ts +++ b/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.test.ts @@ -9,7 +9,6 @@ import { getArrayPropertyValue, getColumnType, getDerivedColumns, - getHeaderClassNameOnDragDirection, getOriginalRowIndex, getSelectOptions, getSelectRowIndex, @@ -2542,20 +2541,6 @@ describe("generateNewColumnOrderFromStickyValue", () => { }); }); -describe("getHeaderClassNameOnDragDirection", () => { - test("Should return left highlight class when dragging from right to left", () => { - expect(getHeaderClassNameOnDragDirection(3, 2)).toEqual( - "th header-reorder highlight-left", - ); - }); - - test("Should return right highlight class when dragging from left to right", () => { - expect(getHeaderClassNameOnDragDirection(1, 2)).toEqual( - "th header-reorder highlight-right", - ); - }); -}); - describe("getSelectOptions", () => { it("Should return select options when user is not adding a new row", () => { const columnProperties = { diff --git a/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.ts b/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.ts index cae3e18557..a13706ef8e 100644 --- a/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.ts +++ b/app/client/src/widgets/wds/WDSTableWidget/widget/utilities.ts @@ -25,11 +25,6 @@ import { SelectColumnOptionsValidations } from "./propertyUtils"; import type { TableWidgetProps } from "../constants"; import { get } from "lodash"; import { getNextEntityName } from "utils/AppsmithUtils"; -import { - combineDynamicBindings, - getDynamicBindings, -} from "utils/DynamicBindingUtils"; -import { ButtonVariantTypes } from "components/constants"; import { dateFormatOptions } from "WidgetProvider/constants"; import moment from "moment"; import type { Stylesheet } from "entities/AppTheming"; @@ -668,32 +663,11 @@ export const createColumn = (props: TableWidgetProps, baseName: string) => { }; export const createEditActionColumn = (props: TableWidgetProps) => { - const themeProps: Record = {}; - - if (props.childStylesheet[ColumnTypes.EDIT_ACTIONS]) { - Object.entries(props.childStylesheet[ColumnTypes.EDIT_ACTIONS]).forEach( - ([key, value]) => { - const { jsSnippets, stringSegments } = getDynamicBindings( - value as string, - ); - - const js = combineDynamicBindings(jsSnippets, stringSegments); - - themeProps[ - key - ] = `{{${props.widgetName}.processedTableData.map((currentRow, currentIndex) => ( ${js}))}}`; - }, - ); - } - const column = { ...createColumn(props, "EditActions"), ...getEditActionColumnProperties(), - ...themeProps, columnType: ColumnTypes.EDIT_ACTIONS, label: "Save / Discard", - discardButtonVariant: ButtonVariantTypes.TERTIARY, - discardButtonColor: Colors.DANGER_SOLID, sticky: StickyType.RIGHT, }; const columnOrder = [...(props.columnOrder || [])]; @@ -944,26 +918,27 @@ export const getAllStickyColumnsCount = (columns: TableColumnProps[]) => { }; /** + * returns the highlight position when the column header is dragged * * @param currentIndex: current dragging item index * @param targetIndex: Index poistion of of header that is being hovered - * @returns + * @returns "start" | "end" | "none */ -export const getHeaderClassNameOnDragDirection = ( +export const getHighlightPosition = ( currentIndex: number, targetIndex: number, ) => { - let parentClasses = "th header-reorder"; + let position = "none"; if (currentIndex !== -1) { if (targetIndex > currentIndex) { - parentClasses += " highlight-right"; + position = "end"; } else if (targetIndex < currentIndex) { - parentClasses += " highlight-left"; + position = "start"; } } - return parentClasses; + return position; }; export const getIndexByColumnName = ( @@ -1001,7 +976,7 @@ export const getDragHandlers = ( ) => { // We get the parent element(.th) so as to apply left and right highlighting const targetElem = e.target as HTMLDivElement; - const parentTargetElem = targetElem.closest(".th.header-reorder"); + const parentTargetElem = targetElem.closest("th"); const currentIndex = getIndexByColumnName( currentDraggedColumn.current, @@ -1009,30 +984,30 @@ export const getDragHandlers = ( ); if (parentTargetElem) { - parentTargetElem.className = getHeaderClassNameOnDragDirection( - currentIndex, - targetIndex, - ); + if (parentTargetElem) { + parentTargetElem.dataset.highlightPosition = getHighlightPosition( + currentIndex, + targetIndex, + ); + } } + e.stopPropagation(); e.preventDefault(); }; const onDragEnd = (e: React.DragEvent) => { const targetElem = e.target as HTMLDivElement; - targetElem.className = targetElem.className.replace( - " draggable-header--dragging", - "", - ); + targetElem.dataset.status = ""; e.preventDefault(); }; const onDragLeave = (e: React.DragEvent) => { const targetElem = e.target as HTMLDivElement; - const parentTargetElem = targetElem.closest(".th.header-reorder"); + const parentTargetElem = targetElem.closest("th"); if (parentTargetElem) { - parentTargetElem.className = "th header-reorder"; + parentTargetElem.dataset.highlightPosition = "none"; } e.preventDefault(); @@ -1043,7 +1018,7 @@ export const getDragHandlers = ( ) => { // We get the parent element(.th) so as to apply left and right highlighting const targetElem = e.target as HTMLDivElement; - const parentTargetElem = targetElem.closest(".th.header-reorder"); + const parentTargetElem = targetElem.closest("th"); const currentIndex = getIndexByColumnName( currentDraggedColumn.current, @@ -1051,7 +1026,7 @@ export const getDragHandlers = ( ); if (parentTargetElem) { - parentTargetElem.className = getHeaderClassNameOnDragDirection( + parentTargetElem.dataset.highlightPosition = getHighlightPosition( currentIndex, targetIndex, ); @@ -1064,7 +1039,7 @@ export const getDragHandlers = ( const onDragStart = (e: React.DragEvent, index: number) => { currentDraggedColumn.current = columns[index].alias; const targetElem = e.target as HTMLDivElement; - targetElem.className = targetElem.className + " draggable-header--dragging"; + targetElem.dataset.status = "dragging"; e.stopPropagation(); }; @@ -1078,10 +1053,7 @@ export const getDragHandlers = ( partialColumnOrder.splice(index, 0, currentDraggedColumn.current); handleReorderColumn(partialColumnOrder); } - targetElem.className = targetElem.className.replace( - " draggable-header--dragging", - "", - ); + targetElem.dataset.status = ""; e.stopPropagation(); };