Николай Ланец
4 июня 2019 г., 23:43

VerticalTimeline

Всем привет!

Сегодня добавился новый элемент, точнее два: VerticalTimeline и VerticalTimelineItem. Используется он для того, чтобы вертикально выводить какие-нибудь сущности с привязкой ко времени (хотя привязка не обязательна). За основу был взят vertical-timeline-component-for-react.

Пример использования можно увидеть здесь: https://front-editor.prisma-cms.com/templates/cjwidh5xcrow20a89w1ms6ahi

Вообще этот компонент интересно изучить с точки зрения кастомизации фронт-редактора. Прежде чем запилить его в ядро, я сделал сначала вот такое на другом проекте: https://youtu.be/9tT4tKdjD38.
Всего за два часа! И это включая добавление кастомного типа объектов в базу данных, резолверы, добавление запросов на создание/редактирование/вывод данных, добавление раздела на сайте и выбор реакт-компонента для рендеринга (из изученных больше всех понравился именно vertical-timeline-component-for-react, хотя и он не идеален и я отправил 3 багрепорта). При чем в процессе разработки раскрыл некоторые незадокументированные возможности фронт-редактора, о которых и сам не очень догадывался :)

К примеру, как оказалось, весьма не сложно кастомизировать активную область компонента: http://joxi.ru/KAgY7JySE9eaom. Мне так хотелось, чтобы визуально было понятно куда кидать внутренние компоненты, так как лейбл в моем случае редактировался в отдельном поле. Вот пример кода.

Здесь есть еще одна причина почему корневой элемент надо было вывести именно так. Дело в том, что сторонний компонент не умеет на себя принимать какие-либо свойства кроме тех, что там прописаны (что не есть правильно ИМХО). Соответственно все, что требуется в режиме редактирования (события клика и наведения, Drag n Drop и т.п.) - все это игнорировалось. При этом данный компонент должен быть прямым потомком для родительского, иначе у него терялась логика с пробрасываемыми в него свойствами. А так получилось и сторонний компонент в прямых потомках вывести, и свои кастомные свойства отрендерить.

Во-вторых, при выводе в цикле, мне захотелось, чтобы прошедшие этапы лейбл был одного цвета, будущие другое, а текущий этап - третьего. http://joxi.ru/KAgY7JySE9V7zm. Подводный камень заключается в том, что нет прямой идентификации, что это текущий этап. По сути текущий - это один из тех, дата старта которых меньше, чем сейчас, просто это последний элемент из таких. А в процессе итерации каждый отдельный элемент выводится в самостоятельном компоненте и просто так всего массива элементов нет в наличии. Но этот массив можно получить через родителя. В объекты класса Iterable передается массив items и его можно получить через свойство parent и в этом массиве уже найти текущий элемент. Вот пример кода:
prepareRootElementProps(props) { const { object, parent, } = props; const { startDateStr, startDate, } = object || {}; const items = parent && parent.props && parent.props.items || []; const current = items.filter(n => n.startDate && moment(n.startDate) < moment()).pop(); /** * 0 - Неизвестно. * 1 - Будущее. * -1 - прошедшее. */ const dateStatus = !startDate ? 0 : moment(startDate) > moment() ? 1 : -1; return { ...super.prepareRootElementProps(props), dateText: startDateStr, dateInnerStyle: { background: current && current === object ? '#61b8ff' : dateStatus === 1 ? 'rgb(150, 150, 150)' : dateStatus === -1 ? "#76bb7f" : undefined, } } }
Данный код просто для примера, потому что в текущей реализации данной логики нет (ибо нет смысла запиливать под какую-то определенную структуру данных). В текущей реализации логика чуть другая: Первый дочерний элемент уходит в лейбл, а остальное все в основную область. http://joxi.ru/vAWlRe5tg6yyLr
И вот с этим пришлось попыхтеть... Хотелось не просто выводить в лейбл первый компонент только в режиме штатного рендеринга, но и хотелось, чтобы его можно было редактировать. А для этого надо было разделить имеющийся массив дочерних компонентов и вывести их в двух разных местах, при чем на входе у нас не готовые react компоненты, а просто JSON-данные. Для этого пришлось довольно большой коммит в ядро отправить. В итоге в лейбл я вывожу первый дочерний компонент через новый метод this.renderComponent(component), который позволяет делать рендер дочерних элементов просто с передачей JSON-данных, а в основную область я отсекаю первый элемент из массива дочерних.

Только в этих случаях важно не нарушать целостность исходного массива дочерних компонентов, иначе попрут коллизии.

Если вдруг вы захотите тоже подобным образом поиграться, напоминаю, что собственный кастомные элементы добавлять несложно, вот подробная статья.

Добавить комментарий