diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index c9265cc9264..a334a4bb8ce 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -689,7 +689,15 @@ function CellFocusRing() { return (
@@ -1927,7 +1935,12 @@ const rowTextColor = { const row = style< RowRenderProps & - S2TableProps & {isInFooter?: boolean; isNextSelected?: boolean; isPrevSelected?: boolean} + S2TableProps & { + isInFooter?: boolean; + isNextSelected?: boolean; + isPrevSelected?: boolean; + isFirstItem?: boolean; + } >({ height: 'full', position: 'relative', @@ -2030,20 +2043,18 @@ const row = style< } } }, - // When checkbox selection, render the gray divider between rows as a border borderTopWidth: 0, - borderBottomWidth: { - selectionStyle: { - highlight: 0, - checkbox: 1 - } - }, + borderBottomWidth: 1, borderStartWidth: 0, borderEndWidth: 0, borderStyle: 'solid', borderColor: { selectionStyle: { - highlight: 'transparent', + highlight: { + default: 'gray-300', + isSelected: 'transparent', + isNextSelected: 'transparent' + }, checkbox: { default: 'gray-300', forcedColors: 'ButtonBorder' @@ -2074,20 +2085,11 @@ const row = style< isSelected: '--borderColorBlue' } }, - // When highlight selection, render gray dividers as box shadow - boxShadow: { - selectionStyle: { - highlight: { - default: '[inset 0 -1px 0px var(--borderColorGray)]', - isNextSelected: '[inset 0 0 0 var(--borderColorGray)]' - // TODO: Determine if we want to support gray dividers between selected grouped rows - // isSelected: { - // isNextSelected: '[inset 0 -1px 0px var(--borderColorGray)]' - // } - } - }, - forcedColors: { - isFocusVisible: '[inset 0 0 0 2px Highlight]' + '--focusRingColor': { + type: 'outlineColor', + value: { + default: 'focus-ring', + forcedColors: 'Highlight' } }, fontWeight: { @@ -2095,20 +2097,50 @@ const row = style< isInFooter: 'bold' }, isolation: 'isolate', - forcedColorAdjust: 'none' + forcedColorAdjust: 'none', + '--topFocusRing': { + type: 'top', + value: { + default: '[-1px]', + isFirstItem: 0 + } + }, + '--topHighlightBorder': { + type: 'top', + value: { + default: 0, + isSelected: '[-1px]', + // Don't overlap focus ring of row above. + isPrevSelected: 0, + isFirstItem: 0, + forcedColors: 0 + } + }, + '--bottomPosition': { + type: 'bottom', + value: { + selectionStyle: { + checkbox: { + default: '[-1px]', + // Avoid the next row's selected background covering this row's focus ring. + isNextSelected: 0 + }, + highlight: '[-1px]' + } + } + } }); // Sticky cells (the drag cell, and the checkbox cell when present) get an inline z-index=2 applied by the virtualizer's layout -// To ensure that the highlight selection border is painted above the stick cells, set z-index to 3 +// To ensure that the highlight selection border is painted above the sticky cells, set z-index to 3 const highlightSelectionBorder = css( `&:before { content: ""; - width: 100%; - height: 100%; + top: var(--topHighlightBorder); + bottom: -1px; + inset-inline: 0; position: absolute; - inset: 0; z-index: 3; - box-sizing: border-box; border-style: solid; border-color: var(--borderColor); border-top-width: var(--borderTopWidth); @@ -2127,15 +2159,15 @@ const highlightSelectionBorder = css( const focusIndicator = css( `&:after { content: ""; - width: 100%; - height: 100%; - top: 0; - z-index: 2; + top: var(--topFocusRing); + bottom: var(--bottomPosition); + z-index: 3; inset-inline-start: 0; + inset-inline-end: 0; border-radius: 5px; position: absolute; outline-style: solid; - outline-color: var(--borderColorBlue); + outline-color: var(--focusRingColor); outline-width: 2px; outline-offset: -2px; pointer-events: none; @@ -2191,6 +2223,7 @@ export const Row = /*#__PURE__*/ (forwardRef as forwardRefType)(function Row( ...tableVisualOptions, selectionStyle, isInFooter, + isFirstItem: isFirstItem(renderProps.id, renderProps.state), isNextSelected: isNextSelected(renderProps.id, renderProps.state), isPrevSelected: isPrevSelected(renderProps.id, renderProps.state) }) + @@ -2271,3 +2304,10 @@ export function isPrevSelected(id: Key | undefined, state: TableState) let keyBefore = state.collection.getKeyBefore(id); return keyBefore != null && state.selectionManager.isSelected(keyBefore); } + +function isFirstItem(id: Key | undefined, state: TableState) { + if (id == null || !state) { + return false; + } + return state.collection.getFirstKey() === id; +}