カスタムコンポーネント
Web SDK は、カスタムコンポーネントを統合するための複数の方法を提供しており、その機能を拡張およびカスタマイズできます。このガイドでは、いくつかの一般的な方法を紹介します。
Univer は、コンポーネントをレンダリング関数に直接渡すことはありません。さまざまなマウントポイントで使用する前に、Facade API を介してコンポーネントを Univer に登録する必要があります。
Facade API のインスタンスを取得する方法に慣れていない場合は、Facade API を参照してください。
カスタムコンポーネントの登録
univerAPI.registerComponent(componentKey, CustomComponent, options)univerAPI.registerComponent メソッドを使用してカスタムコンポーネントを登録します。このメソッドは 3 つのパラメータを受け取ります:
componentKey: コンポーネントの一意の識別子で、Univer 内で参照するために使用されます。CustomComponent: コンポーネントの実装で、React、Vue、または Web Component にすることができます。options: オプションの設定オプションで、コンポーネントが依存するフレームワークやその他の関連設定を指定するために使用できます。
React コンポーネント
React コンポーネントを登録するには、追加の設定は必要ありません。コンポーネントが有効な React コンポーネントであることを確認するだけです。以下は簡単な例です:
function ReactComponent(props: Record<string, any>) { return <div>Hello Univer!</div>}univerAPI.registerComponent('MyReactComponent', ReactComponent)Vue コンポーネント
Vue 3.x
Vue コンポーネントを登録したい場合は、@univerjs/ui-adapter-vue3 パッケージから UniverVue3AdapterPlugin をインストールして登録してください:
pnpm add @univerjs/ui-adapter-vue3npm install @univerjs/ui-adapter-vue3yarn add @univerjs/ui-adapter-vue3bun add @univerjs/ui-adapter-vue3import { UniverVue3AdapterPlugin } from '@univerjs/ui-adapter-vue3'univer.registerPlugin(UniverVue3AdapterPlugin)Vue コンポーネントを登録する際は、framework オプションを 'vue3' として指定する必要があります:
const Vue3Component = defineComponent({ setup(props) { return () => <div>Hello Univer!</div> },})univerAPI.registerComponent('MyVue3Component', Vue3Component, { framework: 'vue3',})Vue 2.x
Vue 2.x は EOL(End of Life)でメンテナンスされなくなったため、Univer は現在 Vue 2.x 用の UI アダプタープラグインを提供していません。ただし、カスタムプラグインを作成することで Vue 2.x アダプターを実装できます。以下は Vue 2.x アダプタープラグインの作成例です:
import { DependentOn, Inject, Injector, Plugin } from '@univerjs/core'import { ComponentManager, UniverUIPlugin } from '@univerjs/ui'import Vue from 'vue'/** * Univer が Vue 2 コンポーネントを UI コンポーネントとして使用できるようにするプラグイン。 */@DependentOn(UniverUIPlugin)export class UniverVue2AdapterPlugin extends Plugin { static override pluginName = 'UNIVER_UI_VUE2_ADAPTER_PLUGIN' constructor( private readonly _config = {}, @Inject(Injector) protected readonly _injector: Injector, @Inject(ComponentManager) protected readonly _componentManager: ComponentManager, ) { super() } override onStarting(): void { const { createElement, useEffect, useRef } = this._componentManager.reactUtils this._componentManager.setHandler('vue2', (component: any) => { return (props: Record<string, any>) => createElement(VueComponentWrapper, { component, props: Object.keys(props).reduce<Record<string, any>>((acc, key) => { if (key !== 'key') { acc[key] = props[key] } return acc }, {}), reactUtils: { createElement, useEffect, useRef }, }) }) }}export function VueComponentWrapper(options: { component: any props: Record<string, any> reactUtils: typeof ComponentManager.prototype.reactUtils}) { const { component, props, reactUtils } = options const { createElement, useEffect, useRef } = reactUtils const domRef = useRef<HTMLDivElement>(null) useEffect(() => { if (!domRef.current) return const Constructor = Vue.extend(component) const instance = new Constructor({ data: props, }) instance.$mount() domRef.current.appendChild(instance.$el) return () => { instance.$destroy() } }, [props]) return createElement('div', { ref: domRef })}その後、登録します:
import { UniverVue2AdapterPlugin } from './ui-adapter-vue2'univer.registerPlugin(UniverUIPlugin)univer.registerPlugin(UniverVue2AdapterPlugin)Vue 2.x コンポーネントを登録する際は、framework オプションを 'vue2' として指定する必要があります:
const Vue2Component = Vue.component('MyVue2Component', { template: '<div>Hello, Univer!</div>',})univerAPI.registerComponent('MyVue2Component', Vue2Component, { framework: 'vue2',})Web Components
Web Components を登録したい場合は、コンポーネントが Web Components 標準に準拠していることを確認し、@univerjs/ui-adapter-web-component パッケージから UniverWebComponentAdapterPlugin をインストールして登録してください:
pnpm add @univerjs/ui-adapter-web-componentnpm install @univerjs/ui-adapter-web-componentyarn add @univerjs/ui-adapter-web-componentbun add @univerjs/ui-adapter-web-componentimport { UniverWebComponentAdapterPlugin } from '@univerjs/ui-adapter-web-component'univer.registerPlugin(UniverWebComponentAdapterPlugin)Web Components を登録する際は、framework オプションを 'web-component' として指定する必要があります:
class WebComponent extends HTMLElement { constructor() { super() const shadow = this.attachShadow({ mode: 'open' }) const div = document.createElement('div') div.textContent = 'Hello Univer!' shadow.appendChild(div) }}univerAPI.registerComponent('my-web-component', WebComponent, { framework: 'web-component',})Angular
@angular/elements の createCustomElement で Angular コンポーネントをカスタム要素に変換し、Univer の Web Component アダプターに登録します。これにより、Univer のサイドバーやダイアログで Angular コンポーネントを使用できます。
@angular/core と同じバージョンの @angular/elements と、他の Univer パッケージと同じバージョンの @univerjs/ui-adapter-web-component を追加してください。
Univer の初期化後に次の関数を呼び出します。ホストコンポーネントで private readonly injector = inject(Injector) により Angular インジェクターを取得し、registerAngularPanel(univer, univerAPI, this.injector) に渡します。ホスト側の inject と Injector は @angular/core からインポートしてください。
import type { Injector } from '@angular/core'import type { FUniver, Univer } from '@univerjs/presets'import { Component } from '@angular/core'import { createCustomElement } from '@angular/elements'import { UniverWebComponentAdapterPlugin } from '@univerjs/ui-adapter-web-component'@Component({ selector: 'app-angular-panel', standalone: true, template: '<p>Hello from Angular!</p>',})export class AngularPanelComponent {}export function registerAngularPanel(univer: Univer, univerAPI: FUniver, injector: Injector) { const element = createCustomElement(AngularPanelComponent, { injector }) univer.registerPlugin(UniverWebComponentAdapterPlugin) return univerAPI.registerComponent('univer-angular-panel', element, { framework: 'web-component', })}エディターの描画後、登録したキーをサイドバーの内容として指定します。
const sidebar = univerAPI.openSidebar({ header: { title: 'Angular' }, children: { label: 'univer-angular-panel' }, width: 360,})返された登録とサイドバーのハンドルを保持し、不要になったらそれぞれの dispose() を呼び出します。カスタム要素はアプリケーションで一度だけ登録してください。名前にはハイフンが必要で、Angular コンポーネントの selector とは別の名前にします。
Angular Elements は入力を要素のプロパティに、出力を DOM の CustomEvent に変換します。Univer アダプターはプロパティを設定しますが Angular の出力を自動購読しないため、必要なイベントは明示的に接続してください。
カスタムコンポーネントの使用
以下のメソッドを使用することで、様々なカスタムコンポーネントを Univer に柔軟に統合し、その機能を拡張・カスタマイズできます。
注意事項
- これらのメソッドを使用する前に、Univer のレンダリングが完了していることを確認してください。 2.
登録が必要なコンポーネントについては、使用前に正しく登録されていることを確認してください。 3.
dispose()メソッドを使用して追加されたコンポーネントをクリーンアップし、メモリリークを避けてください。
カスタムメニューアイテムの追加
トップメニューバー(Ribbon)と右クリックメニュー(Context Menu)の両方にカスタムコンポーネントを含めることができます。メニューアイテムにカスタムコンポーネントを追加するには、カスタムプラグインを作成する必要があります。カスタムメニューアイテム追加のベストプラクティス を用意して、素早く開始できるようにしています。
組み込みコンポーネントの置き換え
警告
組み込みコンポーネントを置き換えると、一部の機能が正常に動作しなくなる可能性があります。コンポーネントの置き換えを試みる前に、ソースコードとドキュメントを十分に読み、慎重に進めてください。
univerAPI.registerComponent は既定でオーバーライドを登録します(override: true)。プラグインが既定コンポーネントを登録する順序に関係なく、オーバーライドが優先されます。各 componentKey で有効にできるオーバーライドは 1 つです。再登録する前に以前の登録を破棄してください。戻り値の dispose() を呼ぶと、登録済みの既定コンポーネントに戻ります。{ override: false } は既定コンポーネントを登録します。
対応するビューを初めて開く前に登録してください。登録の変更だけでは、マウント済みのビューは再描画されません。
Sheets は次のキーをパッケージの公開エントリーから提供し、対応する組み込みコンポーネントを置き換えられます。
| コンポーネント | 公開キー | パッケージ |
|---|---|---|
| 定義された名前 | DEFINED_NAME_CONTAINER | @univerjs/sheets-ui |
| その他の関数 | MORE_FUNCTIONS_COMPONENT | @univerjs/sheets-formula-ui |
| データの入力規則 | DATA_VALIDATION_PANEL | @univerjs/sheets-data-validation-ui |
| 条件付き書式 | CF_PANEL_KEY | @univerjs/sheets-conditional-formatting-ui |
例えば、組み込みの ColorPicker コンポーネントを簡単に置き換えるには:
// Following code only replaces the UI of the built-in ColorPicker component, not its functionalityuniverAPI.registerComponent('UI_COLOR_PICKER_COMPONENT', () => <input type="color" />)コンテンツコンポーネントとしての使用
サイドバーで
univerAPI.openSidebar メソッドを使用して、カスタムコンポーネントを含む Univer インターフェースのサイドバーを開くことができます。
// 適切なタイミング(例:Univer が読み込まれた後)でコンポーネントを登録する必要がありますuniverAPI.registerComponent('MyCustomSidebarComponent', () => <div>Hello Univer!</div>)const sidebar = univerAPI.openSidebar({ header: { title: 'My Sidebar' }, children: { label: 'MyCustomSidebarComponent' }, onClose: () => { console.log('close') }, width: 360,})// 後でサイドバーを閉じるsidebar.dispose()ダイアログで
univerAPI.openDialog メソッドを使用して、カスタムコンポーネントを含むダイアログを開くことができます。
// 適切なタイミング(例:Univer が読み込まれた後)でコンポーネントを登録する必要がありますuniverAPI.registerComponent('MyCustomDialogComponent', () => <div>Hello Univer!</div>)const dialog = univerAPI.openDialog({ id: 'unique-dialog-id', // ダイアログの一意の識別子 draggable: true, width: 300, title: { title: 'My Dialog' }, children: { label: 'MyCustomDialogComponent', }, destroyOnClose: true, preservePositionOnDestroy: true, onClose: () => {},})// 後でダイアログを閉じるdialog.dispose()セルにポップアップを添付
FRange.attachPopup メソッドを使用して、特定のセル範囲にカスタムポップアップを添付できます。
- ポップアップは、セルに添付される一時的な DOM 要素で、通常は一時的なステータス情報を表示するために使用され、永続的な保存をサポートしません。
FRange.attachPopup(popup: IFCanvasPopup)メソッドを使用して、特定のセル範囲にカスタムポップアップを添付できます。- ポップアップはセルの端に添付され、遮蔽されると自動的に位置と向きを調整します。
// 適切なタイミング(例:Univer が読み込まれた後)でコンポーネントを登録する必要がありますuniverAPI.registerComponent( 'MyCustomPopupComponent', () => <div>Hello Univer!</div>,)const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:J10')// 範囲の最初のセルにポップアップを添付// `disposable` が null の場合、ポップアップが正常に追加されなかったことを示しますconst disposable = fRange.attachPopup({ componentKey: 'MyCustomPopupComponent',})// ポップアップを削除disposable.dispose()アラートポップアップを添付
FRange.attachAlertPopup メソッドを使用して、指定された範囲の開始セルにアラートポップアップを添付できます。
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const fRange = fWorksheet.getRange('A1:B2')const disposable = fRange.attachAlertPopup({ key: 'unique-alert-key', // 一意の識別子 title: 'これは警告です!', message: 'これは警告です!', width: 300, height: 200, // 0: 情報 // 1: 警告 // 2: エラー type: 0,})// ポップアップを削除disposable.dispose()ワークシートにフローティングDOMを追加
FWorksheet.addFloatDomToPosition メソッドを使用して、ワークシートにフローティング DOM を追加できます。
- このメソッドを使用する前に、
@univerjs/sheets-drawing-uiプラグインまたは@univerjs/preset-sheets-drawingプリセットをインストールする必要があります。 - フローティング DOM は、ワークシートの上に浮かぶドラッグ可能なコンポーネントで、永続的なストレージをサポートしています。
- このメソッドは、Univer のレンダリングが完了した後に呼び出す必要があります。
componentKey: コンポーネントの一意の識別子で、Univer 内で参照するために使用されます。- 完全なパラメータ定義
// 適切なタイミング(例:Univer が読み込まれた後)でコンポーネントを登録する必要がありますuniverAPI.registerComponent( 'MyCustomFloatDOMComponent', ({ data }) => ( <div> Hello {data?.label} ! </div> ),)const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// ワークシートにフローティング DOM を追加// `disposable` が null の場合、フローティング DOM が正常に追加されなかったことを示しますconst disposable = fWorksheet.addFloatDomToPosition({ componentKey: 'MyCustomFloatDOMComponent', initPosition: { startX: 100, endX: 200, startY: 100, endY: 200, }, // コンポーネントのデータ data: { label: 'Univer', },})// フローティング DOM を削除disposable.dispose()このガイドはいかがですか?