diff --git a/app/controllers/wiki_pages_api_controller.rb b/app/controllers/wiki_pages_api_controller.rb
index 468767aa3cc..f4c88ddc421 100644
--- a/app/controllers/wiki_pages_api_controller.rb
+++ b/app/controllers/wiki_pages_api_controller.rb
@@ -354,7 +354,9 @@ class WikiPagesApiController < ApplicationController
@wiki = @context.wiki
@page = @wiki.build_wiki_page(@current_user, initial_params)
if authorized_action(@page, @current_user, :create)
- update_params = get_update_params(Set[:title, :body])
+ allowed_fields = Set[:title, :body]
+ allowed_fields << :block_editor_attributes if @context.account.feature_enabled?(:block_editor)
+ update_params = get_update_params(allowed_fields)
assign_todo_date
if !update_params.is_a?(Symbol) && @page.update(update_params) && process_front_page
log_asset_access(@page, "wiki", @wiki, "participate")
@@ -434,6 +436,7 @@ class WikiPagesApiController < ApplicationController
if @page.new_record?
perform_update = true if authorized_action(@page, @current_user, [:create])
allowed_fields = Set[:title, :body]
+ allowed_fields << :block_editor_attributes if @context.account.feature_enabled?(:block_editor)
elsif authorized_action(@page, @current_user, [:update, :update_content])
perform_update = true
allowed_fields = Set[]
@@ -639,7 +642,9 @@ class WikiPagesApiController < ApplicationController
def get_update_params(allowed_fields = Set[])
# normalize parameters
- page_params = params[:wiki_page] ? params[:wiki_page].permit(*%w[title body notify_of_update published front_page editing_roles publish_at]) : {}
+ wiki_page_params = %w[title body notify_of_update published front_page editing_roles publish_at]
+ wiki_page_params += [block_editor_attributes: [:time, :version, { blocks: [:id, :type, { data: strong_anything }] }]] if @context.account.feature_enabled?(:block_editor)
+ page_params = params[:wiki_page] ? params[:wiki_page].permit(*wiki_page_params) : {}
if page_params.key?(:published)
published_value = page_params.delete(:published)
@@ -665,6 +670,10 @@ class WikiPagesApiController < ApplicationController
end
change_front_page = !!@set_front_page
+ if page_params.key?(:block_editor_attributes)
+ page_params[:block_editor_attributes][:root_account_id] = @context.root_account_id
+ end
+
# check user permissions
rejected_fields = Set[]
if @wiki.grants_right?(@current_user, session, :update)
@@ -683,6 +692,7 @@ class WikiPagesApiController < ApplicationController
unless @page.grants_right?(@current_user, session, :update)
allowed_fields << :body
+ allowed_fields << :block_editor_attributes if @context.account.feature_enabled?(:block_editor)
rejected_fields << :title if page_params.include?(:title) && page_params[:title] != @page.title
rejected_fields << :front_page if change_front_page && !@wiki.grants_right?(@current_user, session, :update)
diff --git a/app/controllers/wiki_pages_controller.rb b/app/controllers/wiki_pages_controller.rb
index 5d0152a9201..4d3bbdeffa7 100644
--- a/app/controllers/wiki_pages_controller.rb
+++ b/app/controllers/wiki_pages_controller.rb
@@ -174,7 +174,8 @@ class WikiPagesController < ApplicationController
wiki_page_menu_tools: external_tools_display_hashes(:wiki_page_menu),
wiki_index_menu_tools: external_tools_display_hashes(:wiki_index_menu),
DISPLAY_SHOW_ALL_LINK: tab_enabled?(context.class::TAB_PAGES, no_render: true) && !@k5_details_view,
- CAN_SET_TODO_DATE: context.grants_any_right?(@current_user, session, :manage_content, :manage_course_content_edit)
+ CAN_SET_TODO_DATE: context.grants_any_right?(@current_user, session, :manage_content, :manage_course_content_edit),
+ BLOCK_EDITOR: context.account.feature_enabled?(:block_editor)
}
if Account.site_admin.feature_enabled?(:permanent_page_links)
title_availability_path = context.is_a?(Course) ? api_v1_course_page_title_availability_path : api_v1_group_page_title_availability_path
diff --git a/app/models/block_editor.rb b/app/models/block_editor.rb
new file mode 100644
index 00000000000..3d8a337f196
--- /dev/null
+++ b/app/models/block_editor.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+#
+# Copyright (C) 2024 - present Instructure, Inc.
+#
+# This file is part of Canvas.
+#
+# Canvas is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, version 3 of the License.
+#
+# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see .
+#
+
+class BlockEditor < ActiveRecord::Base
+ belongs_to :context, polymorphic: [:wiki_page]
+
+ alias_attribute :version, :editor_version
+end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 301ed36754c..e5235b498b8 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -59,6 +59,8 @@ class WikiPage < ActiveRecord::Base
has_one :master_content_tag, class_name: "MasterCourses::MasterContentTag", inverse_of: :wiki_page
has_many :assignment_overrides, dependent: :destroy, inverse_of: :wiki_page
has_many :assignment_override_students, dependent: :destroy
+ has_one :block_editor, as: :context, dependent: :destroy
+ accepts_nested_attributes_for :block_editor, allow_destroy: true
acts_as_url :title, sync_url: true
validate :validate_front_page_visibility
diff --git a/config/feature_flags/learning_foundations_release_flags.yml b/config/feature_flags/learning_foundations_release_flags.yml
index 81c607c738b..cf2623c816a 100644
--- a/config/feature_flags/learning_foundations_release_flags.yml
+++ b/config/feature_flags/learning_foundations_release_flags.yml
@@ -240,3 +240,11 @@ observer_appointment_groups:
state: allowed_on
development:
state: allowed_on
+
+block_editor:
+ applies_to: Account
+ state: hidden
+ display_name: Block Editor
+ description: |-
+ Enable the new block editor for the rich content editor.
+ beta: true
diff --git a/db/migrate/20240207181908_create_block_editors.rb b/db/migrate/20240207181908_create_block_editors.rb
new file mode 100644
index 00000000000..ebdde6ad778
--- /dev/null
+++ b/db/migrate/20240207181908_create_block_editors.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+#
+# Copyright (C) 2024 - present Instructure, Inc.
+#
+# This file is part of Canvas.
+#
+# Canvas is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, version 3 of the License.
+#
+# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see .
+#
+
+class CreateBlockEditors < ActiveRecord::Migration[7.0]
+ tag :predeploy
+
+ def change
+ create_table :block_editors do |t|
+ t.references :root_account, null: false, foreign_key: { to_table: :accounts }, index: false
+ t.references :context, polymorphic: true, null: false, index: true
+ t.bigint :time
+ t.jsonb :blocks, default: [], null: false
+ t.string :editor_version
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20240208204317_add_replica_identity_to_block_editors.rb b/db/migrate/20240208204317_add_replica_identity_to_block_editors.rb
new file mode 100644
index 00000000000..aca729da8fd
--- /dev/null
+++ b/db/migrate/20240208204317_add_replica_identity_to_block_editors.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+#
+# Copyright (C) 2024 - present Instructure, Inc.
+#
+# This file is part of Canvas.
+#
+# Canvas is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, version 3 of the License.
+#
+# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see .
+#
+
+class AddReplicaIdentityToBlockEditors < ActiveRecord::Migration[7.0]
+ tag :predeploy
+
+ def change
+ add_replica_identity "BlockEditor", :root_account_id
+ end
+end
diff --git a/spec/apis/v1/wiki_pages_api_spec.rb b/spec/apis/v1/wiki_pages_api_spec.rb
index 97c469a89fc..0cb572fc50c 100644
--- a/spec/apis/v1/wiki_pages_api_spec.rb
+++ b/spec/apis/v1/wiki_pages_api_spec.rb
@@ -130,6 +130,43 @@ describe WikiPagesApiController, type: :request do
create_wiki_page(@teacher, { title: "New Page", editing_roles: "public" }, 401)
expect(WikiPage.last).to be_nil
end
+
+ context "with the block editor" do
+ context "with the block editor feature flag on" do
+ before do
+ Account.default.enable_feature!(:block_editor)
+ end
+
+ it "succeeds" do
+ block_editor_attributes = {
+ time: Time.now.to_i,
+ blocks: [{ "data" => { "text" => "test" }, "id" => "R0iGYLKhw2", "type" => "paragraph" }],
+ version: "1.0"
+ }
+ create_wiki_page(@teacher, { title: "New Page", block_editor_attributes: })
+ expect(WikiPage.last.title).to eq "New Page"
+ expect(WikiPage.last.block_editor).to be_present
+ expect(WikiPage.last.block_editor.blocks).to eq([{ "data" => { "text" => "test" }, "id" => "R0iGYLKhw2", "type" => "paragraph" }])
+ end
+ end
+
+ context "with the block editor feature flag off" do
+ before do
+ Account.default.disable_feature!(:block_editor)
+ end
+
+ it "ignores the block_editor_attributes" do
+ block_editor_attributes = {
+ time: Time.now.to_i,
+ blocks: [{ "data" => { "text" => "test" }, "id" => "R0iGYLKhw2", "type" => "paragraph" }],
+ version: "1.0"
+ }
+ create_wiki_page(@teacher, { title: "New Page", block_editor_attributes: })
+ expect(WikiPage.last.title).to eq "New Page"
+ expect(WikiPage.last.block_editor).not_to be_present
+ end
+ end
+ end
end
context "with the user not having manage_wiki_create permission" do
diff --git a/ui/featureBundles.ts b/ui/featureBundles.ts
index 7bac570c802..3f895e69719 100644
--- a/ui/featureBundles.ts
+++ b/ui/featureBundles.ts
@@ -45,6 +45,7 @@ const featureBundles: {
available_pronouns_list: () => import('./features/available_pronouns_list/index'),
blueprint_course_child: () => import('./features/blueprint_course_child/index'),
blueprint_course_master: () => import('./features/blueprint_course_master/index'),
+ block_editor: () => import('./features/block_editor/index'),
brand_configs: () => import('./features/brand_configs/index'),
calendar_appointment_group_edit: () => import('./features/calendar_appointment_group_edit/index'),
calendar: () => import('./features/calendar/index'),
diff --git a/ui/features/block_editor/index.tsx b/ui/features/block_editor/index.tsx
new file mode 100644
index 00000000000..b9da1f0cadd
--- /dev/null
+++ b/ui/features/block_editor/index.tsx
@@ -0,0 +1,28 @@
+// @ts-nocheck
+/*
+ * Copyright (C) 2024 - present Instructure, Inc.
+ *
+ * This file is part of Canvas.
+ *
+ * Canvas is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, version 3 of the License.
+ *
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see .
+ */
+
+import React from 'react'
+import ReactDOM from 'react-dom'
+import ready from '@instructure/ready'
+
+import {BlockEditor} from '@canvas/block-editor'
+
+ready(() => {
+ ReactDOM.render(, document.getElementById('block_editor'))
+})
diff --git a/ui/features/block_editor/package.json b/ui/features/block_editor/package.json
new file mode 100644
index 00000000000..07b170e2335
--- /dev/null
+++ b/ui/features/block_editor/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@canvas-features/block_editor",
+ "private": true,
+ "version": "0.1.0",
+ "owner": "LF"
+}
diff --git a/ui/shared/block-editor/package.json b/ui/shared/block-editor/package.json
new file mode 100644
index 00000000000..139b39f00a0
--- /dev/null
+++ b/ui/shared/block-editor/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "@canvas/block-editor",
+ "private": true,
+ "version": "1.0.0",
+ "author": "neme",
+ "main": "./react/index.tsx",
+ "dependencies": {
+ "@editorjs/editorjs": "^2.28.2",
+ "@editorjs/header": "^2.7.0",
+ "@editorjs/nested-list": "^1.3.0",
+ "@editorjs/paragraph": "^2.11.3",
+ "@editorjs/quote": "^2.5.0"
+ }
+}
diff --git a/ui/shared/block-editor/react/BlockEditor.stories.tsx b/ui/shared/block-editor/react/BlockEditor.stories.tsx
new file mode 100644
index 00000000000..badb4565b77
--- /dev/null
+++ b/ui/shared/block-editor/react/BlockEditor.stories.tsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 - present Instructure, Inc.
+ *
+ * This file is part of Canvas.
+ *
+ * Canvas is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, version 3 of the License.
+ *
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see .
+ */
+
+import React from 'react'
+
+import BlockEditor from './BlockEditor'
+
+export default {
+ title: 'Examples/Shared/BlockEditor',
+ component: BlockEditor,
+}
+
+const Template = args => {
+ return (
+ <>
+
+ >
+ )
+}
+
+export const DefaultEditor = Template.bind({})
diff --git a/ui/shared/block-editor/react/BlockEditor.tsx b/ui/shared/block-editor/react/BlockEditor.tsx
new file mode 100644
index 00000000000..1141fe7c7e4
--- /dev/null
+++ b/ui/shared/block-editor/react/BlockEditor.tsx
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 - present Instructure, Inc.
+ *
+ * This file is part of Canvas.
+ *
+ * Canvas is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, version 3 of the License.
+ *
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see .
+ */
+
+import React, {useRef} from 'react'
+import {useScope as useI18nScope} from '@canvas/i18n'
+import EditorJS from '@editorjs/editorjs'
+import Header from '@editorjs/header'
+import NestedList from '@editorjs/nested-list'
+import Paragraph from '@editorjs/paragraph'
+import Quote from '@editorjs/quote'
+
+import {View} from '@instructure/ui-view'
+
+const I18n = useI18nScope('block-editor')
+
+export default function BlockEditor() {
+ const editor = useRef(null)
+
+ React.useEffect(() => {
+ editor.current = new EditorJS({
+ holder: 'canvas-block-editor',
+ tools: {
+ header: {
+ class: Header,
+ inlineToolbar: true,
+ },
+ list: {
+ class: NestedList,
+ inlineToolbar: true,
+ config: {
+ defaultStyle: 'unordered',
+ },
+ },
+ paragraph: {
+ class: Paragraph,
+ inlineToolbar: false,
+ },
+ quote: {
+ class: Quote,
+ config: {
+ quotePlaceholder: 'Enter your quote here',
+ },
+ },
+ },
+ defaultBlock: 'paragraph',
+ placeholder: I18n.t('Press tab for more options'),
+ })
+ window.block_editor = editor.current
+ }, [])
+
+ return (
+
+
+
+
+ )
+}
diff --git a/ui/shared/block-editor/react/index.tsx b/ui/shared/block-editor/react/index.tsx
new file mode 100644
index 00000000000..41fe6b25bdf
--- /dev/null
+++ b/ui/shared/block-editor/react/index.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 - present Instructure, Inc.
+ *
+ * This file is part of Canvas.
+ *
+ * Canvas is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, version 3 of the License.
+ *
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see .
+ */
+
+import React from 'react'
+import ReactDOM from 'react-dom'
+import BlockEditor from './BlockEditor'
+
+export {BlockEditor}
+
+export default function renderBlockEditorApp(_, elt) {
+ ReactDOM.render(, elt)
+}
diff --git a/ui/shared/wiki/backbone/views/WikiPageEditView.jsx b/ui/shared/wiki/backbone/views/WikiPageEditView.jsx
index ffb0bbce75f..db00ff93904 100644
--- a/ui/shared/wiki/backbone/views/WikiPageEditView.jsx
+++ b/ui/shared/wiki/backbone/views/WikiPageEditView.jsx
@@ -19,6 +19,7 @@ import $ from 'jquery'
import React from 'react'
import ReactDOM from 'react-dom'
import RichContentEditor from '@canvas/rce/RichContentEditor'
+import {BlockEditor} from '@canvas/block-editor'
import template from '../../jst/WikiPageEdit.handlebars'
import ValidatedFormView from '@canvas/forms/backbone/views/ValidatedFormView'
import WikiPageDeleteDialog from './WikiPageDeleteDialog'
@@ -185,7 +186,11 @@ export default class WikiPageEditView extends ValidatedFormView {
})
}
- RichContentEditor.loadNewEditor(this.$wikiPageBody, {focus: true, manageParent: true})
+ if (window.ENV.BLOCK_EDITOR) {
+ ReactDOM.render(, document.getElementById('block_editor'))
+ } else {
+ RichContentEditor.loadNewEditor(this.$wikiPageBody, {focus: true, manageParent: true})
+ }
this.checkUnsavedOnLeave = true
$(window).on('beforeunload', this.onUnload.bind(this))
@@ -291,7 +296,7 @@ export default class WikiPageEditView extends ValidatedFormView {
)
}
- submit(event) {
+ async submit(event) {
this.checkUnsavedOnLeave = false
if (this.reloadPending) {
if (
@@ -309,6 +314,13 @@ export default class WikiPageEditView extends ValidatedFormView {
return
}
}
+ if (window.block_editor) {
+ let blockEditorData
+ await window.block_editor.save().then((outputData) => {
+ blockEditorData = outputData
+ })
+ this.blockEditorData = blockEditorData
+ }
if (this.reloadView != null) {
this.reloadView.stopPolling()
@@ -349,7 +361,9 @@ export default class WikiPageEditView extends ValidatedFormView {
if (page_data.publish_at) {
page_data.publish_at = $.unfudgeDateForProfileTimezone(page_data.publish_at)
}
-
+ if (this.blockEditorData) {
+ page_data.block_editor_attributes = this.blockEditorData
+ }
if (this.shouldPublish) page_data.published = true
return page_data
}
diff --git a/ui/shared/wiki/jst/WikiPageEdit.handlebars b/ui/shared/wiki/jst/WikiPageEdit.handlebars
index 74f18120d46..a6b000aa0d4 100644
--- a/ui/shared/wiki/jst/WikiPageEdit.handlebars
+++ b/ui/shared/wiki/jst/WikiPageEdit.handlebars
@@ -17,7 +17,11 @@
{{{body}}}
{{else}}
-
+ {{#if ENV.BLOCK_EDITOR}}
+
+ {{else}}
+
+ {{/if}}
{{/if}}
{{#if CAN.EDIT_ROLES}}
diff --git a/yarn.lock b/yarn.lock
index eb1cf25cf5f..84ef3603893 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1307,6 +1307,21 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
+"@codexteam/icons@^0.0.2":
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.0.2.tgz#9183996a38b75a93506890373a015e3a2a369264"
+ integrity sha512-KdeKj3TwaTHqM3IXd5YjeJP39PBUZTb+dtHjGlf5+b0VgsxYD4qzsZkb11lzopZbAuDsHaZJmAYQ8LFligIT6Q==
+
+"@codexteam/icons@^0.0.4":
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.0.4.tgz#8b72dcd3f3a1b0d880bdceb2abebd74b46d3ae13"
+ integrity sha512-V8N/TY2TGyas4wLrPIFq7bcow68b3gu8DfDt1+rrHPtXxcexadKauRJL6eQgfG7Z0LCrN4boLRawR4S9gjIh/Q==
+
+"@codexteam/icons@^0.0.5":
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.0.5.tgz#d17f39b6a0497c6439f57dd42711817a3dd3679c"
+ integrity sha512-s6H2KXhLz2rgbMZSkRm8dsMJvyUNZsEjxobBEg9ztdrb1B2H3pEzY6iTwI4XUPJWJ3c3qRKwV4TrO3J5jUdoQA==
+
"@colors/colors@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
@@ -1324,6 +1339,39 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
+"@editorjs/editorjs@^2.28.2":
+ version "2.29.0"
+ resolved "https://registry.yarnpkg.com/@editorjs/editorjs/-/editorjs-2.29.0.tgz#1c9846af19b2afab62a6bb3a815641721c0587f1"
+ integrity sha512-w2BVboSHokMBd/cAOZn0UU328o3gSZ8XUvFPA2e9+ciIGKILiRSPB70kkNdmhHkuNS3q2px+vdaIFaywBl7wGA==
+
+"@editorjs/header@^2.7.0":
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/@editorjs/header/-/header-2.8.1.tgz#ba16f43aaf461aa920c3594bdf0d854c4b5119b9"
+ integrity sha512-y0HVXRP7m2W617CWo3fsb5HhXmSLaRpb9GzFx0Vkp/HEm9Dz5YO1s8tC7R8JD3MskwoYh7V0hRFQt39io/r6hA==
+ dependencies:
+ "@codexteam/icons" "^0.0.5"
+
+"@editorjs/nested-list@^1.3.0":
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/@editorjs/nested-list/-/nested-list-1.4.2.tgz#2b47b9c3ee1ce11dec02eae0b176bd4107360847"
+ integrity sha512-qb1dAoJ+bihqmlR3822TC2GuIxEjTCLTZsZVWNces3uJIZ+W4019G3IJKBt/MOOgz4Evzad/RvUEKwPCPe6YOQ==
+ dependencies:
+ "@codexteam/icons" "^0.0.2"
+
+"@editorjs/paragraph@^2.11.3":
+ version "2.11.3"
+ resolved "https://registry.yarnpkg.com/@editorjs/paragraph/-/paragraph-2.11.3.tgz#fb438de863179739f18de7d8851671a0d8447923"
+ integrity sha512-ON72lhvhgWzPrq4VXpHUeut9bsFeJgVATDeL850FVToOwYHKvdsNpfu0VgxEodhkXgzU/IGl4FzdqC2wd3AJUQ==
+ dependencies:
+ "@codexteam/icons" "^0.0.4"
+
+"@editorjs/quote@^2.5.0":
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/@editorjs/quote/-/quote-2.6.0.tgz#5ff02b5b3cac1fcea4157c31ac975e3acb3906a8"
+ integrity sha512-8DiCMBT4n4UDV5bgzvfRH26HmL6YWddGC4+twvjhR+PzX0gwrnY8nFifvro79EeSqxwRtFjjlGnu5I0VTfw5aQ==
+ dependencies:
+ "@codexteam/icons" "^0.0.5"
+
"@emotion/babel-plugin@^11.11.0":
version "11.11.0"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c"