@@ -14,13 +14,14 @@ import {
14
14
Switch as AriaSwitch ,
15
15
SwitchProps as AriaSwitchProps ,
16
16
ContextValue ,
17
- SwitchRenderProps
17
+ SwitchRenderProps ,
18
+ useLocale
18
19
} from 'react-aria-components' ;
19
20
import { baseColor , focusRing , fontRelative , style } from '../style' with { type : 'macro' } ;
20
21
import { CenterBaseline } from './CenterBaseline' ;
21
22
import { controlFont , controlSize , getAllowedOverrides , StyleProps } from './style-utils' with { type : 'macro' } ;
22
23
import { createContext , forwardRef , ReactNode , useContext , useRef } from 'react' ;
23
- import { FocusableRef , FocusableRefValue , GlobalDOMAttributes } from '@react-types/shared' ;
24
+ import { Direction , FocusableRef , FocusableRefValue , GlobalDOMAttributes } from '@react-types/shared' ;
24
25
import { FormContext , useFormProps } from './Form' ;
25
26
import { pressScale } from './pressScale' ;
26
27
import { useFocusableRef } from '@react-spectrum/utils' ;
@@ -124,7 +125,7 @@ const handle = style<RenderProps>({
124
125
} ) ;
125
126
126
127
// Use an inline style to calculate the transform so we can combine it with the press scale.
127
- const transformStyle = ( { isSelected} : SwitchRenderProps ) => ( {
128
+ const transformStyle = ( { isSelected, direction } : SwitchRenderProps & { direction : Direction } ) => {
128
129
// In the default state, the handle is 8px smaller than the track. When selected it grows to 6px smaller than the track.
129
130
// Normally this could be calculated as a scale transform with (trackHeight - 8px) / trackHeight, however,
130
131
// CSS does not allow division with units. To solve this we use a 3d perspective transform. Perspective is the
@@ -143,11 +144,15 @@ const transformStyle = ({isSelected}: SwitchRenderProps) => ({
143
144
//
144
145
// defaultPerspective = trackHeight - 8px
145
146
// selectedPerspective = 2 * (trackHeight - 6px)
146
- transform : isSelected
147
- // The selected state also translates the X position to the end of the track (minus the borders).
148
- ? 'translateX(calc(var(--trackWidth) - 100% - 4px)) perspective(calc(2 * (var(--trackHeight) - 6px))) translateZ(-4px)'
149
- : 'perspective(calc(var(--trackHeight) - 8px)) translateZ(-4px)'
150
- } ) ;
147
+ const placement =
148
+ direction === 'ltr'
149
+ ? // The selected state also translates the X position to the end of the track (minus the borders).
150
+ 'translateX(calc(var(--trackWidth) - 100% - 4px)) perspective(calc(2 * (var(--trackHeight) - 6px))) translateZ(-4px)'
151
+ : 'translateX(calc(100% - var(--trackWidth) + 4px)) perspective(calc(2 * (var(--trackHeight) - 6px))) translateZ(-4px)' ;
152
+ return {
153
+ transform : isSelected ? placement : 'perspective(calc(var(--trackHeight) - 8px)) translateZ(-4px)'
154
+ } ;
155
+ } ;
151
156
152
157
/**
153
158
* Switches allow users to turn an individual option on or off.
@@ -160,6 +165,7 @@ export const Switch = /*#__PURE__*/ forwardRef(function Switch(props: SwitchProp
160
165
let domRef = useFocusableRef ( ref , inputRef ) ;
161
166
let handleRef = useRef ( null ) ;
162
167
let isInForm = ! ! useContext ( FormContext ) ;
168
+ let { direction} = useLocale ( ) ;
163
169
props = useFormProps ( props ) ;
164
170
return (
165
171
< AriaSwitch
@@ -179,7 +185,7 @@ export const Switch = /*#__PURE__*/ forwardRef(function Switch(props: SwitchProp
179
185
} ) } >
180
186
< div
181
187
ref = { handleRef }
182
- style = { pressScale ( handleRef , transformStyle ) ( renderProps ) }
188
+ style = { pressScale ( handleRef , transformStyle ) ( { ... renderProps , direction } ) }
183
189
className = { handle ( renderProps ) } />
184
190
</ div >
185
191
</ CenterBaseline >
0 commit comments