Files
AFFiNE-Mirror/packages/frontend/component/src/ui/input/input.tsx
JimmFly f4a52c031f feat(core): support sidebar page item dnd (#5132)
Added the ability to drag page items from the `all pages` view to the sidebar, including `favourites,` `collection` and `trash`. Page items in `favourites` and `collection` can also be dragged between each other. However, linked subpages cannot be dragged.

Additionally, an operation menu and ‘add’ button have been provided for the sidebar’s page items, enabling the addition of a subpage, renaming, deletion or removal from the sidebar.

On the code front, the `useSidebarDrag` hooks have been implemented for consolidating drag events. The functions `getDragItemId` and `getDropItemId` have been created, and they accept type and ID to obtain itemId.

https://github.com/toeverything/AFFiNE/assets/102217452/d06bac18-3c28-41c9-a7d4-72de955d7b11
2023-12-12 16:04:58 +00:00

131 lines
3.2 KiB
TypeScript

import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import type {
ChangeEvent,
CSSProperties,
FocusEvent,
FocusEventHandler,
ForwardedRef,
InputHTMLAttributes,
KeyboardEvent,
KeyboardEventHandler,
ReactNode,
} from 'react';
import { forwardRef, useCallback, useState } from 'react';
import { input, inputWrapper, widthVar } from './style.css';
export type InputProps = {
disabled?: boolean;
width?: CSSProperties['width'];
onChange?: (value: string) => void;
onBlur?: FocusEventHandler<HTMLInputElement>;
onKeyDown?: KeyboardEventHandler<HTMLInputElement>;
noBorder?: boolean;
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,
width,
onChange: propsOnChange,
noBorder = false,
className,
status = 'default',
style = {},
inputStyle = {},
size = 'default',
onFocus,
onBlur,
preFix,
endFix,
onEnter,
onKeyDown,
autoFocus,
...otherProps
}: InputProps,
ref: ForwardedRef<HTMLInputElement>
) {
const [isFocus, setIsFocus] = useState(false);
const handleAutoFocus = useCallback((ref: HTMLInputElement | null) => {
if (ref) {
window.setTimeout(() => ref.focus(), 0);
}
}, []);
return (
<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',
})}
style={{
...assignInlineVars({
[widthVar]: width ? `${width}px` : '100%',
}),
...style,
}}
>
{preFix}
<input
className={clsx(input, {
large: size === 'large',
'extra-large': size === 'extraLarge',
})}
ref={autoFocus ? handleAutoFocus : 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>
);
});