From 3f4714861bc60805d62cd58136690ee45d678632 Mon Sep 17 00:00:00 2001 From: vincent Date: Thu, 3 Feb 2022 15:32:02 +0100 Subject: [PATCH] Add description to plan category --- .../api/plan_categories_controller.rb | 2 +- .../javascript/components/base/fab-modal.tsx | 67 +-- .../javascript/components/base/rhf-input.tsx | 71 +++ .../base/text-editor/fab-text-editor.tsx | 94 ++++ .../components/base/text-editor/menu-bar.tsx | 168 +++++++ .../plan-categories/delete-plan-category.tsx | 10 +- .../plan-categories/manage-plan-category.tsx | 99 ++++ .../plan-categories/plan-categories-list.tsx | 13 +- .../plan-categories/plan-category-form.tsx | 69 +++ .../src/javascript/models/plan-category.ts | 1 + app/frontend/src/stylesheets/application.scss | 7 +- .../stylesheets/modules/base/fab-button.scss | 2 - .../stylesheets/modules/base/fab-modal.scss | 42 +- .../modules/base/fab-text-editor.scss | 170 +++++++ .../stylesheets/modules/base/rhf-input.scss | 74 +++ .../plan-categories/create-plan-category.scss | 7 - .../plan-categories/edit-plan-category.scss | 10 - .../plan-categories/manage-plan-category.scss | 4 + .../plan-categories/plan-categories-list.scss | 4 + .../src/stylesheets/variables/colors.scss | 48 ++ .../src/stylesheets/variables/typography.scss | 110 +++++ .../api/plan_categories/index.json.jbuilder | 2 +- .../api/plan_categories/show.json.jbuilder | 2 +- config/locales/app.admin.en.yml | 58 +-- config/locales/app.shared.en.yml | 5 + package.json | 10 + yarn.lock | 425 ++++++++++++++++++ 27 files changed, 1441 insertions(+), 133 deletions(-) create mode 100644 app/frontend/src/javascript/components/base/rhf-input.tsx create mode 100644 app/frontend/src/javascript/components/base/text-editor/fab-text-editor.tsx create mode 100644 app/frontend/src/javascript/components/base/text-editor/menu-bar.tsx create mode 100644 app/frontend/src/javascript/components/plan-categories/manage-plan-category.tsx create mode 100644 app/frontend/src/javascript/components/plan-categories/plan-category-form.tsx create mode 100644 app/frontend/src/stylesheets/modules/base/fab-text-editor.scss create mode 100644 app/frontend/src/stylesheets/modules/base/rhf-input.scss delete mode 100644 app/frontend/src/stylesheets/modules/plan-categories/create-plan-category.scss delete mode 100644 app/frontend/src/stylesheets/modules/plan-categories/edit-plan-category.scss create mode 100644 app/frontend/src/stylesheets/modules/plan-categories/manage-plan-category.scss create mode 100644 app/frontend/src/stylesheets/variables/colors.scss create mode 100644 app/frontend/src/stylesheets/variables/typography.scss diff --git a/app/controllers/api/plan_categories_controller.rb b/app/controllers/api/plan_categories_controller.rb index a83998b8f..407bfd0e6 100644 --- a/app/controllers/api/plan_categories_controller.rb +++ b/app/controllers/api/plan_categories_controller.rb @@ -45,6 +45,6 @@ class API::PlanCategoriesController < API::ApiController end def plan_category_params - params.require(:plan_category).permit(:name, :weight) + params.require(:plan_category).permit(:name, :weight, :description) end end diff --git a/app/frontend/src/javascript/components/base/fab-modal.tsx b/app/frontend/src/javascript/components/base/fab-modal.tsx index 7cc4042db..7cc6975d3 100644 --- a/app/frontend/src/javascript/components/base/fab-modal.tsx +++ b/app/frontend/src/javascript/components/base/fab-modal.tsx @@ -1,9 +1,7 @@ -import React, { ReactNode, BaseSyntheticEvent, useEffect, useState } from 'react'; +import React, { ReactNode, BaseSyntheticEvent, useEffect } from 'react'; import Modal from 'react-modal'; import { useTranslation } from 'react-i18next'; import { Loader } from './loader'; -import CustomAssetAPI from '../../api/custom-asset'; -import { CustomAsset, CustomAssetName } from '../../models/custom-asset'; import { FabButton } from './fab-button'; Modal.setAppElement('body'); @@ -36,79 +34,32 @@ interface FabModalProps { export const FabModal: React.FC = ({ title, isOpen, toggleModal, children, confirmButton, className, width = 'sm', closeButton, customHeader, customFooter, onConfirm, preventConfirm, onCreation, onConfirmSendFormId }) => { const { t } = useTranslation('shared'); - const [blackLogo, setBlackLogo] = useState(null); - - // initial request to the API to get the theme's logo, for back backgrounds - useEffect(() => { - CustomAssetAPI.get(CustomAssetName.LogoBlackFile).then(data => setBlackLogo(data)); - }, []); - useEffect(() => { if (typeof onCreation === 'function' && isOpen) { onCreation(); } }, [isOpen]); - /** - * Check if the confirm button should be present - */ - const hasConfirmButton = (): boolean => { - return confirmButton !== undefined; - }; - - /** - * Check if the behavior of the confirm button is to send a form, using the provided ID - */ - const confirmationSendForm = (): boolean => { - return onConfirmSendFormId !== undefined; - }; - - /** - * Should we display the close button? - */ - const hasCloseButton = (): boolean => { - return closeButton; - }; - - /** - * Check if there's a custom footer - */ - const hasCustomFooter = (): boolean => { - return customFooter !== undefined; - }; - - /** - * Check if there's a custom header - */ - const hasCustomHeader = (): boolean => { - return customHeader !== undefined; - }; - return ( + {closeButton && {t('app.shared.buttons.close')}}
- - {blackLogo && {blackLogo.custom_asset_file_attributes.attachment}} - - {!hasCustomHeader() &&

{ title }

} - {hasCustomHeader() && customHeader} + {!customHeader &&

{ title }

} + {customHeader && customHeader}
{children}
-
+ {(customFooter || confirmButton) &&
- {hasCloseButton() && {t('app.shared.buttons.close')}} - {hasConfirmButton() && !confirmationSendForm() && {confirmButton}} - {hasConfirmButton() && confirmationSendForm() && {confirmButton}} - {hasCustomFooter() && customFooter} + {confirmButton && !onConfirmSendFormId && {confirmButton}} + {confirmButton && onConfirmSendFormId && {confirmButton}} + {customFooter && customFooter} -
+
}
); }; diff --git a/app/frontend/src/javascript/components/base/rhf-input.tsx b/app/frontend/src/javascript/components/base/rhf-input.tsx new file mode 100644 index 000000000..941bd5b88 --- /dev/null +++ b/app/frontend/src/javascript/components/base/rhf-input.tsx @@ -0,0 +1,71 @@ +import React, { ReactNode } from 'react'; +import { FieldErrors, UseFormRegister, Validate } from 'react-hook-form'; + +type inputType = string|number|readonly string []; +type ruleTypes = { + required?: boolean | string, + pattern?: RegExp | {value: RegExp, message: string}, + minLenght?: number, + maxLenght?: number, + min?: number, + max?: number, + validate?: Validate; +}; + +interface RHFInputProps { + id: string, + register: UseFormRegister, + label?: string, + tooltip?: string, + defaultValue?: inputType, + icon?: ReactNode, + addOn?: ReactNode, + addOnClassName?: string, + classes?: string, + rules?: ruleTypes, + readOnly?: boolean, + disabled?: boolean, + placeholder?: string, + error?: FieldErrors, + type?: 'text' | 'date' | 'password' | 'url' | 'time' | 'tel' | 'search' | 'number' | 'month' | 'email' | 'datetime-local' | 'week', + step?: number | 'any' +} + +/** + * This component is a template for an input component to use within React Hook Form + */ +export const RHFInput: React.FC = ({ id, register, label, tooltip, defaultValue, icon, classes, rules, readOnly, disabled, type, addOn, addOnClassName, placeholder, error, step }) => { + // Compose classnames from props + const classNames = ` + rhf-input ${classes || ''} + ${error && error[id] ? 'is-incorrect' : ''} + ${rules && rules.required ? 'is-required' : ''} + ${readOnly ? 'is-readOnly' : ''} + ${disabled ? 'is-disabled' : ''}`; + + return ( + + ); +}; diff --git a/app/frontend/src/javascript/components/base/text-editor/fab-text-editor.tsx b/app/frontend/src/javascript/components/base/text-editor/fab-text-editor.tsx new file mode 100644 index 000000000..19b293c20 --- /dev/null +++ b/app/frontend/src/javascript/components/base/text-editor/fab-text-editor.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { react2angular } from 'react2angular'; +import { IApplication } from '../../../models/application'; +import { Loader } from '../loader'; +import { useEditor, EditorContent } from '@tiptap/react'; +import StarterKit from '@tiptap/starter-kit'; +import Placeholder from '@tiptap/extension-placeholder'; +import CharacterCount from '@tiptap/extension-character-count'; +import Underline from '@tiptap/extension-underline'; +import Link from '@tiptap/extension-link'; +import { MenuBar } from './menu-bar'; +import { WarningOctagon } from 'phosphor-react'; + +declare const Application: IApplication; + +interface FabTextEditorProps { + label?: string, + paragraphTools?: boolean, + content?: string, + limit?: number, + onChange?: (content: string) => void, + placeholder?: string, + error?: string, +} + +/** + * This component is a WYSIWYG text editor + */ +export const FabTextEditor: React.FC = ({ label, paragraphTools, content, limit = 400, onChange, placeholder, error }) => { + const { t } = useTranslation('shared'); + const placeholderText = placeholder || t('app.shared.text_editor.placeholder'); + // TODO: Add ctrl+click on link to visit + + // Setup the editor + // Extensions add functionalities to the editor (Bold, Italic…) + // Events fire action (onUpdate -> get the content as HTML) + const editor = useEditor({ + extensions: [ + StarterKit.configure({ + heading: { + levels: [3] + } + }), + Underline, + Link.configure({ + openOnClick: false + }), + Placeholder.configure({ + placeholder: placeholderText + }), + CharacterCount.configure({ + limit + }) + ], + content, + onUpdate: ({ editor }) => { + onChange(editor.getHTML()); + } + }); + + const focusEditor = () => { + editor.commands.focus('start'); + }; + + return ( + <> + {label && } +
+ + +
+ {editor?.storage.characterCount.characters()} / {limit} +
+ {error && +
+ +

{error}

+
+ } +
+ + ); +}; + +const FabTextEditorWrapper: React.FC = ({ label, paragraphTools, content, limit, placeholder, error }) => { + return ( + + + + ); +}; + +Application.Components.component('fabTextEditor', react2angular(FabTextEditorWrapper, ['label', 'paragraphTools', 'content', 'limit', 'placeholder', 'error'])); diff --git a/app/frontend/src/javascript/components/base/text-editor/menu-bar.tsx b/app/frontend/src/javascript/components/base/text-editor/menu-bar.tsx new file mode 100644 index 000000000..4d19ae195 --- /dev/null +++ b/app/frontend/src/javascript/components/base/text-editor/menu-bar.tsx @@ -0,0 +1,168 @@ +import React, { useCallback, useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import useOnclickOutside from 'react-cool-onclickoutside'; +import { Editor } from '@tiptap/react'; +import { TextAa, TextBolder, TextItalic, TextUnderline, LinkSimpleHorizontal, ListBullets, Quotes, Trash, CheckCircle } from 'phosphor-react'; + +interface MenuBarProps { + paragraphTools?: boolean, + editor?: Editor, +} + +/** + * This component is the menu bar for the WYSIWYG text editor + */ +export const MenuBar: React.FC = ({ editor, paragraphTools }) => { + const { t } = useTranslation('shared'); + + const [linkMenu, setLinkMenu] = useState(false); + const resetUrl = { href: '', target: '_blank' }; + const [url, setUrl] = useState(resetUrl); + const ref = useOnclickOutside(() => { + setLinkMenu(false); + }); + + // Reset state values when the link menu is closed + useEffect(() => { + if (!linkMenu) { + setUrl(resetUrl); + } + }, [linkMenu]); + + // Toggle link menu's visibility + const toggleLinkMenu = () => { + if (!linkMenu) { + setLinkMenu(true); + const previousUrl = { + href: editor.getAttributes('link').href, + target: editor.getAttributes('link').target || '' + }; + // display selected text's attributes if it's a link + if (previousUrl.href) { + setUrl(previousUrl); + } + } else { + setLinkMenu(false); + setUrl(resetUrl); + } + }; + + // Set link's target + const toggleTarget = (evt) => { + evt.target.checked + ? setUrl({ href: url.href, target: '_blank' }) + : setUrl({ href: url.href, target: '' }); + }; + + // Update url + const handleChange = (evt) => { + setUrl({ ...url, href: evt.target.value }); + }; + // Support keyboard "Enter" key event to validate + const handleEnter = (evt) => { + if (evt.keyCode === 13) { + setLink(); + } + }; + + // Update the selected link + const setLink = useCallback((closeLinkMenu?: boolean) => { + if (url.href === '') { + unsetLink(); + return; + } + editor.chain().focus().extendMarkRange('link').setLink({ href: url.href, target: url.target }).run(); + if (closeLinkMenu) { + setLinkMenu(false); + } + }, [editor, url]); + + // Remove the link tag from the selected text + const unsetLink = () => { + editor.chain().focus().extendMarkRange('link').unsetLink().run(); + setLinkMenu(false); + }; + + if (!editor) { + return null; + } + + return ( + <> +
+ { paragraphTools && + (<> + + + + + ) + } + + + + +
+
+
+ + +
+
+ + +
+
+ + ); +}; diff --git a/app/frontend/src/javascript/components/plan-categories/delete-plan-category.tsx b/app/frontend/src/javascript/components/plan-categories/delete-plan-category.tsx index cf8644694..35a3026ea 100644 --- a/app/frontend/src/javascript/components/plan-categories/delete-plan-category.tsx +++ b/app/frontend/src/javascript/components/plan-categories/delete-plan-category.tsx @@ -34,9 +34,9 @@ const DeletePlanCategoryComponent: React.FC = ({ onSucc */ const onDeleteConfirmed = (): void => { PlanCategoryAPI.destroy(category.id).then(() => { - onSuccess(t('app.admin.delete_plan_category.category_deleted')); + onSuccess(t('app.admin.manage_plan_category.delete_category.success')); }).catch((error) => { - onError(t('app.admin.delete_plan_category.unable_to_delete') + error); + onError(t('app.admin.manage_plan_category.delete_category.error') + error); }); toggleDeletionModal(); }; @@ -44,13 +44,13 @@ const DeletePlanCategoryComponent: React.FC = ({ onSucc return (
} onClick={toggleDeletionModal} /> - - {t('app.admin.delete_plan_category.delete_confirmation')} + {t('app.admin.manage_plan_category.delete_category.confirm')}
); diff --git a/app/frontend/src/javascript/components/plan-categories/manage-plan-category.tsx b/app/frontend/src/javascript/components/plan-categories/manage-plan-category.tsx new file mode 100644 index 000000000..2ea78b4c2 --- /dev/null +++ b/app/frontend/src/javascript/components/plan-categories/manage-plan-category.tsx @@ -0,0 +1,99 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PlanCategory } from '../../models/plan-category'; +import { FabButton } from '../base/fab-button'; +import { FabModal } from '../base/fab-modal'; +import { Loader } from '../base/loader'; +import { PlanCategoryForm } from './plan-category-form'; + +interface ManagePlanCategoryProps { + category?: PlanCategory, + action: 'create' | 'update', + onSuccess: (message: string) => void, + onError: (message: string) => void, +} + +/** + * This component shows a button. + * When clicked, we show a modal dialog allowing to fill the parameters with a new plan-category. + */ +const ManagePlanCategoryComponent: React.FC = ({ category, action, onSuccess, onError }) => { + const { t } = useTranslation('admin'); + + // is the creation modal open? + const [isOpen, setIsOpen] = useState(false); + // when editing, we store the category here, until the edition is over + const [tempCategory, setTempCategory] = useState(category); + + /** + * Opens/closes the new plan-category (creation) modal + */ + const toggleModal = (): void => { + setIsOpen(!isOpen); + }; + + /** + * Initialize a new plan-category for creation + * or refresh plan-category data for update + */ + const initCategoryCreation = () => { + if (action === 'create') { + setTempCategory({ name: '', description: '', weight: 0 }); + } else { + setTempCategory(category); + } + }; + + /** + * Close the modal if the form submission was successful + */ + const handleSuccess = (message) => { + setIsOpen(false); + onSuccess(message); + }; + + /** + * Render the appropriate button depending on the action type + */ + const toggleBtn = () => { + switch (action) { + case 'create': + return ( + } + className="btn-warning" + onClick={toggleModal}> + {t('app.admin.create_plan_category.new_category')} + + ); + case 'update': + return (} + className="edit-button" + onClick={toggleModal} />); + } + }; + + return ( +
+ { toggleBtn() } + + + {tempCategory && } + + +
+ ); +}; + +export const ManagePlanCategory: React.FC = ({ category, action, onSuccess, onError }) => { + return ( + + + + ); +}; diff --git a/app/frontend/src/javascript/components/plan-categories/plan-categories-list.tsx b/app/frontend/src/javascript/components/plan-categories/plan-categories-list.tsx index 212a235ec..615846d89 100644 --- a/app/frontend/src/javascript/components/plan-categories/plan-categories-list.tsx +++ b/app/frontend/src/javascript/components/plan-categories/plan-categories-list.tsx @@ -5,8 +5,7 @@ import { PlanCategory } from '../../models/plan-category'; import { react2angular } from 'react2angular'; import { Loader } from '../base/loader'; import { IApplication } from '../../models/application'; -import { CreatePlanCategory } from './create-plan-category'; -import { EditPlanCategory } from './edit-plan-category'; +import { ManagePlanCategory } from './manage-plan-category'; import { DeletePlanCategory } from './delete-plan-category'; declare const Application: IApplication; @@ -51,15 +50,15 @@ export const PlanCategoriesList: React.FC = ({ onSucces return (
- +

{t('app.admin.plan_categories_list.categories_list')}

{categories && categories.length === 0 && {t('app.admin.plan_categories_list.no_categories')}} {categories && categories.length > 0 && - - + + + @@ -68,7 +67,7 @@ export const PlanCategoriesList: React.FC = ({ onSucces )} diff --git a/app/frontend/src/javascript/components/plan-categories/plan-category-form.tsx b/app/frontend/src/javascript/components/plan-categories/plan-category-form.tsx new file mode 100644 index 000000000..c02872ac6 --- /dev/null +++ b/app/frontend/src/javascript/components/plan-categories/plan-category-form.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import PlanCategoryAPI from '../../api/plan-category'; +import { PlanCategory } from '../../models/plan-category'; +import { Loader } from '../base/loader'; +import { useForm, Controller, SubmitHandler } from 'react-hook-form'; +import { FabTextEditor } from '../base/text-editor/fab-text-editor'; +import { RHFInput } from '../base/rhf-input'; +import { FabAlert } from '../base/fab-alert'; +import { FabButton } from '../base/fab-button'; + +interface PlanCategoryFormProps { + action: 'create' | 'update', + category: PlanCategory, + onSuccess: (message: string) => void, + onError: (message: string) => void +} + +const PlanCategoryFormComponent: React.FC = ({ action, category, onSuccess, onError }) => { + const { t } = useTranslation('admin'); + + const { register, control, handleSubmit } = useForm({ defaultValues: { ...category } }); + /** + * The action has been confirmed by the user. + * Push the created/updated plan-category to the API. + */ + const onSubmit: SubmitHandler = (data: PlanCategory) => { + switch (action) { + case 'create': + PlanCategoryAPI.create(data).then(() => { + onSuccess(t('app.admin.manage_plan_category.create_category.success')); + }).catch((error) => { + onError(t('app.admin.manage_plan_category.create_category.error') + error); + }); + break; + case 'update': + PlanCategoryAPI.update(data).then(() => { + onSuccess(t('app.admin.manage_plan_category.update_category.success')); + }).catch((error) => { + onError(t('app.admin.manage_plan_category.update_category.error') + error); + }); + break; + } + }; + + return ( +
+ + + + + } /> + + + + {t('app.admin.manage_plan_category.info')} + + {t(`app.admin.manage_plan_category.${action}_category.cta`)} + + ); +}; + +export const PlanCategoryForm: React.FC = ({ action, category, onSuccess, onError }) => { + return ( + + + + ); +}; diff --git a/app/frontend/src/javascript/models/plan-category.ts b/app/frontend/src/javascript/models/plan-category.ts index 5bdac7922..3d9d41d64 100644 --- a/app/frontend/src/javascript/models/plan-category.ts +++ b/app/frontend/src/javascript/models/plan-category.ts @@ -1,5 +1,6 @@ export interface PlanCategory { id?: number, name: string, + description?: string, weight: number, } diff --git a/app/frontend/src/stylesheets/application.scss b/app/frontend/src/stylesheets/application.scss index f01f1461b..132d0b81e 100644 --- a/app/frontend/src/stylesheets/application.scss +++ b/app/frontend/src/stylesheets/application.scss @@ -1,3 +1,5 @@ +@import "variables/colors"; +@import "variables/typography"; @import "app.functions"; @import "bootstrap_and_overrides"; @@ -23,10 +25,12 @@ @import "modules/tour"; @import "modules/base/fab-modal"; @import "modules/base/fab-input"; +@import "modules/base/rhf-input"; @import "modules/base/fab-button"; @import "modules/base/fab-alert"; @import "modules/base/fab-popover"; @import "modules/base/labelled-input"; +@import "modules/base/fab-text-editor"; @import "modules/payment-schedule/payment-schedule-summary"; @import "modules/wallet-info"; @import "modules/document-filters"; @@ -49,8 +53,7 @@ @import "modules/payment/payzen/payzen-update-card-modal"; @import "modules/payment/local-payment/local-payment-modal"; @import "modules/plan-categories/plan-categories-list"; -@import "modules/plan-categories/create-plan-category"; -@import "modules/plan-categories/edit-plan-category"; +@import "modules/plan-categories/manage-plan-category"; @import "modules/plan-categories/delete-plan-category"; @import "modules/machines/machine-card"; @import "modules/machines/machines-list"; diff --git a/app/frontend/src/stylesheets/modules/base/fab-button.scss b/app/frontend/src/stylesheets/modules/base/fab-button.scss index 14a2f76fc..5f70a2d3a 100644 --- a/app/frontend/src/stylesheets/modules/base/fab-button.scss +++ b/app/frontend/src/stylesheets/modules/base/fab-button.scss @@ -46,6 +46,4 @@ &--icon { margin-right: 0.5em; } - - &--icon-only {} } diff --git a/app/frontend/src/stylesheets/modules/base/fab-modal.scss b/app/frontend/src/stylesheets/modules/base/fab-modal.scss index 132f71afc..a6d64d326 100644 --- a/app/frontend/src/stylesheets/modules/base/fab-modal.scss +++ b/app/frontend/src/stylesheets/modules/base/fab-modal.scss @@ -1,6 +1,7 @@ @keyframes slideInFromTop { 0% { transform: translate(0, -25%); } 100% { transform: translate(0, 0); } + } @keyframes fadeIn { @@ -38,6 +39,25 @@ border-radius: 6px; outline: 0; + .modal-btn--close { + position: absolute; + right: 0; + top: 0; + transform: translateY(calc(-100% + 4px)); + padding-bottom: 1rem; + color: var(--gray-soft-lightest); + background-color: transparent; + border: none; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + &:hover { + color: var(--gray-hard-darkest); + background-color: var(--gray-soft-lightest); + cursor: pointer; + } + } + .fab-modal-header { padding: 8px; border-bottom: 1px solid #e5e5e5; @@ -60,6 +80,18 @@ .fab-modal-content { position: relative; padding: 15px; + + form { + display: flex; + flex-direction: column; + + button[type="submit"] { + margin-left: auto; + background-color: var(--secondary); + border: none; + &:hover { background-color: var(--secondary-dark);} + } + } } .fab-modal-footer { @@ -69,16 +101,6 @@ border-top: 1px solid #e5e5e5; .modal-btn { - &--close { - color: black; - background-color: #fbfbfb; - border: 1px solid #c9c9c9; - - &:hover { - background-color: #f2f2f2; - } - } - &--confirm { margin-left: 0.5em; } diff --git a/app/frontend/src/stylesheets/modules/base/fab-text-editor.scss b/app/frontend/src/stylesheets/modules/base/fab-text-editor.scss new file mode 100644 index 000000000..dc2068a69 --- /dev/null +++ b/app/frontend/src/stylesheets/modules/base/fab-text-editor.scss @@ -0,0 +1,170 @@ +.fab-textEditor { + position: relative; + margin-bottom: 1.6rem; + padding-bottom: 1.6rem; + background-color: var(--gray-soft-lightest); + border: 1px solid var(--gray-soft-dark); + // TODO: border radius from variable + border-radius: 8px; + + &-label { + display: block; + margin-bottom: 0.8rem; + } + + @mixin button($height, $width: $height) { + width: $width; + height: $height; + display: flex; + justify-content: center; + align-items: center; + border-radius: 4px; + color: var(--gray-hard-darkest); + background-color: transparent; + border: none; + &.is-active { color: var(--information); } + &:hover { + background-color: var(--gray-soft); + cursor: pointer; + } + } + + &-menu { + display: flex; + align-items: center; + padding: 0.8rem; + border-bottom: 1px solid var(--gray-soft-darkest); + & > *:not(:last-child) { + margin-right: 4px; + } + + button { @include button(4rem); } + .divider { + width: 2px; + height: 2.4rem; + background-color: var(--gray-soft-dark); + border-radius: 1px; + } + } + + // tiptap class for the editor + .ProseMirror { + padding: 1.6rem 1.6rem 1.2rem; + &:focus { outline: none; } + @include editor; + } + + &-character-count { + padding-right: 1.6rem; + @include text-sm; + text-align: right; + color: var(--gray-hard-lightest); + } + + &-linkMenu { + position: absolute; + top: 4.5rem; + right: 0; + left: 0; + max-width: 50ch; + margin: 0 0.8rem; + padding: 1.2rem; + background-color: var(--gray-soft-lightest); + border: 1px solid var(--gray-soft-darkest); + border-radius: 8px; + // TODO: shadow from variable + box-shadow: 0 0 10px rgba(39, 32, 32, 0.25); + opacity: 0; + pointer-events: none; + transition: opacity 0.25s ease-out; + z-index: 10; + &.is-active { + opacity: 1; + pointer-events: all; + } + & > div { + display: flex; + align-items: center + } + .url { + margin-bottom: 0.8rem; + input { + width: 100%; + height: 4rem; + margin-right: 1.2rem; + padding: 0.4rem 0.8rem; + background-color: var(--gray-soft-light); + border: 1px solid var(--secondary); + border-radius: 8px; + font-size: var(--text-base); + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + &::placeholder { color: var(--gray-soft-darkest);} + } + } + .tab { + display: flex; + align-items: center; + margin: 0; + cursor: pointer; + p { + margin: 0 1.2rem 0 0; + @include text-sm(); + color: var(--gray-hard); + } + input[type="checkbox"] { opacity: 0; width: 0; height: 0; } + .switch { + position: relative; + width: 3.6rem; + height: 2rem; + background-color: var(--gray-soft); + border-radius: 2rem; + &::after { + content: ""; + position: absolute; + left: 0; + width: 2rem; + height: 2rem; + background-color: var(--gray-soft-lightest); + border: 2px solid var(--gray-soft); + border-radius: 2rem; + } + } + input:checked + .switch { background-color: var(--information); } + input:checked + .switch::after { + left: auto; + right: 0; + border-color: var(--information); + } + } + + button { + @include button(3.2rem); + margin-left: auto; + } + } + + &-error { + position: absolute; + top: 4.5rem; + right: 0; + left: 0; + display: flex; + max-width: 50ch; + margin: 0 0.8rem; + padding: 1.2rem; + color: var(--main-dark); + background-color: var(--main-lightest); + border: 1px solid var(--main-light); + border-radius: 8px; + // TODO: shadow from variable + box-shadow: 0 0 10px rgba(39, 32, 32, 0.25); + + svg { + flex-shrink: 0; + margin-right: 1.2rem; + } + p { margin: 0; } + } +} diff --git a/app/frontend/src/stylesheets/modules/base/rhf-input.scss b/app/frontend/src/stylesheets/modules/base/rhf-input.scss new file mode 100644 index 000000000..8d9a19a2a --- /dev/null +++ b/app/frontend/src/stylesheets/modules/base/rhf-input.scss @@ -0,0 +1,74 @@ +.rhf-input { + width: 100%; + margin-bottom: 1.6rem; + + &-header { + width: 100%; + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 0.8rem; + p { margin: 0; } + } + &.is-required &-header p::after { + content: "*"; + margin-left: 0.5ch; + color: var(--error); + } + + &-field { + height: 4rem; + display: grid; + grid-template-areas: "icon input addon"; + grid-template-columns: min-content 1fr min-content; + border: 1px solid var(--gray-soft-dark); + border-radius: 4px; + overflow: hidden; + transition: border-color ease-in-out 0.15s; + + .icon, + .addon { + width: 4rem; + display: flex; + justify-content: center; + align-items: center; + color: var(--gray-hard-light); + background-color: var(--gray-soft); + } + .icon { + grid-area: icon; + border-right: 1px solid var(--gray-soft-dark); + } + input { + grid-area: input; + border: none; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .08); + padding: 0 0.8rem; + color: var(--gray-hard-darkest); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .addon { + grid-area: addon; + border-left: 1px solid var(--gray-soft-dark); + } + } + &.is-incorrect &-field { + border-color: var(--error); + .icon { + color: var(--error); + border-color: var(--error); + background-color: var(--error-lightest); + } + } + &.is-disabled &-field input, + &.is-readOnly &-field input { + background-color: var(--gray-soft-light); + } + + &-error { + margin-top: 0.4rem; + color: var(--error); + } +} diff --git a/app/frontend/src/stylesheets/modules/plan-categories/create-plan-category.scss b/app/frontend/src/stylesheets/modules/plan-categories/create-plan-category.scss deleted file mode 100644 index b5ca81cae..000000000 --- a/app/frontend/src/stylesheets/modules/plan-categories/create-plan-category.scss +++ /dev/null @@ -1,7 +0,0 @@ -.create-plan-category {} - -.create-plan-category-modal { - .significance-info { - margin-top: 10px; - } -} diff --git a/app/frontend/src/stylesheets/modules/plan-categories/edit-plan-category.scss b/app/frontend/src/stylesheets/modules/plan-categories/edit-plan-category.scss deleted file mode 100644 index fa1570b9a..000000000 --- a/app/frontend/src/stylesheets/modules/plan-categories/edit-plan-category.scss +++ /dev/null @@ -1,10 +0,0 @@ -.edit-plan-category { - display: inline; - margin-right: 5px; -} - -.edit-plan-category-modal { - .significance-info { - margin-top: 10px; - } -} diff --git a/app/frontend/src/stylesheets/modules/plan-categories/manage-plan-category.scss b/app/frontend/src/stylesheets/modules/plan-categories/manage-plan-category.scss new file mode 100644 index 000000000..4932f14dc --- /dev/null +++ b/app/frontend/src/stylesheets/modules/plan-categories/manage-plan-category.scss @@ -0,0 +1,4 @@ +.manage-plan-category { + display: inline; + margin-right: 5px; +} diff --git a/app/frontend/src/stylesheets/modules/plan-categories/plan-categories-list.scss b/app/frontend/src/stylesheets/modules/plan-categories/plan-categories-list.scss index 72f8bc6e5..c2f1834b0 100644 --- a/app/frontend/src/stylesheets/modules/plan-categories/plan-categories-list.scss +++ b/app/frontend/src/stylesheets/modules/plan-categories/plan-categories-list.scss @@ -19,7 +19,11 @@ border-color: #c9c9c9; } + .category-weight { + width: 13ch; + } .category-actions { + width: 110px; text-align: right; } } diff --git a/app/frontend/src/stylesheets/variables/colors.scss b/app/frontend/src/stylesheets/variables/colors.scss new file mode 100644 index 000000000..708531e7f --- /dev/null +++ b/app/frontend/src/stylesheets/variables/colors.scss @@ -0,0 +1,48 @@ +:root { + --gray-soft-lightest: #FFFFFF; + --gray-soft-light: #F5F5F5; + --gray-soft: #E5E5E5; + --gray-soft-dark: #D1D1D1; + --gray-soft-darkest: #A3A3A3; + + --gray-hard-lightest: #757575; + --gray-hard-light: #575757; + --gray-hard: #383838; + --gray-hard-dark: #1F1F1F; + --gray-hard-darkest: #0F0F0F; + + --main-lightest: #FDF1F1; + --main-light: #F6ACAC; + --main: #E72223; + --main-dark: #BC1415; + --main-darkest: #57090A; + + --secondary-light: #FFF8B3; + --secondary: #FDE500; + --secondary-dark: #CCB800; + --secondary-darkest: #3D3700; + + --success-lightest: #E3FCEC; + --success-light: #88E8AA; + --success: #259D58; + --success-dark: #229051; + --success-darkest: #155239; + + --error-lightest: #FDF1F1; + --error-light: #EA8585; + --error: #DA3030; + --error-dark: #9F1D1D; + --error-darkest: #611818; + + --information-lightest: #EFF6FF; + --information-light: #93C5FD; + --information: #1A5DF9; + --information-dark: #1E3A8A; + --information-darkest: #122354; + + --warning-lightest: #FFFCF4; + --warning-light: #FAE29F; + --warning: #D6AE47; + --warning-dark: #8C6D1F; + --warning-darkest: #5C4813; +} diff --git a/app/frontend/src/stylesheets/variables/typography.scss b/app/frontend/src/stylesheets/variables/typography.scss new file mode 100644 index 000000000..156b8144b --- /dev/null +++ b/app/frontend/src/stylesheets/variables/typography.scss @@ -0,0 +1,110 @@ +// Font +@import url('https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap'); + +:root { + --font-text: 'Work Sans', sans-serif; +} + +// Title +@mixin title-xl { + font-family: var(--font-text); + font-weight: 700; + font-size: 4rem; + line-height: 1.175; +} +@mixin title-lg { + font-family: var(--font-text); + font-weight: 600; + font-size: 2.8rem; + line-height: 1.175; +} +@mixin title-base { + font-family: var(--font-text); + font-weight: 600; + font-size: 2rem; + line-height: 1.175; +} +@mixin title-sm { + font-family: var(--font-text); + font-weight: 400; + font-size: 1.8rem; + line-height: 1.175; +} + +// Text +@mixin text-xl { + font-family: var(--font-text); + font-weight: 500; + font-size: 2rem; + line-height: 1.175; +} +@mixin text-lg($weight: normal) { + font-family: var(--font-text); + font-weight: $weight; + font-size: 1.8rem; + line-height: normal; +} +@mixin text-base($weight: normal) { + font-family: var(--font-text); + font-weight: $weight; + font-size: 1.6rem; + line-height: normal; +} +@mixin text-sm($weight: normal) { + font-family: var(--font-text); + font-weight: $weight; + font-size: 1.4rem; + line-height: normal; +} + +// Text Editor +@mixin editor { + *:first-child { + margin-top: 0; + } + h3 { + @include text-lg(600); + margin: 0 0 1rem; + color: var(--gray-hard-darkest); + } + ul { + padding-inline-start: 2.2rem; + } + blockquote { + position: relative; + margin: 2rem 0; + padding: 0.3rem 1.2rem; + border: none; + font-style: italic; + &::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 4px; + border-radius: 2px; + background-color: var(--gray-hard-darkest); + } + } + + p { @include text-base; } + p:last-of-type { margin: 0; } + //placeholder + p.is-editor-empty:first-child:before { + content: attr(data-placeholder); + height: 0; + float: left; + pointer-events: none; + color: var(--gray-soft-darkest); + } + + strong { font-weight: 600; } + em { font-style: italic; } + u { text-decoration: underline; } + + a { + color: var(--main-dark); + text-decoration: underline; + } +} diff --git a/app/views/api/plan_categories/index.json.jbuilder b/app/views/api/plan_categories/index.json.jbuilder index fb63cd67c..65e94b01b 100644 --- a/app/views/api/plan_categories/index.json.jbuilder +++ b/app/views/api/plan_categories/index.json.jbuilder @@ -1,5 +1,5 @@ # frozen_string_literal: true json.array!(@categories) do |category| - json.extract! category, :id, :name, :weight + json.extract! category, :id, :name, :weight, :description end diff --git a/app/views/api/plan_categories/show.json.jbuilder b/app/views/api/plan_categories/show.json.jbuilder index 85366f247..2df946d08 100644 --- a/app/views/api/plan_categories/show.json.jbuilder +++ b/app/views/api/plan_categories/show.json.jbuilder @@ -1,3 +1,3 @@ # frozen_string_literal: true -json.extract! @category, :id, :name, :weight +json.extract! @category, :id, :name, :weight, :description diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index e4cc9de5a..4104590f3 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -435,6 +435,35 @@ en: edit_extended_price: "Edit the extended price" confirm_changes: "Confirm changes" extended_price_successfully_updated: "The extended price was successfully updated." + plans_categories: + manage_plans_categories: "Manage plans' categories" + plan_categories_list: + categories_list: "List of the plan's categories" + no_categories: "No categories" + name: "Name" + description: "Description" + significance: "Significance" + manage_plan_category: + name: "Name" + description: "Description" + significance: "Significance" + info: "Categories will be shown ordered by signifiance. The higher you set the significance, the first the category will be shown." + create_category: + title: "New category" + cta: "Create the category" + success: "The new category was successfully created" + error: "Unable to create the category: " + update_category: + title: "Edit the category" + cta: "Validate" + success: "The category was successfully updated" + error: "Unable to update the category: " + delete_category: + title: "Delete a category" + confirm: "Are you sure you want to delete this category? If you do, the plans associated with this category won't be sorted anymore." + cta: "Delete" + success: "The category was successfully deleted" + error: "Unable to delete the category: " #ajouter un code promotionnel coupons_new: add_a_coupon: "Add a coupon" @@ -1427,35 +1456,6 @@ en: report_will_be_destroyed: "Once the report has been processed, it will be deleted. This can't be undone, continue?" report_removed: "The report has been deleted" failed_to_remove: "An error occurred, unable to delete the report" - plans_categories: - manage_plans_categories: "Manage plans' categories" - plan_categories_list: - categories_list: "List of the plan's categories" - no_categories: "No categories" - name: "Name" - significance: "Significance" - create_plan_category: - new_category: "New category" - name: "Name" - significance: "Significance" - significance_info: "Categories will be shown ordered by signifiance. The higher you set the significance, the first the category will be shown." - confirm_create: "Create the category" - category_created: "The new category was successfully created" - unable_to_create: "Unable to create the category: " - edit_plan_category: - edit_category: "Edit the category" - name: "Name" - significance: "Significance" - confirm_edition: "Validate" - category_updated: "The category was successfully updated" - unable_to_update: "Unable to update the category: " - significance_info: "Categories will be shown ordered by signifiance. The higher you set the significance, the first the category will be shown." - delete_plan_category: - delete_category: "Delete a category" - confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this category? If you do, the plans associated with this category won't be sorted anymore." - category_deleted: "The category was successfully deleted" - unable_to_delete: "Unable to delete the category: " local_payment: validate_cart: "Validate my cart" offline_payment: "Payment on site" diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index b7f029d88..cca1ce37e 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -23,6 +23,11 @@ en: you_will_lose_any_unsaved_modification_if_you_reload_this_page: "You will lose any unsaved modification if you reload this page" payment_card_error: "A problem has occurred with your credit card:" payment_card_declined: "Your card was declined." + #text editor + text_editor: + placeholder: "Type something…" + link_placeholder: "Paste link…" + new_tab: "Open in a new tab" #user edition form user: man: "Man" diff --git a/package.json b/package.json index 5843e905d..16c1ae9b9 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,13 @@ "@lyracom/embedded-form-glue": "^0.3.3", "@stripe/react-stripe-js": "^1.4.0", "@stripe/stripe-js": "^1.13.2", + "@tiptap/core": "^2.0.0-beta.1", + "@tiptap/extension-character-count": "^2.0.0-beta.24", + "@tiptap/extension-link": "^2.0.0-beta.36", + "@tiptap/extension-placeholder": "^2.0.0-beta.47", + "@tiptap/extension-underline": "^2.0.0-beta.22", + "@tiptap/react": "^2.0.0-beta.107", + "@tiptap/starter-kit": "^2.0.0-beta.180", "@types/angular": "^1.7.3", "@types/prop-types": "^15.7.2", "@types/react": "^17.0.3", @@ -118,11 +125,14 @@ "ngUpload": "0.5", "ngtemplate-loader": "^2.1.0", "nvd3": "1.8", + "phosphor-react": "^1.4.0", "process": "^0.11.10", "prop-types": "^15.7.2", "rails-erb-loader": "^5.5.2", "react": "^17.0.2", + "react-cool-onclickoutside": "^1.7.0", "react-dom": "^17.0.2", + "react-hook-form": "^7.25.3", "react-i18next": "^11.15.6", "react-modal": "^3.11.2", "react-select": "^4.3.1", diff --git a/yarn.lock b/yarn.lock index 76dca88dd..2e023a086 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1398,6 +1398,11 @@ schema-utils "^3.0.0" source-map "^0.7.3" +"@popperjs/core@^2.9.0": + version "2.11.5" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" + integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== + "@stripe/react-stripe-js@^1.4.0": version "1.4.1" resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.4.1.tgz#884d59286fff00ba77389b32c045516f65d7a340" @@ -1410,6 +1415,212 @@ resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.15.1.tgz#a3809ecc5aa8a03bd261a2f970d11cfdcbf11c4f" integrity sha512-yJiDGutlwu25iajCy51VRJeoH3UMs+s5qVIDGfmPUuFpZ+F6AJ9g9EFrsBNvHxAGBahQFMLlBdzlCVydhGp6tg== +"@tiptap/core@^2.0.0-beta.1", "@tiptap/core@^2.0.0-beta.175": + version "2.0.0-beta.175" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.175.tgz#d23f6e60308cde192451121e21df83c256bdcd92" + integrity sha512-dDf+2GtifskNLysn49kaCIz0o5hf6VDZ8J7jSQAfoPDEkEkfw9OKhWrR7NzWW6J34CSJreFDRiWkGt8Qz283Vg== + dependencies: + "@types/prosemirror-commands" "^1.0.4" + "@types/prosemirror-keymap" "^1.0.4" + "@types/prosemirror-model" "^1.16.0" + "@types/prosemirror-schema-list" "^1.0.3" + "@types/prosemirror-state" "^1.2.8" + "@types/prosemirror-transform" "^1.1.5" + "@types/prosemirror-view" "^1.23.1" + prosemirror-commands "^1.2.1" + prosemirror-keymap "^1.1.5" + prosemirror-model "^1.16.1" + prosemirror-schema-list "^1.1.6" + prosemirror-state "^1.3.4" + prosemirror-transform "^1.3.3" + prosemirror-view "^1.23.6" + +"@tiptap/extension-blockquote@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.26.tgz#e5ae4b7bd9376db37407a23e22080c7b11287f3b" + integrity sha512-A6yjcYovONJfOjQFk6vDYXswaCdCtCwjL7w9VTB0R2DLTuJvvRt9DWN0IDcMrj5G+aMgDq4GUUTitv+2Y8krDg== + +"@tiptap/extension-bold@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.26.tgz#aa1c7850df28cec8e0614fde437183bd4ae3e66b" + integrity sha512-pnO0I5sEQM3pmowjMGQ74adLzvc6HqGyLyqMizaGMicPu9uTYlSdId+qckYEEgPwPMaEShtv2Vg+ZHs7KVqfcg== + +"@tiptap/extension-bubble-menu@^2.0.0-beta.56": + version "2.0.0-beta.56" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.56.tgz#d99cb673610a3af7e12444f4538463c7c58bfa04" + integrity sha512-nZozwauICdaNPmDPrSn1JFd/9/2rLtK8i2vBOcqxWHObVROvu8ZlJspnrJv23vS6P7/ZO3e/QLVHpnn+1yVq3g== + dependencies: + prosemirror-state "^1.3.4" + prosemirror-view "^1.23.6" + tippy.js "^6.3.7" + +"@tiptap/extension-bullet-list@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.26.tgz#b42126d2d984c04041b14037e8d3ec1bcf16e7ec" + integrity sha512-1n5HV8gY1tLjPk4x48nva6SZlFHoPlRfF6pqSu9JcJxPO7FUSPxUokuz4swYNe0LRrtykfyNz44dUcxKVhoFow== + +"@tiptap/extension-character-count@^2.0.0-beta.24": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-character-count/-/extension-character-count-2.0.0-beta.26.tgz#c1730f759da5782b04dddd6fb03da55a6a282b36" + integrity sha512-x2CRg6njaKPhVj5o5fdWR3Wbz0kRDq1V/lp5SopkRNxntVY6cAi3ceie/S4kI/Yhcu7345jNJqYmsZlLPGhuSQ== + dependencies: + prosemirror-model "^1.16.1" + prosemirror-state "^1.3.4" + +"@tiptap/extension-code-block@^2.0.0-beta.37": + version "2.0.0-beta.37" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.37.tgz#c07c007248a21d9e0434458fd05c363b7078227f" + integrity sha512-mJAM+PHaNoKRYwM3D36lZ51/aoPxxvZNQn3UBnZ6G7l0ZJSgB3JvBEzqK6S8nNFeYIIxGwv4QF6vXe4MG9ie2g== + dependencies: + prosemirror-state "^1.3.4" + +"@tiptap/extension-code@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.26.tgz#bbfa600a252ee2cded6947b56b6c4c33d998e53a" + integrity sha512-QcFWdEFfbJ1n5UFFBD17QPPAJ3J5p/b7XV484u0shCzywO7aNPV32QeHy1z0eMoyZtCbOWf6hg/a7Ugv8IwpHw== + +"@tiptap/extension-document@^2.0.0-beta.15": + version "2.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.15.tgz#5d17a0289244a913ab2ef08e8495a1e46950711e" + integrity sha512-ypENC+xUYD5m2t+KOKNYqyXnanXd5fxyIyhR1qeEEwwQwMXGNrO3kCH6O4mIDCpy+/WqHvVay2tV5dVsXnvY8w== + +"@tiptap/extension-dropcursor@^2.0.0-beta.25": + version "2.0.0-beta.25" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.25.tgz#962f290a200259533a26194daca5a4b4a53e72d3" + integrity sha512-GYf5s6dkZtsDy+TEkrQK6kLbfbitG4qnk02D+FlhlJMI/Nnx8rYCRJbwEHDdqrfX7XwZzULMqqqHvzxZYrEeNg== + dependencies: + "@types/prosemirror-dropcursor" "^1.0.3" + prosemirror-dropcursor "^1.4.0" + +"@tiptap/extension-floating-menu@^2.0.0-beta.51": + version "2.0.0-beta.51" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.51.tgz#a1e53fd1c1d2ac00025d7f094d2b62eb08e81902" + integrity sha512-rEe7jADK9xr2n2LJsrGEN3Dz7sEGC1JT/7AdTdaZBxQRQvwxTjomqYGrt+LnX+v0MYggh6swMzj7upJosnKbBg== + dependencies: + prosemirror-state "^1.3.4" + prosemirror-view "^1.23.6" + tippy.js "^6.3.7" + +"@tiptap/extension-gapcursor@^2.0.0-beta.34": + version "2.0.0-beta.34" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.34.tgz#0e4971affb1621934422dd5fc4bf2dd7a84f70f7" + integrity sha512-Vm8vMWWQ2kJcUOLfB5CEo5pYgyudI7JeeiZvX9ScPmUmgKVYhEpt3EAICY9pUYJ41aAVH35gZLXkUtsz2f9GHw== + dependencies: + "@types/prosemirror-gapcursor" "^1.0.4" + prosemirror-gapcursor "^1.2.1" + +"@tiptap/extension-hard-break@^2.0.0-beta.30": + version "2.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.30.tgz#165494f1194a7bad08907e6d64d349dd15851b72" + integrity sha512-X9xj/S+CikrbIE7ccUFVwit5QHEbflnKVxod+4zPwr1cxogFbE9AyLZE2MpYdx3z9LcnTYYi9leBqFrP4T/Olw== + +"@tiptap/extension-heading@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.26.tgz#112b14b4d488772bda36abbf7cb2bc8aba7c42f5" + integrity sha512-nR6W/3rjnZH1Swo7tGBoYsmO6xMvu9MGq6jlm3WVHCB7B3CsrRvCkTwGjVIbKTaZC4bQfx5gvAUpQFvwuU+M5w== + +"@tiptap/extension-history@^2.0.0-beta.21": + version "2.0.0-beta.21" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.21.tgz#5d96a17a83a7130744f0757a3275dd5b11eb1bf7" + integrity sha512-0v8Cl30V4dsabdpspLdk+f+lMoIvLFlJN5WRxtc7RRZ5gfJVxPHwooIKdvC51brfh/oJtWFCNMRjhoz0fRaF9A== + dependencies: + "@types/prosemirror-history" "^1.0.3" + prosemirror-history "^1.2.0" + +"@tiptap/extension-horizontal-rule@^2.0.0-beta.31": + version "2.0.0-beta.31" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.31.tgz#efb383a6cedbbf4f2175d7d207eaeeba626faab0" + integrity sha512-MNc4retfjRgkv3qxqGya0+/BEd1Kmn+oMsCRvE+8x3sXyKIse+vdqMuG5qUcA6np0ZD/9hh1riiQ1GQdgc23Ng== + dependencies: + prosemirror-state "^1.3.4" + +"@tiptap/extension-italic@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.26.tgz#b00c9e32b81b1bd94eaed24bb2a22e44d5dc54a3" + integrity sha512-vejGe2ra4K5ipFOn1U9viqF9X9nPTX8WSJpSOux+9UbKjHpANy7bz69tp66OIi/Wh5L/MMDc+luH/04qfVnpZw== + +"@tiptap/extension-link@^2.0.0-beta.36": + version "2.0.0-beta.37" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.37.tgz#8d569284b82860e6a9aac42b85ed9c0911e50599" + integrity sha512-G5sM1a8Kjm1ZMro+BGsk+yApIDMl7RF/u1PY929HHld7JPsjgB+DZbbQ1U7e9Kxiu/9aDwgOa+w+SLqLiajedw== + dependencies: + linkifyjs "^3.0.5" + prosemirror-model "^1.16.1" + prosemirror-state "^1.3.4" + +"@tiptap/extension-list-item@^2.0.0-beta.20": + version "2.0.0-beta.20" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.20.tgz#7169528b226dee4590e013bdf6e5fc6d83729b0f" + integrity sha512-5IPEspJt38t9ROj4xLUesOVEYlTT/R9Skd9meHRxJQZX1qrzBICs5PC/WRIsnexrvTBhdxpYgCYjpvpsJBlKuQ== + +"@tiptap/extension-ordered-list@^2.0.0-beta.27": + version "2.0.0-beta.27" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.27.tgz#ed48a53a9b012d578613b68375db31e8664bfdc9" + integrity sha512-apFDeignxdZb3cA3p1HJu0zw1JgJdBYUBz1r7f99qdNybYuk3I/1MPUvlOuOgvIrBB/wydoyVDP+v9F7QN3tfQ== + +"@tiptap/extension-paragraph@^2.0.0-beta.23": + version "2.0.0-beta.23" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.23.tgz#2ab77308519494994d7a9e5a4acd14042f45f28c" + integrity sha512-VWAxyzecErYWk97Kv/Gkghh97zAQTcaVOisEnYYArZAlyYDaYM48qVssAC/vnRRynP2eQxb1EkppbAxE+bMHAA== + +"@tiptap/extension-placeholder@^2.0.0-beta.47": + version "2.0.0-beta.48" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.0-beta.48.tgz#aff02fbdcd27772ff503b5f84a2f1d83da846006" + integrity sha512-TZNGAHocPoV5DtB8Q5BwQU2uf5vDiwLxbgVHRAIme9P4VsVqa/U1i1TkyN5A5BVdfOzc+E4EOU7cKuyjy7DNyA== + dependencies: + prosemirror-model "^1.16.1" + prosemirror-state "^1.3.4" + prosemirror-view "^1.23.6" + +"@tiptap/extension-strike@^2.0.0-beta.27": + version "2.0.0-beta.27" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.27.tgz#c5187bf3c28837f95a5c0c0617d0dd31c318353d" + integrity sha512-2dmCgtesuDdivM/54Q+Y6Tc3JbGz1SkHP6c62piuqBiYLWg3xa16zChZOhfN8szbbQlBgLT6XRTDt3c2Ux+Dug== + +"@tiptap/extension-text@^2.0.0-beta.15": + version "2.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.15.tgz#f08cff1b78f1c6996464dfba1fef8ec1e107617f" + integrity sha512-S3j2+HyV2gsXZP8Wg/HA+YVXQsZ3nrXgBM9HmGAxB0ESOO50l7LWfip0f3qcw1oRlh5H3iLPkA6/f7clD2/TFA== + +"@tiptap/extension-underline@^2.0.0-beta.22": + version "2.0.0-beta.23" + resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.0.0-beta.23.tgz#050a31ac55b7ad63e8abf57ac941c62e255f57b8" + integrity sha512-pMjFH/NpFWLd2XQQa5rG9rGVQ9mu3ygdtu6VGfJ3aAjzBiyLXDKhE4biIFWyFsr8zLpp7DjwbrmLV0UGvbG1WQ== + +"@tiptap/react@^2.0.0-beta.107": + version "2.0.0-beta.109" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.0.0-beta.109.tgz#0998989f7f81e2f90a10fb37c55d531d7015bbee" + integrity sha512-kx/I+9DbiKX+LPFYTQf1Mycbw4U77nRsuztMi5UyGoONnwVwVxOUN6sxdnsNX0uo/H0Rf5ZAtQn8vQBaTWPzsQ== + dependencies: + "@tiptap/extension-bubble-menu" "^2.0.0-beta.56" + "@tiptap/extension-floating-menu" "^2.0.0-beta.51" + prosemirror-view "^1.23.6" + +"@tiptap/starter-kit@^2.0.0-beta.180": + version "2.0.0-beta.184" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.184.tgz#c621d51d9cb8a1b18cbec7af6080ce8288bdce72" + integrity sha512-FgF94i5RQzXiGAIkaubnXEaYwJfiZRbMPZcmarwNo8IyqPnLT34Q1yjw/qZ3nv7rDehWV5l/zenbrrNtPYVCkA== + dependencies: + "@tiptap/core" "^2.0.0-beta.175" + "@tiptap/extension-blockquote" "^2.0.0-beta.26" + "@tiptap/extension-bold" "^2.0.0-beta.26" + "@tiptap/extension-bullet-list" "^2.0.0-beta.26" + "@tiptap/extension-code" "^2.0.0-beta.26" + "@tiptap/extension-code-block" "^2.0.0-beta.37" + "@tiptap/extension-document" "^2.0.0-beta.15" + "@tiptap/extension-dropcursor" "^2.0.0-beta.25" + "@tiptap/extension-gapcursor" "^2.0.0-beta.34" + "@tiptap/extension-hard-break" "^2.0.0-beta.30" + "@tiptap/extension-heading" "^2.0.0-beta.26" + "@tiptap/extension-history" "^2.0.0-beta.21" + "@tiptap/extension-horizontal-rule" "^2.0.0-beta.31" + "@tiptap/extension-italic" "^2.0.0-beta.26" + "@tiptap/extension-list-item" "^2.0.0-beta.20" + "@tiptap/extension-ordered-list" "^2.0.0-beta.27" + "@tiptap/extension-paragraph" "^2.0.0-beta.23" + "@tiptap/extension-strike" "^2.0.0-beta.27" + "@tiptap/extension-text" "^2.0.0-beta.15" + "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -1534,6 +1745,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.4.tgz#e1cf817d70a1e118e81922c4ff6683ce9d422e26" integrity sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA== +"@types/orderedmap@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/orderedmap/-/orderedmap-1.0.0.tgz#807455a192bba52cbbb4517044bc82bdbfa8c596" + integrity sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -1549,6 +1765,89 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== +"@types/prosemirror-commands@*", "@types/prosemirror-commands@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz#d08551415127d93ae62e7239d30db0b5e7208e22" + integrity sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-dropcursor@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.3.tgz#49250849b8a0b86e8c29eb1ba70a463e53e46947" + integrity sha512-b0/8njnJ4lwyHKcGuCMf3x7r1KjxyugB1R/c2iMCjplsJHSC7UY9+OysqgJR5uUXRekUSGniiLgBtac/lvH6wg== + dependencies: + "@types/prosemirror-state" "*" + +"@types/prosemirror-gapcursor@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz#7df7d373edb33ea8da12084bfd462cf84cd69761" + integrity sha512-9xKjFIG5947dzerFvkLWp6F53JwrUYoYwh3SgcTFEp8SbSfNNrez/PFYVZKPnoqPoaK5WtTdQTaMwpCV9rXQIg== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-history@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-history/-/prosemirror-history-1.0.3.tgz#f1110efbe758129b5475e466ff077f0a8d9b964f" + integrity sha512-5TloMDRavgLjOAKXp1Li8u0xcsspzbT1Cm9F2pwHOkgvQOz1jWQb2VIXO7RVNsFjLBZdIXlyfSLivro3DuMWXg== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-keymap@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz#f73c79810e8d0e0a20d153d84f998f02e5afbc0c" + integrity sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg== + dependencies: + "@types/prosemirror-commands" "*" + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-model@*", "@types/prosemirror-model@^1.16.0": + version "1.16.2" + resolved "https://registry.yarnpkg.com/@types/prosemirror-model/-/prosemirror-model-1.16.2.tgz#8896adac3a5d5d66f06491bb13940aa734a7b6e8" + integrity sha512-1XPJopkKP3oHSBP61uuSuW13DIDZPWvAzP6Pv2/6mixk8EBPUeRGIW548DjJTicMo23gEg1zvCZy9asblQdWag== + dependencies: + "@types/orderedmap" "*" + +"@types/prosemirror-schema-list@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz#bdf1893a7915fbdc5c49b3cac9368e96213d70de" + integrity sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA== + dependencies: + "@types/orderedmap" "*" + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.8": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.3.0.tgz#7fd25db7244c027eef0849d79b112a8a0dfbb483" + integrity sha512-nMdUF6w8B++NH4V54X+4GvDty7M02UfuHQW0s1AS25Z4ZrOW4RSY2+s57doXBbeMSjzYV/QoMxCY2sT3KQ2VdQ== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-transform" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-transform@*", "@types/prosemirror-transform@^1.1.5": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@types/prosemirror-transform/-/prosemirror-transform-1.4.0.tgz#dbbc3f94b5879bb5e2027b908447e768a963ec6f" + integrity sha512-ntfuTl9nJWHvFykCmqJj4YQMws6G5H9nBaxHW0xRqfTxDxUvX2bCloqRN7bQTWg9h3VSP2lx45UuET1fn/oQ9Q== + dependencies: + "@types/prosemirror-model" "*" + +"@types/prosemirror-view@*", "@types/prosemirror-view@^1.23.1": + version "1.23.2" + resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.23.2.tgz#1e9b90ccf7947c647b2757eb758e46af9a58138e" + integrity sha512-P/qlXsUAZeZVJQkIy6hzc1RBWbeQIN01jtUo686ou7O8RDXWVKpVYMa1soR8nfUfKE8QHvCjCVe+7u6V3C/1fw== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-transform" "*" + "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -4553,6 +4852,11 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkifyjs@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-3.0.5.tgz#99e51a3a0c0e232fcb63ebb89eea3ff923378f34" + integrity sha512-1Y9XQH65eQKA9p2xtk+zxvnTeQBG7rdAXSkUG97DmuI/Xhji9uaUzaWxRj6rf9YC0v8KKHkxav7tnLX82Sz5Fg== + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -5126,6 +5430,11 @@ optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" +orderedmap@^1.1.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-1.1.5.tgz#4174c90b61bd7c25294932edf789f3b5677744d0" + integrity sha512-/fzlCGKRmfayGoI9UUXvJfc2nMZlJHW30QqEvwPvlg8tsX7jyiUSomYie6mYqx7Z9bOMGoag0H/q1PS/0PjYkg== + os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -5295,6 +5604,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +phosphor-react@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/phosphor-react/-/phosphor-react-1.4.1.tgz#97b0e034d9937db9b97fe53b186e9646464fd4e7" + integrity sha512-gO5j7U0xZrdglTAYDYPACU4xDOFBTJmptrrB/GeR+tHhCZF3nUMyGmV/0hnloKjuTrOmpSFlbfOY78H39rgjUQ== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -5622,6 +5936,90 @@ prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +prosemirror-commands@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.2.2.tgz#1bd167372ee20abf488aca9cece63c43fab182c9" + integrity sha512-TX+KpWudMon06frryfpO/u7hsQv2hu8L4VSVbCpi3/7wXHBgl+35mV85qfa3RpT8xD2f3MdeoTqH0vy5JdbXPg== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-dropcursor@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.4.0.tgz#91a859d4ee79c99b1c0ba6ee61c093b195c0d9f0" + integrity sha512-6+YwTjmqDwlA/Dm+5wK67ezgqgjA/MhSDgaNxKUzH97SmeuWFXyLeDRxxOPZeSo7yTxcDGUCWTEjmQZsVBuMrQ== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + prosemirror-view "^1.1.0" + +prosemirror-gapcursor@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.2.2.tgz#7394613ba4a1601fad1f36f1cff8961968c22ffa" + integrity sha512-7YzuRBbu9W7HGQde84kCHfIjaRLNcAdeijbgqrm/R9dsdTWkV+rrdcmic/sCc+bptiNpvjCEE+R6hrbT8zFQeQ== + dependencies: + prosemirror-keymap "^1.0.0" + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-view "^1.0.0" + +prosemirror-history@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.2.0.tgz#04cc4df8d2f7b2a46651a2780de191ada6d465ea" + integrity sha512-B9v9xtf4fYbKxQwIr+3wtTDNLDZcmMMmGiI3TAPShnUzvo+Rmv1GiUrsQChY1meetHl7rhML2cppF3FTs7f7UQ== + dependencies: + prosemirror-state "^1.2.2" + prosemirror-transform "^1.0.0" + rope-sequence "^1.3.0" + +prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.1.5.tgz#b5984c7d30f5c75956c853126c54e9e624c0327b" + integrity sha512-8SZgPH3K+GLsHL2wKuwBD9rxhsbnVBTwpHCO4VUO5GmqUQlxd/2GtBVWTsyLq4Dp3N9nGgPd3+lZFKUDuVp+Vw== + dependencies: + prosemirror-state "^1.0.0" + w3c-keyname "^2.2.0" + +prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.16.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.16.1.tgz#fb388270bc9609b66298d6a7e15d0cc1d6c61253" + integrity sha512-r1/w0HDU40TtkXp0DyKBnFPYwd8FSlUSJmGCGFv4DeynfeSlyQF2FD0RQbVEMOe6P3PpUSXM6LZBV7W/YNZ4mA== + dependencies: + orderedmap "^1.1.0" + +prosemirror-schema-list@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.1.6.tgz#c3e13fe2f74750e4a53ff88d798dc0c4ccca6707" + integrity sha512-aFGEdaCWmJzouZ8DwedmvSsL50JpRkqhQ6tcpThwJONVVmCgI36LJHtoQ4VGZbusMavaBhXXr33zyD2IVsTlkw== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.3.4.tgz#4c6b52628216e753fc901c6d2bfd84ce109e8952" + integrity sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.3.3: + version "1.4.2" + resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.4.2.tgz#35f56091bcab3359f1eb90e82ce9f20cc52105c1" + integrity sha512-bcIsf3uRZhfab0xRfyyxOEh6eqSszq/hJbDbmUumFnbHBoWhB/uXbpz6vvUxfk0XiEvrZDJ+5pXRrNDc1Hu3vQ== + dependencies: + prosemirror-model "^1.0.0" + +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.23.6: + version "1.23.13" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.23.13.tgz#d423c601d33ad3adfd1ab73fb72270acc9de9adf" + integrity sha512-X/NcwZv8pgcEWfs3n++Wz4nDgqDIeDvJ9kfCk6DCoC9XUlDekqJLFt9wCcCUBXedb8hs/dmd+JmcaLgbr67XZw== + dependencies: + prosemirror-model "^1.16.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + proxy-addr@~2.0.5: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -5675,6 +6073,11 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +react-cool-onclickoutside@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/react-cool-onclickoutside/-/react-cool-onclickoutside-1.7.0.tgz#abc844e14852220fe15f81d7ef44976d15cd9980" + integrity sha512-HVZK2155Unee+enpoHKyYP2UdQK69thw90XAOUCjvJBcgRSgfRPgWWt/W1dYzoGp3+nleAa8SJxF1d4FMA4Qmw== + react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -5684,6 +6087,11 @@ react-dom@^17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" +react-hook-form@^7.25.3: + version "7.30.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.30.0.tgz#c9e2fd54d3627e43bd94bf38ef549df2e80c1371" + integrity sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ== + react-i18next@^11.15.6: version "11.15.6" resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.15.6.tgz#693430fbee5ac7d0774bd88683575d62adb24afb" @@ -6033,6 +6441,11 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +rope-sequence@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.2.tgz#a19e02d72991ca71feb6b5f8a91154e48e3c098b" + integrity sha512-ku6MFrwEVSVmXLvy3dYph3LAMNS0890K7fabn+0YIRQ2T96T9F4gkFf0vf0WW0JUraNWwGRtInEpH7yO4tbQZg== + run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -6629,6 +7042,13 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tippy.js@^6.3.7: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6843,6 +7263,11 @@ void-elements@3.1.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= +w3c-keyname@^2.2.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.4.tgz#4ade6916f6290224cdbd1db8ac49eab03d0eef6b" + integrity sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw== + warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
{t('app.admin.plan_categories_list.name')}{t('app.admin.plan_categories_list.significance')} {t('app.admin.plan_categories_list.name')}{t('app.admin.plan_categories_list.significance')}
{c.name} {c.weight} - +