mcpField
U
umbraco-tiptap-statusbar-extension

umbraco-tiptap-statusbar-extension

github.com/umbraco開発27374 回インストール6 週間前に更新
リポジトリ

umbraco-tiptap-statusbar-extension について

Umbraco Tiptap のステータスバー拡張を作成するためのスキルです。最新ドキュメントの確認から、マニフェストと要素の作成、テスト方法の説明までを案内します。

主な機能

  1. 01ステータスバー拡張の案内
  2. 02マニフェストと要素の例
  3. 03エディターコンテキストとイベントへのアクセス
  4. 04ドキュメント確認を優先するワークフロー

活用シーン

  1. 01単語数や文字数の表示
  2. 02要素パスのパンくず表示
  3. 03カーソル位置やエディター状態の追跡

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-tiptap-statusbar-extension

インストール後、Claude Code で/umbraco-tiptap-statusbar-extensionを入力して読み込まれたか確認します。

詳細

Umbraco Tiptap ステータスバー拡張機能

これは何ですか?

Tiptap ステータスバー拡張機能は、リッチテキストエディター下部のステータスバーにコンポーネントを追加します。一般的な用途としては、要素パス(パンくずナビゲーション)の表示、単語数、文字数、その他のエディター状態情報の表示などがあります。ツールバー拡張機能とは異なり、ステータスバー拡張機能は純粋に視覚的・情報的な要素です。

ドキュメント

実装前に必ず最新のドキュメントを取得してください:

関連スキル

  • Tiptap 拡張機能: エディター機能を追加するため

    • 参照スキル: umbraco-tiptap-extension
  • Umbraco 要素: ステータスバー要素を実装するため

    • 参照スキル: umbraco-umbraco-element
  • Context API: Tiptap RTE コンテキストにアクセスするため

    • 参照スキル: umbraco-context-api

ワークフロー

  1. ドキュメントを取得 - 上記の URL に対して WebFetch を使用します
  2. 質問する - どのような情報を表示しますか? リアルタイム更新は必要ですか?
  3. ファイルを生成 - 最新のドキュメントに基づいてマニフェスト + 要素を作成します
  4. 説明 - 作成された内容とテスト方法を示します

最小限の例

マニフェスト (manifests.ts)
import type { ManifestTiptapStatusbarExtension } from '@umbraco-cms/backoffice/extension-registry';

const manifest: ManifestTiptapStatusbarExtension = {
  type: 'tiptapStatusbarExtension',
  alias: 'My.TiptapStatusbar.WordCount',
  name: 'Word Count Statusbar',
  element: () => import('./word-count.statusbar-element.js'),
  forExtensions: [], // Optional: link to specific tiptap extensions
  meta: {
    alias: 'wordCount',
    icon: 'icon-document',
    label: 'Word Count',
  },
};

export const manifests = [manifest];
ステータスバー要素 (word-count.statusbar-element.ts)
import { html, css, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_TIPTAP_RTE_CONTEXT } from '@umbraco-cms/backoffice/tiptap';

@customElement('my-word-count-statusbar')
export class WordCountStatusbarElement extends UmbLitElement {
  @state()
  private _wordCount = 0;

  @state()
  private _charCount = 0;

  constructor() {
    super();

    this.consumeContext(UMB_TIPTAP_RTE_CONTEXT, (context) => {
      this.observe(context.editor, (editor) => {
        if (editor) {
          // Update counts when editor content changes
          editor.on('update', () => this.#updateCounts(editor));
          // Initial count
          this.#updateCounts(editor);
        }
      });
    });
  }

  #updateCounts(editor: any) {
    const text = editor.getText();
    this._charCount = text.length;
    this._wordCount = text.trim() ? text.trim().split(/\s+/).length : 0;
  }

  render() {
    return html`
      <span class="count">Words: ${this._wordCount}</span>
      <span class="count">Characters: ${this._charCount}</span>
    `;
  }

  static styles = css`
    :host {
      display: flex;
      gap: var(--uui-size-space-4);
      font-size: var(--uui-type-small-size);
      color: var(--uui-color-text-alt);
    }

    .count {
      padding: 0 var(--uui-size-space-2);
    }
  `;
}

export default WordCountStatusbarElement;

declare global {
  interface HTMLElementTagNameMap {
    'my-word-count-statusbar': WordCountStatusbarElement;
  }
}
要素パスステータスバー(パンくずナビゲーション)
import { html, css, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_TIPTAP_RTE_CONTEXT } from '@umbraco-cms/backoffice/tiptap';

@customElement('my-element-path-statusbar')
export class ElementPathStatusbarElement extends UmbLitElement {
  @state()
  private _path: string[] = [];

  constructor() {
    super();

    this.consumeContext(UMB_TIPTAP_RTE_CONTEXT, (context) => {
      this.observe(context.editor, (editor) => {
        if (editor) {
          editor.on('selectionUpdate', () => this.#updatePath(editor));
          this.#updatePath(editor);
        }
      });
    });
  }

  #updatePath(editor: any) {
    const { $from } = editor.state.selection;
    const path: string[] = [];

    for (let depth = $from.depth; depth > 0; depth--) {
      const node = $from.node(depth);
      path.unshift(node.type.name);
    }

    this._path = path;
  }

  #handleClick(index: number) {
    // Could implement navigation to that element
    console.log('Navigate to:', this._path[index]);
  }

  render() {
    return html`
      ${this._path.map(
        (name, index) => html`
          ${index > 0 ? html`<span class="separator">›</span>` : ''}
          <button @click=${() => this.#handleClick(index)}>${name}</button>
        `
      )}
    `;
  }

  static styles = css`
    :host {
      display: flex;
      align-items: center;
      font-size: var(--uui-type-small-size);
    }

    button {
      background: none;
      border: none;
      padding: var(--uui-size-space-1) var(--uui-size-space-2);
      cursor: pointer;
      color: var(--uui-color-text-alt);
    }

    button:hover {
      color: var(--uui-color-text);
      text-decoration: underline;
    }

    .separator {
      color: var(--uui-color-border);
      margin: 0 var(--uui-size-space-1);
    }
  `;
}

export default ElementPathStatusbarElement;
カーソル位置ステータスバー
import { html, css, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_TIPTAP_RTE_CONTEXT } from '@umbraco-cms/backoffice/tiptap';

@customElement('my-cursor-position-statusbar')
export class CursorPositionStatusbarElement extends UmbLitElement {
  @state()
  private _line = 1;

  @state()
  private _column = 1;

  constructor() {
    super();

    this.consumeContext(UMB_TIPTAP_RTE_CONTEXT, (context) => {
      this.observe(context.editor, (editor) => {
        if (editor) {
          editor.on('selectionUpdate', () => this.#updatePosition(editor));
        }
      });
    });
  }

  #updatePosition(editor: any) {
    const { from } = editor.state.selection;
    // Simplified line/column calculation
    const doc = editor.state.doc;
    let pos = 0;
    let line = 1;

    doc.descendants((node: any, nodePos: number) => {
      if (nodePos >= from) return false;
      if (node.isBlock) line++;
      return true;
    });

    this._line = line;
    this._column = from - pos;
  }

  render() {
    return html`
      <span>Ln ${this._line}, Col ${this._column}</span>
    `;
  }

  static styles = css`
    :host {
      font-size: var(--uui-type-small-size);
      color: var(--uui-color-text-alt);
    }
  `;
}

export default CursorPositionStatusbarElement;

メタプロパティ

プロパティ説明
aliasステータスバー項目の一意の識別子
iconアイコン(構成 UI で使用されます)
label表示名

エディターコンテキストへのアクセス

UMB_TIPTAP_RTE_CONTEXT を使用して Tiptap エディターインスタンスにアクセスし、以下のようなイベントを購読します:

  • update - コンテンツが変更されました
  • selectionUpdate - カーソル/選択範囲が変更されました
  • focus / blur - フォーカス状態が変更されました

以上です! 常に最新のドキュメントを取得し、例を最小限に保ち、完全に動作するコードを生成してください。

コメント