React.js рендер - Rete.js

React.js рендер

Цей гайд є розширенням гайду Базовий редактор і містить детальні інструкції щодо використання rete-react-plugin

БазовийКонтролиКастомізаціяПлагінReact.jsКонтекстне менюМіні-картаЗміна маршруту

Цей плагін використовує класичний пресет, який включає візуальні компоненти для вузлів, з’єднань, сокетів і контроли полів вводу. Він використовує styled-components для стилізації цих компонентів.

Цей плагін можна використовувати в будь-якому додатку, незалежно від стеку (React.js, Vue.js, Angular тощо).

Встановити залежності

bash
npm i rete-react-plugin rete-render-utils styled-components

Якщо ви використовуєте цей плагін у додатку, яка не використовує React.js, обов’язково також установіть необхідні залежності React.js.

bash
npm i react@18 react-dom@18

Connect the plugin

ts
import { createRoot } from "react-dom/client";
import { AreaPlugin } from "rete-area-plugin";
import { ReactPlugin, Presets, ReactArea2D } from "rete-react-plugin";

type AreaExtra = ReactArea2D<Schemes>;

// ....

const render = new ReactPlugin<Schemes, AreaExtra>({ createRoot });

render.addPreset(Presets.classic.setup());

area.use(render);

Перегляньте сторінку Базовий редактор, щоб отримати приклад використання цього плагіна рендерінгу.

Використання React.js 16

У випадку, якщо ви використовуєте React.js версії 16 (або 17), просто видаліть метод createRoot

ts
const render = new ReactPlugin<Schemes, AreaExtra>();

"useRete" хук

Під час роботи з додатком на React хук useRete усуває необхідність шаблонного коду, який прив’язує редактор до елемента HTML. Це особливо важливо для динамічних оновлень додатку, коли старий екземпляр редактора потрібно видалити та замінити новим.

tsx
import { useRete } from 'rete-react-plugin';

function App() {
  const [ref, editor] = useRete(createEditor)

  return <div ref={ref} className="rete"></div>
}

де createEditor має повернути об’єкт із методом destroy (зазвичай він має виклик area.destroy())

Контроли

Цей плагін містить вбудовані контроли, які відображаються на основі таких об’єктів:

  • ClassicPreset.InputControl як <input type="number" /> або <input type="text" />

Просто додайте контрол до вузла

ts
node.addControl('my-control', new ClassicPreset.InputControl("number", {
  initial: 0,
  readonly: false,
  change(value) { }
}))

Якщо ви хочете додати різні типи контролів, ви можете повернути необхідний функціональний компонент в обробнику control властивості customize.

tsx
render.addPreset(Presets.classic.setup({
  customize: {
    control(context) {
      if (context.payload.isButton) {
        return (props: { data: { isButton: true, label: string, onClick: () => void }}) => (
          <button
            onPointerDown={(e) => e.stopPropagation()}
            onClick={props.data.onClick}
          >
            {props.data.label}
          </button>
        )
      }
      if (context.payload instanceof ClassicPreset.InputControl) { // не забудьте явно вказати вбудований Presets.classic.Control
        return Presets.classic.Control;
      }
    }
  }
}));

node.addControl('my-button', { isButton: true, label: 'Click', onClick() {} })

Це спрощена версія, яка підходить для ознайомлення. Для проектів рекомендується дотримуватися підходу, продемонстрованого в прикладі

Обов’язково викликайте stopPropagation в onPointerDown, щоб запобігти перехопленню областю таких подій, як click. Якщо ви зіткнулися з цією проблемою в React 16 або ваші інтерактивні елементи додаються до кастомного вузла замість контрола, спробуйте наступне рішення:

tsx
import { Drag } from "rete-react-plugin";

<Drag.NoDrag>
  <button>
    {props.data.label}
  </button>
</Drag.NoDrag>

Або використовуйте хук, щоб уникнути додаткового вкладення

tsx
const ref = React.useRef(null)

Drag.useNoDrag(ref)

<button ref={ref}>
  {props.data.label}
</button>

Кастомізація

Подібно до підходу, описаного вище, ви можете замінити компоненти вузла, з’єднання або сокета.

Стилізація вузла

Найпростішим підходом є розширення поточного компонента та використання styled-components для додавання стилів.

tsx
import { Presets } from "rete-react-plugin";
import { css } from "styled-components";

const myStyles = css<{ selected?: boolean }>`
  background: white;
  ${(props) => props.selected && css`
    border-color: red;
  `}
`;

function StyledNode(props: { data: Schemes['Node'] }) {
  return <Presets.classic.Node styles={() => myStyles} {...props} />;
}

render.addPreset(Presets.classic.setup({
  customize: {
    node() {
      return StyledNode
    }
  }
}))

Реалізація цього призведе до того, що всі ваші вузли будуть використовувати myStyles.

Специфічні вузли

Ви можете додати умову для застосування цих стилів лише до певних вузлів.

ts
render.addPreset(Presets.classic.setup({
  customize: {
    node(context) {
      if (context.payload.label === "White") {
        return StyledNode;
      }
      return Presets.classic.Node;
    }
  }
}))

await editor.addNode(new ClassicPreset.Node('White'))

Full node customization

Якщо ви хочете повністю змінити структуру вузла, ви можете реалізувати власний компонент, подібний до Node.tsx із класичного пресету.

ts
import { CustomNode } from './CustomNode'

render.addPreset(Presets.classic.setup({
  customize: {
    node() {
      return CustomNode
    }
  }
}))

Реалізація CustomNode доступна у файлі CustomNode.tsx прикладу Кастомізація для React.js.

Повна кастомізація з'єднань

Використовуйте Connection.tsx як відправну точку з presets/classic/components директорії вихідного коду плагіна.

ts
import { CustomConnection } from './CustomConnection'

render.addPreset(Presets.classic.setup({
  customize: {
    connection() {
      return CustomConnection
    }
  }
}))

Повна кастомізація сокета

Використовуйте Socket.tsx як відправну точку з presets/classic/components директорії вихідного коду плагіна.

ts
import { CustomSocket } from './CustomSocket'

render.addPreset(Presets.classic.setup({
  customize: {
    socket() {
      return CustomSocket
    }
  }
}))

Кастомізація контекстне меню

Оскільки компоненти контекстного меню використовують styled-components, ви можете кастомізувати їхні стилі за допомогою:

ts
import styled from "styled-components";

const { Menu, Common, Search, Item, Subitems } = Presets.contextMenu

const CustomMenu = styled(Menu)`
  width: 320px;
`
const CustomItem = styled(Item)`
  background: grey;
`

render.addPreset(Presets.contextMenu.setup({
  customize: {
    main: () => CustomMenu,
    item: () => CustomItem,
    common: () => Common,
    search: () => Search,
    subitems: () => Subitems
  }
}))

Інші пресети

Перегляньте повний результат на сторінці прикладу Кастомізація для React.js.