From 3195ec60a9358d6e94d4735cf16edca3ceb2f0ff Mon Sep 17 00:00:00 2001 From: Wenzhao Hu Date: Sun, 27 Apr 2025 10:41:12 +0800 Subject: [PATCH] feat(design): input support slot usage (#5095) --- .../uni-formula-ui/package.json | 1 - .../src/components/input/Input.stories.tsx | 22 ++++++ .../design/src/components/input/Input.tsx | 69 ++++++++++++++----- .../src/views/dialog/FindReplaceDialog.tsx | 6 +- .../src/views/dialog/SearchInput.tsx | 38 +++++----- pnpm-lock.yaml | 3 - 6 files changed, 98 insertions(+), 41 deletions(-) diff --git a/packages-experimental/uni-formula-ui/package.json b/packages-experimental/uni-formula-ui/package.json index d4f75f9b23..a0f6103547 100644 --- a/packages-experimental/uni-formula-ui/package.json +++ b/packages-experimental/uni-formula-ui/package.json @@ -67,7 +67,6 @@ }, "dependencies": { "@univerjs/core": "workspace:*", - "@univerjs/design": "workspace:*", "@univerjs/docs": "workspace:*", "@univerjs/docs-ui": "workspace:*", "@univerjs/engine-render": "workspace:*", diff --git a/packages/design/src/components/input/Input.stories.tsx b/packages/design/src/components/input/Input.stories.tsx index a3f7002fd6..d8b7e8ccff 100644 --- a/packages/design/src/components/input/Input.stories.tsx +++ b/packages/design/src/components/input/Input.stories.tsx @@ -16,6 +16,7 @@ import type { Meta } from '@storybook/react'; +import { Pager } from '../pager/Pager'; import { Input } from './Input'; const meta: Meta = { @@ -62,3 +63,24 @@ export const InputDisabled = { ); }, }; + +export const Clear = { + render() { + return ( + <> + + + + ); + }, +}; + +export const ClearWithPage = { + render() { + return ( + <> + } /> + + ); + }, +}; diff --git a/packages/design/src/components/input/Input.tsx b/packages/design/src/components/input/Input.tsx index 9c1e12aca8..5ff91b439a 100644 --- a/packages/design/src/components/input/Input.tsx +++ b/packages/design/src/components/input/Input.tsx @@ -17,7 +17,7 @@ import type { VariantProps } from 'class-variance-authority'; import { CloseSingle } from '@univerjs/icons'; import { cva } from 'class-variance-authority'; -import { forwardRef } from 'react'; +import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react'; import { clsx } from '../../helper/clsx'; type InputProps = React.InputHTMLAttributes; @@ -26,7 +26,7 @@ export const inputVariants = cva( ` univer-box-border univer-w-full univer-rounded-md univer-border univer-border-solid univer-border-gray-200 univer-bg-white univer-transition-colors univer-duration-200 - dark:univer-bg-gray-700 dark:univer-border-gray-600 dark:univer-text-white + dark:univer-border-gray-600 dark:univer-bg-gray-700 dark:univer-text-white focus:univer-border-primary-500 focus:univer-outline-none focus:univer-ring-2 focus:univer-ring-primary-500/20 placeholder:univer-text-gray-400 `, @@ -59,6 +59,7 @@ export interface IInputProps extends Pick, onChange?: (value: string) => void; inputClass?: string; inputStyle?: React.CSSProperties; + slot?: React.ReactNode; } export const Input = forwardRef( @@ -77,6 +78,7 @@ export const Input = forwardRef( onChange, onFocus, onBlur, + slot, inputClass, inputStyle, ...props @@ -90,6 +92,30 @@ export const Input = forwardRef( onChange?.(e.target.value); }; + const hasSlotContent = useMemo(() => { + return (allowClear && value && !disabled) || slot; + }, [allowClear, disabled, slot, value]); + + const [paddingRight, setPaddingRight] = useState(0); + const slotRef = useRef(null); + + useEffect(() => { + let observer: MutationObserver | null = null; + if (slot && slotRef.current) { + observer = new MutationObserver(() => { + if (slotRef.current) { + setPaddingRight(slotRef.current.offsetWidth + 4 * 2); + } + }); + + observer.observe(slotRef.current, { childList: true, subtree: true }); + // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect + setPaddingRight(slotRef.current.offsetWidth + 4 * 2); + } + + return () => observer?.disconnect(); + }, [slotRef.current]); + return (
( className={clsx( inputVariants({ size }), disabled && ` - univer-cursor-not-allowed univer-text-gray-400 univer-bg-gray-50 + univer-cursor-not-allowed univer-bg-gray-50 univer-text-gray-400 dark:univer-text-gray-500 `, - allowClear && 'univer-pr-8', + (allowClear && !slot) && 'univer-pr-8', inputClass )} placeholder={placeholder} @@ -120,23 +146,34 @@ export const Input = forwardRef( onChange={handleChange} onFocus={onFocus} onBlur={onBlur} - style={inputStyle} + style={{ ...inputStyle, paddingRight }} {...props} /> - {allowClear && value && !disabled && ( - + {slot} + {allowClear && value && !disabled && ( + + )} +
)} ); diff --git a/packages/find-replace/src/views/dialog/FindReplaceDialog.tsx b/packages/find-replace/src/views/dialog/FindReplaceDialog.tsx index 409f20af12..54da218b3e 100644 --- a/packages/find-replace/src/views/dialog/FindReplaceDialog.tsx +++ b/packages/find-replace/src/views/dialog/FindReplaceDialog.tsx @@ -38,7 +38,7 @@ function useFindInputFocus(findReplaceService: IFindReplaceService, ref: Forward }, []); const selectHasFocus = useCallback(() => { - const allInputs = document.querySelectorAll('.univer-find-replace-dialog-container .univer-select-selection-search-input'); + const allInputs = document.querySelectorAll('[data-u-comp="find-replace-dialog"] [data-u-comp="search-input"]'); return Array.from(allInputs).some((input) => input === document.activeElement); }, []); @@ -95,7 +95,7 @@ export const FindDialog = forwardRef(function FindDialogImpl(_props, ref) { ); }); -export const ReplaceDialog = forwardRef(function ReplaceDIalogImpl(_props, ref) { +export const ReplaceDialog = forwardRef(function ReplaceDialogImpl(_props, ref) { const findReplaceService = useDependency(IFindReplaceService); const localeService = useDependency(LocaleService); const commandService = useDependency(ICommandService); @@ -297,7 +297,7 @@ export function FindReplaceDialog() { }, [setDialogContainerFocus, setDialogInputFocus]); return ( -
+
{!state.replaceRevealed ? : }
); diff --git a/packages/find-replace/src/views/dialog/SearchInput.tsx b/packages/find-replace/src/views/dialog/SearchInput.tsx index c91b5a4ef4..83b881bba2 100644 --- a/packages/find-replace/src/views/dialog/SearchInput.tsx +++ b/packages/find-replace/src/views/dialog/SearchInput.tsx @@ -40,30 +40,32 @@ export function SearchInput(props: ISearchInputProps) { return (
e.stopPropagation()}> onChange?.(value)} + slot={( + { + if (matchesPosition === matchesCount && newIndex === 1) { + findReplaceService.moveToNextMatch(); + } else if (matchesPosition === 1 && newIndex === matchesCount) { + findReplaceService.moveToPreviousMatch(); + } else if (newIndex < matchesPosition) { + findReplaceService.moveToPreviousMatch(); + } else { + findReplaceService.moveToNextMatch(); + } + }} + /> + )} {...rest} /> - - { - if (matchesPosition === matchesCount && newIndex === 1) { - findReplaceService.moveToNextMatch(); - } else if (matchesPosition === 1 && newIndex === matchesCount) { - findReplaceService.moveToPreviousMatch(); - } else if (newIndex < matchesPosition) { - findReplaceService.moveToPreviousMatch(); - } else { - findReplaceService.moveToNextMatch(); - } - }} - />
); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2671297ec2..644a306556 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -804,9 +804,6 @@ importers: '@univerjs/core': specifier: workspace:* version: link:../../packages/core - '@univerjs/design': - specifier: workspace:* - version: link:../../packages/design '@univerjs/docs': specifier: workspace:* version: link:../../packages/docs