block_editor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +147 -0
  4. data/Rakefile +18 -0
  5. data/app/assets/config/block_editor_manifest.js +1 -0
  6. data/app/assets/stylesheets/block_editor/backend.scss +4 -0
  7. data/app/assets/stylesheets/block_editor/backend/blocks.scss +0 -0
  8. data/app/assets/stylesheets/block_editor/frontend.scss +1 -0
  9. data/app/assets/stylesheets/block_editor/frontend/blocks.scss +0 -0
  10. data/app/controllers/block_editor/application_controller.rb +4 -0
  11. data/app/helpers/block_editor/application_helper.rb +11 -0
  12. data/app/javascript/block_editor/blocks/button/edit.js +240 -0
  13. data/app/javascript/block_editor/blocks/column/edit.js +93 -0
  14. data/app/javascript/block_editor/blocks/image/edit.js +656 -0
  15. data/app/javascript/block_editor/blocks/index.js +263 -0
  16. data/app/javascript/block_editor/components/block-editor/index.js +88 -0
  17. data/app/javascript/block_editor/components/block-editor/styles.scss +39 -0
  18. data/app/javascript/block_editor/components/header/index.js +45 -0
  19. data/app/javascript/block_editor/components/header/redo.js +36 -0
  20. data/app/javascript/block_editor/components/header/styles.scss +14 -0
  21. data/app/javascript/block_editor/components/header/undo.js +36 -0
  22. data/app/javascript/block_editor/components/media-upload/index.js +37 -0
  23. data/app/javascript/block_editor/components/notices/index.js +26 -0
  24. data/app/javascript/block_editor/components/notices/styles.scss +9 -0
  25. data/app/javascript/block_editor/components/sidebar/index.js +31 -0
  26. data/app/javascript/block_editor/components/sidebar/styles.scss +43 -0
  27. data/app/javascript/block_editor/stores/action-types.js +4 -0
  28. data/app/javascript/block_editor/stores/actions.js +41 -0
  29. data/app/javascript/block_editor/stores/controls.js +21 -0
  30. data/app/javascript/block_editor/stores/index.js +30 -0
  31. data/app/javascript/block_editor/stores/reducer.js +20 -0
  32. data/app/javascript/block_editor/stores/resolvers.js +10 -0
  33. data/app/javascript/block_editor/stores/selectors.js +13 -0
  34. data/app/javascript/controllers/block_editor_controller.jsx +42 -0
  35. data/app/javascript/controllers/index.js +6 -0
  36. data/app/javascript/packs/block_editor/application.js +2 -0
  37. data/app/javascript/packs/block_editor/application.scss +108 -0
  38. data/app/jobs/block_editor/application_job.rb +4 -0
  39. data/app/mailers/block_editor/application_mailer.rb +6 -0
  40. data/app/models/block_editor/application_record.rb +5 -0
  41. data/app/models/block_editor/block_list.rb +7 -0
  42. data/app/models/concerns/block_editor/listable.rb +24 -0
  43. data/app/views/layouts/block_editor/application.html.erb +15 -0
  44. data/config/initializers/webpacker_extension.rb +12 -0
  45. data/config/routes.rb +2 -0
  46. data/config/webpack/development.js +5 -0
  47. data/config/webpack/environment.js +3 -0
  48. data/config/webpack/production.js +5 -0
  49. data/config/webpack/test.js +5 -0
  50. data/config/webpacker.yml +92 -0
  51. data/db/migrate/20210312032114_create_block_lists.rb +11 -0
  52. data/lib/block_editor.rb +26 -0
  53. data/lib/block_editor/block_list_renderer.rb +43 -0
  54. data/lib/block_editor/blocks/base.rb +32 -0
  55. data/lib/block_editor/engine.rb +34 -0
  56. data/lib/block_editor/instance.rb +19 -0
  57. data/lib/block_editor/version.rb +3 -0
  58. data/lib/tasks/block_editor_tasks.rake +59 -0
  59. metadata +131 -0
@@ -0,0 +1,14 @@
1
+ .block-editor__header {
2
+ align-items: center;
3
+ background: $white;
4
+ border-bottom: 1px solid $light-gray-500;
5
+ display: flex;
6
+ height: $header-height;
7
+ justify-content: space-between;
8
+ left: 0;
9
+ // Stick the toolbar to the top, because the admin bar is not fixed on mobile.
10
+ position: sticky;
11
+ right: 0;
12
+ top: 0;
13
+ z-index: 1;
14
+ }
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { __ } from '@wordpress/i18n';
4
+ import { Button } from '@wordpress/components';
5
+ import { withSelect, withDispatch } from '@wordpress/data';
6
+ import { compose } from '@wordpress/compose';
7
+ import { displayShortcut } from '@wordpress/keycodes';
8
+ import { undo as undoIcon } from '@wordpress/icons';
9
+
10
+ function HistoryUndo( { hasUndo, undo, ...props } ) {
11
+ return (
12
+ <Button
13
+ { ...props }
14
+ icon={ undoIcon }
15
+ label={ __( 'Undo' ) }
16
+ shortcut={ displayShortcut.primary( 'z' ) }
17
+ // If there are no undo levels we don't want to actually disable this
18
+ // button, because it will remove focus for keyboard users.
19
+ // See: https://github.com/WordPress/gutenberg/issues/3486
20
+ aria-disabled={ ! hasUndo }
21
+ onClick={ hasUndo ? undo : undefined }
22
+ className="editor-history__undo"
23
+ />
24
+ );
25
+ }
26
+
27
+ const EnhancedHistoryUndo = compose( [
28
+ withSelect( ( select ) => ( {
29
+ hasUndo: select( 'block-editor' ).hasUndo(),
30
+ } ) ),
31
+ withDispatch( ( dispatch ) => ( {
32
+ undo: dispatch( 'block-editor' ).undo,
33
+ } ) ),
34
+ ] )( HistoryUndo );
35
+
36
+ export default EnhancedHistoryUndo;
@@ -0,0 +1,37 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+
4
+ /**
5
+ * WordPress dependencies
6
+ */
7
+ import { Component } from '@wordpress/element';
8
+
9
+ class MediaUpload extends Component {
10
+ constructor( {
11
+ allowedTypes,
12
+ gallery = false,
13
+ unstableFeaturedImageFlow = false,
14
+ modalClass,
15
+ multiple = false,
16
+ title = 'Select or Upload Media',
17
+ } ) {
18
+ super( ...arguments );
19
+ this.openUploader = this.openUploader.bind( this );
20
+ }
21
+
22
+ openUploader() {
23
+ if (window.MediaUploader == undefined) {
24
+ console.log('window.MediaUploader undefined. Pulling in random image from Unsplash')
25
+
26
+ this.props.onSelect( { url: 'https://source.unsplash.com/random/800x500' });
27
+ } else {
28
+ this.MediaUploader.open(this.props.onSelect);
29
+ }
30
+ }
31
+
32
+ render() {
33
+ return this.props.render( { open: this.openUploader } );
34
+ }
35
+ }
36
+
37
+ export default MediaUpload;
@@ -0,0 +1,26 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+
4
+ /**
5
+ * WordPress dependencies
6
+ */
7
+ import { useSelect, useDispatch } from '@wordpress/data';
8
+ import { SnackbarList } from '@wordpress/components';
9
+
10
+ export default function Notices() {
11
+ const notices = useSelect(
12
+ ( select ) =>
13
+ select( 'core/notices' )
14
+ .getNotices()
15
+ .filter( ( notice ) => notice.type === 'snackbar' ),
16
+ []
17
+ );
18
+ const { removeNotice } = useDispatch( 'core/notices' );
19
+ return (
20
+ <SnackbarList
21
+ className="edit-site-notices"
22
+ notices={ notices }
23
+ onRemove={ removeNotice }
24
+ />
25
+ );
26
+ }
@@ -0,0 +1,9 @@
1
+ .edit-site-notices {
2
+ bottom: 20px;
3
+ padding-left: 16px;
4
+ padding-right: 16px;
5
+ position: fixed;
6
+ right: 0;
7
+ }
8
+
9
+ @include editor-left(".edit-site-notices");
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+
4
+ /**
5
+ * WordPress dependencies
6
+ */
7
+ import { createSlotFill, Panel } from '@wordpress/components';
8
+ import { __ } from '@wordpress/i18n';
9
+
10
+ const { Slot: InspectorSlot, Fill: InspectorFill } = createSlotFill(
11
+ 'StandAloneBlockEditorSidebarInspector'
12
+ );
13
+
14
+ function Sidebar() {
15
+ return (
16
+ <div
17
+ className="block-editor__sidebar"
18
+ role="region"
19
+ aria-label={ __( 'Standalone Block Editor advanced settings.' ) }
20
+ tabIndex="-1"
21
+ >
22
+ <Panel header={ __( 'Inspector' ) }>
23
+ <InspectorSlot bubblesVirtually />
24
+ </Panel>
25
+ </div>
26
+ );
27
+ }
28
+
29
+ Sidebar.InspectorFill = InspectorFill;
30
+
31
+ export default Sidebar;
@@ -0,0 +1,43 @@
1
+ .block-editor__sidebar {
2
+ background: $white;
3
+ border-left: $border-width solid $light-gray-500;
4
+ bottom: 0;
5
+ color: $dark-gray-500;
6
+ height: 100vh;
7
+ overflow: hidden;
8
+ position: absolute;
9
+ right: 0;
10
+ top: 0;
11
+ width: $sidebar-width;
12
+ //z-index: z-index(".edit-site-sidebar");
13
+
14
+ @include break-small() {
15
+ -webkit-overflow-scrolling: touch;
16
+ height: auto;
17
+ overflow: auto;
18
+ // top: $admin-bar-height-big + $header-height;
19
+ }
20
+
21
+ // @include break-medium() {
22
+ // top: $admin-bar-height + $header-height;
23
+ // }
24
+
25
+ @include break-small() {
26
+ display: block;
27
+ }
28
+
29
+ > .components-panel {
30
+ border-left: 0;
31
+ border-right: 0;
32
+ margin-bottom: -1px;
33
+ margin-top: -1px;
34
+
35
+ > .components-panel__header {
36
+ background: $light-gray-200;
37
+ }
38
+ }
39
+
40
+ .block-editor-block-inspector__card {
41
+ margin: 0;
42
+ }
43
+ }
@@ -0,0 +1,4 @@
1
+ export const UPDATE_BLOCKS = "UPDATE_BLOCKS";
2
+ export const PERSIST_BLOCKS = "PERSIST_BLOCKS";
3
+ export const FETCH_BLOCKS_FROM_STORAGE = "FETCH_BLOCKS_FROM_STORAGE";
4
+ export const PERSIST_BLOCKS_TO_STORAGE = "PERSIST_BLOCKS_TO_STORAGE";
@@ -0,0 +1,41 @@
1
+ import {
2
+ UPDATE_BLOCKS,
3
+ PERSIST_BLOCKS,
4
+ FETCH_BLOCKS_FROM_STORAGE,
5
+ PERSIST_BLOCKS_TO_STORAGE,
6
+ } from "./action-types";
7
+ import { ActionCreators as ReduxUndo } from "redux-undo";
8
+
9
+
10
+ export function undo() {
11
+ return ReduxUndo.undo();
12
+ }
13
+
14
+ export function redo() {
15
+ return ReduxUndo.redo();
16
+ }
17
+
18
+ export function *updateBlocks( blocks, persist = false ) {
19
+
20
+ if( persist ) {
21
+ yield persistBlocksToStorage(blocks);
22
+ }
23
+
24
+ return {
25
+ type: persist ? PERSIST_BLOCKS : UPDATE_BLOCKS,
26
+ blocks,
27
+ };
28
+ }
29
+
30
+ export function fetchBlocksFromStorage() {
31
+ return {
32
+ type: FETCH_BLOCKS_FROM_STORAGE,
33
+ };
34
+ };
35
+
36
+ export function persistBlocksToStorage(blocks) {
37
+ return {
38
+ type: PERSIST_BLOCKS_TO_STORAGE,
39
+ blocks,
40
+ };
41
+ }
@@ -0,0 +1,21 @@
1
+ import {
2
+ FETCH_BLOCKS_FROM_STORAGE,
3
+ PERSIST_BLOCKS_TO_STORAGE,
4
+ } from "./action-types";
5
+ import { serialize } from "@wordpress/blocks";
6
+
7
+ export default {
8
+ [PERSIST_BLOCKS_TO_STORAGE](action) {
9
+ return new Promise((resolve, reject) => {
10
+ window.localStorage.setItem("blockEditorBlocks", serialize(action.blocks));
11
+ resolve(action.blocks);
12
+ });
13
+ },
14
+ [FETCH_BLOCKS_FROM_STORAGE]() {
15
+ return new Promise((resolve, reject) => {
16
+ const storedBlocks =
17
+ window.localStorage.getItem("blockEditorBlocks") || [];
18
+ resolve(storedBlocks);
19
+ });
20
+ },
21
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { registerStore } from '@wordpress/data';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import reducer from './reducer';
10
+ import * as selectors from './selectors';
11
+ import * as actions from './actions';
12
+ import * as resolvers from "./resolvers";
13
+ import controls from './controls';
14
+
15
+ /**
16
+ * Module Constants
17
+ */
18
+ const MODULE_KEY = 'block-editor';
19
+
20
+ const store = registerStore(MODULE_KEY, {
21
+ reducer,
22
+ selectors,
23
+ actions,
24
+ controls,
25
+ resolvers,
26
+ });
27
+
28
+ window.blockEditorStore = store;
29
+
30
+ export default store;
@@ -0,0 +1,20 @@
1
+ import undoable, { groupByActionTypes, includeAction } from "redux-undo";
2
+ import { UPDATE_BLOCKS, PERSIST_BLOCKS } from "./action-types";
3
+
4
+ function blocksReducer(state = [], action) {
5
+ switch (action.type) {
6
+ case UPDATE_BLOCKS:
7
+ case PERSIST_BLOCKS:
8
+ const { blocks } = action;
9
+
10
+ return {
11
+ blocks,
12
+ };
13
+ }
14
+
15
+ return state;
16
+ }
17
+
18
+ export default undoable(blocksReducer, {
19
+ filter: includeAction(PERSIST_BLOCKS),
20
+ });
@@ -0,0 +1,10 @@
1
+ import { parse } from "@wordpress/blocks";
2
+ import { fetchBlocksFromStorage, updateBlocks } from "./actions";
3
+
4
+ export function *getBlocks() {
5
+ const rawBlocks = yield fetchBlocksFromStorage();
6
+ const persist = false;
7
+ const blocks = parse(rawBlocks);
8
+ yield updateBlocks(blocks, persist);
9
+ return blocks;
10
+ }
@@ -0,0 +1,13 @@
1
+ import { createRegistrySelector } from '@wordpress/data';
2
+
3
+ export const getBlocks = ( state ) => {
4
+ return state.present.blocks || [];
5
+ }
6
+
7
+ export const hasUndo = (state) => {
8
+ return state.past?.length;
9
+ };
10
+
11
+ export const hasRedo = (state) => {
12
+ return state.future?.length;
13
+ };
@@ -0,0 +1,42 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+ import PropTypes from 'prop-types'
4
+
5
+ import { Controller } from "stimulus"
6
+
7
+ import { render } from '@wordpress/element'
8
+
9
+ import BlockEditor from '../block_editor/components/block-editor'
10
+ import { registerBlocks } from '../block_editor/blocks'
11
+
12
+ registerBlocks()
13
+
14
+ export default class extends Controller {
15
+ static targets = [ "output", "input" ]
16
+
17
+ connect() {
18
+ const settings = {
19
+ imageSizes: false,
20
+ disableCustomFontSizes: true,
21
+ fontSizes: false,
22
+ disableCustomColors: true,
23
+ colors: false,
24
+ disableCustomGradients: true,
25
+ __experimentalDisableDropCap: true,
26
+ __experimentalDisableCustomLineHeight: true,
27
+ mediaUpload: function uploadMedia( {
28
+ allowedTypes,
29
+ additionalData = {},
30
+ filesList,
31
+ maxUploadFileSize,
32
+ onError = noop,
33
+ onFileChange,
34
+ wpAllowedMimeTypes = null,
35
+ } ) {
36
+ }
37
+ }
38
+
39
+ window.localStorage.setItem("blockEditorBlocks", this.inputTarget.value);
40
+ this.editor = render( <BlockEditor input={ this.inputTarget } settings={ settings } />, this.outputTarget )
41
+ }
42
+ }
@@ -0,0 +1,6 @@
1
+ import { Application } from "stimulus"
2
+ import { definitionsFromContext } from "stimulus/webpack-helpers"
3
+
4
+ const application = Application.start()
5
+ const context = require.context("controllers", true, /_controller\.jsx$/)
6
+ application.load(definitionsFromContext(context))
@@ -0,0 +1,2 @@
1
+ import "controllers"
2
+ import './application.scss'
@@ -0,0 +1,108 @@
1
+ $primary-color: #1b8ecf;
2
+
3
+ @function theme($selector) {
4
+ @return $primary-color;
5
+ }
6
+
7
+ @function color($color) {
8
+ @return $color;
9
+ }
10
+
11
+ @import "~@wordpress/base-styles/colors";
12
+ @import "~@wordpress/base-styles/variables";
13
+ @import "~@wordpress/base-styles/mixins";
14
+ @import "~@wordpress/base-styles/breakpoints";
15
+ @import "~@wordpress/base-styles/animations";
16
+ @import "~@wordpress/base-styles/z-index";
17
+
18
+ .block-editor {
19
+ label {
20
+ font-size: $default-font-size;
21
+ }
22
+ }
23
+
24
+ @import "~@wordpress/components/src/style";
25
+ @import "~@wordpress/block-editor/src/style";
26
+ @import "~@wordpress/block-library/src/style";
27
+
28
+ $header-height: 50px;
29
+
30
+ // Internal
31
+ @import "../../block_editor/components/sidebar/styles";
32
+ @import "../../block_editor/components/header/styles";
33
+ @import "../../block_editor/components/block-editor/styles";
34
+
35
+ .block-editor {
36
+ @include reset;
37
+ position: relative;
38
+ margin: 1rem 0;
39
+ padding: 0;
40
+ font-family: $default-font;
41
+ font-size: $default-font-size;
42
+ border: 1px solid #f3f4f5;
43
+ min-height: 500px;
44
+
45
+ a,
46
+ div {
47
+ outline: 0;
48
+ }
49
+
50
+ .block-editor-url-popover__additional-controls,
51
+ .block-editor-media-replace-flow__options .components-form-file-upload {
52
+ display: none;
53
+ }
54
+
55
+ &:not(.block-editor__fullscreen) {
56
+ .block-editor__size-toggle-button__minimize {
57
+ display: none;
58
+ }
59
+ }
60
+
61
+ &.block-editor__fullscreen {
62
+ .block-editor__size-toggle-button__maximize {
63
+ display: none;
64
+ }
65
+ }
66
+
67
+ &__size-toggle-button {
68
+ position: absolute;
69
+ right: 0;
70
+ top: 7px;
71
+ z-index: 1;
72
+ }
73
+
74
+ &__fullscreen {
75
+ position: absolute;
76
+ top: 0px;
77
+ right: 0px;
78
+ bottom: 0px;
79
+ left: 0px;
80
+ padding: 0;
81
+ z-index: 99;
82
+ margin: 0;
83
+ .block-editor {
84
+ height: 100%;
85
+ }
86
+ }
87
+ }
88
+
89
+ // In order to use mix-blend-mode, this element needs to have an explicitly set background-color.
90
+ // We scope it to .wp-toolbar to be wp-admin only, to prevent bleed into other implementations.
91
+ html.wp-toolbar {
92
+ background: $white;
93
+ }
94
+
95
+ // The modals are shown outside the .block-editor wrapper, they need these styles.
96
+ .block-editor, .components-modal__frame {
97
+ @include reset;
98
+ }
99
+
100
+ .block-editor-block-breadcrumb {
101
+ position: absolute;
102
+ bottom: 0;
103
+ z-index: 1;
104
+ background-color: $white;
105
+ width: 100%;
106
+ border-top: 1px solid #f3f4f5;
107
+ padding: 0.5rem 0;
108
+ }