GithubXDiscord

customization-guide > カスタムコンポーネントの使用方法

カスタムコンポーネントの使用方法

ノーションプレッソは、様々なノーションのブロックタイプに対する基本コンポーネントを提供します。このセクションでは、これらの基本コンポーネントの使用方法とカスタマイズ方法、そして新しいカスタムコンポーネントを作成する方法を説明します。

基本コンポーネントの使用例

Headingコンポーネント

Headingコンポーネントは、ノーションの見出しブロックをレンダリングします。以下はHeadingコンポーネントをカスタマイズする例です:

import React from "react";
import { Heading, type HeadingArgs } from "@notionpresso/react";

const CustomHeading: React.FC<HeadingArgs> = (props) => {
  // level 3 ヘディングに下線を追加
  if (props.type === "heading_3") {
    return <Heading {...props} style={{ textDecoration: "underline" }} />;
  }
  return <Heading {...props} />;
};

export default CustomHeading;

この例では、level 属性を確認して、特定のレベルのヘディングに対してスタイルを変更しています。

Paragraphコンポーネント

Paragraphコンポーネントは、一般的なテキストブロックをレンダリングします。以下はParagraphコンポーネントをカスタマイズする例です:

import React from "react";
import { Paragraph, type ParagraphArgs } from "@notionpresso/react";

const CustomParagraph: React.FC<ParagraphArgs> = (props) => {
  return (
    <Paragraph
      {...props}
      className="custom-paragraph"
      style={{ lineHeight: "1.8", marginBottom: "1em" }}
    />
  );
};

export default CustomParagraph;

この例では、すべての段落に対して行間と下の余白を調整し、ユーザー定義のクラスを追加しています。

Toggleコンポーネントのカスタマイズ例

Toggleコンポーネントは、ノーションのトグルブロックを実装します。以下はToggleコンポーネントをカスタマイズする高度な例です:

import React, { useState } from "react";
import { Toggle, type ToggleArgs } from "@notionpresso/react";
import { ChevronDown, ChevronRight } from "your-icon-library";

const CustomToggle: React.FC<ToggleArgs> = (props) => {
  const [isOpen, setIsOpen] = useState(false);

  const handleChangeOpen = (open: boolean) => {
    setIsOpen(open);
    // ここに追加のロジックを追加できます。
    console.log(`Toggle state changed to: ${open}`);
  };

  return (
    <Toggle {...props} isOpen={isOpen} onChangeOpen={handleChangeOpen}>
      <Toggle.Icon>
        {isOpen ? <ChevronDown size={20} /> : <ChevronRight size={20} />}
      </Toggle.Icon>
      <Toggle.Content>{props.children}</Toggle.Content>
    </Toggle>
  );
};

export default CustomToggle;

この例では:

  1. useStateを使用してトグルの開閉状態を管理します。
  2. handleChangeOpen関数を使用して状態の変更を処理し、必要に応じて追加のロジックを実装できます。
  3. ToggleコンポーネントにisOpenonChangeOpenプロップを渡して状態を直接制御します。
  4. isOpen状態に応じて異なるアイコンを表示します。

<Toggle.Icon>にコンテンツを提供しない場合、デフォルトのアイコンが使用されます。

カスタムコンポーネントの適用

ノーションプレッソでカスタムコンポーネントを使用する方法は以下の通りです:

import { Notion } from "@notionpresso/react";
import CustomHeading from "./CustomHeading";
import CustomParagraph from "./CustomParagraph";
import CustomToggle from "./CustomToggle";

const MyNotionPage = ({ pageData }) => {
  const customComponents = {
    heading_1: CustomHeading,
    heading_2: CustomHeading,
    heading_3: CustomHeading,
    paragraph: CustomParagraph,
    toggle: CustomToggle,
  };

  return (
    <Notion custom={customComponents}>
      <Notion.Body>
        <Notion.Blocks blocks={pageData.blocks} />
      </Notion.Body>
    </Notion>
  );
};

この例では、customプロップを使用してカスタムコンポーネントをNotionコンポーネントに渡します。各ブロックタイプに対してカスタムコンポーネントを指定できます。

完全なカスタムコンポーネントの作成

ノーションプレッソの基本コンポーネントを使用せずに、完全に新しいコンポーネントを作成することも可能です。以下はTodoコンポーネントを最初から作成する例です:

import React from "react";
import { RichText, type TodoProps } from "@notionpresso/react";

const Todo: React.FC<TodoProps> = ({ children, ...props }) => {
  const {
    to_do: { color, rich_text: texts, checked },
  } = props;

  const colorClass = color !== "default" ? `notion-${color}` : "";

  return (
    <div className={`notion-block notion-to-do ${colorClass}`}>
      <div className="notion-to-do-item">
        <div className="notion-to-do-item-content">
          <input
            type="checkbox"
            checked={checked}
            readOnly
            className="notion-to-do-checkbox"
          />
          <div
            className={`notion-to-do-text ${checked ? "notion-to-do-checked" : ""}`}
          >
            <RichText props={texts} />
          </div>
        </div>
        {children}
      </div>
    </div>
  );
};

export default Todo;

この例では、以下の点に注意してください:

  • RichTextコンポーネントのみNotionpressoからインポートします。これは複雑なテキストレンダリングを処理するためです。
  • CSSクラス名はすべてnotion-で始まります。これはNotionpressoのスタイルルールに従っているためです。
  • gnotion-${color}形式のクラスを追加します。デフォルトの色("default")の場合、追加のクラスは適用されません。
  • コンポーネントはchildrenプロップを受け取り、サブコンテンツをレンダリングできるようにします。これは入れ子構造をサポートするためです。

コンポーネントの作成時に注意すべき点

  1. 型の安全性: TypeScriptを使用してpropの型を明確に定義してください。Notionpressoから提供される型(例:HeadingArgs, ParagraphArgs)を使用してください。
  2. propの渡し: カスタムコンポーネントで基本コンポーネントにすべてのpropを渡す場合、{...props}を使用してください。これは型の安全性を維持しながら不要なpropの列挙を避けるためです。
  3. スタイルのオーバーライド: 既存のスタイルを完全に置き換えるのではなく、classNameを追加するか、styleプロップを拡張する方法を使用してください。
  4. パフォーマンスの考慮: 不要なリレンダリングを避けるために、React.memouseMemo, useCallbackを適切に使用してください。
  5. アクセシビリティ: カスタムコンポーネントを作成する際にアクセシビリティ(a11y)を考慮してください。例えば、トグルボタンに適切なaria-属性を追加することが推奨されます。
  6. テーマのサポート: Notionpressoのテーマシステムと互換性があるように、カスタムコンポーネントを設計してください。CSS変数を使用すると、ダークモードなどのテーマの切り替えを簡単にサポートできます。

カスタムコンポーネントの適用

ノーションプレッソでカスタムコンポーネントを使用する方法は以下の通りです:

import { Notion, type NotionPage, type CustomComponents } from 'Notionpresso';
import CustomParagraph from './CustomParagraph';
import CustomToggle from './CustomToggle';

const MyNotionPage = ({ pageData }: { pageData: NotionPage }) => {
  const customComponents = useMemo<CustomComponents>(() => ({
    paragraph: CustomParagraph,
    toggle: CustomToggle,
  }), []);

  return (
    <Notion custom={customComponents}>
    <Notion.Cover cover={pageData.cover} />
      <Notion.Body>
        <Notion.Title title={pageData.title} />
        <Notion.Blocks blocks={pageData.blocks} />
      </Notion.Body>
    </Notion>
  );
};

この例では、customプロップを使用してカスタムコンポーネントをNotionコンポーネントに渡します。

これらのガイドラインに従うことで、Notionpressoの機能を拡張しながら、一貫性と保守性を維持できます。