/widgetly

Library that helps you to create widgets, including widgets that work via an iframe

Primary LanguageTypeScriptMIT LicenseMIT

Widgetly

Widgetly помогает создавать виджеты, в том числе работающие через iframe

Mediator

Медиатор - это инстанция фабрики widgetly, после создания инстанции, можно декларировать виджеты. Если вы используете iframe-виджеты, то этот код нужно размещать в родительском окне.

// ./mediator.js
import widgetly from 'widgetly'

export const mediator = widgetly({
  // префикс для data-атрибутов при вставке виджетов через HTML-код
  prefix: 'rc'
}, {
  myMethod() {
    return 1
  },
  someProp: {
    someMethod() {
      return 2
    }
  }
})

Декларация виджетов

После декларации медиатора, можно начать декларировать виджеты. Виджет декларируется через фабрику, которая имеет следующий интерфейс (поля, отмеченные * - обязательны):

mediator.defineWidget(config, properties)
Название параметра Тип Описание
config Object* Конфиг виджета
config.name String* Название виджета
config.initialize Function* Функция инициализации виджета. Должна возвращать Promise
config.destroy Function Функции уничтожения виджета
config.externalizeAsProvider Function Функция должна экспортировать объект с методами, доступными для this.iframe
config.externalize Function Функция должна экспортировать объект с методами, доступными внешнему потребителю, по умолчанию экспортирует все properties (см. ниже) и свойства, которые экспортировал this.iframe, если он есть
properties Object Дополнительные свойства виджета

Пример встроенного виджета

// ./widget.js
import {mediator} from './mediator'
// импортируем лэйаут встроенного виджета
import {EmbedLayout} from 'widgetly'

// декларируем виджет
mediator.defineWidget({
  // название виджета 
  name: 'EmbedComments',

  // функция инициализации виджета
  // этот метод должен возвращать Promise
  // в этом методе должен отрисовывать виджет
  initialize() {
    // Доступные свойства на момент инициализации:
    // this.params - параметры создания виджета
    // this.container - контейнер виджета
    // this.createIframe(url) - создать айфрейм, привязанный к текущему виджету
    
    return this.container.whenEnterViewport({ lazy: true }).then(() => {
      this.iframe = this.createIframe(iframeUrl)
      this.layout = new EmbedLayout({
        spinner: '<div class="Spinner" />'
      })
      this.layout.showLoading()
      this.layout.addToDOM(this.container)
      this.layout.setContent(this.iframe)
      return this.iframe.initialize().then(() => this.layout.hideLoading())
    })
  }
}, {
  // Все методы, объявленные здесь, обоготят this
  hide() {
    this.layout.hide()
  },

  show() {
    this.layout.show()
  }
})

Пример виджета открываемого в модальном окне

// ./widget.js
import {mediator} from './mediator'
// импортируем лэйаут встроенного виджета
import {OverlayLayout} from 'widgetly'

// декларируем виджет
mediator.defineWidget({
  // название виджета 
  name: 'LoginModal',

  // функция инициализации виджета
  // этот метод должен возвращать Promise
  // в этом методе должен отрисовывать виджет
  initialize() {
    // Доступные свойства на момент инициализации:
    // this.params - параметры создания виджета
    // this.container - контейнер виджета
    // this.createIframe(url) - создать айфрейм, привязанный к текущему виджету
    
    this.iframe = this.createIframe(iframeUrl)
    this.layout = new OverlayLayout({ hidden: true })
    this.layout.setContainer(this.container)
    this.layout.setContent(this.iframe)
    return this.iframe.initialize().then(() => this.layout.show())
  }
})

Лэйаут

Лэйаут представляет собой элемент, в который вставляется iframe и лоадер.

Лэйауты существуют следующих типов:

Тип Описание
EmbedLayout Лэйаут встраиваемый в конкретный элемент на странице
OverlayLayout Лэйаут-оверлей, может использоваться для модальных окон
SidebarLayout Лэйаут для виджета, показываемого в сайдбаре

Каждый лэйаут должен реализовывать следующий интерфейс:

Метод/Свойство Описание
constructor(options) Конструктор класса
initialize(container) Инициализация виджета
showLoading() Показать статус загрузки
hideLoading() Скрыть статус загрузки
setContent({ContentElement}) Установить контент для лэйаута
hide() Скрыть лэйаут
show() Показать лэйаут
destroy() Этот метод должен удалять layout.element из DOM
id уникальный ID лэйаута
events EventEmitter лэйаута. Должен кидать следующие события: destroy
element Рутовый элемент лэйаута

IFrame

Внутри айфрейма нужно обернуть инициализацию вашего виджета:

registerIFrame(config, properties)
Название параметра Тип Описание
config Object* Конфиг
config.initialize Function* Функция инициализации виджета. Должна отрисовывать приложение и возвращать Promise
config.externalizeAsConsumer Function Этот метод должен возвращать фасад с методами, которые будут доступны виджету
config.externalize Function Этот метод должен возвращать фасад с методами, которые видны снаружи виджета
properties Object Дополнительные свойства

Пример инициализации

// ./app.js
import React, {useEffect} from 'react'

export const App = ({transport, onReady}) => {
  useEffect(() => {
    onReady()
  }, [onReady])

  return (
    <TransportContext.Provider value={transport}>
      <main>
        ...
      </main>
    </TransportContext.Provider>
  )
}
// ./iframe.js
import React from 'react'
import {render} from 'react-dom'
import {registerIFrame} from 'widgetly'
import App from './app'

const container = document.getElementById('my_app')

registerIFrame({
  initialize() {
    return new Promise(resolve => {
      const app = (
        <App 
          transport={this} 
          onReady={resolve} 
        />
      )
      render(app, container)
    })
  }
})

Использование виджетов

Медиатор может создавать виджеты автоматически в контейнеры с соответствующими data атрибутами при появлении его в DOM.

// ./app.js
import React from 'react'
import './mediator'

export const App = () => {
  return (
    <div
      data-rc-widget="EmbedComments"
      data-rc-app-id={APP_ID}
      data-rc-page-url={window.location.pathname}
    />
  )
}

Для получения полного контроля над виджета, его можно создавать через фабрику, которая имеет следующий интерфейс (поля, отмеченные * - обязательны):

mediator.buildWidget(name, containerElement, params)
Название параметра Тип Описание
name String* Название виджета
containerElement `HTMLElement String*`
params Object* Параметры инициализации виджета

Пример создания виджета

// ./app.js
import mediator from './mediator'

const container = document.getElementById('my_comments');

mediator.buildWidget('EmbedComments', container, {
  appId: APP_ID,
  pageUrl: window.location.pathname
}).then(widget => {
  // В этот момент можно пользоваться методами инстанции виджета
});

Лицензия

MIT