[go: nahoru, domu]

Skip to content

Commit

Permalink
feat(ui): enhance component container (#2395)
Browse files Browse the repository at this point in the history
* feat(ui): enhance component container

* feat: support passing injector to the hook

* fix: fix message not disposable
  • Loading branch information
wzhudev committed Jun 3, 2024
1 parent dc8b0ac commit 54460f9
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 9 deletions.
9 changes: 7 additions & 2 deletions packages/design/src/components/message/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/* eslint-disable react-refresh/only-export-components */

import { ErrorSingle, Loading, SuccessSingle, WarningSingle } from '@univerjs/icons';
import { render } from 'rc-util/lib/React/render';
import { render, unmount } from 'rc-util/lib/React/render';
import type { CSSProperties, ReactElement } from 'react';
import React from 'react';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
Expand Down Expand Up @@ -98,7 +98,7 @@ const MessageContainer = (props: { messages: IMessageProps[] }) => {
);
};

export class Message {
export class Message implements IDisposable {
protected _container: HTMLDivElement;

protected _messages: IMessageProps[] = [];
Expand All @@ -110,6 +110,11 @@ export class Message {
this.render();
}

dispose(): void {
unmount(this._container);
this._container.remove();
}

append(type: MessageType, options: IMessageOptions): IDisposable {
const { content, duration = 3000 } = options;
const key = `${Date.now()}`;
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export { IZenZoneService } from './services/zen-zone/zen-zone.service';
export { UniverUIPlugin, DISABLE_AUTO_FOCUS_KEY } from './ui-plugin';
export * from './utils';
export { type IConfirmPartMethodOptions } from './views/components/confirm-part/interface';
export { ComponentContainer } from './views/components/ComponentContainer';
export { ComponentContainer, useComponentsOfPart, type IComponentContainerProps } from './views/components/ComponentContainer';
export { IEditorService, EditorService } from './services/editor/editor.service';
export { TextEditor } from './components/editor/TextEditor';
export { SetEditorResizeOperation } from './commands/operations/editor/set-editor-resize.operation';
Expand Down
10 changes: 9 additions & 1 deletion packages/ui/src/services/message/desktop-message.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,19 @@ import type { IDisposable } from '@wendellhu/redi';

import type { IMessageService } from './message.service';

export class DesktopMessageService implements IMessageService {
export class DesktopMessageService implements IMessageService, IDisposable {
protected _portalContainer: HTMLElement = document.body;
protected _message?: Message;

dispose(): void {
this._message?.dispose();
}

setContainer(container: HTMLElement): void {
if (this._message) {
return;
}

this._portalContainer = container;
this._message = new Message(container);
}
Expand Down
45 changes: 40 additions & 5 deletions packages/ui/src/views/components/ComponentContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,49 @@
* limitations under the License.
*/

import { useDependency } from '@wendellhu/redi/react-bindings';
import type { ComponentType } from 'react';
import React from 'react';
import React, { useMemo, useRef } from 'react';
import { filter, map } from 'rxjs';
import type { Injector } from '@wendellhu/redi';
import { useObservable } from '../../components/hooks/observable';
import { IUIPartsService } from '../../services/parts/parts.service';

export function ComponentContainer(props: { components?: Set<() => ComponentType> }) {
const { components } = props;
if (!components) return null;
export interface IComponentContainerProps {
components?: Set<() => ComponentType>;
fallback?: React.ReactNode;
sharedProps?: Record<string, unknown>;
}

export function ComponentContainer(props: IComponentContainerProps) {
const { components, fallback, sharedProps } = props;
if (!components || components.size === 0) return fallback ?? null;

return Array.from(components.values()).map((component, index) =>
React.createElement(component(), { key: `${index}` })
React.createElement(component(), { key: `${index}`, ...sharedProps })
);
}

/**
* Get a set of render functions to render components of a part.
*
* @param part The part name.
* @param injector The injector to get the service. It is optional. However, you should not change this prop in a given
* component.
*/
export function useComponentsOfPart(part: string, injector?: Injector) {
const uiPartsService = injector?.get(IUIPartsService) ?? useDependency(IUIPartsService);
const updateCounterRef = useRef<number>(0);
const componentPartUpdateCount = useObservable(
() => uiPartsService.componentRegistered$.pipe(
filter((key) => key === part),
map(() => updateCounterRef.current += 1)
),
undefined,
undefined,
[uiPartsService]
);

// eslint-disable-next-line react-hooks/exhaustive-deps
return useMemo(() => uiPartsService.getComponents(part), [componentPartUpdateCount]);
}

0 comments on commit 54460f9

Please sign in to comment.