From 10f9cc23e637b50ce4954f3ab3a86b5ecdb4ced9 Mon Sep 17 00:00:00 2001 From: Albert Yu Date: Thu, 28 Nov 2024 13:52:56 +0800 Subject: [PATCH 1/5] Add rtl RadioGroup test --- .../components/radio-group/radio-group.mdx | 12 ++ .../radio-group/root/RadioGroupRoot.test.tsx | 111 +++++++++--------- 2 files changed, 70 insertions(+), 53 deletions(-) diff --git a/docs/data/components/radio-group/radio-group.mdx b/docs/data/components/radio-group/radio-group.mdx index a505c7ff86..c31420a402 100644 --- a/docs/data/components/radio-group/radio-group.mdx +++ b/docs/data/components/radio-group/radio-group.mdx @@ -109,3 +109,15 @@ The `Radio` components have a `[data-radio]` attribute with values `"checked"` o background: white; } ``` + +## RTL + +Place the component inside an HTML element or component with the HTML `dir="rtl"` attribute to reverse arrow key navigation for right-to-left languages: + +```jsx + + + {/* RTL keyboard behavior*/} + + +``` diff --git a/packages/react/src/radio-group/root/RadioGroupRoot.test.tsx b/packages/react/src/radio-group/root/RadioGroupRoot.test.tsx index 0ae966d703..dab94ccfeb 100644 --- a/packages/react/src/radio-group/root/RadioGroupRoot.test.tsx +++ b/packages/react/src/radio-group/root/RadioGroupRoot.test.tsx @@ -3,14 +3,11 @@ import { RadioGroup } from '@base-ui-components/react/radio-group'; import { Radio } from '@base-ui-components/react/radio'; import { expect } from 'chai'; import { spy } from 'sinon'; -import { createRenderer, act, screen, fireEvent } from '@mui/internal-test-utils'; -import userEvent from '@testing-library/user-event'; +import { createRenderer, act, screen, fireEvent, describeSkipIf } from '@mui/internal-test-utils'; import { describeConformance } from '../../../test/describeConformance'; const isJSDOM = /jsdom/.test(window.navigator.userAgent); -const user = userEvent.setup(); - describe('', () => { const { render } = createRenderer(); @@ -22,7 +19,6 @@ describe('', () => { describe('extra props', () => { it('can override the built-in attributes', () => { const { container } = render(); - // eslint-disable-next-line testing-library/no-node-access expect(container.firstElementChild as HTMLElement).to.have.attribute('role', 'switch'); }); }); @@ -111,7 +107,6 @@ describe('', () => { const group = screen.getByTestId('root'); const item = screen.getByTestId('item'); - // eslint-disable-next-line testing-library/no-node-access const input = group.querySelector('input')!; fireEvent.click(input); @@ -150,7 +145,6 @@ describe('', () => { it('should set the name attribute on the input', () => { render(); const group = screen.getByRole('radiogroup'); - // eslint-disable-next-line testing-library/no-node-access expect(group.nextElementSibling).to.have.attribute('name', 'radio-group'); }); @@ -198,7 +192,7 @@ describe('', () => { }); it('should automatically select radio upon navigation', async () => { - render( + const { user } = await render( @@ -222,77 +216,88 @@ describe('', () => { expect(b).to.have.attribute('aria-checked', 'true'); }); - it('should manage arrow key navigation', async () => { - render( -
-
, - ); + describe('should manage arrow key navigation', () => { + [ + ['ltr', 'ArrowRight', 'ArrowLeft'], + ['rtl', 'ArrowLeft', 'ArrowRight'], + ].forEach((entry) => { + const [direction, horizontalNextKey, horizontalPrevKey] = entry; - const a = screen.getByTestId('a'); - const b = screen.getByTestId('b'); - const c = screen.getByTestId('c'); - const after = screen.getByTestId('after'); + describeSkipIf(isJSDOM && direction === 'rtl')(direction, () => { + it(direction, async () => { + const { user } = await render( +
+
, + ); - act(() => { - a.focus(); - }); + const a = screen.getByTestId('a'); + const b = screen.getByTestId('b'); + const c = screen.getByTestId('c'); + const after = screen.getByTestId('after'); - expect(a).toHaveFocus(); + act(() => { + a.focus(); + }); - await user.keyboard('{ArrowDown}'); + expect(a).toHaveFocus(); - expect(b).toHaveFocus(); + await user.keyboard('{ArrowDown}'); - await user.keyboard('{ArrowDown}'); + expect(b).toHaveFocus(); - expect(c).toHaveFocus(); + await user.keyboard('{ArrowDown}'); - await user.keyboard('{ArrowDown}'); + expect(c).toHaveFocus(); - expect(a).toHaveFocus(); + await user.keyboard('{ArrowDown}'); - await user.keyboard('{ArrowUp}'); + expect(a).toHaveFocus(); - expect(c).toHaveFocus(); + await user.keyboard('{ArrowUp}'); - await user.keyboard('{ArrowUp}'); + expect(c).toHaveFocus(); - expect(b).toHaveFocus(); + await user.keyboard('{ArrowUp}'); - await user.keyboard('{ArrowUp}'); + expect(b).toHaveFocus(); - expect(a).toHaveFocus(); + await user.keyboard('{ArrowUp}'); - await user.keyboard('{ArrowLeft}'); + expect(a).toHaveFocus(); - expect(c).toHaveFocus(); + await user.keyboard(`{${horizontalPrevKey}}`); - await user.keyboard('{ArrowRight}'); + expect(c).toHaveFocus(); - expect(a).toHaveFocus(); + await user.keyboard(`{${horizontalNextKey}}`); - await user.tab(); + expect(a).toHaveFocus(); - expect(after).toHaveFocus(); + await user.tab(); - await user.tab({ shift: true }); + expect(after).toHaveFocus(); - expect(a).toHaveFocus(); + await user.tab({ shift: true }); - await user.keyboard('{ArrowLeft}'); + expect(a).toHaveFocus(); - expect(c).toHaveFocus(); + await user.keyboard(`{${horizontalPrevKey}}`); - await user.tab({ shift: true }); - await user.tab(); + expect(c).toHaveFocus(); - expect(c).toHaveFocus(); + await user.tab({ shift: true }); + await user.tab(); + + expect(c).toHaveFocus(); + }); + }); + }); }); }); From fb36f2b70589dfae3d94053e69711a674ad6e024 Mon Sep 17 00:00:00 2001 From: Albert Yu Date: Thu, 28 Nov 2024 14:55:54 +0800 Subject: [PATCH 2/5] Update tabs --- docs/data/api/tabs-root.json | 4 - docs/data/components/tabs/tabs.mdx | 12 + .../api-docs/tabs-root/tabs-root.json | 1 - docs/reference/generated/tabs-root.json | 5 - .../react/src/tabs/root/TabsRoot.test.tsx | 266 +++++++++--------- packages/react/src/tabs/root/TabsRoot.tsx | 20 -- .../react/src/tabs/root/TabsRootContext.ts | 4 - packages/react/src/tabs/root/styleHooks.ts | 1 - packages/react/src/tabs/root/useTabsRoot.ts | 34 +-- .../src/tabs/tab-indicator/TabIndicator.tsx | 8 +- .../src/tabs/tab-panel/TabPanel.test.tsx | 1 - .../react/src/tabs/tab-panel/TabPanel.tsx | 4 +- packages/react/src/tabs/tab/Tab.test.tsx | 1 - .../src/tabs/tabs-list/TabsList.test.tsx | 1 - .../react/src/tabs/tabs-list/TabsList.tsx | 4 +- 15 files changed, 156 insertions(+), 210 deletions(-) diff --git a/docs/data/api/tabs-root.json b/docs/data/api/tabs-root.json index e3d5d1f5c8..0a6fd74aaa 100644 --- a/docs/data/api/tabs-root.json +++ b/docs/data/api/tabs-root.json @@ -2,10 +2,6 @@ "props": { "className": { "type": { "name": "union", "description": "func
| string" } }, "defaultValue": { "type": { "name": "any" }, "default": "0" }, - "direction": { - "type": { "name": "enum", "description": "'ltr'
| 'rtl'" }, - "default": "'ltr'" - }, "onValueChange": { "type": { "name": "func" } }, "orientation": { "type": { "name": "enum", "description": "'horizontal'
| 'vertical'" }, diff --git a/docs/data/components/tabs/tabs.mdx b/docs/data/components/tabs/tabs.mdx index d24bd1efa7..7704c427f5 100644 --- a/docs/data/components/tabs/tabs.mdx +++ b/docs/data/components/tabs/tabs.mdx @@ -154,6 +154,18 @@ Base UI Tabs follow the [Tabs WAI-ARIA design pattern](https://www.w3.org/WAI/A | Down Arrow | Moves focus to the next tab (when `orientation="vertical"`) and activates it if `activateOnFocus` is set. | | Space, Enter | Activates the focused tab. | +## RTL + +Place horizontal tabs inside an HTML element or component with the HTML `dir="rtl"` attribute to reverse arrow key navigation for right-to-left languages: + +```jsx + + + {/* RTL keyboard behavior*/} + + +``` + ### Labeling To make the Tabs component suite accessible to assistive technology, label the `` element with `aria-label`. diff --git a/docs/data/translations/api-docs/tabs-root/tabs-root.json b/docs/data/translations/api-docs/tabs-root/tabs-root.json index 27020d8d4f..d6bf5a38ed 100644 --- a/docs/data/translations/api-docs/tabs-root/tabs-root.json +++ b/docs/data/translations/api-docs/tabs-root/tabs-root.json @@ -7,7 +7,6 @@ "defaultValue": { "description": "The default value. Use when the component is not controlled. When the value is null, no Tab will be selected." }, - "direction": { "description": "The direction of the text." }, "onValueChange": { "description": "Callback invoked when new value is being set." }, "orientation": { "description": "The component orientation (layout flow direction)." }, "render": { "description": "A function to customize rendering of the component." }, diff --git a/docs/reference/generated/tabs-root.json b/docs/reference/generated/tabs-root.json index 33998d6c74..b953ac03c1 100644 --- a/docs/reference/generated/tabs-root.json +++ b/docs/reference/generated/tabs-root.json @@ -11,11 +11,6 @@ "default": "0", "description": "The default value. Use when the component is not controlled.\nWhen the value is `null`, no Tab will be selected." }, - "direction": { - "type": "'ltr' | 'rtl'", - "default": "'ltr'", - "description": "The direction of the text." - }, "onValueChange": { "type": "(value, event) => void", "description": "Callback invoked when new value is being set." diff --git a/packages/react/src/tabs/root/TabsRoot.test.tsx b/packages/react/src/tabs/root/TabsRoot.test.tsx index 823173819b..3daea2ebc0 100644 --- a/packages/react/src/tabs/root/TabsRoot.test.tsx +++ b/packages/react/src/tabs/root/TabsRoot.test.tsx @@ -286,19 +286,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, , lastTab] = getAllByRole('tab'); await act(async () => { @@ -318,19 +319,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, secondTab] = getAllByRole('tab'); await act(async () => { @@ -352,19 +354,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, , lastTab] = getAllByRole('tab'); await act(async () => { @@ -385,19 +388,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, secondTab] = getAllByRole('tab'); await act(async () => { @@ -418,18 +422,19 @@ describe('', () => { it('skips over disabled tabs', async () => { const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, , lastTab] = getAllByRole('tab'); await act(async () => { @@ -451,19 +456,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, , lastTab] = getAllByRole('tab'); await act(async () => { @@ -483,19 +489,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [, secondTab, lastTab] = getAllByRole('tab'); await act(async () => { @@ -517,19 +524,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, , lastTab] = getAllByRole('tab'); await act(async () => { @@ -550,19 +558,20 @@ describe('', () => { const handleChange = spy(); const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [, secondTab, lastTab] = getAllByRole('tab'); await act(async () => { @@ -583,18 +592,19 @@ describe('', () => { it('skips over disabled tabs', async () => { const handleKeyDown = spy(); const { getAllByRole } = await render( - - - - - - - , +
+ + + + + + + +
, ); const [firstTab, , lastTab] = getAllByRole('tab'); await act(async () => { diff --git a/packages/react/src/tabs/root/TabsRoot.tsx b/packages/react/src/tabs/root/TabsRoot.tsx index f9bcf00f11..18983cb370 100644 --- a/packages/react/src/tabs/root/TabsRoot.tsx +++ b/packages/react/src/tabs/root/TabsRoot.tsx @@ -26,7 +26,6 @@ const TabsRoot = React.forwardRef(function TabsRoot( const { className, defaultValue = 0, - direction: directionProp = 'ltr', onValueChange: onValueChangeProp, orientation = 'horizontal', render, @@ -35,8 +34,6 @@ const TabsRoot = React.forwardRef(function TabsRoot( } = props; const { - getRootProps, - direction, getTabElementBySelectedValue, getTabIdByPanelValueOrIndex, getTabPanelIdByTabValueOrIndex, @@ -50,12 +47,10 @@ const TabsRoot = React.forwardRef(function TabsRoot( value: valueProp, defaultValue, onValueChange: onValueChangeProp, - direction: directionProp, }); const tabsContextValue: TabsRootContext = React.useMemo( () => ({ - direction, getTabElementBySelectedValue, getTabIdByPanelValueOrIndex, getTabPanelIdByTabValueOrIndex, @@ -66,7 +61,6 @@ const TabsRoot = React.forwardRef(function TabsRoot( value, }), [ - direction, getTabElementBySelectedValue, getTabIdByPanelValueOrIndex, getTabPanelIdByTabValueOrIndex, @@ -80,12 +74,10 @@ const TabsRoot = React.forwardRef(function TabsRoot( const state: TabsRoot.State = { orientation, - direction, tabActivationDirection, }; const { renderElement } = useComponentRenderer({ - propGetter: getRootProps, render: render ?? 'div', className, state, @@ -104,14 +96,12 @@ const TabsRoot = React.forwardRef(function TabsRoot( }); export type TabsOrientation = 'horizontal' | 'vertical'; -export type TabsDirection = 'ltr' | 'rtl'; export type TabActivationDirection = 'left' | 'right' | 'up' | 'down' | 'none'; export type TabValue = any | null; namespace TabsRoot { export type State = { orientation: TabsOrientation; - direction: TabsDirection; tabActivationDirection: TabActivationDirection; }; @@ -132,11 +122,6 @@ namespace TabsRoot { * @default 'horizontal' */ orientation?: TabsOrientation; - /** - * The direction of the text. - * @default 'ltr' - */ - direction?: TabsDirection; /** * Callback invoked when new value is being set. */ @@ -165,11 +150,6 @@ TabsRoot.propTypes /* remove-proptypes */ = { * @default 0 */ defaultValue: PropTypes.any, - /** - * The direction of the text. - * @default 'ltr' - */ - direction: PropTypes.oneOf(['ltr', 'rtl']), /** * Callback invoked when new value is being set. */ diff --git a/packages/react/src/tabs/root/TabsRootContext.ts b/packages/react/src/tabs/root/TabsRootContext.ts index 9fe68c4458..8e567a38c3 100644 --- a/packages/react/src/tabs/root/TabsRootContext.ts +++ b/packages/react/src/tabs/root/TabsRootContext.ts @@ -20,10 +20,6 @@ export interface TabsRootContext { * The component orientation (layout flow direction). */ orientation: 'horizontal' | 'vertical'; - /** - * The direction of the tabs. - */ - direction: 'ltr' | 'rtl'; /** * Gets the element of the Tab with the given value. * @param {any | undefined} value Value to find the tab for. diff --git a/packages/react/src/tabs/root/styleHooks.ts b/packages/react/src/tabs/root/styleHooks.ts index 4929d153ae..87481b41d2 100644 --- a/packages/react/src/tabs/root/styleHooks.ts +++ b/packages/react/src/tabs/root/styleHooks.ts @@ -2,7 +2,6 @@ import type { TabsRoot } from './TabsRoot'; import type { CustomStyleHookMapping } from '../../utils/getStyleHookProps'; export const tabsStyleHookMapping: CustomStyleHookMapping = { - direction: () => null, tabActivationDirection: (dir) => ({ 'data-activation-direction': dir, }), diff --git a/packages/react/src/tabs/root/useTabsRoot.ts b/packages/react/src/tabs/root/useTabsRoot.ts index 2938c5f1f1..18ce3dc3ea 100644 --- a/packages/react/src/tabs/root/useTabsRoot.ts +++ b/packages/react/src/tabs/root/useTabsRoot.ts @@ -1,7 +1,5 @@ 'use client'; import * as React from 'react'; -import { mergeReactProps } from '../../utils/mergeReactProps'; -import { GenericHTMLProps } from '../../utils/types'; import { useControlled } from '../../utils/useControlled'; import type { CompositeMetadata } from '../../composite/list/CompositeList'; import type { TabPanelMetadata } from '../tab-panel/useTabPanel'; @@ -9,12 +7,7 @@ import type { TabMetadata } from '../tab/useTab'; import type { TabActivationDirection, TabValue } from './TabsRoot'; function useTabsRoot(parameters: useTabsRoot.Parameters): useTabsRoot.ReturnValue { - const { - value: valueProp, - defaultValue, - onValueChange: onValueChangeProp, - direction = 'ltr', - } = parameters; + const { value: valueProp, defaultValue, onValueChange: onValueChangeProp } = parameters; const tabPanelRefs = React.useRef<(HTMLElement | null)[]>([]); @@ -122,17 +115,7 @@ function useTabsRoot(parameters: useTabsRoot.Parameters): useTabsRoot.ReturnValu [tabMap], ); - const getRootProps: useTabsRoot.ReturnValue['getRootProps'] = React.useCallback( - (otherProps = {}) => - mergeReactProps<'div'>(otherProps, { - dir: direction, - }), - [direction], - ); - return { - getRootProps, - direction, getTabElementBySelectedValue, getTabIdByPanelValueOrIndex, getTabPanelIdByTabValueOrIndex, @@ -157,11 +140,6 @@ namespace useTabsRoot { * The default value. Use when the component is not controlled. */ defaultValue?: TabValue; - /** - * The direction of the text. - * @default 'ltr' - */ - direction?: 'ltr' | 'rtl'; /** * Callback invoked when new value is being set. */ @@ -169,16 +147,6 @@ namespace useTabsRoot { } export interface ReturnValue { - /** - * Resolver for the Root component's props. - * @param externalProps additional props for Tabs.Root - * @returns props that should be spread on Tabs.Root - */ - getRootProps: (externalProps?: GenericHTMLProps) => GenericHTMLProps; - /** - * The direction of the text. - */ - direction: 'ltr' | 'rtl'; /** * Gets the element of the Tab with the given value. * @param {any | undefined} value Value to find the tab for. diff --git a/packages/react/src/tabs/tab-indicator/TabIndicator.tsx b/packages/react/src/tabs/tab-indicator/TabIndicator.tsx index f1c13b2f84..de24e2da6a 100644 --- a/packages/react/src/tabs/tab-indicator/TabIndicator.tsx +++ b/packages/react/src/tabs/tab-indicator/TabIndicator.tsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; import { useOnMount } from '../../utils/useOnMount'; import type { BaseUIComponentProps } from '../../utils/types'; -import type { TabsDirection, TabsOrientation, TabsRoot } from '../root/TabsRoot'; +import type { TabsOrientation, TabsRoot } from '../root/TabsRoot'; import { useTabsRootContext } from '../root/TabsRootContext'; import { tabsStyleHookMapping } from '../root/styleHooks'; import { useTabsListContext } from '../tabs-list/TabsListContext'; @@ -27,7 +27,7 @@ const TabIndicator = React.forwardRef( function TabIndicator(props, forwardedRef) { const { className, render, renderBeforeHydration = false, ...other } = props; - const { direction, getTabElementBySelectedValue, orientation, tabActivationDirection, value } = + const { getTabElementBySelectedValue, orientation, tabActivationDirection, value } = useTabsRootContext(); const { tabsListRef } = useTabsListContext(); @@ -46,12 +46,11 @@ const TabIndicator = React.forwardRef( const state: TabIndicator.State = React.useMemo( () => ({ - direction, orientation, selectedTabPosition, tabActivationDirection, }), - [direction, orientation, selectedTabPosition, tabActivationDirection], + [orientation, selectedTabPosition, tabActivationDirection], ); const { renderElement } = useComponentRenderer({ @@ -94,7 +93,6 @@ namespace TabIndicator { export interface State extends TabsRoot.State { selectedTabPosition: ActiveTabPosition | null; orientation: TabsOrientation; - direction: TabsDirection; } export interface Props extends BaseUIComponentProps<'span', TabIndicator.State> { diff --git a/packages/react/src/tabs/tab-panel/TabPanel.test.tsx b/packages/react/src/tabs/tab-panel/TabPanel.test.tsx index 4746039bdb..8aa9546152 100644 --- a/packages/react/src/tabs/tab-panel/TabPanel.test.tsx +++ b/packages/react/src/tabs/tab-panel/TabPanel.test.tsx @@ -13,7 +13,6 @@ describe('', () => { getTabElementBySelectedValue: () => null, getTabIdByPanelValueOrIndex: () => '', getTabPanelIdByTabValueOrIndex: () => '', - direction: 'ltr', orientation: 'horizontal', tabActivationDirection: 'none', }; diff --git a/packages/react/src/tabs/tab-panel/TabPanel.tsx b/packages/react/src/tabs/tab-panel/TabPanel.tsx index a18de9deef..6c43b34e2a 100644 --- a/packages/react/src/tabs/tab-panel/TabPanel.tsx +++ b/packages/react/src/tabs/tab-panel/TabPanel.tsx @@ -28,7 +28,6 @@ const TabPanel = React.forwardRef(function TabPanel( value: selectedValue, getTabIdByPanelValueOrIndex, orientation, - direction, tabActivationDirection, } = useTabsRootContext(); @@ -41,12 +40,11 @@ const TabPanel = React.forwardRef(function TabPanel( const state: TabPanel.State = React.useMemo( () => ({ - direction, hidden, orientation, tabActivationDirection, }), - [direction, hidden, orientation, tabActivationDirection], + [hidden, orientation, tabActivationDirection], ); const { renderElement } = useComponentRenderer({ diff --git a/packages/react/src/tabs/tab/Tab.test.tsx b/packages/react/src/tabs/tab/Tab.test.tsx index a0df40aadc..c52060addc 100644 --- a/packages/react/src/tabs/tab/Tab.test.tsx +++ b/packages/react/src/tabs/tab/Tab.test.tsx @@ -32,7 +32,6 @@ describe('', () => { getTabIdByPanelValueOrIndex: () => '', getTabPanelIdByTabValueOrIndex: () => '', orientation: 'horizontal', - direction: 'ltr', tabActivationDirection: 'none', }; diff --git a/packages/react/src/tabs/tabs-list/TabsList.test.tsx b/packages/react/src/tabs/tabs-list/TabsList.test.tsx index 17ce391fec..3ca0a1988e 100644 --- a/packages/react/src/tabs/tabs-list/TabsList.test.tsx +++ b/packages/react/src/tabs/tabs-list/TabsList.test.tsx @@ -20,7 +20,6 @@ describe('', () => { getTabIdByPanelValueOrIndex: () => '', getTabPanelIdByTabValueOrIndex: () => '', orientation: 'horizontal', - direction: 'ltr', tabActivationDirection: 'none', }} > diff --git a/packages/react/src/tabs/tabs-list/TabsList.tsx b/packages/react/src/tabs/tabs-list/TabsList.tsx index 28ca823047..4d405cd364 100644 --- a/packages/react/src/tabs/tabs-list/TabsList.tsx +++ b/packages/react/src/tabs/tabs-list/TabsList.tsx @@ -28,7 +28,6 @@ const TabsList = React.forwardRef(function TabsList( const { activateOnFocus = true, className, loop = true, render, ...other } = props; const { - direction = 'ltr', getTabElementBySelectedValue, onValueChange, orientation = 'horizontal', @@ -53,11 +52,10 @@ const TabsList = React.forwardRef(function TabsList( const state: TabsList.State = React.useMemo( () => ({ - direction, orientation, tabActivationDirection, }), - [direction, orientation, tabActivationDirection], + [orientation, tabActivationDirection], ); const { renderElement } = useComponentRenderer({ From faf67fa517d1a7397b4b84aede2afd3e97880d4f Mon Sep 17 00:00:00 2001 From: Albert Yu Date: Thu, 28 Nov 2024 16:01:23 +0800 Subject: [PATCH 3/5] Update progress --- docs/data/api/progress-root.json | 4 - .../progress/IndeterminateProgress.js | 83 +----- .../progress/IndeterminateProgress.tsx | 83 +----- .../IndeterminateProgress.tsx.preview | 16 +- docs/data/components/progress/RtlProgress.js | 67 +---- docs/data/components/progress/RtlProgress.tsx | 67 +---- .../progress/RtlProgress.tsx.preview | 18 +- .../css-modules/index.js | 85 +----- .../css-modules/index.tsx | 85 +----- .../css-modules/index.tsx.preview | 15 +- .../system/index.js | 1 + .../system/index.tsx | 1 + .../tailwind/index.js | 9 +- .../tailwind/index.tsx | 9 +- docs/data/components/progress/progress.mdx | 12 +- .../components/progress/styles.module.css | 45 +++ .../api-docs/progress-root/progress-root.json | 1 - docs/reference/generated/progress-root.json | 5 - docs/src/app/experiments/progress.tsx | 256 ------------------ packages/react/src/progress/index.parts.ts | 5 +- .../indicator/ProgressIndicator.test.tsx | 23 +- .../progress/indicator/ProgressIndicator.tsx | 3 +- .../indicator/useProgressIndicator.ts | 14 +- .../react/src/progress/root/ProgressRoot.tsx | 13 +- .../react/src/progress/root/styleHooks.ts | 1 - .../src/progress/root/useProgressRoot.ts | 27 +- .../src/progress/track/ProgressTrack.test.tsx | 2 - 27 files changed, 200 insertions(+), 750 deletions(-) create mode 100644 docs/data/components/progress/styles.module.css delete mode 100644 docs/src/app/experiments/progress.tsx diff --git a/docs/data/api/progress-root.json b/docs/data/api/progress-root.json index 49b89e1fff..3cc51d0c56 100644 --- a/docs/data/api/progress-root.json +++ b/docs/data/api/progress-root.json @@ -4,10 +4,6 @@ "aria-labelledby": { "type": { "name": "string" } }, "aria-valuetext": { "type": { "name": "string" } }, "className": { "type": { "name": "union", "description": "func
| string" } }, - "direction": { - "type": { "name": "enum", "description": "'ltr'
| 'rtl'" }, - "default": "'ltr'" - }, "getAriaLabel": { "type": { "name": "func" }, "signature": { diff --git a/docs/data/components/progress/IndeterminateProgress.js b/docs/data/components/progress/IndeterminateProgress.js index bf80c97f2c..0573d7e4d8 100644 --- a/docs/data/components/progress/IndeterminateProgress.js +++ b/docs/data/components/progress/IndeterminateProgress.js @@ -1,76 +1,21 @@ 'use client'; import * as React from 'react'; -import { Progress as BaseProgress } from '@base-ui-components/react/progress'; -import { Box, styled, keyframes, css } from '@mui/system'; +import { Progress } from '@base-ui-components/react/progress'; +import classes from './styles.module.css'; export default function IndeterminateProgress() { return ( - - - - Uploading files - - - - - - + + + Uploading files + + + + + ); } - -const Progress = styled(BaseProgress.Root)` - display: flex; - flex-flow: column nowrap; - gap: 1rem; -`; - -const ProgressTrack = styled(BaseProgress.Track)( - ({ theme }) => ` - position: relative; - width: 100%; - height: 4px; - border-radius: 9999px; - background-color: ${theme.palette.mode === 'dark' ? grey[400] : grey[400]}; - display: flex; - overflow: hidden; - `, -); - -const indeterminateProgress = keyframes` - from { - transform: translateX(-100%); - } - - to { - transform: translateX(20rem); - } -`; - -const ProgressIndicator = styled(BaseProgress.Indicator)( - ({ theme }) => css` - background-color: ${theme.palette.mode === 'dark' ? BLUE400 : BLUE500}; - border-radius: inherit; - - &[data-indeterminate] { - width: 25%; - animation: ${indeterminateProgress} 1.5s infinite ease-in-out; - will-change: transform; - } - `, -); - -const grey = { - 50: '#F3F6F9', - 100: '#E5EAF2', - 200: '#DAE2ED', - 300: '#C7D0DD', - 400: '#B0B8C4', - 500: '#9DA8B7', - 600: '#6B7A90', - 700: '#434D5B', - 800: '#303740', - 900: '#1C2025', -}; - -const BLUE400 = '#3399FF'; -const BLUE500 = '#007FFF'; diff --git a/docs/data/components/progress/IndeterminateProgress.tsx b/docs/data/components/progress/IndeterminateProgress.tsx index bf80c97f2c..0573d7e4d8 100644 --- a/docs/data/components/progress/IndeterminateProgress.tsx +++ b/docs/data/components/progress/IndeterminateProgress.tsx @@ -1,76 +1,21 @@ 'use client'; import * as React from 'react'; -import { Progress as BaseProgress } from '@base-ui-components/react/progress'; -import { Box, styled, keyframes, css } from '@mui/system'; +import { Progress } from '@base-ui-components/react/progress'; +import classes from './styles.module.css'; export default function IndeterminateProgress() { return ( - - - - Uploading files - - - - - - + + + Uploading files + + + + + ); } - -const Progress = styled(BaseProgress.Root)` - display: flex; - flex-flow: column nowrap; - gap: 1rem; -`; - -const ProgressTrack = styled(BaseProgress.Track)( - ({ theme }) => ` - position: relative; - width: 100%; - height: 4px; - border-radius: 9999px; - background-color: ${theme.palette.mode === 'dark' ? grey[400] : grey[400]}; - display: flex; - overflow: hidden; - `, -); - -const indeterminateProgress = keyframes` - from { - transform: translateX(-100%); - } - - to { - transform: translateX(20rem); - } -`; - -const ProgressIndicator = styled(BaseProgress.Indicator)( - ({ theme }) => css` - background-color: ${theme.palette.mode === 'dark' ? BLUE400 : BLUE500}; - border-radius: inherit; - - &[data-indeterminate] { - width: 25%; - animation: ${indeterminateProgress} 1.5s infinite ease-in-out; - will-change: transform; - } - `, -); - -const grey = { - 50: '#F3F6F9', - 100: '#E5EAF2', - 200: '#DAE2ED', - 300: '#C7D0DD', - 400: '#B0B8C4', - 500: '#9DA8B7', - 600: '#6B7A90', - 700: '#434D5B', - 800: '#303740', - 900: '#1C2025', -}; - -const BLUE400 = '#3399FF'; -const BLUE500 = '#007FFF'; diff --git a/docs/data/components/progress/IndeterminateProgress.tsx.preview b/docs/data/components/progress/IndeterminateProgress.tsx.preview index e45ea5cb8b..c1fbaf3882 100644 --- a/docs/data/components/progress/IndeterminateProgress.tsx.preview +++ b/docs/data/components/progress/IndeterminateProgress.tsx.preview @@ -1,8 +1,12 @@ - - + + Uploading files - - - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/docs/data/components/progress/RtlProgress.js b/docs/data/components/progress/RtlProgress.js index 5419bd2d25..6b87eb1320 100644 --- a/docs/data/components/progress/RtlProgress.js +++ b/docs/data/components/progress/RtlProgress.js @@ -1,60 +1,23 @@ 'use client'; import * as React from 'react'; -import { Progress as BaseProgress } from '@base-ui-components/react/progress'; -import { Box, styled } from '@mui/system'; +import { Progress } from '@base-ui-components/react/progress'; +import classes from './styles.module.css'; export default function RtlProgress() { return ( - - - - Uploading files (RTL) +
+ + + تحميل الملفات (RTL) - - - - - + + + + +
); } - -const Progress = styled(BaseProgress.Root)` - display: flex; - flex-flow: column nowrap; - gap: 1rem; -`; - -const ProgressTrack = styled(BaseProgress.Track)( - ({ theme }) => ` - position: relative; - width: 100%; - height: 4px; - border-radius: 9999px; - background-color: ${theme.palette.mode === 'dark' ? grey[400] : grey[400]}; - display: flex; - overflow: hidden; - `, -); - -const ProgressIndicator = styled(BaseProgress.Indicator)( - ({ theme }) => ` - background-color: ${theme.palette.mode === 'dark' ? BLUE400 : BLUE500}; - border-radius: inherit; - `, -); - -const grey = { - 50: '#F3F6F9', - 100: '#E5EAF2', - 200: '#DAE2ED', - 300: '#C7D0DD', - 400: '#B0B8C4', - 500: '#9DA8B7', - 600: '#6B7A90', - 700: '#434D5B', - 800: '#303740', - 900: '#1C2025', -}; - -const BLUE400 = '#3399FF'; -const BLUE500 = '#007FFF'; diff --git a/docs/data/components/progress/RtlProgress.tsx b/docs/data/components/progress/RtlProgress.tsx index 5419bd2d25..6b87eb1320 100644 --- a/docs/data/components/progress/RtlProgress.tsx +++ b/docs/data/components/progress/RtlProgress.tsx @@ -1,60 +1,23 @@ 'use client'; import * as React from 'react'; -import { Progress as BaseProgress } from '@base-ui-components/react/progress'; -import { Box, styled } from '@mui/system'; +import { Progress } from '@base-ui-components/react/progress'; +import classes from './styles.module.css'; export default function RtlProgress() { return ( - - - - Uploading files (RTL) +
+ + + تحميل الملفات (RTL) - - - - - + + + + +
); } - -const Progress = styled(BaseProgress.Root)` - display: flex; - flex-flow: column nowrap; - gap: 1rem; -`; - -const ProgressTrack = styled(BaseProgress.Track)( - ({ theme }) => ` - position: relative; - width: 100%; - height: 4px; - border-radius: 9999px; - background-color: ${theme.palette.mode === 'dark' ? grey[400] : grey[400]}; - display: flex; - overflow: hidden; - `, -); - -const ProgressIndicator = styled(BaseProgress.Indicator)( - ({ theme }) => ` - background-color: ${theme.palette.mode === 'dark' ? BLUE400 : BLUE500}; - border-radius: inherit; - `, -); - -const grey = { - 50: '#F3F6F9', - 100: '#E5EAF2', - 200: '#DAE2ED', - 300: '#C7D0DD', - 400: '#B0B8C4', - 500: '#9DA8B7', - 600: '#6B7A90', - 700: '#434D5B', - 800: '#303740', - 900: '#1C2025', -}; - -const BLUE400 = '#3399FF'; -const BLUE500 = '#007FFF'; diff --git a/docs/data/components/progress/RtlProgress.tsx.preview b/docs/data/components/progress/RtlProgress.tsx.preview index daa832be54..73c648ad8b 100644 --- a/docs/data/components/progress/RtlProgress.tsx.preview +++ b/docs/data/components/progress/RtlProgress.tsx.preview @@ -1,8 +1,12 @@ - - - Uploading files (RTL) + + + تحميل الملفات (RTL) - - - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.js b/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.js index ef47b513e9..636787c6d6 100644 --- a/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.js +++ b/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.js @@ -1,80 +1,21 @@ 'use client'; import * as React from 'react'; -import { useTheme } from '@mui/system'; import { Progress } from '@base-ui-components/react/progress'; +import classes from '../../styles.module.css'; export default function UnstyledProgressIntroduction() { return ( -
- - - Uploading files - - - - - - -
+ + + Uploading files + + + + + ); } - -function useIsDarkMode() { - const theme = useTheme(); - return theme.palette.mode === 'dark'; -} - -export function Styles() { - const isDarkMode = useIsDarkMode(); - return ( - - ); -} - -const grey = { - 50: '#F3F6F9', - 100: '#E5EAF2', - 200: '#DAE2ED', - 300: '#C7D0DD', - 400: '#B0B8C4', - 500: '#9DA8B7', - 600: '#6B7A90', - 700: '#434D5B', - 800: '#303740', - 900: '#1C2025', -}; - -const BLUE400 = '#3399FF'; -const BLUE500 = '#007FFF'; diff --git a/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx b/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx index ef47b513e9..636787c6d6 100644 --- a/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx +++ b/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx @@ -1,80 +1,21 @@ 'use client'; import * as React from 'react'; -import { useTheme } from '@mui/system'; import { Progress } from '@base-ui-components/react/progress'; +import classes from '../../styles.module.css'; export default function UnstyledProgressIntroduction() { return ( -
- - - Uploading files - - - - - - -
+ + + Uploading files + + + + + ); } - -function useIsDarkMode() { - const theme = useTheme(); - return theme.palette.mode === 'dark'; -} - -export function Styles() { - const isDarkMode = useIsDarkMode(); - return ( - - ); -} - -const grey = { - 50: '#F3F6F9', - 100: '#E5EAF2', - 200: '#DAE2ED', - 300: '#C7D0DD', - 400: '#B0B8C4', - 500: '#9DA8B7', - 600: '#6B7A90', - 700: '#434D5B', - 800: '#303740', - 900: '#1C2025', -}; - -const BLUE400 = '#3399FF'; -const BLUE500 = '#007FFF'; diff --git a/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx.preview b/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx.preview index 28317020bb..ac12393167 100644 --- a/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx.preview +++ b/docs/data/components/progress/UnstyledProgressIntroduction/css-modules/index.tsx.preview @@ -1,9 +1,12 @@ - - + + Uploading files - - + + - - \ No newline at end of file + \ No newline at end of file diff --git a/docs/data/components/progress/UnstyledProgressIntroduction/system/index.js b/docs/data/components/progress/UnstyledProgressIntroduction/system/index.js index 4268250b97..ab6b900fa9 100644 --- a/docs/data/components/progress/UnstyledProgressIntroduction/system/index.js +++ b/docs/data/components/progress/UnstyledProgressIntroduction/system/index.js @@ -62,6 +62,7 @@ const ProgressIndicator = styled(BaseProgress.Indicator)` const Label = styled('span')` cursor: unset; font-weight: bold; + color: var(--color-gray-700); `; function useIsDarkMode() { diff --git a/docs/data/components/progress/UnstyledProgressIntroduction/system/index.tsx b/docs/data/components/progress/UnstyledProgressIntroduction/system/index.tsx index 4268250b97..ab6b900fa9 100644 --- a/docs/data/components/progress/UnstyledProgressIntroduction/system/index.tsx +++ b/docs/data/components/progress/UnstyledProgressIntroduction/system/index.tsx @@ -62,6 +62,7 @@ const ProgressIndicator = styled(BaseProgress.Indicator)` const Label = styled('span')` cursor: unset; font-weight: bold; + color: var(--color-gray-700); `; function useIsDarkMode() { diff --git a/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.js b/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.js index 523131f9e3..6a3411f163 100644 --- a/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.js +++ b/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.js @@ -74,7 +74,7 @@ const ProgressIndicator = React.forwardRef(function ProgressIndicator(props, ref ref={ref} className={(state) => classNames( - 'rounded-[inherit] bg-gray-500 dark:bg-gray-400', + 'rounded-[inherit] bg-[background-color:var(--code-6)]', typeof props.className === 'function' ? props.className(state) : props.className, @@ -92,7 +92,12 @@ ProgressIndicator.propTypes = { }; function Label(props) { - return ; + return ( + + ); } function classNames(...classes) { diff --git a/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.tsx b/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.tsx index 8ac23cc6fc..dd7ef543e0 100644 --- a/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.tsx +++ b/docs/data/components/progress/UnstyledProgressIntroduction/tailwind/index.tsx @@ -68,7 +68,7 @@ const ProgressIndicator = React.forwardRef(function ProgressIndicator( ref={ref} className={(state) => classNames( - 'rounded-[inherit] bg-gray-500 dark:bg-gray-400', + 'rounded-[inherit] bg-[background-color:var(--code-6)]', typeof props.className === 'function' ? props.className(state) : props.className, @@ -79,7 +79,12 @@ const ProgressIndicator = React.forwardRef(function ProgressIndicator( }); function Label(props: React.HTMLAttributes) { - return ; + return ( + + ); } function classNames(...classes: Array) { diff --git a/docs/data/components/progress/progress.mdx b/docs/data/components/progress/progress.mdx index c3d5e8ea65..4086f79d09 100644 --- a/docs/data/components/progress/progress.mdx +++ b/docs/data/components/progress/progress.mdx @@ -72,10 +72,18 @@ Set `value` to `null` to configure an indeterminate progress bar. The `data-inde ## RTL -Set the `direction` prop to `'rtl'` to change the direction that the `Indicator` fills towards for right-to-left languages: +Place the component inside an HTML element or component with the HTML `dir="rtl"` attribute to change the direction that the `Indicator` fills towards for right-to-left languages: ```jsx -{/* Subcomponents */} + + + + + {/* fills from right to left */} + + + + ``` diff --git a/docs/data/components/progress/styles.module.css b/docs/data/components/progress/styles.module.css new file mode 100644 index 0000000000..b32f75c08f --- /dev/null +++ b/docs/data/components/progress/styles.module.css @@ -0,0 +1,45 @@ +.progress { + display: flex; + flex-flow: column nowrap; + gap: 1rem; + width: 20rem; + margin-top: 2rem; + margin-bottom: 2rem; +} + +.track { + position: relative; + width: 100%; + height: 4px; + border-radius: 9999px; + background-color: var(--color-gray-400); + display: flex; + overflow: hidden; +} + +.indicator { + background-color: var(--code-6); + border-radius: inherit; +} + +.indicator[data-indeterminate] { + width: 25%; + animation: indeterminateProgress 1.5s infinite ease-in-out; + will-change: transform; +} + +.label { + cursor: unset; + font-weight: bold; + color: var(--color-gray-700); +} + +@keyframes indeterminateProgress { + from { + transform: translateX(-100%); + } + + to { + transform: translateX(20rem); + } +} diff --git a/docs/data/translations/api-docs/progress-root/progress-root.json b/docs/data/translations/api-docs/progress-root/progress-root.json index cdac80157b..a6c23105e8 100644 --- a/docs/data/translations/api-docs/progress-root/progress-root.json +++ b/docs/data/translations/api-docs/progress-root/progress-root.json @@ -11,7 +11,6 @@ "className": { "description": "Class names applied to the element or a function that returns them based on the component's state." }, - "direction": { "description": "The direction that progress bars fill in" }, "getAriaLabel": { "description": "Accepts a function which returns a string value that provides an accessible name for the Indicator component", "typeDescriptions": { "value": "The component's value" } diff --git a/docs/reference/generated/progress-root.json b/docs/reference/generated/progress-root.json index 7f3684add5..e955a196da 100644 --- a/docs/reference/generated/progress-root.json +++ b/docs/reference/generated/progress-root.json @@ -18,11 +18,6 @@ "type": "string | (state) => string", "description": "Class names applied to the element or a function that returns them based on the component's state." }, - "direction": { - "type": "'ltr' | 'rtl'", - "default": "'ltr'", - "description": "The direction that progress bars fill in" - }, "getAriaLabel": { "type": "(value) => string", "description": "Accepts a function which returns a string value that provides an accessible name for the Indicator component" diff --git a/docs/src/app/experiments/progress.tsx b/docs/src/app/experiments/progress.tsx deleted file mode 100644 index e7d183a2eb..0000000000 --- a/docs/src/app/experiments/progress.tsx +++ /dev/null @@ -1,256 +0,0 @@ -'use client'; -import * as React from 'react'; -import { useTheme } from '@mui/system'; -import { Progress } from '@base-ui-components/react/progress'; - -const VAL1 = 33; - -const CUSTOM_BUFFER_VAL = 77; - -export default function ProgressDemos() { - return ( -
- - - - - - - - - Indeterminate Progress - - - - - - - - - Progress (RTL) - - - - - - - - - Indeterminate (RTL) - - - - - - -

Customizations

- - - `${value}% complete, ${CUSTOM_BUFFER_VAL}% buffered` - } - max={Math.min(100, CUSTOM_BUFFER_VAL)} - > - - Custom Buffer Component - - - - - - - - - `${value}% complete, ${CUSTOM_BUFFER_VAL}% buffered` - } - max={Math.min(100, CUSTOM_BUFFER_VAL)} - direction="rtl" - > - - Custom Buffer Component (RTL) - - - - - - - -
- ); -} - -function MyBuffer(props: any) { - const { value, style, ...rest } = props; - const percentageValue = valueToPercent(value, 0, 100); - return ( - - ); -} - -function valueToPercent(value: number | undefined, min: number, max: number) { - if (value === undefined) { - return value; - } - - return ((value - min) * 100) / (max - min); -} - -const grey = { - 50: '#F3F6F9', - 100: '#E5EAF2', - 200: '#DAE2ED', - 300: '#C7D0DD', - 400: '#B0B8C4', - 500: '#9DA8B7', - 600: '#6B7A90', - 700: '#434D5B', - 800: '#303740', - 900: '#1C2025', -}; - -const BLUE400 = '#3399FF'; -const BLUE500 = '#007FFF'; - -function useIsDarkMode() { - const theme = useTheme(); - return theme.palette.mode === 'dark'; -} - -export function Styles() { - const isDarkMode = useIsDarkMode(); - return ( - - ); -} diff --git a/packages/react/src/progress/index.parts.ts b/packages/react/src/progress/index.parts.ts index f481f8116b..de92865297 100644 --- a/packages/react/src/progress/index.parts.ts +++ b/packages/react/src/progress/index.parts.ts @@ -2,7 +2,4 @@ export { ProgressRoot as Root } from './root/ProgressRoot'; export { ProgressTrack as Track } from './track/ProgressTrack'; export { ProgressIndicator as Indicator } from './indicator/ProgressIndicator'; -export type { - ProgressStatus as Status, - ProgressDirection as Direction, -} from './root/useProgressRoot'; +export type { ProgressStatus as Status } from './root/useProgressRoot'; diff --git a/packages/react/src/progress/indicator/ProgressIndicator.test.tsx b/packages/react/src/progress/indicator/ProgressIndicator.test.tsx index 10e713810e..3c3b4bb9f8 100644 --- a/packages/react/src/progress/indicator/ProgressIndicator.test.tsx +++ b/packages/react/src/progress/indicator/ProgressIndicator.test.tsx @@ -1,17 +1,18 @@ import * as React from 'react'; import { expect } from 'chai'; import { Progress } from '@base-ui-components/react/progress'; +import { describeSkipIf } from '@mui/internal-test-utils'; import { createRenderer, describeConformance } from '#test-utils'; import { ProgressRootContext } from '../root/ProgressRootContext'; +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + const contextValue: ProgressRootContext = { - direction: 'ltr', max: 100, min: 0, value: 30, status: 'progressing', state: { - direction: 'ltr', max: 100, min: 0, status: 'progressing', @@ -30,14 +31,8 @@ describe('', () => { refInstanceof: window.HTMLSpanElement, })); - describe('internal styles', () => { - it('determinate', async function test(t = {}) { - if (/jsdom/.test(window.navigator.userAgent)) { - // @ts-expect-error to support mocha and vitest - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - this?.skip?.() || t?.skip(); - } - + describeSkipIf(isJSDOM)('internal styles', () => { + it('determinate', async () => { const { getByTestId } = await render( @@ -54,13 +49,7 @@ describe('', () => { }); }); - it('indeterminate', async function test(t = {}) { - if (/jsdom/.test(window.navigator.userAgent)) { - // @ts-expect-error to support mocha and vitest - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - this?.skip?.() || t?.skip(); - } - + it('indeterminate', async () => { const { getByTestId } = await render( diff --git a/packages/react/src/progress/indicator/ProgressIndicator.tsx b/packages/react/src/progress/indicator/ProgressIndicator.tsx index 2100238f5c..0558291f35 100644 --- a/packages/react/src/progress/indicator/ProgressIndicator.tsx +++ b/packages/react/src/progress/indicator/ProgressIndicator.tsx @@ -24,10 +24,9 @@ const ProgressIndicator = React.forwardRef(function ProgressIndicator( ) { const { render, className, ...otherProps } = props; - const { direction, max, min, value, state } = useProgressRootContext(); + const { max, min, value, state } = useProgressRootContext(); const { getRootProps } = useProgressIndicator({ - direction, max, min, value, diff --git a/packages/react/src/progress/indicator/useProgressIndicator.ts b/packages/react/src/progress/indicator/useProgressIndicator.ts index 73a4e0ecc1..130af5aecc 100644 --- a/packages/react/src/progress/indicator/useProgressIndicator.ts +++ b/packages/react/src/progress/indicator/useProgressIndicator.ts @@ -1,7 +1,6 @@ 'use client'; import * as React from 'react'; import { mergeReactProps } from '../../utils/mergeReactProps'; -import { ProgressDirection } from '../root/useProgressRoot'; function valueToPercent(value: number, min: number, max: number) { return ((value - min) * 100) / (max - min); @@ -10,9 +9,7 @@ function valueToPercent(value: number, min: number, max: number) { function useProgressIndicator( parameters: useProgressIndicator.Parameters, ): useProgressIndicator.ReturnValue { - const { direction, max = 100, min = 0, value } = parameters; - - const isRtl = direction === 'rtl'; + const { max = 100, min = 0, value } = parameters; const percentageValue = Number.isFinite(value) && value !== null ? valueToPercent(value, min, max) : null; @@ -23,11 +20,11 @@ function useProgressIndicator( } return { - [isRtl ? 'right' : 'left']: 0, + insetInlineStart: 0, height: 'inherit', width: `${percentageValue}%`, }; - }, [isRtl, percentageValue]); + }, [percentageValue]); const getRootProps: useProgressIndicator.ReturnValue['getRootProps'] = React.useCallback( (externalProps = {}) => @@ -44,11 +41,6 @@ function useProgressIndicator( namespace useProgressIndicator { export interface Parameters { - /** - * The direction that progress bars fill in - * @default 'ltr' - */ - direction?: ProgressDirection; /** * The maximum value * @default 100 diff --git a/packages/react/src/progress/root/ProgressRoot.tsx b/packages/react/src/progress/root/ProgressRoot.tsx index 6e3ce6b26d..1031bf4c3a 100644 --- a/packages/react/src/progress/root/ProgressRoot.tsx +++ b/packages/react/src/progress/root/ProgressRoot.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { type ProgressDirection, ProgressStatus, useProgressRoot } from './useProgressRoot'; +import { ProgressStatus, useProgressRoot } from './useProgressRoot'; import { ProgressRootContext } from './ProgressRootContext'; import { progressStyleHookMapping } from './styleHooks'; import { BaseUIComponentProps } from '../../utils/types'; @@ -25,7 +25,6 @@ const ProgressRoot = React.forwardRef(function ProgressRoot( 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-valuetext': ariaValuetext, - direction = 'ltr', getAriaLabel, getAriaValueText, max = 100, @@ -40,7 +39,6 @@ const ProgressRoot = React.forwardRef(function ProgressRoot( 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-valuetext': ariaValuetext, - direction, getAriaLabel, getAriaValueText, max, @@ -50,12 +48,11 @@ const ProgressRoot = React.forwardRef(function ProgressRoot( const state: ProgressRoot.State = React.useMemo( () => ({ - direction, max, min, status: progress.status, }), - [direction, max, min, progress.status], + [max, min, progress.status], ); const contextValue: ProgressRootContext = React.useMemo( @@ -85,7 +82,6 @@ const ProgressRoot = React.forwardRef(function ProgressRoot( namespace ProgressRoot { export type State = { - direction: ProgressDirection; max: number; min: number; status: ProgressStatus; @@ -119,11 +115,6 @@ ProgressRoot.propTypes /* remove-proptypes */ = { * Class names applied to the element or a function that returns them based on the component's state. */ className: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), - /** - * The direction that progress bars fill in - * @default 'ltr' - */ - direction: PropTypes.oneOf(['ltr', 'rtl']), /** * Accepts a function which returns a string value that provides an accessible name for the Indicator component * @param {number | null} value The component's value diff --git a/packages/react/src/progress/root/styleHooks.ts b/packages/react/src/progress/root/styleHooks.ts index 0d7b31fa3d..cc92f49def 100644 --- a/packages/react/src/progress/root/styleHooks.ts +++ b/packages/react/src/progress/root/styleHooks.ts @@ -2,7 +2,6 @@ import type { CustomStyleHookMapping } from '../../utils/getStyleHookProps'; import type { ProgressRoot } from './ProgressRoot'; export const progressStyleHookMapping: CustomStyleHookMapping = { - direction: () => null, max: () => null, min: () => null, status(value): Record | null { diff --git a/packages/react/src/progress/root/useProgressRoot.ts b/packages/react/src/progress/root/useProgressRoot.ts index 69af98024b..5412d84f1b 100644 --- a/packages/react/src/progress/root/useProgressRoot.ts +++ b/packages/react/src/progress/root/useProgressRoot.ts @@ -4,8 +4,6 @@ import { mergeReactProps } from '../../utils/mergeReactProps'; export type ProgressStatus = 'indeterminate' | 'progressing' | 'complete'; -export type ProgressDirection = 'ltr' | 'rtl'; - function getDefaultAriaValueText(value: number | null) { if (value === null) { return 'indeterminate progress'; @@ -19,7 +17,6 @@ function useProgressRoot(parameters: useProgressRoot.Parameters): useProgressRoo 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-valuetext': ariaValuetext, - direction = 'ltr', getAriaLabel, getAriaValueText, max = 100, @@ -43,25 +40,14 @@ function useProgressRoot(parameters: useProgressRoot.Parameters): useProgressRoo 'aria-valuetext': getAriaValueText ? getAriaValueText(value) : (ariaValuetext ?? getDefaultAriaValueText(value)), - dir: direction, role: 'progressbar', }), - [ - ariaLabel, - ariaLabelledby, - ariaValuetext, - direction, - getAriaLabel, - getAriaValueText, - max, - min, - value, - ], + [ariaLabel, ariaLabelledby, ariaValuetext, getAriaLabel, getAriaValueText, max, min, value], ); return { getRootProps, - direction, + max, min, value, @@ -83,11 +69,6 @@ namespace useProgressRoot { * A string value that provides a human-readable text alternative for the current value of the progress indicator. */ 'aria-valuetext'?: string; - /** - * The direction that progress bars fill in - * @default 'ltr' - */ - direction?: ProgressDirection; /** * Accepts a function which returns a string value that provides an accessible name for the Indicator component * @param {number | null} value The component's value @@ -121,10 +102,6 @@ namespace useProgressRoot { getRootProps: ( externalProps?: React.ComponentPropsWithRef<'div'>, ) => React.ComponentPropsWithRef<'div'>; - /** - * The direction that progress bars fill in - */ - direction: ProgressDirection; /** * The maximum value */ diff --git a/packages/react/src/progress/track/ProgressTrack.test.tsx b/packages/react/src/progress/track/ProgressTrack.test.tsx index bd4d3e7617..faa41433cd 100644 --- a/packages/react/src/progress/track/ProgressTrack.test.tsx +++ b/packages/react/src/progress/track/ProgressTrack.test.tsx @@ -4,13 +4,11 @@ import { createRenderer, describeConformance } from '#test-utils'; import { ProgressRootContext } from '../root/ProgressRootContext'; const contextValue: ProgressRootContext = { - direction: 'ltr', max: 100, min: 0, value: 30, status: 'progressing', state: { - direction: 'ltr', max: 100, min: 0, status: 'progressing', From 3adec4e6315a33cded3d73b5fbe1225e82263542 Mon Sep 17 00:00:00 2001 From: Albert Yu Date: Thu, 28 Nov 2024 16:25:18 +0800 Subject: [PATCH 4/5] Fix cross-orientation arrow key on Tabs --- packages/react/src/tabs/tabs-list/TabsList.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/src/tabs/tabs-list/TabsList.tsx b/packages/react/src/tabs/tabs-list/TabsList.tsx index 4d405cd364..e6425cd0b5 100644 --- a/packages/react/src/tabs/tabs-list/TabsList.tsx +++ b/packages/react/src/tabs/tabs-list/TabsList.tsx @@ -92,6 +92,7 @@ const TabsList = React.forwardRef(function TabsList( highlightedIndex={highlightedTabIndex} enableHomeAndEndKeys loop={loop} + orientation={orientation} onHighlightedIndexChange={setHighlightedTabIndex} onMapChange={setTabMap} render={renderElement()} From bdee765e45b6439e28b4f70f1f3b7d61f88acbe9 Mon Sep 17 00:00:00 2001 From: Albert Yu Date: Fri, 29 Nov 2024 12:54:03 +0800 Subject: [PATCH 5/5] Fix comments --- docs/data/components/progress/styles.module.css | 6 +++--- docs/data/components/radio-group/radio-group.mdx | 2 +- docs/data/components/tabs/tabs.mdx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/data/components/progress/styles.module.css b/docs/data/components/progress/styles.module.css index b32f75c08f..a06a557284 100644 --- a/docs/data/components/progress/styles.module.css +++ b/docs/data/components/progress/styles.module.css @@ -12,13 +12,13 @@ width: 100%; height: 4px; border-radius: 9999px; - background-color: var(--color-gray-400); + background-color: var(--color-gray-400, oklch(12% 8% 264 / 38%)); display: flex; overflow: hidden; } .indicator { - background-color: var(--code-6); + background-color: var(--code-6, #00749e); border-radius: inherit; } @@ -31,7 +31,7 @@ .label { cursor: unset; font-weight: bold; - color: var(--color-gray-700); + color: var(--color-gray-700, oklch(12% 6% 264 / 77%)); } @keyframes indeterminateProgress { diff --git a/docs/data/components/radio-group/radio-group.mdx b/docs/data/components/radio-group/radio-group.mdx index c31420a402..bedab85d2f 100644 --- a/docs/data/components/radio-group/radio-group.mdx +++ b/docs/data/components/radio-group/radio-group.mdx @@ -117,7 +117,7 @@ Place the component inside an HTML element or component with the HTML `dir="rtl" ```jsx - {/* RTL keyboard behavior*/} + {/* RTL keyboard behavior */} ``` diff --git a/docs/data/components/tabs/tabs.mdx b/docs/data/components/tabs/tabs.mdx index 7704c427f5..65e26ead8e 100644 --- a/docs/data/components/tabs/tabs.mdx +++ b/docs/data/components/tabs/tabs.mdx @@ -161,7 +161,7 @@ Place horizontal tabs inside an HTML element or component with the HTML `dir="rt ```jsx - {/* RTL keyboard behavior*/} + {/* RTL keyboard behavior */} ```