File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 66 * Copyright Oxide Computer Company
77 */
88import cn from 'classnames'
9- import * as m from 'motion/react-m'
109import { type MouseEventHandler , type ReactNode } from 'react'
1110
1211import { type BadgeColor } from '@oxide/design-system/ui'
@@ -120,25 +119,19 @@ export const Button = ({
120119 { ...rest }
121120 >
122121 { loading && (
123- < m . span
124- animate = { { opacity : 1 , y : '-50%' , x : '-50%' } }
125- initial = { { opacity : 0 , y : 'calc(-50% - 25px)' , x : '-50%' } }
126- transition = { { type : 'spring' , duration : 0.3 , bounce : 0 } }
127- className = "absolute top-1/2 left-1/2 flex items-center justify-center"
128- >
122+ < span className = "button-spinner-in absolute top-1/2 left-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center" >
129123 < Spinner variant = { variantToBadgeColorMap [ variant || 'primary' ] } />
130- </ m . span >
124+ </ span >
131125 ) }
132- < m . span
133- className = { cn ( 'flex items-center' , innerClassName ) }
134- animate = { {
135- opacity : loading ? 0 : 1 ,
136- y : loading ? 25 : 0 ,
137- } }
138- transition = { { type : 'spring' , duration : 0.3 , bounce : 0 } }
126+ < span
127+ className = { cn (
128+ 'button-content flex items-center' ,
129+ loading ? 'translate-y-[25px] opacity-0' : 'translate-y-0 opacity-100' ,
130+ innerClassName
131+ ) }
139132 >
140133 { children }
141- </ m . span >
134+ </ span >
142135 </ button >
143136 </ Wrap >
144137 )
Original file line number Diff line number Diff line change 88
99.ox-button {
1010 @apply relative;
11+ /*
12+ * Shared by the spinner keyframes and the .button-content transition below.
13+ * Approximates Motion's { type: 'spring', duration: 0.3, bounce: 0 }.
14+ */
15+ --button-loading-easing : cubic-bezier (0.35 , 0.98 , 0.35 , 1 );
1116
1217 & : after {
1318 content : '' ;
7277.active-clicked : active : not (.visually-disabled ) {
7378 @apply motion-safe:translate-y-px;
7479}
80+
81+ /* Animating transform is deliberate: the spinner's centering utilities set the
82+ * separate translate property, which composes with transform instead of being
83+ * overridden by it. */
84+ @keyframes button-spinner-in {
85+ from {
86+ opacity : 0 ;
87+ transform : translateY (-25px );
88+ }
89+ to {
90+ opacity : 1 ;
91+ transform : translateY (0 );
92+ }
93+ }
94+
95+ @media (prefers-reduced-motion : no-preference) {
96+ .ox-button .button-spinner-in {
97+ animation : button-spinner-in 0.3s var (--button-loading-easing );
98+ }
99+
100+ /* Button label; swaps out as the spinner drops in. Loading state is toggled
101+ * with utility classes in Button.tsx. */
102+ .ox-button .button-content {
103+ transition :
104+ opacity 0.3s var (--button-loading-easing ),
105+ translate 0.3s var (--button-loading-easing );
106+ }
107+ }
You can’t perform that action at this time.
0 commit comments