mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-23 21:38:44 +08:00
fix(core): handle composition event for Input component (#8351)
close AF-1065
This commit is contained in:
@@ -30,11 +30,7 @@ export const AuthInput = ({
|
|||||||
className={clsx(className)}
|
className={clsx(className)}
|
||||||
size="extraLarge"
|
size="extraLarge"
|
||||||
status={error ? 'error' : 'default'}
|
status={error ? 'error' : 'default'}
|
||||||
onKeyDown={e => {
|
onEnter={onEnter}
|
||||||
if (e.key === 'Enter') {
|
|
||||||
onEnter?.();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
/>
|
/>
|
||||||
{error && errorHint && !withoutHint ? (
|
{error && errorHint && !withoutHint ? (
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './input';
|
export * from './input';
|
||||||
|
export * from './row-input';
|
||||||
import { Input } from './input';
|
import { Input } from './input';
|
||||||
export default Input;
|
export default Input;
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import type {
|
import type {
|
||||||
ChangeEvent,
|
|
||||||
CSSProperties,
|
CSSProperties,
|
||||||
ForwardedRef,
|
ForwardedRef,
|
||||||
InputHTMLAttributes,
|
InputHTMLAttributes,
|
||||||
KeyboardEvent,
|
|
||||||
KeyboardEventHandler,
|
KeyboardEventHandler,
|
||||||
ReactNode,
|
ReactNode,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { forwardRef, useCallback, useEffect } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
|
||||||
import { useAutoFocus, useAutoSelect } from '../../hooks';
|
import { RowInput } from './row-input';
|
||||||
import { input, inputWrapper } from './style.css';
|
import { input, inputWrapper } from './style.css';
|
||||||
|
|
||||||
export type InputProps = {
|
export type InputProps = {
|
||||||
@@ -50,32 +48,6 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
|||||||
}: InputProps,
|
}: InputProps,
|
||||||
upstreamRef: ForwardedRef<HTMLInputElement>
|
upstreamRef: ForwardedRef<HTMLInputElement>
|
||||||
) {
|
) {
|
||||||
const focusRef = useAutoFocus<HTMLInputElement>(autoFocus);
|
|
||||||
const selectRef = useAutoSelect<HTMLInputElement>(autoSelect);
|
|
||||||
|
|
||||||
const inputRef = (el: HTMLInputElement | null) => {
|
|
||||||
focusRef.current = el;
|
|
||||||
selectRef.current = el;
|
|
||||||
if (upstreamRef) {
|
|
||||||
if (typeof upstreamRef === 'function') {
|
|
||||||
upstreamRef(el);
|
|
||||||
} else {
|
|
||||||
upstreamRef.current = el;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// use native blur event to get event after unmount
|
|
||||||
// don't use useLayoutEffect here, because the cleanup function will be called before unmount
|
|
||||||
useEffect(() => {
|
|
||||||
if (!onBlur) return;
|
|
||||||
selectRef.current?.addEventListener('blur', onBlur as any);
|
|
||||||
return () => {
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
selectRef.current?.removeEventListener('blur', onBlur as any);
|
|
||||||
};
|
|
||||||
}, [onBlur, selectRef]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(inputWrapper, className, {
|
className={clsx(inputWrapper, className, {
|
||||||
@@ -96,29 +68,20 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{preFix}
|
{preFix}
|
||||||
<input
|
<RowInput
|
||||||
className={clsx(input, {
|
className={clsx(input, {
|
||||||
large: size === 'large',
|
large: size === 'large',
|
||||||
'extra-large': size === 'extraLarge',
|
'extra-large': size === 'extraLarge',
|
||||||
})}
|
})}
|
||||||
ref={inputRef}
|
ref={upstreamRef}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
style={inputStyle}
|
style={inputStyle}
|
||||||
onChange={useCallback(
|
onChange={propsOnChange}
|
||||||
(e: ChangeEvent<HTMLInputElement>) => {
|
onEnter={onEnter}
|
||||||
propsOnChange?.(e.target.value);
|
onKeyDown={onKeyDown}
|
||||||
},
|
onBlur={onBlur}
|
||||||
[propsOnChange]
|
autoFocus={autoFocus}
|
||||||
)}
|
autoSelect={autoSelect}
|
||||||
onKeyDown={useCallback(
|
|
||||||
(e: KeyboardEvent<HTMLInputElement>) => {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
onEnter?.();
|
|
||||||
}
|
|
||||||
onKeyDown?.(e);
|
|
||||||
},
|
|
||||||
[onKeyDown, onEnter]
|
|
||||||
)}
|
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
{endFix}
|
{endFix}
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import type {
|
||||||
|
ChangeEvent,
|
||||||
|
CompositionEventHandler,
|
||||||
|
CSSProperties,
|
||||||
|
ForwardedRef,
|
||||||
|
InputHTMLAttributes,
|
||||||
|
KeyboardEvent,
|
||||||
|
KeyboardEventHandler,
|
||||||
|
} from 'react';
|
||||||
|
import { forwardRef, useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import { useAutoFocus, useAutoSelect } from '../../hooks';
|
||||||
|
|
||||||
|
export type RowInputProps = {
|
||||||
|
disabled?: boolean;
|
||||||
|
onChange?: (value: string) => void;
|
||||||
|
onBlur?: (ev: FocusEvent & { currentTarget: HTMLInputElement }) => void;
|
||||||
|
onKeyDown?: KeyboardEventHandler<HTMLInputElement>;
|
||||||
|
autoSelect?: boolean;
|
||||||
|
type?: HTMLInputElement['type'];
|
||||||
|
style?: CSSProperties;
|
||||||
|
onEnter?: () => void;
|
||||||
|
} & Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'size' | 'onBlur'>;
|
||||||
|
|
||||||
|
// RowInput component that is used in the selector layout for search input
|
||||||
|
// handles composition events and enter key press
|
||||||
|
export const RowInput = forwardRef<HTMLInputElement, RowInputProps>(
|
||||||
|
function RowInput(
|
||||||
|
{
|
||||||
|
disabled,
|
||||||
|
onChange: propsOnChange,
|
||||||
|
className,
|
||||||
|
style = {},
|
||||||
|
onEnter,
|
||||||
|
onKeyDown,
|
||||||
|
onBlur,
|
||||||
|
autoFocus,
|
||||||
|
autoSelect,
|
||||||
|
...otherProps
|
||||||
|
}: RowInputProps,
|
||||||
|
upstreamRef: ForwardedRef<HTMLInputElement>
|
||||||
|
) {
|
||||||
|
const [composing, setComposing] = useState(false);
|
||||||
|
const focusRef = useAutoFocus<HTMLInputElement>(autoFocus);
|
||||||
|
const selectRef = useAutoSelect<HTMLInputElement>(autoSelect);
|
||||||
|
|
||||||
|
const inputRef = (el: HTMLInputElement | null) => {
|
||||||
|
focusRef.current = el;
|
||||||
|
selectRef.current = el;
|
||||||
|
if (upstreamRef) {
|
||||||
|
if (typeof upstreamRef === 'function') {
|
||||||
|
upstreamRef(el);
|
||||||
|
} else {
|
||||||
|
upstreamRef.current = el;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// use native blur event to get event after unmount
|
||||||
|
// don't use useLayoutEffect here, because the cleanup function will be called before unmount
|
||||||
|
useEffect(() => {
|
||||||
|
if (!onBlur) return;
|
||||||
|
selectRef.current?.addEventListener('blur', onBlur as any);
|
||||||
|
return () => {
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
selectRef.current?.removeEventListener('blur', onBlur as any);
|
||||||
|
};
|
||||||
|
}, [onBlur, selectRef]);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
propsOnChange?.(e.target.value);
|
||||||
|
},
|
||||||
|
[propsOnChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleKeyDown = useCallback(
|
||||||
|
(e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
onKeyDown?.(e);
|
||||||
|
if (e.key !== 'Enter' || composing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onEnter?.();
|
||||||
|
},
|
||||||
|
[onKeyDown, composing, onEnter]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleCompositionStart: CompositionEventHandler<HTMLInputElement> =
|
||||||
|
useCallback(() => {
|
||||||
|
setComposing(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleCompositionEnd: CompositionEventHandler<HTMLInputElement> =
|
||||||
|
useCallback(() => {
|
||||||
|
setComposing(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
className={className}
|
||||||
|
ref={inputRef}
|
||||||
|
disabled={disabled}
|
||||||
|
style={style}
|
||||||
|
onChange={handleChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
onCompositionStart={handleCompositionStart}
|
||||||
|
onCompositionEnd={handleCompositionEnd}
|
||||||
|
{...otherProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
+19
-15
@@ -1,5 +1,11 @@
|
|||||||
import type { MenuProps } from '@affine/component';
|
import type { MenuProps } from '@affine/component';
|
||||||
import { IconButton, Input, Menu, Scrollable } from '@affine/component';
|
import {
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
Menu,
|
||||||
|
RowInput,
|
||||||
|
Scrollable,
|
||||||
|
} from '@affine/component';
|
||||||
import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper';
|
import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper';
|
||||||
import { WorkspaceLegacyProperties } from '@affine/core/modules/properties';
|
import { WorkspaceLegacyProperties } from '@affine/core/modules/properties';
|
||||||
import type { Tag } from '@affine/core/modules/tag';
|
import type { Tag } from '@affine/core/modules/tag';
|
||||||
@@ -239,12 +245,9 @@ export const TagsEditor = ({ pageId, readonly }: TagsEditorProps) => {
|
|||||||
[setOpen, setSelectedTagIds]
|
[setOpen, setSelectedTagIds]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback((value: string) => {
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
setInputValue(value);
|
||||||
setInputValue(e.target.value);
|
}, []);
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onToggleTag = useCallback(
|
const onToggleTag = useCallback(
|
||||||
(id: string) => {
|
(id: string) => {
|
||||||
@@ -297,14 +300,15 @@ export const TagsEditor = ({ pageId, readonly }: TagsEditorProps) => {
|
|||||||
},
|
},
|
||||||
[onCreateTag, onToggleTag, focusInput, tagIds.length]
|
[onCreateTag, onToggleTag, focusInput, tagIds.length]
|
||||||
);
|
);
|
||||||
|
const onEnter = useCallback(() => {
|
||||||
|
if (safeFocusedIndex >= 0) {
|
||||||
|
onSelectTagOption(tagOptions[safeFocusedIndex]);
|
||||||
|
}
|
||||||
|
}, [onSelectTagOption, safeFocusedIndex, tagOptions]);
|
||||||
|
|
||||||
const onInputKeyDown = useCallback(
|
const onInputKeyDown = useCallback(
|
||||||
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Backspace' && inputValue === '' && tagIds.length) {
|
||||||
if (safeFocusedIndex >= 0) {
|
|
||||||
onSelectTagOption(tagOptions[safeFocusedIndex]);
|
|
||||||
}
|
|
||||||
} else if (e.key === 'Backspace' && inputValue === '' && tagIds.length) {
|
|
||||||
const tagToRemove =
|
const tagToRemove =
|
||||||
safeInlineFocusedIndex < 0 || safeInlineFocusedIndex >= tagIds.length
|
safeInlineFocusedIndex < 0 || safeInlineFocusedIndex >= tagIds.length
|
||||||
? tagIds.length - 1
|
? tagIds.length - 1
|
||||||
@@ -341,7 +345,6 @@ export const TagsEditor = ({ pageId, readonly }: TagsEditorProps) => {
|
|||||||
inputValue,
|
inputValue,
|
||||||
tagIds,
|
tagIds,
|
||||||
safeFocusedIndex,
|
safeFocusedIndex,
|
||||||
onSelectTagOption,
|
|
||||||
tagOptions,
|
tagOptions,
|
||||||
safeInlineFocusedIndex,
|
safeInlineFocusedIndex,
|
||||||
tags,
|
tags,
|
||||||
@@ -358,11 +361,12 @@ export const TagsEditor = ({ pageId, readonly }: TagsEditorProps) => {
|
|||||||
focusedIndex={safeInlineFocusedIndex}
|
focusedIndex={safeInlineFocusedIndex}
|
||||||
onRemove={focusInput}
|
onRemove={focusInput}
|
||||||
>
|
>
|
||||||
<input
|
<RowInput
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
onKeyDown={onInputKeyDown}
|
onKeyDown={onInputKeyDown}
|
||||||
|
onEnter={onEnter}
|
||||||
autoFocus
|
autoFocus
|
||||||
className={styles.searchInput}
|
className={styles.searchInput}
|
||||||
placeholder="Type here ..."
|
placeholder="Type here ..."
|
||||||
@@ -380,7 +384,7 @@ export const TagsEditor = ({ pageId, readonly }: TagsEditorProps) => {
|
|||||||
>
|
>
|
||||||
{tagOptions.map((tag, idx) => {
|
{tagOptions.map((tag, idx) => {
|
||||||
const commonProps = {
|
const commonProps = {
|
||||||
focused: safeFocusedIndex === idx,
|
...(safeFocusedIndex === idx ? { focused: 'true' } : {}),
|
||||||
onClick: () => onSelectTagOption(tag),
|
onClick: () => onSelectTagOption(tag),
|
||||||
onMouseEnter: () => setFocusedIndex(idx),
|
onMouseEnter: () => setFocusedIndex(idx),
|
||||||
['data-testid']: 'tag-selector-item',
|
['data-testid']: 'tag-selector-item',
|
||||||
|
|||||||
+4
-4
@@ -6,6 +6,7 @@ import {
|
|||||||
MenuTrigger,
|
MenuTrigger,
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
type RadioItem,
|
type RadioItem,
|
||||||
|
RowInput,
|
||||||
Scrollable,
|
Scrollable,
|
||||||
Switch,
|
Switch,
|
||||||
useConfirmModal,
|
useConfirmModal,
|
||||||
@@ -33,7 +34,6 @@ import {
|
|||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {
|
import {
|
||||||
type ChangeEvent,
|
|
||||||
forwardRef,
|
forwardRef,
|
||||||
type HTMLAttributes,
|
type HTMLAttributes,
|
||||||
type PropsWithChildren,
|
type PropsWithChildren,
|
||||||
@@ -171,8 +171,8 @@ const FontMenuItems = ({ onSelect }: { onSelect: (font: string) => void }) => {
|
|||||||
const searchText = useLiveData(systemFontFamily.searchText$);
|
const searchText = useLiveData(systemFontFamily.searchText$);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(
|
||||||
(e: ChangeEvent<HTMLInputElement>) => {
|
(value: string) => {
|
||||||
systemFontFamily.search(e.target.value);
|
systemFontFamily.search(value);
|
||||||
},
|
},
|
||||||
[systemFontFamily]
|
[systemFontFamily]
|
||||||
);
|
);
|
||||||
@@ -187,7 +187,7 @@ const FontMenuItems = ({ onSelect }: { onSelect: (font: string) => void }) => {
|
|||||||
<div>
|
<div>
|
||||||
<div className={styles.InputContainer}>
|
<div className={styles.InputContainer}>
|
||||||
<SearchIcon className={styles.searchIcon} />
|
<SearchIcon className={styles.searchIcon} />
|
||||||
<input
|
<RowInput
|
||||||
value={searchText ?? ''}
|
value={searchText ?? ''}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
onKeyDown={onInputKeyDown}
|
onKeyDown={onInputKeyDown}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Divider,
|
Divider,
|
||||||
Menu,
|
Menu,
|
||||||
|
RowInput,
|
||||||
Scrollable,
|
Scrollable,
|
||||||
useConfirmModal,
|
useConfirmModal,
|
||||||
} from '@affine/component';
|
} from '@affine/component';
|
||||||
@@ -285,12 +286,9 @@ export const SwitchTag = ({ onClick }: SwitchTagProps) => {
|
|||||||
inputValue ? tagList.filterTagsByName$(inputValue) : tagList.tags$
|
inputValue ? tagList.filterTagsByName$(inputValue) : tagList.tags$
|
||||||
);
|
);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback((value: string) => {
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
setInputValue(value);
|
||||||
setInputValue(e.target.value);
|
}, []);
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
setInputValue('');
|
setInputValue('');
|
||||||
@@ -301,7 +299,7 @@ export const SwitchTag = ({ onClick }: SwitchTagProps) => {
|
|||||||
<div className={styles.tagsEditorRoot}>
|
<div className={styles.tagsEditorRoot}>
|
||||||
<div className={styles.tagsEditorSelectedTags}>
|
<div className={styles.tagsEditorSelectedTags}>
|
||||||
<SearchIcon className={styles.searchIcon} />
|
<SearchIcon className={styles.searchIcon} />
|
||||||
<input
|
<RowInput
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button } from '@affine/component';
|
import { Button, RowInput } from '@affine/component';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { type PropsWithChildren, type ReactNode, useCallback } from 'react';
|
import { type PropsWithChildren, type ReactNode, useCallback } from 'react';
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ export const SelectorLayout = ({
|
|||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
const onSearchChange = useCallback(
|
const onSearchChange = useCallback(
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
(value: string) => {
|
||||||
onSearch?.(e.target.value);
|
onSearch?.(value);
|
||||||
},
|
},
|
||||||
[onSearch]
|
[onSearch]
|
||||||
);
|
);
|
||||||
@@ -46,7 +46,7 @@ export const SelectorLayout = ({
|
|||||||
return (
|
return (
|
||||||
<div className={styles.root}>
|
<div className={styles.root}>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<input
|
<RowInput
|
||||||
className={styles.search}
|
className={styles.search}
|
||||||
placeholder={searchPlaceholder}
|
placeholder={searchPlaceholder}
|
||||||
onChange={onSearchChange}
|
onChange={onSearchChange}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
WorkspacesService,
|
WorkspacesService,
|
||||||
} from '@toeverything/infra';
|
} from '@toeverything/infra';
|
||||||
import { useSetAtom } from 'jotai';
|
import { useSetAtom } from 'jotai';
|
||||||
import type { KeyboardEvent } from 'react';
|
|
||||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
import { AuthService } from '../../../modules/cloud';
|
import { AuthService } from '../../../modules/cloud';
|
||||||
@@ -76,14 +75,11 @@ const NameWorkspaceContent = ({
|
|||||||
);
|
);
|
||||||
}, [enable, onConfirmName, workspaceName]);
|
}, [enable, onConfirmName, workspaceName]);
|
||||||
|
|
||||||
const handleKeyDown = useCallback(
|
const onEnter = useCallback(() => {
|
||||||
(event: KeyboardEvent<HTMLInputElement>) => {
|
if (workspaceName) {
|
||||||
if (event.key === 'Enter' && workspaceName) {
|
handleCreateWorkspace();
|
||||||
handleCreateWorkspace();
|
}
|
||||||
}
|
}, [handleCreateWorkspace, workspaceName]);
|
||||||
},
|
|
||||||
[handleCreateWorkspace, workspaceName]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Currently, when we create a new workspace and upload an avatar at the same time,
|
// Currently, when we create a new workspace and upload an avatar at the same time,
|
||||||
// an error occurs after the creation is successful: get blob 404 not found
|
// an error occurs after the creation is successful: get blob 404 not found
|
||||||
@@ -117,7 +113,7 @@ const NameWorkspaceContent = ({
|
|||||||
<Input
|
<Input
|
||||||
autoFocus
|
autoFocus
|
||||||
data-testid="create-workspace-input"
|
data-testid="create-workspace-input"
|
||||||
onKeyDown={handleKeyDown}
|
onEnter={onEnter}
|
||||||
placeholder={t['com.affine.nameWorkspace.placeholder']()}
|
placeholder={t['com.affine.nameWorkspace.placeholder']()}
|
||||||
maxLength={64}
|
maxLength={64}
|
||||||
minLength={0}
|
minLength={0}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IconButton, observeResize } from '@affine/component';
|
import { IconButton, observeResize, RowInput } from '@affine/component';
|
||||||
import {
|
import {
|
||||||
ArrowDownSmallIcon,
|
ArrowDownSmallIcon,
|
||||||
ArrowUpSmallIcon,
|
ArrowUpSmallIcon,
|
||||||
@@ -10,7 +10,6 @@ import { useLiveData, useService } from '@toeverything/infra';
|
|||||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {
|
import {
|
||||||
type ChangeEventHandler,
|
|
||||||
type CompositionEventHandler,
|
type CompositionEventHandler,
|
||||||
type KeyboardEventHandler,
|
type KeyboardEventHandler,
|
||||||
type SetStateAction,
|
type SetStateAction,
|
||||||
@@ -102,9 +101,8 @@ export const FindInPageModal = () => {
|
|||||||
toggle(visible);
|
toggle(visible);
|
||||||
}, [visible]);
|
}, [visible]);
|
||||||
|
|
||||||
const handleValueChange: ChangeEventHandler<HTMLInputElement> = useCallback(
|
const handleValueChange = useCallback(
|
||||||
e => {
|
(value: string) => {
|
||||||
const value = e.target.value;
|
|
||||||
setValue(value);
|
setValue(value);
|
||||||
if (!composing) {
|
if (!composing) {
|
||||||
findInPage.findInPage(value);
|
findInPage.findInPage(value);
|
||||||
@@ -227,7 +225,7 @@ export const FindInPageModal = () => {
|
|||||||
>
|
>
|
||||||
<SearchIcon className={styles.searchIcon} />
|
<SearchIcon className={styles.searchIcon} />
|
||||||
<div className={styles.inputMain}>
|
<div className={styles.inputMain}>
|
||||||
<input
|
<RowInput
|
||||||
type="text"
|
type="text"
|
||||||
autoFocus
|
autoFocus
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
Reference in New Issue
Block a user