From 7c1210999a6bf8420df6bf8f1eff16e0827bdb09 Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Tue, 31 Mar 2026 14:08:48 +1100 Subject: [PATCH 1/7] fix: colorwheel stuck and table checkbox not aligned --- packages/@react-spectrum/s2/src/TableView.tsx | 38 +++++++++++++++---- .../react-aria/src/color/useColorWheel.ts | 32 ++++++++-------- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 2b06f0a06d0..644edf4f215 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -867,16 +867,21 @@ const tableHeader = style({ }); const selectAllCheckbox = style({ - marginStart: 16 // table-edge-to-content, same between mobile and desktop + marginStart: 16, + marginEnd: 8 }); const selectAllCheckboxColumn = style({ padding: 0, height: 'full', + paddingX: 0, boxSizing: 'border-box', outlineStyle: 'none', position: 'relative', + display: 'flex', alignContent: 'center', + alignItems: 'center', + justifyContent: 'center', borderColor: { default: 'gray-300', forcedColors: 'ButtonBorder' @@ -1009,8 +1014,13 @@ const stickyCell = { const checkboxCellStyle = style({ ...commonCellStyles, ...stickyCell, - paddingStart: 16, + display: 'flex', + marginStart: 16, + marginEnd: 8, + paddingX: 0, alignContent: 'center', + alignItems: 'center', + justifyContent: 'center', height: 'calc(100% - 1px)', borderBottomWidth: 0, backgroundColor: '--rowBackgroundColor' @@ -1031,7 +1041,10 @@ const cellContent = style({ end: 'end' } }, - width: 'full', + width: { + default: 'full', + isCheckboxCell: 'unset' + }, isolation: 'isolate', padding: { default: 4, @@ -1058,7 +1071,16 @@ export interface CellProps extends Omit) { - let {children, isSticky, showDivider = false, align, textValue, ...otherProps} = props; + let { + children, + isSticky, + showDivider = false, + align, + textValue, + // @ts-ignore + isCheckboxCell, + ...otherProps + } = props; let domRef = useDOMRef(ref); let tableVisualOptions = useContext(InternalTableContext); textValue ||= typeof children === 'string' ? children : undefined; @@ -1079,10 +1101,10 @@ export const Cell = forwardRef(function Cell(props: CellProps, ref: DOMRef {({id, isFocusVisible, hasChildItems, isTreeColumn, isExpanded, isDisabled}) => ( <> - {hasChildItems && isTreeColumn && + {hasChildItems && isTreeColumn && } - {children} + {children} {isFocusVisible && } )} @@ -1252,7 +1274,7 @@ export const EditableCell = forwardRef(function EditableCell(props: EditableCell {...otherProps}> {({id, isFocusVisible, hasChildItems, isTreeColumn, isExpanded, isDisabled}) => ( <> - {hasChildItems && isTreeColumn && + {hasChildItems && isTreeColumn && } } /> @@ -1588,7 +1610,7 @@ export const Row = /*#__PURE__*/ (forwardRef as forwardRefType)(function Row + ( ) )} diff --git a/packages/react-aria/src/color/useColorWheel.ts b/packages/react-aria/src/color/useColorWheel.ts index 844f080ef15..48f571bf682 100644 --- a/packages/react-aria/src/color/useColorWheel.ts +++ b/packages/react-aria/src/color/useColorWheel.ts @@ -237,21 +237,23 @@ export function useColorWheel(props: AriaColorWheelOptions, state: ColorWheelSta }, movePropsContainer); let thumbInteractions = isDisabled ? {} : mergeProps({ - onMouseDown: (e: React.MouseEvent) => { - if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) { - return; - } - onThumbDown(undefined); - }, - onPointerDown: (e: React.PointerEvent) => { - if (e.pointerType === 'mouse' && (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey)) { - return; - } - onThumbDown(e.pointerId); - }, - onTouchStart: (e: React.TouchEvent) => { - onThumbDown(e.changedTouches[0].identifier); - } + ...(typeof PointerEvent !== 'undefined' ? { + onPointerDown: (e: React.PointerEvent) => { + if (e.pointerType === 'mouse' && (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey)) { + return; + } + onThumbDown(e.pointerId); + }} : { + onMouseDown: (e: React.MouseEvent) => { + if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) { + return; + } + onThumbDown(undefined); + }, + onTouchStart: (e: React.TouchEvent) => { + onThumbDown(e.changedTouches[0].identifier); + } + }) }, keyboardProps, movePropsThumb); let {x, y} = state.getThumbPosition(thumbRadius); From 9d4acfd70dc46dc7a3a7480df246dae30145228b Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Wed, 1 Apr 2026 10:47:28 +1100 Subject: [PATCH 2/7] Fix items visible behind checkboxes --- packages/@react-spectrum/s2/src/TableView.tsx | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 644edf4f215..6d43d8e5a50 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -867,21 +867,26 @@ const tableHeader = style({ }); const selectAllCheckbox = style({ - marginStart: 16, - marginEnd: 8 }); const selectAllCheckboxColumn = style({ - padding: 0, + paddingStart: { + default: 0, + ':has([slot="selection"])': 16 + }, + paddingEnd: { + default: 0, + ':has(slot="selection")': 8 + }, + paddingY: 0, height: 'full', - paddingX: 0, boxSizing: 'border-box', outlineStyle: 'none', position: 'relative', display: 'flex', alignContent: 'center', alignItems: 'center', - justifyContent: 'center', + justifyContent: 'start', borderColor: { default: 'gray-300', forcedColors: 'ButtonBorder' @@ -1015,12 +1020,11 @@ const checkboxCellStyle = style({ ...commonCellStyles, ...stickyCell, display: 'flex', - marginStart: 16, - marginEnd: 8, - paddingX: 0, + paddingStart: 16, + paddingEnd: 8, alignContent: 'center', alignItems: 'center', - justifyContent: 'center', + justifyContent: 'start', height: 'calc(100% - 1px)', borderBottomWidth: 0, backgroundColor: '--rowBackgroundColor' @@ -1043,7 +1047,7 @@ const cellContent = style({ }, width: { default: 'full', - isCheckboxCell: 'unset' + ':has([slot="selection"])': 'unset' }, isolation: 'isolate', padding: { @@ -1077,8 +1081,6 @@ export const Cell = forwardRef(function Cell(props: CellProps, ref: DOMRef } - {children} + {children} {isFocusVisible && } )} @@ -1610,7 +1612,7 @@ export const Row = /*#__PURE__*/ (forwardRef as forwardRefType)(function Row + ( ) )} From 56a1ace35cd89ce8a9039fb2d7b4bb48b0d2ee28 Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Wed, 1 Apr 2026 12:16:39 +1100 Subject: [PATCH 3/7] add pending api parity --- packages/@react-spectrum/s2/src/ActionMenu.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/@react-spectrum/s2/src/ActionMenu.tsx b/packages/@react-spectrum/s2/src/ActionMenu.tsx index b7b5cb63269..4b84ecb1115 100644 --- a/packages/@react-spectrum/s2/src/ActionMenu.tsx +++ b/packages/@react-spectrum/s2/src/ActionMenu.tsx @@ -26,7 +26,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface ActionMenuProps extends Pick, - Pick, 'children' | 'items' | 'disabledKeys' | 'onAction'>, + Pick, 'children' | 'items' | 'disabledKeys' | 'onAction' | 'shouldCloseOnSelect'>, Pick, StyleProps, DOMProps, AriaLabelingProps { /** @@ -72,7 +72,8 @@ export const ActionMenu = /*#__PURE__*/(forwardRef as forwardRefType)(function A items={props.items} disabledKeys={props.disabledKeys} onAction={props.onAction} - size={props.menuSize}> + size={props.menuSize} + shouldCloseOnSelect={props.shouldCloseOnSelect}> {props.children} From 09d372b8ac3bacf984839f08641efb1fe831c9cd Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Wed, 1 Apr 2026 12:24:30 +1100 Subject: [PATCH 4/7] update migration --- packages/dev/s2-docs/pages/s2/migrating.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dev/s2-docs/pages/s2/migrating.mdx b/packages/dev/s2-docs/pages/s2/migrating.mdx index fceb6c4b197..f0ad63b50ee 100644 --- a/packages/dev/s2-docs/pages/s2/migrating.mdx +++ b/packages/dev/s2-docs/pages/s2/migrating.mdx @@ -267,7 +267,7 @@ No updates needed. ### MenuTrigger -- Comment out `closeOnSelect` (it has not been implemented yet) +- `closeOnSelect` moved to `Menu` ### NumberField From 22a258e1e14abce5598e6872329d5a12e01d4c05 Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Thu, 2 Apr 2026 06:25:59 +1100 Subject: [PATCH 5/7] update language and codemod --- .../__tests__/__snapshots__/actionmenu.test.ts.snap | 12 ++++++++++++ .../src/s1-to-s2/__tests__/actionmenu.test.ts | 12 ++++++++++++ .../src/codemods/components/ActionMenu/transform.ts | 8 ++++---- packages/dev/s2-docs/pages/s2/migrating.mdx | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/actionmenu.test.ts.snap b/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/actionmenu.test.ts.snap index 1bdbbe57620..93df7da197e 100644 --- a/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/actionmenu.test.ts.snap +++ b/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/actionmenu.test.ts.snap @@ -16,6 +16,18 @@ let actionMenuItems = [ " `; +exports[`Renames closeOnSelect to shouldCloseOnSelect 1`] = ` +"import { MenuItem, ActionMenu } from "@react-spectrum/s2"; + +
+ + Cut + Copy + Paste + +
" +`; + exports[`Static - no change 1`] = ` "import { MenuItem, ActionMenu } from "@react-spectrum/s2"; diff --git a/packages/dev/codemods/src/s1-to-s2/__tests__/actionmenu.test.ts b/packages/dev/codemods/src/s1-to-s2/__tests__/actionmenu.test.ts index b973167c1af..12fd0ecd0bc 100644 --- a/packages/dev/codemods/src/s1-to-s2/__tests__/actionmenu.test.ts +++ b/packages/dev/codemods/src/s1-to-s2/__tests__/actionmenu.test.ts @@ -33,3 +33,15 @@ let actionMenuItems = [ `); + +test('Renames closeOnSelect to shouldCloseOnSelect', ` +import {ActionMenu, Item} from '@adobe/react-spectrum'; + +
+ + Cut + Copy + Paste + +
+`); diff --git a/packages/dev/codemods/src/s1-to-s2/src/codemods/components/ActionMenu/transform.ts b/packages/dev/codemods/src/s1-to-s2/src/codemods/components/ActionMenu/transform.ts index 163a7c03ede..75c30cce999 100644 --- a/packages/dev/codemods/src/s1-to-s2/src/codemods/components/ActionMenu/transform.ts +++ b/packages/dev/codemods/src/s1-to-s2/src/codemods/components/ActionMenu/transform.ts @@ -1,15 +1,15 @@ -import {commentOutProp} from '../../shared/transforms'; +import {commentOutProp, updatePropName} from '../../shared/transforms'; import {NodePath} from '@babel/traverse'; import * as t from '@babel/types'; /** * Transforms ActionMenu: - * - Comment out closeOnSelect (it has not been implemented yet). + * - Rename `closeOnSelect` to `shouldCloseOnSelect`. * - Comment out trigger (it has not been implemented yet). */ export default function transformActionMenu(path: NodePath): void { - // Comment out closeOnSelect - commentOutProp(path, {propName: 'closeOnSelect'}); + // Rename `closeOnSelect` to `shouldCloseOnSelect` + updatePropName(path, {oldPropName: 'closeOnSelect', newPropName: 'shouldCloseOnSelect'}); // Comment out trigger commentOutProp(path, {propName: 'trigger'}); diff --git a/packages/dev/s2-docs/pages/s2/migrating.mdx b/packages/dev/s2-docs/pages/s2/migrating.mdx index f0ad63b50ee..a13ef6b65a9 100644 --- a/packages/dev/s2-docs/pages/s2/migrating.mdx +++ b/packages/dev/s2-docs/pages/s2/migrating.mdx @@ -267,7 +267,7 @@ No updates needed. ### MenuTrigger -- `closeOnSelect` moved to `Menu` +- Rename `closeOnSelect` to `shouldCloseOnSelect` ### NumberField From 7775ed0f916ac5b2c720739f29e4216aac2769f5 Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Thu, 2 Apr 2026 09:56:27 +1100 Subject: [PATCH 6/7] add codemods for Menu as well --- .../__tests__/__snapshots__/menu.test.ts.snap | 13 +++++ .../src/s1-to-s2/__tests__/menu.test.ts | 13 +++++ .../components/MenuTrigger/transform.ts | 17 +++++++ .../src/codemods/shared/transforms.ts | 51 +++++++++++++++++++ packages/dev/s2-docs/pages/s2/migrating.mdx | 2 +- 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 packages/dev/codemods/src/s1-to-s2/src/codemods/components/MenuTrigger/transform.ts diff --git a/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/menu.test.ts.snap b/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/menu.test.ts.snap index bf4bf187f32..8c6b13b359d 100644 --- a/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/menu.test.ts.snap +++ b/packages/dev/codemods/src/s1-to-s2/__tests__/__snapshots__/menu.test.ts.snap @@ -179,6 +179,19 @@ exports[`Renames ContextualHelpTrigger to UnavailableMenuItemTrigger and Dialog " `; +exports[`Renames closeOnSelect to shouldCloseOnSelect and moves to Menu 1`] = ` +"import { MenuItem, Menu, MenuTrigger, Button } from "@react-spectrum/s2"; + + + + + Cut + Copy + Paste + +" +`; + exports[`Static - Renames Item to MenuItem, Section to MenuSection 1`] = ` "import { MenuItem, diff --git a/packages/dev/codemods/src/s1-to-s2/__tests__/menu.test.ts b/packages/dev/codemods/src/s1-to-s2/__tests__/menu.test.ts index 489289df985..6e18c3c9803 100644 --- a/packages/dev/codemods/src/s1-to-s2/__tests__/menu.test.ts +++ b/packages/dev/codemods/src/s1-to-s2/__tests__/menu.test.ts @@ -217,3 +217,16 @@ import {Menu, MenuTrigger, ContextualHelpTrigger, Item, Button, Dialog, Heading, `); + +test('Renames closeOnSelect to shouldCloseOnSelect and moves to Menu', ` +import {Menu, MenuTrigger, Item, Button} from '@adobe/react-spectrum'; + + + + + Cut + Copy + Paste + + +`); diff --git a/packages/dev/codemods/src/s1-to-s2/src/codemods/components/MenuTrigger/transform.ts b/packages/dev/codemods/src/s1-to-s2/src/codemods/components/MenuTrigger/transform.ts new file mode 100644 index 00000000000..870744faaa2 --- /dev/null +++ b/packages/dev/codemods/src/s1-to-s2/src/codemods/components/MenuTrigger/transform.ts @@ -0,0 +1,17 @@ +import {movePropToChildComponent, updatePropName} from '../../shared/transforms'; +import {NodePath} from '@babel/traverse'; +import * as t from '@babel/types'; + +/** + * Transforms MenuTrigger: + * - Rename `closeOnSelect` to `shouldCloseOnSelect` and move it to the child `Menu`. + */ +export default function transformMenuTrigger(path: NodePath): void { + updatePropName(path, {oldPropName: 'closeOnSelect', newPropName: 'shouldCloseOnSelect'}); + + movePropToChildComponent(path, { + parentComponentName: 'MenuTrigger', + childComponentName: 'Menu', + propName: 'shouldCloseOnSelect' + }); +} diff --git a/packages/dev/codemods/src/s1-to-s2/src/codemods/shared/transforms.ts b/packages/dev/codemods/src/s1-to-s2/src/codemods/shared/transforms.ts index d0cf4f5e5c1..71caec0f1d2 100644 --- a/packages/dev/codemods/src/s1-to-s2/src/codemods/shared/transforms.ts +++ b/packages/dev/codemods/src/s1-to-s2/src/codemods/shared/transforms.ts @@ -595,6 +595,57 @@ export function movePropToParentComponent( }); } +/** + * Moves a prop from the parent component onto a direct child JSX element. + * + * Example: + * - MenuTrigger: Remove `shouldCloseOnSelect` and add it to the child `Menu` instead. + */ +export function movePropToChildComponent( + path: NodePath, + options: { + parentComponentName: string, + childComponentName: string, + propName: string + } +): void { + const {parentComponentName, childComponentName, propName} = options; + + if ( + !t.isJSXIdentifier(path.node.openingElement.name) || + getName(path, path.node.openingElement.name) !== parentComponentName + ) { + return; + } + + let attrs = path.node.openingElement.attributes; + let propAttr = attrs.find( + (attr): attr is t.JSXAttribute => t.isJSXAttribute(attr) && attr.name.name === propName + ); + if (!propAttr) { + return; + } + + let childPath = path.get('children').find( + (child) => + child.isJSXElement() && + t.isJSXIdentifier(child.node.openingElement.name) && + getName(path, child.node.openingElement.name) === childComponentName + ); + + if (!childPath?.isJSXElement()) { + return; + } + + childPath.node.openingElement.attributes.push( + t.jsxAttribute(t.jsxIdentifier(propName), propAttr.value) + ); + let index = attrs.indexOf(propAttr); + if (index !== -1) { + attrs.splice(index, 1); + } +} + /** * Update to use a new component. * diff --git a/packages/dev/s2-docs/pages/s2/migrating.mdx b/packages/dev/s2-docs/pages/s2/migrating.mdx index a13ef6b65a9..f5dfa069f46 100644 --- a/packages/dev/s2-docs/pages/s2/migrating.mdx +++ b/packages/dev/s2-docs/pages/s2/migrating.mdx @@ -267,7 +267,7 @@ No updates needed. ### MenuTrigger -- Rename `closeOnSelect` to `shouldCloseOnSelect` +- Rename `closeOnSelect` to `shouldCloseOnSelect` and move to `Menu` ### NumberField From ae2596b10b3e575b354a3ef0ebe7733c13d0dc5d Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Thu, 2 Apr 2026 10:56:53 +1100 Subject: [PATCH 7/7] fix hidden focus ring --- packages/@react-spectrum/s2/src/TableView.tsx | 5 ++++- packages/@react-spectrum/s2/style/spectrum-theme.ts | 11 +++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 6d43d8e5a50..cdb2a1ecf04 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -1031,7 +1031,10 @@ const checkboxCellStyle = style({ }); const cellContent = style({ - truncate: true, + truncate: { + default: true, + isSticky: false + }, whiteSpace: { default: 'nowrap', overflowMode: { diff --git a/packages/@react-spectrum/s2/style/spectrum-theme.ts b/packages/@react-spectrum/s2/style/spectrum-theme.ts index 0cf5302c724..a961056fd38 100644 --- a/packages/@react-spectrum/s2/style/spectrum-theme.ts +++ b/packages/@react-spectrum/s2/style/spectrum-theme.ts @@ -1112,12 +1112,11 @@ export const style = createTheme({ animationDuration: 150, animationTimingFunction: 'default' }), - // eslint-disable-next-line @typescript-eslint/no-unused-vars - truncate: (_value: true) => ({ - overflowX: 'hidden', - overflowY: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap' + truncate: (value: boolean) => ({ + overflowX: value ? 'hidden' : 'visible', + overflowY: value ? 'hidden' : 'visible', + textOverflow: value ? 'ellipsis' : 'clip', + whiteSpace: value ? 'nowrap' : 'normal' }), font: (value: keyof typeof fontSize) => { let type = value.split('-')[0];