diff --git a/packages/docs-quick-insert-ui/package.json b/packages/docs-quick-insert-ui/package.json index 6e7b1b6e48..837e69dba0 100644 --- a/packages/docs-quick-insert-ui/package.json +++ b/packages/docs-quick-insert-ui/package.json @@ -70,6 +70,7 @@ "@univerjs/design": "workspace:*", "@univerjs/docs": "workspace:*", "@univerjs/docs-drawing": "workspace:*", + "@univerjs/docs-drawing-ui": "workspace:*", "@univerjs/docs-ui": "workspace:*", "@univerjs/drawing": "workspace:*", "@univerjs/drawing-ui": "workspace:*", diff --git a/packages/docs-quick-insert-ui/src/controllers/doc-quick-insert-ui.controller.ts b/packages/docs-quick-insert-ui/src/controllers/doc-quick-insert-ui.controller.ts index 822826a05f..54a946be1c 100644 --- a/packages/docs-quick-insert-ui/src/controllers/doc-quick-insert-ui.controller.ts +++ b/packages/docs-quick-insert-ui/src/controllers/doc-quick-insert-ui.controller.ts @@ -23,6 +23,7 @@ import { of } from 'rxjs'; import { DeleteSearchKeyCommand } from '../commands/commands/doc-quick-insert.command'; import { CloseQuickInsertPopupOperation, ShowQuickInsertPopupOperation } from '../commands/operations/quick-insert-popup.operation'; import { DocQuickInsertPopupService } from '../services/doc-quick-insert-popup.service'; +import { KeywordInputPlaceholder } from '../views/KeywordInputPlaceholder'; import { QuickInsertPopup } from '../views/QuickInsertPopup'; import { builtInMenus } from './built-in-menus'; @@ -52,6 +53,7 @@ export class DocQuickInsertUIController extends Disposable { private _initComponents() { this.disposeWithMe(this._componentManager.register(QuickInsertPopup.componentKey, QuickInsertPopup)); + this.disposeWithMe(this._componentManager.register(KeywordInputPlaceholder.componentKey, KeywordInputPlaceholder)); this.disposeWithMe(this._componentManager.register('DividerSingle', DividerSingle)); this.disposeWithMe(this._componentManager.register('TextSingle', TextSingle)); diff --git a/packages/docs-quick-insert-ui/src/locale/en-US.ts b/packages/docs-quick-insert-ui/src/locale/en-US.ts index feb5482f95..f2d0549510 100644 --- a/packages/docs-quick-insert-ui/src/locale/en-US.ts +++ b/packages/docs-quick-insert-ui/src/locale/en-US.ts @@ -27,6 +27,8 @@ const locale: typeof zhCN = { group: { basics: 'Basics', }, + placeholder: 'No results found', + keywordInputPlaceholder: 'Enter keywords', }, }; diff --git a/packages/docs-quick-insert-ui/src/locale/fa-IR.ts b/packages/docs-quick-insert-ui/src/locale/fa-IR.ts index 4d2b824471..0a080273ea 100644 --- a/packages/docs-quick-insert-ui/src/locale/fa-IR.ts +++ b/packages/docs-quick-insert-ui/src/locale/fa-IR.ts @@ -27,6 +27,8 @@ const locale: typeof zhCN = { group: { basics: 'بنیادی', }, + placeholder: 'هیچ نتیجهای یافت نشد', + keywordInputPlaceholder: 'وارد کلمات کلیدی', }, }; diff --git a/packages/docs-quick-insert-ui/src/locale/fr-FR.ts b/packages/docs-quick-insert-ui/src/locale/fr-FR.ts index 31c154ee48..ef9f8f92dc 100644 --- a/packages/docs-quick-insert-ui/src/locale/fr-FR.ts +++ b/packages/docs-quick-insert-ui/src/locale/fr-FR.ts @@ -27,6 +27,8 @@ const locale: typeof enUS = { group: { basics: 'Basiques', }, + placeholder: 'Aucun résultat', + keywordInputPlaceholder: 'Entrez des mots clés', }, }; diff --git a/packages/docs-quick-insert-ui/src/locale/ru-RU.ts b/packages/docs-quick-insert-ui/src/locale/ru-RU.ts index b88399b29c..51393b9a08 100644 --- a/packages/docs-quick-insert-ui/src/locale/ru-RU.ts +++ b/packages/docs-quick-insert-ui/src/locale/ru-RU.ts @@ -27,6 +27,8 @@ const locale: typeof zhCN = { group: { basics: 'Основные', }, + placeholder: 'Нет результатов', + keywordInputPlaceholder: 'Введите ключевые слова', }, }; diff --git a/packages/docs-quick-insert-ui/src/locale/vi-VN.ts b/packages/docs-quick-insert-ui/src/locale/vi-VN.ts index e9e4d220d8..59ff9ad57f 100644 --- a/packages/docs-quick-insert-ui/src/locale/vi-VN.ts +++ b/packages/docs-quick-insert-ui/src/locale/vi-VN.ts @@ -27,6 +27,8 @@ const locale: typeof zhCN = { group: { basics: 'Cơ bản', }, + placeholder: 'Không có kết quả', + keywordInputPlaceholder: 'Nhập từ khóa', }, }; diff --git a/packages/docs-quick-insert-ui/src/locale/zh-CN.ts b/packages/docs-quick-insert-ui/src/locale/zh-CN.ts index 2c0692e773..cf1d31d8e5 100644 --- a/packages/docs-quick-insert-ui/src/locale/zh-CN.ts +++ b/packages/docs-quick-insert-ui/src/locale/zh-CN.ts @@ -25,6 +25,8 @@ const locale = { group: { basics: '基础', }, + placeholder: '暂无结果', + keywordInputPlaceholder: '输入关键词', }, }; diff --git a/packages/docs-quick-insert-ui/src/locale/zh-TW.ts b/packages/docs-quick-insert-ui/src/locale/zh-TW.ts index 7f6dab3f51..e89a579369 100644 --- a/packages/docs-quick-insert-ui/src/locale/zh-TW.ts +++ b/packages/docs-quick-insert-ui/src/locale/zh-TW.ts @@ -27,6 +27,8 @@ const locale: typeof zhCN = { group: { basics: '基礎', }, + placeholder: '無結果', + keywordInputPlaceholder: '輸入關鍵詞', }, }; diff --git a/packages/docs-quick-insert-ui/src/services/doc-quick-insert-popup.service.ts b/packages/docs-quick-insert-ui/src/services/doc-quick-insert-popup.service.ts index dac4fd77f0..1a4e3d7ac8 100644 --- a/packages/docs-quick-insert-ui/src/services/doc-quick-insert-popup.service.ts +++ b/packages/docs-quick-insert-ui/src/services/doc-quick-insert-popup.service.ts @@ -18,9 +18,11 @@ import type { DocumentDataModel, IDisposable, Nullable } from '@univerjs/core'; import type { IInsertCommandParams } from '@univerjs/docs-ui'; import type { Observable } from 'rxjs'; import { Disposable, ICommandService, Inject, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { DocFloatDomController } from '@univerjs/docs-drawing-ui'; import { DocCanvasPopManagerService } from '@univerjs/docs-ui'; -import { BehaviorSubject, distinctUntilChanged, map } from 'rxjs'; +import { BehaviorSubject, combineLatest, distinctUntilChanged, map, tap } from 'rxjs'; import { DeleteSearchKeyCommand } from '../commands/commands/doc-quick-insert.command'; +import { KeywordInputPlaceholder } from '../views/KeywordInputPlaceholder'; import { QuickInsertPopup } from '../views/QuickInsertPopup'; export interface IDocPopupGroupItem { @@ -42,7 +44,7 @@ export type DocPopupMenu = IDocPopupGroupItem | IDocPopupMenuItem; export interface IDocPopup { keyword: string; menus$: Observable; - placeholder?: React.ReactNode; + Placeholder?: React.ComponentType; preconditions?: (params: IInsertCommandParams) => boolean; } @@ -75,10 +77,16 @@ export class DocQuickInsertPopupService extends Disposable { private _menuSelectedCallbacks: Set<(menu: IDocPopupMenuItem) => void> = new Set(); + private _inputPlaceholderRenderRoot: { + unmount?: IDisposable; + mount: () => void; + } | null = null; + constructor( @Inject(DocCanvasPopManagerService) private readonly _docCanvasPopupManagerService: DocCanvasPopManagerService, @Inject(IUniverInstanceService) private readonly _univerInstanceService: IUniverInstanceService, - @Inject(ICommandService) private readonly _commandService: ICommandService + @Inject(ICommandService) private readonly _commandService: ICommandService, + @Inject(DocFloatDomController) private readonly _docFloatDomController: DocFloatDomController ) { super(); @@ -94,6 +102,21 @@ export class DocQuickInsertPopupService extends Disposable { }), distinctUntilChanged() ); + + this.disposeWithMe(combineLatest([ + this.filterKeyword$.pipe(tap((filterKeyword) => { + if (filterKeyword.length > 0) { + this._inputPlaceholderRenderRoot?.unmount?.dispose(); + } else { + this._inputPlaceholderRenderRoot?.mount(); + } + })), + this.editPopup$.pipe(tap((popup) => { + if (!popup) { + this._inputPlaceholderRenderRoot?.unmount?.dispose(); + } + })), + ]).subscribe()); } resolvePopup(keyword: string) { @@ -108,6 +131,19 @@ export class DocQuickInsertPopupService extends Disposable { }; } + private _createInputPlaceholderRenderRoot(mount: () => IDisposable) { + const renderRoot: { + unmount?: IDisposable; + mount: () => void; + } = { + mount() { + this.unmount = mount(); + }, + }; + + return renderRoot; + } + showPopup(options: { popup: IDocPopup; index: number; unitId: string }) { const { popup, index, unitId } = options; @@ -125,6 +161,23 @@ export class DocQuickInsertPopupService extends Disposable { unitId ); + this._inputPlaceholderRenderRoot = this._createInputPlaceholderRenderRoot(() => { + const disposable = this._docCanvasPopupManagerService.attachPopupToRange( + { startOffset: index + 1, endOffset: index + 1, collapsed: false }, + { + componentKey: KeywordInputPlaceholder.componentKey, + onClickOutside: () => { + disposable.dispose(); + }, + direction: 'horizontal', + }, + unitId + ); + + return disposable; + }); + this._inputPlaceholderRenderRoot.mount(); + this._editPopup$.next({ disposable, popup, anchor: index, unitId }); } diff --git a/packages/docs-quick-insert-ui/src/views/KeywordInputPlaceholder.tsx b/packages/docs-quick-insert-ui/src/views/KeywordInputPlaceholder.tsx new file mode 100644 index 0000000000..a5896cbad7 --- /dev/null +++ b/packages/docs-quick-insert-ui/src/views/KeywordInputPlaceholder.tsx @@ -0,0 +1,28 @@ +/** + * 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 { LocaleService } from '@univerjs/core'; +import { useDependency } from '@univerjs/ui'; + +const KeywordInputPlaceholder = () => { + const localeService = useDependency(LocaleService); + // TODO: 需要根据fontSize来计算高度跟偏移 + return
{localeService.t('docQuickInsert.keywordInputPlaceholder')}
; +}; + +KeywordInputPlaceholder.componentKey = 'KeywordInputPlaceholder'; + +export { KeywordInputPlaceholder }; diff --git a/packages/docs-quick-insert-ui/src/views/QuickInsertPlaceholder.tsx b/packages/docs-quick-insert-ui/src/views/QuickInsertPlaceholder.tsx new file mode 100644 index 0000000000..440e2b8489 --- /dev/null +++ b/packages/docs-quick-insert-ui/src/views/QuickInsertPlaceholder.tsx @@ -0,0 +1,32 @@ +/** + * 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 { LocaleService } from '@univerjs/core'; +import { useDependency } from '@univerjs/ui'; + +export const QuickInsertPlaceholder = () => { + const localeService = useDependency(LocaleService); + return ( +
+ {localeService.t('docQuickInsert.placeholder')} +
+ ); +}; diff --git a/packages/docs-quick-insert-ui/src/views/QuickInsertPopup.tsx b/packages/docs-quick-insert-ui/src/views/QuickInsertPopup.tsx index a8665c160b..7445022141 100644 --- a/packages/docs-quick-insert-ui/src/views/QuickInsertPopup.tsx +++ b/packages/docs-quick-insert-ui/src/views/QuickInsertPopup.tsx @@ -21,6 +21,7 @@ import { ComponentManager, IShortcutService, KeyCode, useDependency, useObservab import { useEffect, useMemo, useRef, useState } from 'react'; import { CloseQuickInsertPopupOperation } from '../commands/operations/quick-insert-popup.operation'; import { DocQuickInsertPopupService } from '../services/doc-quick-insert-popup.service'; +import { QuickInsertPlaceholder } from './QuickInsertPlaceholder'; function filterMenusByKeyword(menus: DocPopupMenu[], keyword: string) { return menus @@ -251,6 +252,8 @@ const QuickInsertPopup = () => { const hasMenus = filteredMenus.length > 0; + const Placeholder = currentPopup?.popup.Placeholder || QuickInsertPlaceholder; + return (
{
) - : currentPopup?.popup.placeholder} + : } ); diff --git a/packages/docs-ui/src/services/doc-popup-manager.service.ts b/packages/docs-ui/src/services/doc-popup-manager.service.ts index a0446ffb80..8590043e3e 100644 --- a/packages/docs-ui/src/services/doc-popup-manager.service.ts +++ b/packages/docs-ui/src/services/doc-popup-manager.service.ts @@ -279,6 +279,7 @@ export class DocCanvasPopManagerService extends Disposable { const { positions: bounds, positions$: bounds$, disposable } = this._createRangePositionObserver(range, currentRender); const position$ = bounds$.pipe(map((bounds) => direction.includes('top') ? bounds[0] : bounds[bounds.length - 1])); + const id = this._globalPopupManagerService.addPopup({ ...popup, unitId, @@ -287,10 +288,9 @@ export class DocCanvasPopManagerService extends Disposable { anchorRect$: position$, excludeRects: bounds, excludeRects$: bounds$, - direction: - (direction.includes('top') || direction.includes('bottom')) ? - bounds.length > 1 ? multipleDirection ?? direction : direction - : 'bottom', + direction: (['top', 'bottom', 'horizontal'].includes(direction)) ? + bounds.length > 1 ? multipleDirection ?? direction : direction + : 'bottom', canvasElement: currentRender.engine.getCanvasElement(), }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bad76ee34e..8948e0cf2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1459,6 +1459,9 @@ importers: '@univerjs/docs-drawing': specifier: workspace:* version: link:../docs-drawing + '@univerjs/docs-drawing-ui': + specifier: workspace:* + version: link:../docs-drawing-ui '@univerjs/docs-ui': specifier: workspace:* version: link:../docs-ui