diff --git a/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/dark-mode-ci-chromium-linux.png b/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/dark-mode-ci-chromium-linux.png index ce7337ca80..2114ff10bd 100644 Binary files a/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/dark-mode-ci-chromium-linux.png and b/e2e/visual-comparison/sheets/sheets-visual-comparison.spec.ts-snapshots/dark-mode-ci-chromium-linux.png differ diff --git a/package.json b/package.json index d810e695cb..9640a34341 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "eslint": "9.26.0", "eslint-plugin-format": "^1.0.1", "eslint-plugin-header": "^3.1.1", - "eslint-plugin-jsdoc": "^50.6.14", + "eslint-plugin-jsdoc": "^50.6.17", "eslint-plugin-no-barrel-import": "^0.0.2", "eslint-plugin-no-penetrating-import": "^0.0.1", "eslint-plugin-react": "^7.37.5", diff --git a/packages/design/package.json b/packages/design/package.json index 389f7ec691..6bdb800c23 100644 --- a/packages/design/package.json +++ b/packages/design/package.json @@ -70,6 +70,7 @@ "dependencies": { "@radix-ui/react-dialog": "^1.1.13", "@radix-ui/react-dropdown-menu": "^2.1.14", + "@radix-ui/react-hover-card": "^1.1.13", "@radix-ui/react-popover": "^1.1.13", "@radix-ui/react-separator": "^1.1.6", "@radix-ui/react-slot": "^1.2.2", diff --git a/packages/design/src/components/color-picker/ColorInput.tsx b/packages/design/src/components/color-picker/ColorInput.tsx index 218c609bce..f0b5dbc3a7 100644 --- a/packages/design/src/components/color-picker/ColorInput.tsx +++ b/packages/design/src/components/color-picker/ColorInput.tsx @@ -16,7 +16,7 @@ import { ChevronSortSingle } from '@univerjs/icons'; import React, { useEffect, useMemo, useState } from 'react'; -import { Dropdown } from '../dropdown'; +import { Dropdown } from '../dropdown/Dropdown'; import { hexToHsv, hslToHsv, hsvToHex, hsvToHsl, hsvToRgb, rgbToHsv } from './color-conversion'; interface IColorInputProps { diff --git a/packages/design/src/components/dropdown/Dropdown.tsx b/packages/design/src/components/dropdown/Dropdown.tsx index 3d006cc78c..ad58603bf3 100644 --- a/packages/design/src/components/dropdown/Dropdown.tsx +++ b/packages/design/src/components/dropdown/Dropdown.tsx @@ -14,12 +14,11 @@ * limitations under the License. */ -import type { Content } from '@radix-ui/react-popover'; import type { ComponentProps, ReactNode } from 'react'; import { useState } from 'react'; import { PopoverContent, PopoverPrimitive, PopoverTrigger } from './PopoverPrimitive'; -export interface IDropdownProps extends ComponentProps { +export interface IDropdownProps extends ComponentProps { children: ReactNode; overlay: ReactNode; disabled?: boolean; diff --git a/packages/design/src/components/dropdown/PopoverPrimitive.tsx b/packages/design/src/components/dropdown/PopoverPrimitive.tsx index da2f77275d..56a21e0b11 100644 --- a/packages/design/src/components/dropdown/PopoverPrimitive.tsx +++ b/packages/design/src/components/dropdown/PopoverPrimitive.tsx @@ -47,7 +47,7 @@ function PopoverContent({ ` univer-z-[1080] univer-max-h-[var(--radix-popper-available-height)] univer-overflow-y-auto univer-rounded-md univer-bg-white univer-text-gray-900 univer-shadow-md univer-outline-hidden - dark:!univer-bg-gray-900 dark:!univer-text-white + dark:!univer-bg-gray-900 dark:!univer-text-white dark:focus-visible:univer-border-gray-600 data-[side=bottom]:univer-slide-in-from-top-2 data-[side=left]:univer-slide-in-from-right-2 data-[side=right]:univer-slide-in-from-left-2 diff --git a/packages/design/src/components/dropdown/index.ts b/packages/design/src/components/dropdown/index.ts deleted file mode 100644 index 4889b85bb6..0000000000 --- a/packages/design/src/components/dropdown/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright 2023-present DreamNum Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { Dropdown, type IDropdownProps } from './Dropdown'; diff --git a/packages/design/src/components/hover-card/HoverCard.stories.tsx b/packages/design/src/components/hover-card/HoverCard.stories.tsx new file mode 100644 index 0000000000..c6b3b5054d --- /dev/null +++ b/packages/design/src/components/hover-card/HoverCard.stories.tsx @@ -0,0 +1,70 @@ +/** + * Copyright 2023-present DreamNum Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta } from '@storybook/react'; + +import { borderClassName } from '../../helper/class-utilities'; +import { clsx } from '../../helper/clsx'; +import { HoverCard } from './HoverCard'; + +const meta: Meta = { + title: 'Components / HoverCard', + component: HoverCard, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +}; + +export default meta; + +export const Playground = { + render() { + return ( +
+ + Hello Univer + +
Nested Content
+
Nested Content
+
Nested Content
+
Nested Content
+
+ )} + > + Nested Hover Card + + + )} + > + + Click me + + + + ); + }, +}; diff --git a/packages/design/src/components/hover-card/HoverCard.tsx b/packages/design/src/components/hover-card/HoverCard.tsx new file mode 100644 index 0000000000..18e69c04c9 --- /dev/null +++ b/packages/design/src/components/hover-card/HoverCard.tsx @@ -0,0 +1,68 @@ +/** + * Copyright 2023-present DreamNum Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ComponentProps, ReactNode } from 'react'; +import { useState } from 'react'; +import { HoverCardContent, HoverCardPrimitive, HoverCardTrigger } from './HoverCardPrimitive'; + +export interface IHoverCardProps extends ComponentProps { + children: ReactNode; + overlay: ReactNode; + disabled?: boolean; + /** + * Delay in milliseconds before the dropdown opens. + * @default 200 + */ + openDelay?: number; + open?: boolean; + onOpenChange?: (open: boolean) => void; +} + +export function HoverCard(props: IHoverCardProps) { + const { + children, + overlay, + disabled, + openDelay = 200, + open: controlledOpen, + onOpenChange: controlledOnOpenChange, + ...restProps + } = props; + + const [uncontrolledOpen, setUncontrolledOpen] = useState(false); + + const isControlled = controlledOpen !== undefined; + const open = isControlled ? controlledOpen : uncontrolledOpen; + + function handleChangeOpen(newOpen: boolean) { + if (disabled) return; + + if (!isControlled) { + setUncontrolledOpen(newOpen); + } + + controlledOnOpenChange?.(newOpen); + } + + return ( + + {children} + + {overlay} + + + ); +} diff --git a/packages/design/src/components/hover-card/HoverCardPrimitive.tsx b/packages/design/src/components/hover-card/HoverCardPrimitive.tsx new file mode 100644 index 0000000000..e556bd96e5 --- /dev/null +++ b/packages/design/src/components/hover-card/HoverCardPrimitive.tsx @@ -0,0 +1,57 @@ +/** + * Copyright 2023-present DreamNum Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ComponentPropsWithoutRef, ElementRef } from 'react'; +import { Content, Root, Trigger } from '@radix-ui/react-hover-card'; +import { forwardRef } from 'react'; +import { borderClassName } from '../../helper/class-utilities'; +import { clsx } from '../../helper/clsx'; + +const HoverCardPrimitive = Root; + +const HoverCardTrigger = Trigger; + +const HoverCardContent = forwardRef< + ElementRef, + ComponentPropsWithoutRef +>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( + +)); + +HoverCardContent.displayName = Content.displayName; + +export { HoverCardContent, HoverCardPrimitive, HoverCardTrigger }; diff --git a/packages/design/src/index.ts b/packages/design/src/index.ts index e22cf5f23b..391bb7d075 100644 --- a/packages/design/src/index.ts +++ b/packages/design/src/index.ts @@ -26,7 +26,8 @@ export { ColorPicker, type IColorPickerProps } from './components/color-picker/C export { ConfigContext, ConfigProvider, type IConfigProviderProps } from './components/config-provider/ConfigProvider'; export { Confirm, type IConfirmProps } from './components/confirm/Confirm'; export { Dialog, type IDialogProps } from './components/dialog/Dialog'; -export { Dropdown, type IDropdownProps } from './components/dropdown'; +export { Dropdown, type IDropdownProps } from './components/dropdown/Dropdown'; +export { HoverCard, type IHoverCardProps } from './components/hover-card/HoverCard'; export { type IInputProps, Input } from './components/input/Input'; export { type IInputNumberProps, InputNumber } from './components/input-number/InputNumber'; export { type IMessageProps, message, Messager, MessageType, removeMessage } from './components/message/Message'; diff --git a/packages/ui/src/components/font-size/FontSize.tsx b/packages/ui/src/components/font-size/FontSize.tsx index 8636657f93..12714e312d 100644 --- a/packages/ui/src/components/font-size/FontSize.tsx +++ b/packages/ui/src/components/font-size/FontSize.tsx @@ -46,8 +46,8 @@ export const FontSize = (props: IFontSizeProps) => { className={` univer-block univer-h-6 univer-border-none univer-bg-transparent univer-leading-6 [&_input:focus]:!univer-ring-0 - [&_input]:univer-h-6 [&_input]:univer-w-7 [&_input]:univer-border-none [&_input]:univer-bg-transparent - [&_input]:univer-p-0 [&_input]:univer-text-sm + [&_input]:univer-h-6 [&_input]:univer-w-7 [&_input]:univer-border-none + [&_input]:!univer-bg-transparent [&_input]:univer-p-0 [&_input]:univer-text-sm `} value={_value} controls={false} diff --git a/packages/ui/src/views/components/ribbon/Ribbon.tsx b/packages/ui/src/views/components/ribbon/Ribbon.tsx index 205af1d2b4..eb82d10829 100644 --- a/packages/ui/src/views/components/ribbon/Ribbon.tsx +++ b/packages/ui/src/views/components/ribbon/Ribbon.tsx @@ -18,7 +18,7 @@ import type { ComponentType } from 'react'; import type { Observable } from 'rxjs'; import type { IMenuSchema } from '../../../services/menu/menu-manager.service'; import { LocaleService } from '@univerjs/core'; -import { borderBottomClassName, borderClassName, clsx, divideXClassName, Dropdown } from '@univerjs/design'; +import { borderBottomClassName, borderClassName, clsx, divideXClassName, Dropdown, HoverCard } from '@univerjs/design'; import { DatabaseSingle, EyeSingle, FunctionSingle, HomeSingle, InsertSingle, MoreDownSingle, MoreFunctionSingle } from '@univerjs/icons'; import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { combineLatest } from 'rxjs'; @@ -253,8 +253,8 @@ export function Ribbon(props: IRibbonProps) { */} {ribbon.length > 1 && ( - - + )}
@@ -336,9 +336,11 @@ export function Ribbon(props: IRibbonProps) { ))} + {/* More functions dropdown */} {collapsedIds.length > 0 && (
=16'} - '@es-joy/jsdoccomment@0.50.0': resolution: {integrity: sha512-+zZymuVLH6zVwXPtCAtC+bDymxmEwEqDftdAK+f407IF1bnX49anIxvBhCA1AqUIfD6egj1jM1vUnSuijjNyYg==} engines: {node: '>=18'} + '@es-joy/jsdoccomment@0.50.1': + resolution: {integrity: sha512-fas3qe1hw38JJgU/0m5sDpcrbZGysBeZcMwW5Ws9brYxY64MJyWLXRZCj18keTycT1LFTrFXdSNMS+GRVaU6Hw==} + engines: {node: '>=18'} + '@esbuild/aix-ppc64@0.25.4': resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} engines: {node: '>=18'} @@ -4727,6 +4730,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-hover-card@1.1.13': + resolution: {integrity: sha512-Wtjvx0d/6Bgd/jAYS1mW6IPSUQ25y0hkUSOS1z5/4+U8+DJPwKroqJlM/AlVFl3LywGoruiPmcvB9Aks9mSOQw==} + peerDependencies: + '@types/react': ^19.1.3 + '@types/react-dom': ^19.1.5 + react: ^19.1.0 + react-dom: ^19.1.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-id@1.1.1': resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: @@ -7397,8 +7413,8 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 - eslint-plugin-jsdoc@50.6.14: - resolution: {integrity: sha512-JUudvooQbUx3iB8n/MzXMOV/VtaXq7xL4CeXhYryinr8osck7nV6fE2/xUXTiH3epPXcvq6TE3HQfGQuRHErTQ==} + eslint-plugin-jsdoc@50.6.17: + resolution: {integrity: sha512-hq+VQylhd12l8qjexyriDsejZhqiP33WgMTy2AmaGZ9+MrMWVqPECsM87GPxgHfQn0zw+YTuhqjUfk1f+q67aQ==} engines: {node: '>=18'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -11344,7 +11360,7 @@ snapshots: eslint-plugin-antfu: 3.1.1(eslint@9.26.0(jiti@2.4.2)) eslint-plugin-command: 3.2.0(eslint@9.26.0(jiti@2.4.2)) eslint-plugin-import-x: 4.11.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - eslint-plugin-jsdoc: 50.6.14(eslint@9.26.0(jiti@2.4.2)) + eslint-plugin-jsdoc: 50.6.17(eslint@9.26.0(jiti@2.4.2)) eslint-plugin-jsonc: 2.20.0(eslint@9.26.0(jiti@2.4.2)) eslint-plugin-n: 17.18.0(eslint@9.26.0(jiti@2.4.2)) eslint-plugin-no-only-tests: 3.3.0 @@ -11918,13 +11934,16 @@ snapshots: tslib: 2.8.1 optional: true - '@es-joy/jsdoccomment@0.49.0': + '@es-joy/jsdoccomment@0.50.0': dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.7 + '@typescript-eslint/types': 8.32.0 comment-parser: 1.4.1 esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 - '@es-joy/jsdoccomment@0.50.0': + '@es-joy/jsdoccomment@0.50.1': dependencies: '@types/eslint': 9.6.1 '@types/estree': 1.0.7 @@ -12632,6 +12651,23 @@ snapshots: '@types/react': 19.1.3 '@types/react-dom': 19.1.5(@types/react@19.1.3) + '@radix-ui/react-hover-card@1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.3 + '@types/react-dom': 19.1.5(@types/react@19.1.3) + '@radix-ui/react-id@1.1.1(@types/react@19.1.3)(react@19.1.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -15512,9 +15548,9 @@ snapshots: - supports-color - typescript - eslint-plugin-jsdoc@50.6.14(eslint@9.26.0(jiti@2.4.2)): + eslint-plugin-jsdoc@50.6.17(eslint@9.26.0(jiti@2.4.2)): dependencies: - '@es-joy/jsdoccomment': 0.49.0 + '@es-joy/jsdoccomment': 0.50.1 are-docs-informative: 0.0.2 comment-parser: 1.4.1 debug: 4.4.0