mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-12 15:46:29 +08:00
feat!: affine cloud support (#3813)
Co-authored-by: Hongtao Lye <codert.sn@gmail.com> Co-authored-by: liuyi <forehalo@gmail.com> Co-authored-by: LongYinan <lynweklm@gmail.com> Co-authored-by: X1a0t <405028157@qq.com> Co-authored-by: JimmFly <yangjinfei001@gmail.com> Co-authored-by: Peng Xiao <pengxiao@outlook.com> Co-authored-by: xiaodong zuo <53252747+zuoxiaodong0815@users.noreply.github.com> Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com> Co-authored-by: Qi <474021214@qq.com> Co-authored-by: danielchim <kahungchim@gmail.com>
This commit is contained in:
@@ -8,22 +8,27 @@ import { type CSSProperties, forwardRef } from 'react';
|
||||
|
||||
import * as styles from './styles.css';
|
||||
|
||||
export const RadioButton = forwardRef<HTMLButtonElement, RadioGroupItemProps>(
|
||||
({ children, className, ...props }, ref) => {
|
||||
return (
|
||||
<RadioGroup.Item
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={clsx(styles.radioButton, className)}
|
||||
export const RadioButton = forwardRef<
|
||||
HTMLButtonElement,
|
||||
RadioGroupItemProps & { spanStyle?: string }
|
||||
>(({ children, className, spanStyle, ...props }, ref) => {
|
||||
return (
|
||||
<RadioGroup.Item
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={clsx(styles.radioButton, className)}
|
||||
>
|
||||
<span className={clsx(styles.radioUncheckedButton, spanStyle)}>
|
||||
{children}
|
||||
</span>
|
||||
<RadioGroup.Indicator
|
||||
className={clsx(styles.radioButtonContent, spanStyle)}
|
||||
>
|
||||
<span className={styles.radioUncheckedButton}>{children}</span>
|
||||
<RadioGroup.Indicator className={styles.radioButtonContent}>
|
||||
{children}
|
||||
</RadioGroup.Indicator>
|
||||
</RadioGroup.Item>
|
||||
);
|
||||
}
|
||||
);
|
||||
{children}
|
||||
</RadioGroup.Indicator>
|
||||
</RadioGroup.Item>
|
||||
);
|
||||
});
|
||||
RadioButton.displayName = 'RadioButton';
|
||||
|
||||
export const RadioButtonGroup = forwardRef<
|
||||
|
||||
@@ -25,18 +25,24 @@ export const button = style({
|
||||
'&.text-bold': {
|
||||
fontWeight: 600,
|
||||
},
|
||||
'&:hover': {
|
||||
'&:not(.without-hover):hover': {
|
||||
background: 'var(--affine-hover-color)',
|
||||
},
|
||||
'&.disabled, &.loading': {
|
||||
'&.disabled': {
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
color: 'var(--affine-disable-color)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&.disabled:hover, &.loading:hover': {
|
||||
background: 'inherit',
|
||||
'&.loading': {
|
||||
cursor: 'default',
|
||||
color: 'var(--affine-disable-color)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&.disabled:not(.without-hover):hover, &.loading:not(.without-hover):hover':
|
||||
{
|
||||
background: 'inherit',
|
||||
},
|
||||
|
||||
'&.block': { display: 'flex', width: '100%' },
|
||||
|
||||
@@ -64,6 +70,7 @@ export const button = style({
|
||||
'&.plain': {
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
borderColor: 'transparent',
|
||||
background: 'transparent',
|
||||
},
|
||||
|
||||
'&.primary': {
|
||||
@@ -72,7 +79,7 @@ export const button = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.primary:hover': {
|
||||
'&.primary:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-primary-color)',
|
||||
},
|
||||
@@ -80,7 +87,7 @@ export const button = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.primary.disabled:hover': {
|
||||
'&.primary.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-primary-color)',
|
||||
},
|
||||
|
||||
@@ -90,7 +97,7 @@ export const button = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.error:hover': {
|
||||
'&.error:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-error-color)',
|
||||
},
|
||||
@@ -98,7 +105,7 @@ export const button = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.error.disabled:hover': {
|
||||
'&.error.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-error-color)',
|
||||
},
|
||||
|
||||
@@ -108,7 +115,7 @@ export const button = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.warning:hover': {
|
||||
'&.warning:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-warning-color)',
|
||||
},
|
||||
@@ -116,7 +123,7 @@ export const button = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.warning.disabled:hover': {
|
||||
'&.warning.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-warning-color)',
|
||||
},
|
||||
|
||||
@@ -126,7 +133,7 @@ export const button = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.success:hover': {
|
||||
'&.success:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-success-color)',
|
||||
},
|
||||
@@ -134,7 +141,7 @@ export const button = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.success.disabled:hover': {
|
||||
'&.success.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-success-color)',
|
||||
},
|
||||
|
||||
@@ -144,7 +151,7 @@ export const button = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: 'var(--affine-button-inner-shadow)',
|
||||
},
|
||||
'&.processing:hover': {
|
||||
'&.processing:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-processing-color)',
|
||||
},
|
||||
@@ -152,7 +159,7 @@ export const button = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.processing.disabled:hover': {
|
||||
'&.processing.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-processing-color)',
|
||||
},
|
||||
},
|
||||
@@ -222,18 +229,24 @@ export const iconButton = style({
|
||||
color: 'var(--affine-primary-color)',
|
||||
},
|
||||
|
||||
'&:hover': {
|
||||
'&:not(.without-hover):hover': {
|
||||
background: 'var(--affine-hover-color)',
|
||||
},
|
||||
'&.disabled, &.loading': {
|
||||
'&.disabled': {
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
color: 'var(--affine-disable-color)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&.disabled:hover, &.loading:hover': {
|
||||
background: 'inherit',
|
||||
'&.loading': {
|
||||
cursor: 'default',
|
||||
color: 'var(--affine-disable-color)',
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
'&.disabled:not(.without-hover):hover, &.loading:not(.without-hover):hover':
|
||||
{
|
||||
background: 'inherit',
|
||||
},
|
||||
|
||||
// size
|
||||
'&.large': {
|
||||
@@ -251,6 +264,7 @@ export const iconButton = style({
|
||||
'&.plain': {
|
||||
color: 'var(--affine-icon-color)',
|
||||
borderColor: 'transparent',
|
||||
background: 'transparent',
|
||||
},
|
||||
'&.plain.active': {
|
||||
color: 'var(--affine-primary-color)',
|
||||
@@ -262,7 +276,7 @@ export const iconButton = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
},
|
||||
'&.primary:hover': {
|
||||
'&.primary:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-primary-color)',
|
||||
},
|
||||
@@ -270,7 +284,7 @@ export const iconButton = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.primary.disabled:hover': {
|
||||
'&.primary.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-primary-color)',
|
||||
},
|
||||
|
||||
@@ -280,7 +294,7 @@ export const iconButton = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
},
|
||||
'&.error:hover': {
|
||||
'&.error:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-error-color)',
|
||||
},
|
||||
@@ -288,7 +302,7 @@ export const iconButton = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.error.disabled:hover': {
|
||||
'&.error.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-error-color)',
|
||||
},
|
||||
|
||||
@@ -298,7 +312,7 @@ export const iconButton = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
},
|
||||
'&.warning:hover': {
|
||||
'&.warning:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-warning-color)',
|
||||
},
|
||||
@@ -306,7 +320,7 @@ export const iconButton = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.warning.disabled:hover': {
|
||||
'&.warning.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-warning-color)',
|
||||
},
|
||||
|
||||
@@ -316,7 +330,7 @@ export const iconButton = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
},
|
||||
'&.success:hover': {
|
||||
'&.success:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-success-color)',
|
||||
},
|
||||
@@ -324,7 +338,7 @@ export const iconButton = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.success.disabled:hover': {
|
||||
'&.success.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-success-color)',
|
||||
},
|
||||
|
||||
@@ -334,7 +348,7 @@ export const iconButton = style({
|
||||
borderColor: 'var(--affine-black-10)',
|
||||
boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset',
|
||||
},
|
||||
'&.processing:hover': {
|
||||
'&.processing:not(.without-hover):hover': {
|
||||
background:
|
||||
'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-processing-color)',
|
||||
},
|
||||
@@ -342,7 +356,7 @@ export const iconButton = style({
|
||||
opacity: '.4',
|
||||
cursor: 'default',
|
||||
},
|
||||
'&.processing.disabled:hover': {
|
||||
'&.processing.disabled:not(.without-hover):hover': {
|
||||
background: 'var(--affine-processing-color)',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,14 +8,14 @@ export const SIZE_CONFIG = {
|
||||
[SIZE_SMALL]: {
|
||||
iconSize: 16,
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
borderRadius: 4,
|
||||
borderRadius: 8,
|
||||
height: 28,
|
||||
padding: 6,
|
||||
padding: 12,
|
||||
},
|
||||
[SIZE_MIDDLE]: {
|
||||
iconSize: 20,
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
borderRadius: 4,
|
||||
borderRadius: 8,
|
||||
height: 32,
|
||||
padding: 12,
|
||||
},
|
||||
@@ -24,7 +24,7 @@ export const SIZE_CONFIG = {
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
height: 38,
|
||||
padding: 24,
|
||||
borderRadius: 4,
|
||||
borderRadius: 8,
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -51,6 +51,7 @@ export const getButtonColors = (
|
||||
color: 'var(--affine-white)',
|
||||
borderColor: 'var(--affine-primary-color)',
|
||||
backgroundBlendMode: 'overlay',
|
||||
opacity: disabled ? '.4' : '1',
|
||||
'.affine-button-icon': {
|
||||
color: 'var(--affine-white)',
|
||||
},
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { createVar, style } from '@vanilla-extract/css';
|
||||
|
||||
export const heightVar = createVar('heightVar');
|
||||
export const widthVar = createVar('widthVar');
|
||||
|
||||
export const inputStyle = style({
|
||||
vars: {
|
||||
[heightVar]: 'unset',
|
||||
[widthVar]: '100%',
|
||||
},
|
||||
width: widthVar,
|
||||
height: heightVar,
|
||||
lineHeight: '22px',
|
||||
padding: '8px 12px',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
border: '1px solid',
|
||||
borderColor: 'var(--affine-border-color)', // TODO: check out disableColor,
|
||||
backgroundColor: 'var(--affine-white)',
|
||||
borderRadius: '10px',
|
||||
selectors: {
|
||||
'&[data-no-border="true"]': {
|
||||
border: 'unset',
|
||||
},
|
||||
'&[data-disabled="true"]': {
|
||||
color: 'var(--affine-text-disable-color)',
|
||||
},
|
||||
'&::placeholder': {
|
||||
color: 'var(--affine-placeholder-color)',
|
||||
},
|
||||
'&:focus': {
|
||||
borderColor: 'var(--affine-primary-color)',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,84 +1,120 @@
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import { useCompositionInput } from 'foxact/use-composition-input';
|
||||
import type {
|
||||
ChangeEvent,
|
||||
CSSProperties,
|
||||
FocusEvent,
|
||||
FocusEventHandler,
|
||||
ForwardedRef,
|
||||
HTMLAttributes,
|
||||
InputHTMLAttributes,
|
||||
KeyboardEvent,
|
||||
KeyboardEventHandler,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import { forwardRef, useCallback } from 'react';
|
||||
import { forwardRef, useCallback, useState } from 'react';
|
||||
|
||||
import { heightVar, inputStyle, widthVar } from './index.css';
|
||||
import { input, inputWrapper, widthVar } from './style.css';
|
||||
|
||||
type InputProps = {
|
||||
// We don't have `value` props here,
|
||||
// see https://foxact.skk.moe/use-composition-input
|
||||
defaultValue?: string | undefined;
|
||||
placeholder?: string;
|
||||
export type InputProps = {
|
||||
disabled?: boolean;
|
||||
width?: CSSProperties['width'];
|
||||
height?: CSSProperties['height'];
|
||||
maxLength?: number;
|
||||
minLength?: number;
|
||||
onChange?: (value: string) => void;
|
||||
onBlur?: FocusEventHandler<HTMLInputElement>;
|
||||
onKeyDown?: KeyboardEventHandler<HTMLInputElement>;
|
||||
noBorder?: boolean;
|
||||
} & Omit<
|
||||
HTMLAttributes<HTMLInputElement>,
|
||||
| 'onChange'
|
||||
| 'value'
|
||||
| 'defaultValue'
|
||||
| 'onCompositionStart'
|
||||
| 'onCompositionEnd'
|
||||
>;
|
||||
status?: 'error' | 'success' | 'warning' | 'default';
|
||||
size?: 'default' | 'large' | 'extraLarge';
|
||||
preFix?: ReactNode;
|
||||
endFix?: ReactNode;
|
||||
type?: HTMLInputElement['type'];
|
||||
inputStyle?: CSSProperties;
|
||||
onEnter?: () => void;
|
||||
} & Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'size'>;
|
||||
|
||||
export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
||||
{
|
||||
disabled,
|
||||
defaultValue,
|
||||
placeholder,
|
||||
maxLength,
|
||||
minLength,
|
||||
height,
|
||||
width,
|
||||
onChange,
|
||||
onChange: propsOnChange,
|
||||
noBorder = false,
|
||||
className,
|
||||
status = 'default',
|
||||
style = {},
|
||||
inputStyle = {},
|
||||
size = 'default',
|
||||
onFocus,
|
||||
onBlur,
|
||||
preFix,
|
||||
endFix,
|
||||
onEnter,
|
||||
onKeyDown,
|
||||
...otherProps
|
||||
}: InputProps,
|
||||
ref: ForwardedRef<HTMLInputElement>
|
||||
) {
|
||||
const inputProps = useCompositionInput(
|
||||
useCallback(
|
||||
(value: string) => {
|
||||
onChange && onChange(value);
|
||||
},
|
||||
[onChange]
|
||||
)
|
||||
);
|
||||
const [isFocus, setIsFocus] = useState(false);
|
||||
|
||||
return (
|
||||
<input
|
||||
className={clsx(inputStyle, className)}
|
||||
style={assignInlineVars({
|
||||
[widthVar]: width ? `${width}px` : '100%',
|
||||
[heightVar]: height ? `${height}px` : 'unset',
|
||||
<div
|
||||
className={clsx(inputWrapper, className, {
|
||||
// status
|
||||
disabled: disabled,
|
||||
'no-border': noBorder,
|
||||
focus: isFocus,
|
||||
// color
|
||||
error: status === 'error',
|
||||
success: status === 'success',
|
||||
warning: status === 'warning',
|
||||
default: status === 'default',
|
||||
// size
|
||||
large: size === 'large',
|
||||
'extra-large': size === 'extraLarge',
|
||||
})}
|
||||
data-no-border={noBorder}
|
||||
data-disabled={disabled}
|
||||
ref={ref}
|
||||
defaultValue={defaultValue}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
width={width}
|
||||
maxLength={maxLength}
|
||||
minLength={minLength}
|
||||
height={height}
|
||||
{...otherProps}
|
||||
{...inputProps}
|
||||
/>
|
||||
style={{
|
||||
...assignInlineVars({
|
||||
[widthVar]: width ? `${width}px` : '100%',
|
||||
}),
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
{preFix}
|
||||
<input
|
||||
className={clsx(input)}
|
||||
ref={ref}
|
||||
disabled={disabled}
|
||||
style={inputStyle}
|
||||
onFocus={useCallback(
|
||||
(e: FocusEvent<HTMLInputElement>) => {
|
||||
setIsFocus(true);
|
||||
onFocus?.(e);
|
||||
},
|
||||
[onFocus]
|
||||
)}
|
||||
onBlur={useCallback(
|
||||
(e: FocusEvent<HTMLInputElement>) => {
|
||||
setIsFocus(false);
|
||||
onBlur?.(e);
|
||||
},
|
||||
[onBlur]
|
||||
)}
|
||||
onChange={useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
propsOnChange?.(e.target.value);
|
||||
},
|
||||
[propsOnChange]
|
||||
)}
|
||||
onKeyDown={useCallback(
|
||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
onEnter?.();
|
||||
}
|
||||
onKeyDown?.(e);
|
||||
},
|
||||
[onKeyDown, onEnter]
|
||||
)}
|
||||
{...otherProps}
|
||||
/>
|
||||
{endFix}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { createVar, style } from '@vanilla-extract/css';
|
||||
|
||||
export const widthVar = createVar('widthVar');
|
||||
|
||||
export const inputWrapper = style({
|
||||
vars: {
|
||||
[widthVar]: '100%',
|
||||
},
|
||||
width: widthVar,
|
||||
height: 28,
|
||||
lineHeight: '22px',
|
||||
padding: '0 10px',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
border: '1px solid',
|
||||
backgroundColor: 'var(--affine-white)',
|
||||
borderRadius: 8,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
|
||||
selectors: {
|
||||
'&.no-border': {
|
||||
border: 'unset',
|
||||
},
|
||||
// size
|
||||
'&.large': {
|
||||
height: 32,
|
||||
},
|
||||
'&.extra-large': {
|
||||
height: 40,
|
||||
fontWeight: 600,
|
||||
},
|
||||
// color
|
||||
'&.disabled': {
|
||||
background: 'var(--affine-hover-color)',
|
||||
},
|
||||
'&.error': {
|
||||
borderColor: 'var(--affine-error-color)',
|
||||
},
|
||||
'&.success': {
|
||||
borderColor: 'var(--affine-success-color)',
|
||||
},
|
||||
'&.warning': {
|
||||
borderColor: 'var(--affine-warning-color)',
|
||||
},
|
||||
'&.default': {
|
||||
borderColor: 'var(--affine-border-color)',
|
||||
},
|
||||
'&.default.focus': {
|
||||
borderColor: 'var(--affine-primary-color)',
|
||||
boxShadow: '0px 0px 0px 2px rgba(30, 150, 235, 0.30);',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const input = style({
|
||||
height: '100%',
|
||||
width: '0',
|
||||
flex: 1,
|
||||
boxSizing: 'border-box',
|
||||
// prevent default style
|
||||
WebkitAppearance: 'none',
|
||||
WebkitTapHighlightColor: 'transparent',
|
||||
outline: 'none',
|
||||
border: 'none',
|
||||
|
||||
selectors: {
|
||||
'&::placeholder': {
|
||||
color: 'var(--affine-placeholder-color)',
|
||||
},
|
||||
'&:disabled': {
|
||||
color: 'var(--affine-text-disable-color)',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -11,20 +11,30 @@ import {
|
||||
export type IconMenuProps = PropsWithChildren<{
|
||||
icon?: ReactElement;
|
||||
endIcon?: ReactElement;
|
||||
iconSize?: [number, number];
|
||||
iconSize?: number;
|
||||
disabled?: boolean;
|
||||
active?: boolean;
|
||||
disableHover?: boolean;
|
||||
gap?: string;
|
||||
fontSize?: string;
|
||||
}> &
|
||||
HTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
export const MenuItem = forwardRef<HTMLButtonElement, IconMenuProps>(
|
||||
({ endIcon, icon, children, ...props }, ref) => {
|
||||
({ endIcon, icon, children, gap, fontSize, iconSize, ...props }, ref) => {
|
||||
return (
|
||||
<StyledMenuItem ref={ref} {...props}>
|
||||
{icon && <StyledStartIconWrapper>{icon}</StyledStartIconWrapper>}
|
||||
<StyledContent>{children}</StyledContent>
|
||||
{endIcon && <StyledEndIconWrapper>{endIcon}</StyledEndIconWrapper>}
|
||||
{icon && (
|
||||
<StyledStartIconWrapper iconSize={iconSize} gap={gap}>
|
||||
{icon}
|
||||
</StyledStartIconWrapper>
|
||||
)}
|
||||
<StyledContent fontSize={fontSize}>{children}</StyledContent>
|
||||
{endIcon && (
|
||||
<StyledEndIconWrapper iconSize={iconSize} gap={gap}>
|
||||
{endIcon}
|
||||
</StyledEndIconWrapper>
|
||||
)}
|
||||
</StyledMenuItem>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,28 +23,36 @@ export const StyledMenuWrapper = styled(StyledPopperContainer, {
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledStartIconWrapper = styled('div')(() => {
|
||||
export const StyledStartIconWrapper = styled('div')<{
|
||||
gap?: CSSProperties['gap'];
|
||||
iconSize?: CSSProperties['fontSize'];
|
||||
}>(({ gap, iconSize }) => {
|
||||
return {
|
||||
display: 'flex',
|
||||
marginRight: '12px',
|
||||
fontSize: '20px',
|
||||
marginRight: gap ? gap : '12px',
|
||||
fontSize: iconSize ? iconSize : '20px',
|
||||
color: 'var(--affine-icon-color)',
|
||||
};
|
||||
});
|
||||
export const StyledEndIconWrapper = styled('div')(() => {
|
||||
export const StyledEndIconWrapper = styled('div')<{
|
||||
gap?: CSSProperties['gap'];
|
||||
iconSize?: CSSProperties['fontSize'];
|
||||
}>(({ gap, iconSize }) => {
|
||||
return {
|
||||
display: 'flex',
|
||||
marginLeft: '12px',
|
||||
fontSize: '20px',
|
||||
marginLeft: gap ? gap : '12px',
|
||||
fontSize: iconSize ? iconSize : '20px',
|
||||
color: 'var(--affine-icon-color)',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledContent = styled('div')(() => {
|
||||
export const StyledContent = styled('div')<{
|
||||
fontSize?: CSSProperties['fontSize'];
|
||||
}>(({ fontSize }) => {
|
||||
return {
|
||||
textAlign: 'left',
|
||||
flexGrow: 1,
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
fontSize: fontSize ? fontSize : 'var(--affine-font-base)',
|
||||
...textEllipsis(1),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Button, type ButtonType } from '@toeverything/components/button';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { Modal, type ModalProps } from './modal';
|
||||
import { ModalCloseButton } from './modal-close-button';
|
||||
import { ModalWrapper } from './modal-wrapper';
|
||||
import {
|
||||
StyledModalContent,
|
||||
StyledModalFooter,
|
||||
StyledModalTitle,
|
||||
} from './styles';
|
||||
|
||||
export interface BaseModalProps
|
||||
extends Omit<ModalProps, 'onClose' | 'children'> {
|
||||
title?: string;
|
||||
content?: string;
|
||||
confirmText?: string;
|
||||
confirmType?: ButtonType;
|
||||
onClose: () => void;
|
||||
onCancel: () => void;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
export const ConfirmModal = ({
|
||||
open,
|
||||
onClose,
|
||||
confirmText,
|
||||
confirmType = 'primary',
|
||||
onCancel,
|
||||
onConfirm,
|
||||
title,
|
||||
content,
|
||||
}: BaseModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
wrapperPosition={['center', 'center']}
|
||||
data-testid="auth-modal"
|
||||
>
|
||||
<ModalWrapper
|
||||
width={480}
|
||||
minHeight={194}
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'var(--affine-white)',
|
||||
boxShadow: 'var(--affine-popover-shadow)',
|
||||
padding: '20px 24px 0',
|
||||
}}
|
||||
>
|
||||
<ModalCloseButton top={22} right={20} onClick={handleClose} />
|
||||
<StyledModalTitle>{title}</StyledModalTitle>
|
||||
<StyledModalContent>{content}</StyledModalContent>
|
||||
<StyledModalFooter>
|
||||
<Button onClick={onCancel} style={{ marginRight: 20 }}>
|
||||
{t['Cancel']()}
|
||||
</Button>
|
||||
<Button type={confirmType} onClick={onConfirm}>
|
||||
{confirmText || t['Confirm']()}
|
||||
</Button>
|
||||
</StyledModalFooter>
|
||||
</ModalWrapper>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import Modal from './modal';
|
||||
|
||||
export * from './confirm-modal';
|
||||
export * from './modal';
|
||||
export * from './modal-close-button';
|
||||
export * from './modal-wrapper';
|
||||
|
||||
@@ -37,5 +37,3 @@ export const ModalCloseButton = ({
|
||||
</IconButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalCloseButton;
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Modal as ModalUnstyled } from '@mui/base/Modal';
|
||||
import type { CSSProperties } from 'react';
|
||||
|
||||
import { styled } from '../../styles';
|
||||
import { Wrapper } from '../layout';
|
||||
|
||||
export const StyledBackdrop = styled('div')(() => {
|
||||
return {
|
||||
@@ -42,10 +41,25 @@ export const StyledModal = styled(ModalUnstyled, {
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledWrapper = styled(Wrapper)(() => {
|
||||
export const StyledModalFooter = styled('div')(() => {
|
||||
return {
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
overflow: 'hidden',
|
||||
marginTop: 40,
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
};
|
||||
});
|
||||
|
||||
export const StyledModalTitle = styled('div')(() => {
|
||||
return {
|
||||
fontWeight: 600,
|
||||
fontSize: 'var(--affine-font-h-6)',
|
||||
};
|
||||
});
|
||||
export const StyledModalContent = styled('div')(() => {
|
||||
return {
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
lineHeight: '24px',
|
||||
marginTop: '12px',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ export type ScrollableContainerProps = {
|
||||
inTableView?: boolean;
|
||||
className?: string;
|
||||
viewPortClassName?: string;
|
||||
styles?: React.CSSProperties;
|
||||
};
|
||||
|
||||
export const ScrollableContainer = ({
|
||||
@@ -17,11 +18,13 @@ export const ScrollableContainer = ({
|
||||
showScrollTopBorder = false,
|
||||
inTableView = false,
|
||||
className,
|
||||
styles: _styles,
|
||||
viewPortClassName,
|
||||
}: PropsWithChildren<ScrollableContainerProps>) => {
|
||||
const [hasScrollTop, ref] = useHasScrollTop();
|
||||
return (
|
||||
<ScrollArea.Root
|
||||
style={_styles}
|
||||
className={clsx(styles.scrollableContainerRoot, className)}
|
||||
>
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user