feat(mobile): mobile experimental feature setting (#8922)

close AF-1802

![CleanShot 2024-11-26 at 10.02.27.gif](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/LakojjjzZNf6ogjOVwKE/09d24e35-a524-497d-b5aa-840bf74f128f.gif)
This commit is contained in:
CatsJuice
2024-11-28 07:25:06 +00:00
parent c95e6ec518
commit 71ab75e30e
10 changed files with 236 additions and 12 deletions

View File

@@ -48,7 +48,7 @@ export interface ModalProps extends DialogProps {
/**
* @default 'fadeScaleTop'
*/
animation?: 'fadeScaleTop' | 'none' | 'slideBottom';
animation?: 'fadeScaleTop' | 'none' | 'slideBottom' | 'slideRight';
/**
* Whether to show the modal in full screen mode
*/

View File

@@ -51,12 +51,23 @@ const contentHideSlideBottom = keyframes({
from: { transform: 'translateY(0)' },
to: { transform: 'translateY(100%)' },
});
const contentShowSlideRight = keyframes({
from: { transform: 'translateX(100%)' },
to: { transform: 'translateX(0)' },
});
const contentHideSlideRight = keyframes({
from: { transform: 'translateX(0)' },
to: { transform: 'translateX(100%)' },
});
const modalContentViewTransitionNameFadeScaleTop = generateIdentifier(
'modal-content-fade-scale-top'
);
const modalContentViewTransitionNameSlideBottom = generateIdentifier(
'modal-content-slide-bottom'
);
const modalContentViewTransitionNameSlideRight = generateIdentifier(
'modal-content-slide-right'
);
export const modalOverlay = style({
position: 'fixed',
inset: 0,
@@ -105,6 +116,13 @@ export const modalContentWrapper = style({
[`${vtScopeSelector(modalVTScope)} &.anim-slideBottom.vt-active`]: {
viewTransitionName: modalContentViewTransitionNameSlideBottom,
},
'&.anim-slideRight': {
animation: `${contentShowSlideRight} 0.23s ease`,
animationFillMode: 'forwards',
},
[`${vtScopeSelector(modalVTScope)} &.anim-slideRight.vt-active`]: {
viewTransitionName: modalContentViewTransitionNameSlideRight,
},
},
});
globalStyle(
@@ -121,6 +139,13 @@ globalStyle(
animationFillMode: 'forwards',
}
);
globalStyle(
`::view-transition-old(${modalContentViewTransitionNameSlideRight})`,
{
animation: `${contentHideSlideRight} 0.23s ease`,
animationFillMode: 'forwards',
}
);
export const modalContent = style({
vars: {

View File

@@ -1,6 +1,18 @@
import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
import { createVar, style } from '@vanilla-extract/css';
export const switchHeightVar = createVar('switchSize');
export const switchPaddingVar = createVar('switchPadding');
const switchWidthVar = createVar('switchWidth');
const dotSizeVar = createVar('dotSize');
export const labelStyle = style({
vars: {
[switchHeightVar]: '26px',
[switchPaddingVar]: '3px',
[switchWidthVar]: `calc((${switchHeightVar} - ${switchPaddingVar}) * 2)`,
[dotSizeVar]: `calc(${switchHeightVar} - ${switchPaddingVar} * 2)`,
},
display: 'flex',
alignItems: 'center',
gap: '10px',
@@ -12,8 +24,8 @@ export const inputStyle = style({
});
export const switchStyle = style({
position: 'relative',
width: '46px',
height: '26px',
height: switchHeightVar,
width: switchWidthVar,
background: cssVar('toggleDisableBackgroundColor'),
borderRadius: '37px',
transition: '200ms all',
@@ -22,12 +34,12 @@ export const switchStyle = style({
transition: 'all .2s cubic-bezier(0.27, 0.2, 0.25, 1.51)',
content: '""',
position: 'absolute',
width: '20px',
height: '20px',
width: dotSizeVar,
height: dotSizeVar,
borderRadius: '50%',
top: '50%',
background: cssVar('toggleCircleBackgroundColor'),
transform: 'translate(3px, -50%)',
transform: `translate(${switchPaddingVar}, -50%)`,
},
},
});
@@ -36,7 +48,7 @@ export const switchCheckedStyle = style({
selectors: {
'&:before': {
borderColor: cssVar('pureBlack10'),
transform: 'translate(23px,-50%)',
transform: `translate(calc(${switchHeightVar} - ${switchPaddingVar}), -50%)`,
},
},
});

View File

@@ -1,7 +1,8 @@
// components/switch.tsx
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import type { HTMLAttributes, ReactNode } from 'react';
import { useCallback, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import * as styles from './index.css';
@@ -10,6 +11,14 @@ export type SwitchProps = Omit<HTMLAttributes<HTMLLabelElement>, 'onChange'> & {
onChange?: (checked: boolean) => void;
children?: ReactNode;
disabled?: boolean;
/**
* The height of the switch (including the padding)
*/
size?: number;
/**
* The padding of the switch
*/
padding?: number;
};
export const Switch = ({
@@ -18,8 +27,13 @@ export const Switch = ({
children,
className,
disabled,
style,
size: propsSize,
padding: propsPadding,
...otherProps
}: SwitchProps) => {
const size = propsSize ?? (BUILD_CONFIG.isMobileEdition ? 24 : 26);
const padding = propsPadding ?? (BUILD_CONFIG.isMobileEdition ? 2 : 3);
const [checkedState, setCheckedState] = useState(checkedProp);
const checked = onChangeProp ? checkedProp : checkedState;
@@ -35,8 +49,23 @@ export const Switch = ({
[disabled, onChangeProp]
);
const labelStyle = useMemo(
() => ({
...assignInlineVars({
[styles.switchHeightVar]: `${size}px`,
[styles.switchPaddingVar]: `${padding}px`,
}),
...style,
}),
[size, padding, style]
);
return (
<label className={clsx(styles.labelStyle, className)} {...otherProps}>
<label
className={clsx(styles.labelStyle, className)}
style={labelStyle}
{...otherProps}
>
{children}
<input
className={clsx(styles.inputStyle)}