From 2f2da023e4b90dc8aedf4e0e876e4289c1e4785b Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 16 Jan 2025 15:23:37 +1100 Subject: [PATCH 1/5] S2 TableView custom column menus --- packages/@react-spectrum/s2/src/TableView.tsx | 61 ++++++---- .../s2/stories/TableView.stories.tsx | 113 +++++++++++++++++- 2 files changed, 148 insertions(+), 26 deletions(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 73663391b86..786413cce43 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -53,7 +53,7 @@ import {IconContext} from './Icon'; // @ts-ignore import intlMessages from '../intl/*.json'; import {LayoutNode} from '@react-stately/layout'; -import {Menu, MenuItem, MenuTrigger} from './Menu'; +import {Menu, MenuItem, MenuSection, MenuTrigger} from './Menu'; import {mergeStyles} from '../style/runtime'; import Nubbin from '../ui-icons/S2_MoveHorizontalTableWidget.svg'; import {ProgressCircle} from './ProgressCircle'; @@ -513,7 +513,8 @@ export interface ColumnProps extends RACColumnProps { */ align?: 'start' | 'center' | 'end', /** The content to render as the column header. */ - children: ReactNode + children: ReactNode, + menu?: ReactNode } /** @@ -526,6 +527,7 @@ export const Column = forwardRef(function Column(props: ColumnProps, ref: DOMRef let domRef = useDOMRef(ref); let isColumnResizable = allowsResizing; + return ( columnStyles({...renderProps, isColumnResizable, align, isQuiet})}> {({allowsSorting, sortDirection, isFocusVisible, sort, startResize, isHovered}) => ( @@ -534,9 +536,9 @@ export const Column = forwardRef(function Column(props: ColumnProps, ref: DOMRef (no need to juggle showing this focus ring if focus is on the menu button and not if it is on the resizer) */} {/* Separate absolutely positioned element because appyling the ring on the column directly via outline means the ring's required borderRadius will cause the bottom gray border to curve as well */} {isFocusVisible && } - {isColumnResizable ? + {isColumnResizable || !!props.menu ? ( - + {children} ) : ( @@ -617,7 +619,7 @@ const resizableMenuButtonWrapper = style({ }, // TODO: when align: end, the dropdown arrow is misaligned with the text, not sure how best to make the svg be flush with the end of the button other than modifying the // paddingEnd - paddingX: 16, + paddingX: 0, backgroundColor: 'transparent', borderStyle: 'none', fontSize: 'control', @@ -709,10 +711,13 @@ const nubbin = style({ } }); -interface ResizableColumnContentProps extends Pick, Pick {} +interface ResizableColumnContentProps extends Pick, Pick { + isColumnResizable?: boolean + menu?: ReactNode +} function ResizableColumnContents(props: ResizableColumnContentProps) { - let {allowsSorting, sortDirection, sort, startResize, children, isHovered, align} = props; + let {allowsSorting, sortDirection, sort, startResize, children, isHovered, align, isColumnResizable, menu} = props; let {setIsInResizeMode, isInResizeMode} = useContext(InternalTableContext); let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/s2'); const onMenuSelect = (key) => { @@ -731,12 +736,13 @@ function ResizableColumnContents(props: ResizableColumnContentProps) { }; let items = useMemo(() => { - let options = [ - { + let options: Array<{label: string, id: string}> = []; + if (isColumnResizable) { + options = [{ label: stringFormatter.format('table.resizeColumn'), id: 'resize' - } - ]; + }]; + } if (allowsSorting) { options = [ { @@ -752,7 +758,7 @@ function ResizableColumnContents(props: ResizableColumnContentProps) { } return options; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [allowsSorting]); + }, [allowsSorting, isColumnResizable]); let buttonAlignment = 'start'; let menuAlign = 'start' as 'start' | 'end'; @@ -784,20 +790,27 @@ function ResizableColumnContents(props: ResizableColumnContentProps) { - - {(item) => {item?.label}} + + + + {(item) => {item?.label}} + + + {menu} -
- resizerHandleContainer({resizableDirection, isResizing, isHovered: isInResizeMode || isHovered})}> - {({isFocusVisible, isResizing}) => ( - <> - - {(isFocusVisible || isInResizeMode) && isResizing &&
} - - )} -
-
+ {isColumnResizable && ( +
+ resizerHandleContainer({resizableDirection, isResizing, isHovered: isInResizeMode || isHovered})}> + {({isFocusVisible, isResizing}) => ( + <> + + {(isFocusVisible || isInResizeMode) && isResizing &&
} + + )} +
+
+ )} ); } diff --git a/packages/@react-spectrum/s2/stories/TableView.stories.tsx b/packages/@react-spectrum/s2/stories/TableView.stories.tsx index a8125d2946a..36db89d5b15 100644 --- a/packages/@react-spectrum/s2/stories/TableView.stories.tsx +++ b/packages/@react-spectrum/s2/stories/TableView.stories.tsx @@ -11,7 +11,7 @@ */ import {action} from '@storybook/addon-actions'; -import {ActionButton, Cell, Column, Content, Heading, IllustratedMessage, Link, Row, TableBody, TableHeader, TableView} from '../src'; +import {ActionButton, Cell, Column, Content, Header, Heading, IllustratedMessage, Link, MenuItem, MenuSection, Row, TableBody, TableHeader, TableView, Text} from '../src'; import {categorizeArgTypes} from './utils'; import FolderOpen from '../spectrum-illustrations/linear/FolderOpen'; import type {Meta} from '@storybook/react'; @@ -19,6 +19,7 @@ import {SortDescriptor} from 'react-aria-components'; import {style} from '../style/spectrum-theme' with {type: 'macro'}; import {useAsyncList} from '@react-stately/data'; import {useState} from 'react'; +import Filter from '../s2wf-icons/S2_Icon_Filter_20_N.svg'; let onActionFunc = action('onAction'); let noOnAction = null; @@ -151,6 +152,94 @@ const DynamicTable = (args: any) => ( ); + +const DynamicTableWithCustomMenus = (args: any) => ( + + + {(column) => ( + + + Filter + + + Hide column + Manage columns + + + }>{column.name} + )} + + + {item => ( + + {(column) => { + return {item[column.id]}; + }} + + )} + + +); + +let sortItems = items; +const DynamicSortableTableWithCustomMenus = (args: any) => { + let [items, setItems] = useState(sortItems); + let [sortDescriptor, setSortDescriptor] = useState({}); + let onSortChange = (sortDescriptor: SortDescriptor) => { + let {direction = 'ascending', column = 'name'} = sortDescriptor; + + let sorted = items.slice().sort((a, b) => { + let cmp = a[column] < b[column] ? -1 : 1; + if (direction === 'descending') { + cmp *= -1; + } + return cmp; + }); + + setItems(sorted); + setSortDescriptor(sortDescriptor); + }; + + return ( + + + {(column) => ( + + + Filter + + + Hide column + Manage columns + + + }>{column.name} + )} + + + {item => ( + + {(column) => { + return {item[column.id]}; + }} + + )} + + + ); +}; + export const Dynamic = { render: DynamicTable, args: { @@ -159,6 +248,22 @@ export const Dynamic = { } }; +export const DynamicCustomMenus = { + render: DynamicTableWithCustomMenus, + args: { + ...Example.args, + disabledKeys: ['Foo 5'] + } +}; + +export const DynamicSortableCustomMenus = { + render: DynamicSortableTableWithCustomMenus, + args: { + ...Example.args, + disabledKeys: ['Foo 5'] + } +}; + function renderEmptyState() { return ( @@ -471,7 +576,11 @@ const SortableResizableTable = (args: any) => { {(column: any) => ( - {column.name} + {column.name} )} From 4fc2b6ec2a7b6981907d2567ac5156c4e8877bb8 Mon Sep 17 00:00:00 2001 From: GitHub Date: Thu, 16 Jan 2025 15:32:35 +1100 Subject: [PATCH 2/5] Fix lint --- packages/@react-spectrum/s2/src/TableView.tsx | 2 +- packages/@react-spectrum/s2/stories/TableView.stories.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 786413cce43..b890fb60507 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -712,7 +712,7 @@ const nubbin = style({ }); interface ResizableColumnContentProps extends Pick, Pick { - isColumnResizable?: boolean + isColumnResizable?: boolean, menu?: ReactNode } diff --git a/packages/@react-spectrum/s2/stories/TableView.stories.tsx b/packages/@react-spectrum/s2/stories/TableView.stories.tsx index 36db89d5b15..0903b67f0b4 100644 --- a/packages/@react-spectrum/s2/stories/TableView.stories.tsx +++ b/packages/@react-spectrum/s2/stories/TableView.stories.tsx @@ -11,15 +11,15 @@ */ import {action} from '@storybook/addon-actions'; -import {ActionButton, Cell, Column, Content, Header, Heading, IllustratedMessage, Link, MenuItem, MenuSection, Row, TableBody, TableHeader, TableView, Text} from '../src'; +import {ActionButton, Cell, Column, Content, Heading, IllustratedMessage, Link, MenuItem, MenuSection, Row, TableBody, TableHeader, TableView, Text} from '../src'; import {categorizeArgTypes} from './utils'; +import Filter from '../s2wf-icons/S2_Icon_Filter_20_N.svg'; import FolderOpen from '../spectrum-illustrations/linear/FolderOpen'; import type {Meta} from '@storybook/react'; import {SortDescriptor} from 'react-aria-components'; import {style} from '../style/spectrum-theme' with {type: 'macro'}; import {useAsyncList} from '@react-stately/data'; import {useState} from 'react'; -import Filter from '../s2wf-icons/S2_Icon_Filter_20_N.svg'; let onActionFunc = action('onAction'); let noOnAction = null; From 1682ec4210fb9adeac8392ebc98882ed061e22a0 Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Fri, 17 Jan 2025 10:33:46 +1100 Subject: [PATCH 3/5] Update TableView.tsx --- packages/@react-spectrum/s2/src/TableView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index b890fb60507..f0f80ef5bee 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -619,7 +619,7 @@ const resizableMenuButtonWrapper = style({ }, // TODO: when align: end, the dropdown arrow is misaligned with the text, not sure how best to make the svg be flush with the end of the button other than modifying the // paddingEnd - paddingX: 0, + paddingX: 16, backgroundColor: 'transparent', borderStyle: 'none', fontSize: 'control', From d027c922b0f5052e3ded18d5f7ae0a24edb6edaf Mon Sep 17 00:00:00 2001 From: GitHub Date: Mon, 20 Jan 2025 11:50:41 +1100 Subject: [PATCH 4/5] fix styles and empty section --- packages/@react-spectrum/s2/src/TableView.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index f0f80ef5bee..64ebc5c4026 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -469,7 +469,7 @@ const columnStyles = style({ }, paddingX: { default: 16, - isColumnResizable: 0 + isMenu: 0 }, textAlign: { align: { @@ -496,7 +496,7 @@ const columnStyles = style({ borderStartWidth: 0, borderEndWidth: { default: 0, - isColumnResizable: 1 + isMenu: 1 }, borderStyle: 'solid', forcedColorAdjust: 'none' @@ -525,20 +525,20 @@ export const Column = forwardRef(function Column(props: ColumnProps, ref: DOMRef let {isQuiet} = useContext(InternalTableContext); let {allowsResizing, children, align = 'start'} = props; let domRef = useDOMRef(ref); - let isColumnResizable = allowsResizing; + let isMenu = allowsResizing || !!props.menu; return ( - columnStyles({...renderProps, isColumnResizable, align, isQuiet})}> + columnStyles({...renderProps, isMenu, align, isQuiet})}> {({allowsSorting, sortDirection, isFocusVisible, sort, startResize, isHovered}) => ( <> {/* Note this is mainly for column's without a dropdown menu. If there is a dropdown menu, the button is styled to have a focus ring for simplicity (no need to juggle showing this focus ring if focus is on the menu button and not if it is on the resizer) */} {/* Separate absolutely positioned element because appyling the ring on the column directly via outline means the ring's required borderRadius will cause the bottom gray border to curve as well */} {isFocusVisible && } - {isColumnResizable || !!props.menu ? + {isMenu ? ( - + {children} ) : ( @@ -791,11 +791,13 @@ function ResizableColumnContents(props: ResizableColumnContentProps) { - - - {(item) => {item?.label}} - - + {items.length > 0 && ( + + + {(item) => {item?.label}} + + + )} {menu} From f975d06633b706ca2789992be0d062cf7e0c8550 Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Mon, 20 Jan 2025 15:14:07 +1100 Subject: [PATCH 5/5] fix lint --- packages/@react-spectrum/s2/src/TableView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 64ebc5c4026..694a908d86f 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -792,7 +792,7 @@ function ResizableColumnContents(props: ResizableColumnContentProps) { {items.length > 0 && ( - + {(item) => {item?.label}}