block_editor 0.1.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -14
  3. data/app/assets/images/block_editor/contact-form-block.svg +1 -0
  4. data/app/assets/stylesheets/block_editor/_utilities.scss +16 -0
  5. data/app/assets/stylesheets/block_editor/backend.scss +70 -2
  6. data/app/assets/stylesheets/block_editor/blocks/_backend.scss +7 -0
  7. data/app/assets/stylesheets/block_editor/blocks/_frontend.scss +11 -0
  8. data/app/assets/stylesheets/block_editor/blocks/be-accordion/_frontend.scss +3 -0
  9. data/app/assets/stylesheets/block_editor/blocks/be-alert/_frontend.scss +13 -0
  10. data/app/assets/stylesheets/block_editor/blocks/be-card/_backend.scss +7 -0
  11. data/app/assets/stylesheets/block_editor/{backend/blocks.scss → blocks/be-card/_frontend.scss} +0 -0
  12. data/app/assets/stylesheets/block_editor/blocks/be-contact-form/_backend.scss +22 -0
  13. data/app/assets/stylesheets/block_editor/blocks/be-cover/_backend.scss +8 -0
  14. data/app/assets/stylesheets/block_editor/blocks/be-cover/_frontend.scss +37 -0
  15. data/app/assets/stylesheets/block_editor/blocks/block/_backend.scss +11 -0
  16. data/app/assets/stylesheets/block_editor/blocks/button/_frontend.scss +46 -0
  17. data/app/assets/stylesheets/block_editor/blocks/buttons/_backend.scss +10 -0
  18. data/app/assets/stylesheets/block_editor/blocks/buttons/_frontend.scss +3 -0
  19. data/app/assets/stylesheets/block_editor/blocks/column/_frontend.scss +18 -0
  20. data/app/assets/stylesheets/block_editor/blocks/columns/_backend.scss +8 -0
  21. data/app/assets/stylesheets/block_editor/blocks/columns/_frontend.scss +14 -0
  22. data/app/assets/stylesheets/block_editor/blocks/image/_backend.scss +10 -0
  23. data/app/assets/stylesheets/block_editor/blocks/image/_frontend.scss +21 -0
  24. data/app/assets/stylesheets/block_editor/blocks/seperator/_frontend.scss +19 -0
  25. data/app/assets/stylesheets/block_editor/blocks/table/_frontend.scss +67 -0
  26. data/app/assets/stylesheets/block_editor/host_app/_variables.scss +1 -0
  27. data/app/assets/stylesheets/block_editor/host_app/blocks/_backend.scss +1 -0
  28. data/app/assets/stylesheets/block_editor/host_app/blocks/_frontend.scss +1 -0
  29. data/app/javascript/block_editor/blocks/be-accordion/index.js +108 -0
  30. data/app/javascript/block_editor/blocks/be-alert/index.js +51 -0
  31. data/app/javascript/block_editor/blocks/be-card/index.js +205 -0
  32. data/app/javascript/block_editor/blocks/be-contact-form/index.js +24 -0
  33. data/app/javascript/block_editor/blocks/be-cover/index.js +135 -0
  34. data/app/javascript/block_editor/blocks/block/edit-panel/index.js +132 -0
  35. data/app/javascript/block_editor/blocks/block/edit.js +163 -0
  36. data/app/javascript/block_editor/blocks/button/edit.js +0 -13
  37. data/app/javascript/block_editor/blocks/index.js +51 -102
  38. data/app/javascript/block_editor/components/block-editor/index.js +107 -36
  39. data/app/javascript/block_editor/components/block-editor/popover-wrapper.js +60 -0
  40. data/app/javascript/block_editor/components/block-editor/styles.scss +0 -11
  41. data/app/javascript/block_editor/components/header/index.js +28 -6
  42. data/app/javascript/block_editor/components/header/redo.js +1 -1
  43. data/app/javascript/block_editor/components/header/styles.scss +12 -11
  44. data/app/javascript/block_editor/components/media-upload/index.js +3 -3
  45. data/app/javascript/block_editor/components/sidebar/index.js +1 -3
  46. data/app/javascript/block_editor/components/sidebar/styles.scss +35 -35
  47. data/app/javascript/block_editor/stores/actions.js +12 -0
  48. data/app/javascript/block_editor/stores/reducer.js +23 -3
  49. data/app/javascript/block_editor/stores/selectors.js +14 -3
  50. data/app/javascript/controllers/block_editor_controller.jsx +15 -8
  51. data/app/javascript/controllers/index.js +2 -0
  52. data/app/javascript/packs/block_editor/application.scss +70 -26
  53. data/app/models/block_editor/block_list.rb +45 -1
  54. data/app/models/block_editor/block_list_connection.rb +6 -0
  55. data/app/views/block_editor/blocks/be/contact-form/_block.html +3 -0
  56. data/db/migrate/20210506220328_create_block_list_connections.rb +8 -0
  57. data/lib/block_editor.rb +3 -1
  58. data/lib/block_editor/block_list_renderer.rb +12 -6
  59. data/lib/block_editor/blocks/base.rb +1 -1
  60. data/lib/block_editor/blocks/contact_form.rb +11 -0
  61. data/lib/block_editor/blocks/reusable.rb +16 -0
  62. data/lib/block_editor/version.rb +1 -1
  63. data/package.json +16 -7
  64. data/yarn.lock +727 -530
  65. metadata +42 -8
  66. data/app/assets/stylesheets/block_editor/frontend.scss +0 -1
  67. data/app/assets/stylesheets/block_editor/frontend/blocks.scss +0 -0
  68. data/app/javascript/block_editor/blocks/image/edit.js +0 -656
@@ -0,0 +1,14 @@
1
+ .wp-block-columns {
2
+ --#{$variable-prefix}gutter-x: #{$grid-gutter-width};
3
+ --#{$variable-prefix}gutter-y: 0;
4
+ display: flex;
5
+ margin-top: calc(var(--#{$variable-prefix}gutter-y) * -1); // stylelint-disable-line function-disallowed-list
6
+ margin-right: calc(var(--#{$variable-prefix}gutter-x) / -2); // stylelint-disable-line function-disallowed-list
7
+ margin-left: calc(var(--#{$variable-prefix}gutter-x) / -2); // stylelint-disable-line function-disallowed-list
8
+
9
+ &:not(.is-style-no-stack) {
10
+ @include media-breakpoint-down(lg) {
11
+ display: block;
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,10 @@
1
+ .block-editor-block-list__block[data-type="core/image"] {
2
+ .block-editor-media-placeholder__url-input-container,
3
+ .components-form-file-upload {
4
+ display: none;
5
+ }
6
+ }
7
+ .components-dropdown-menu__toggle[aria-label="Change alignment"] {
8
+ display: none !important;
9
+ }
10
+
@@ -0,0 +1,21 @@
1
+ .wp-block-image {
2
+ margin-bottom: $paragraph-margin-bottom;
3
+
4
+ img {
5
+ max-width: 100%;
6
+ }
7
+ figcaption {
8
+ margin-top: 5px;
9
+ font-size: 0.9rem;
10
+ }
11
+ &.is-style-padded {
12
+ max-width: 75%;
13
+ margin-left: auto;
14
+ margin-right: auto;
15
+ }
16
+ &.is-style-rounded {
17
+ img {
18
+ border-radius: $border-radius;
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,19 @@
1
+ .wp-block-separator {
2
+ &.is-style-dots {
3
+ background: none !important;
4
+ border: none;
5
+ text-align: center;
6
+ max-width: none;
7
+ line-height: 1;
8
+ height: 1.2*$spacer !important;
9
+ opacity: 1;
10
+ &:before{
11
+ content: "\00b7 \00b7 \00b7";
12
+ font-size: 1.2*$spacer;
13
+ letter-spacing: 2em;
14
+ padding-left: 2em;
15
+ font-family: serif;
16
+ color: $black;
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,67 @@
1
+ .wp-block-table{
2
+ margin-bottom: $paragraph-margin-bottom;
3
+ overflow-x: auto;
4
+ table {
5
+ --#{$variable-prefix}table-bg: #{$table-bg};
6
+ --#{$variable-prefix}table-striped-color: #{$table-striped-color};
7
+ --#{$variable-prefix}table-striped-bg: #{$table-striped-bg};
8
+ --#{$variable-prefix}table-active-color: #{$table-active-color};
9
+ --#{$variable-prefix}table-active-bg: #{$table-active-bg};
10
+ --#{$variable-prefix}table-hover-color: #{$table-hover-color};
11
+ --#{$variable-prefix}table-hover-bg: #{$table-hover-bg};
12
+
13
+ width: 100%;
14
+ color: $table-color;
15
+ vertical-align: $table-cell-vertical-align;
16
+ border-color: $table-border-color;
17
+ overflow-x: auto;
18
+ -webkit-overflow-scrolling: touch;
19
+ > :not(caption) > * > * {
20
+ padding: $table-cell-padding-y $table-cell-padding-x;
21
+ background-color: var(--#{$variable-prefix}table-bg);
22
+ border-bottom-width: $table-border-width;
23
+ box-shadow: inset 0 0 0 9999px var(--#{$variable-prefix}table-accent-bg);
24
+ }
25
+
26
+ > tbody {
27
+ vertical-align: inherit;
28
+ }
29
+ > tbody > tr > th {
30
+ text-align: center;
31
+ }
32
+
33
+ > thead {
34
+ vertical-align: bottom;
35
+ background: $secondary;
36
+ color: $white;
37
+ }
38
+ > thead > tr > th:first-child{
39
+ text-align: center;
40
+ }
41
+
42
+ // Highlight border color between thead, tbody and tfoot.
43
+ > :not(:last-child) > :last-child > * {
44
+ border-bottom-color: $table-group-separator-color;
45
+ }
46
+ //border
47
+ > :not(caption) > * {
48
+ border-width: $table-border-width 0;
49
+
50
+ // stylelint-disable-next-line selector-max-universal
51
+ > * {
52
+ border-width: 0 $table-border-width;
53
+ }
54
+ }
55
+ }
56
+
57
+ > figcaption {
58
+ margin-top: $paragraph-margin-bottom / 4;
59
+ }
60
+
61
+ &.is-style-striped {
62
+ table > tbody > tr:nth-of-type(#{$table-striped-order}) {
63
+ --#{$variable-prefix}table-accent-bg: var(--#{$variable-prefix}table-striped-bg);
64
+ color: var(--#{$variable-prefix}table-striped-color);
65
+ }
66
+ }
67
+ }
@@ -0,0 +1 @@
1
+ // Override this file if you want to include any styling before default Block Editor styles are loaded. This would be a good place to add variables to customise Bootstrap
@@ -0,0 +1 @@
1
+ // Override this file if you want to include backend block styles to the Block Editor and not have to worry about losing any base styles
@@ -0,0 +1 @@
1
+ // Override this file if you want to include frontend block styles to the Block Editor and not have to worry about losing any base styles
@@ -0,0 +1,108 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import classnames from 'classnames';
4
+
5
+ import { PanelBody, ToggleControl } from '@wordpress/components';
6
+ import { InnerBlocks, InspectorControls, PlainText } from '@wordpress/block-editor'
7
+ import { box as icon } from '@wordpress/icons';
8
+
9
+ const name = 'be/accordion';
10
+
11
+ export { name };
12
+
13
+ export const settings = {
14
+ title: 'Accordion',
15
+ description: 'Accordions are elements that help you organize and navigate multiple documents in a single container.',
16
+ icon,
17
+ category: 'layout',
18
+ attributes: {
19
+ blockId: {
20
+ type: 'string'
21
+ },
22
+ title: {
23
+ source: 'text',
24
+ selector: '.accordion-button'
25
+ },
26
+ isOpenByDefault: {
27
+ type: 'boolean',
28
+ default: true
29
+ }
30
+ },
31
+ example: {
32
+ attributes: {
33
+ title: 'Open by default accordion'
34
+ },
35
+ innerBlocks: [
36
+ {
37
+ name: 'core/paragraph',
38
+ attributes: {
39
+ content: 'Use an accordion to structure and optionally collapse content'
40
+ }
41
+ }
42
+ ]
43
+ },
44
+ edit({clientId, attributes, className, setAttributes, isSelected}) {
45
+ const { blockId } = attributes;
46
+ if ( ! blockId ) {
47
+ setAttributes( { blockId: `id-${clientId}` } );
48
+ } else if ( blockId != clientId ) {
49
+ setAttributes( { blockId: `id-${clientId}` } );
50
+ }
51
+
52
+ // TODO: Update this to check if this OR any of the innerblocks are selected
53
+ // let inlineStyle = (isSelected || attributes.isOpenByDefault) ? { display: 'block' } : {};
54
+ let inlineStyle = { display: 'block' };
55
+
56
+ return [
57
+ <InspectorControls>
58
+ <PanelBody title={ 'Accordion settings' }>
59
+ <ToggleControl
60
+ label={ 'Open by default' }
61
+ onChange={ content => setAttributes({ isOpenByDefault: content }) }
62
+ checked={ attributes.isOpenByDefault }
63
+ />
64
+
65
+ </PanelBody>
66
+ </InspectorControls>,
67
+
68
+ <div className="wp-block-be-accordion accordion">
69
+ <div className="accordion-item">
70
+ <h2 className="accordion-header">
71
+ <PlainText
72
+ onChange={ content => setAttributes({ title: content }) }
73
+ value={ attributes.title }
74
+ placeholder="Your accordion title"
75
+ className="accordion-button"
76
+ />
77
+ </h2>
78
+ <div className="accordion-collapse collapse show">
79
+ <div className="accordion-body" style={ inlineStyle }>
80
+ <InnerBlocks/>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ ];
86
+ },
87
+ save({ attributes }) {
88
+ let buttonVisibilityClass = attributes.isOpenByDefault ? "collapsed" : "";
89
+ let accordionVisibilityClass = attributes.isOpenByDefault ? "show" : "";
90
+
91
+ return (
92
+ <div className="wp-block-be-accordion accordion">
93
+ <div className="accordion-item">
94
+ <h2 className="accordion-header">
95
+ <button className={ "accordion-button " + buttonVisibilityClass } type="button" data-bs-toggle="collapse" data-bs-target={ "#" + attributes.blockId }>
96
+ { attributes.title }
97
+ </button>
98
+ </h2>
99
+ <div id={attributes.blockId} className={ "accordion-collapse collapse " + accordionVisibilityClass }>
100
+ <div className="accordion-body">
101
+ <InnerBlocks.Content />
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ );
107
+ }
108
+ };
@@ -0,0 +1,51 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+
4
+ import {
5
+ InnerBlocks
6
+ } from '@wordpress/block-editor';
7
+ import { registerBlockStyle } from '@wordpress/blocks';
8
+ import { createBlock } from '@wordpress/blocks';
9
+ import { rawHandler } from '@wordpress/blocks';
10
+ import { box as icon } from '@wordpress/icons';
11
+
12
+ const name = 'be/alert';
13
+
14
+ export { name };
15
+
16
+ export const settings = {
17
+ title: 'Callout (Alert)',
18
+ description: 'Container to help draw attention to content.',
19
+ icon,
20
+ category: 'formatting',
21
+ styles: [
22
+ { name: 'primary', label: 'Primary', isDefault: true },
23
+ { name: 'secondary', label: 'Secondary' },
24
+ { name: 'success', label: 'Success' },
25
+ { name: 'danger', label: 'Danger' },
26
+ { name: 'warning', label: 'Warning' },
27
+ { name: 'info', label: 'Info' },
28
+ { name: 'light', label: 'Light' },
29
+ { name: 'dark', label: 'Dark' }
30
+ ],
31
+ example: {
32
+ innerBlocks: [
33
+ {
34
+ name: 'core/paragraph',
35
+ attributes: {
36
+ content: 'Use a callout to grab the users attention.'
37
+ }
38
+ }
39
+ ]
40
+ },
41
+ edit(props) {
42
+ return (
43
+ <div role="alert" className={ 'alert ' + props.className }>
44
+ <InnerBlocks/>
45
+ </div>
46
+ );
47
+ },
48
+ save() {
49
+ return <div role="alert" className='alert'><InnerBlocks.Content /></div>;
50
+ }
51
+ };
@@ -0,0 +1,205 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+
4
+ import {
5
+ InnerBlocks
6
+ } from '@wordpress/block-editor';
7
+ import { registerBlockStyle } from '@wordpress/blocks';
8
+ import { createBlock } from '@wordpress/blocks';
9
+ import { rawHandler } from '@wordpress/blocks';
10
+
11
+ import { TextControl, PanelBody, ToggleControl, Button } from '@wordpress/components';
12
+ import { InspectorControls, RichText, MediaUpload, PlainText } from '@wordpress/block-editor'
13
+ import { box as icon } from '@wordpress/icons';
14
+
15
+ const name = 'be/card';
16
+
17
+ export { name };
18
+
19
+ export const settings = {
20
+ title: 'Card',
21
+ description: 'Group a piece of content in an eye catching container.',
22
+ icon,
23
+ category: 'formatting',
24
+ example: {
25
+ attributes: {
26
+ title: 'Container example',
27
+ imageUrl: 'https://s.w.org/images/core/5.3/MtBlanc1.jpg',
28
+ }
29
+ },
30
+ attributes: {
31
+ title: {
32
+ source: 'text',
33
+ selector: '.card-title'
34
+ },
35
+ body: {
36
+ type: 'array',
37
+ source: 'children',
38
+ selector: '.card-content'
39
+ },
40
+ imageAlt: {
41
+ attribute: 'alt',
42
+ selector: '.card-img-top'
43
+ },
44
+ imageUrl: {
45
+ attribute: 'src',
46
+ selector: '.card-img-top'
47
+ },
48
+ hasCallToAction: {
49
+ type: 'boolean'
50
+ },
51
+ callToAction: {
52
+ type: 'text'
53
+ },
54
+ url: {
55
+ type: 'text'
56
+ },
57
+ openInNewTab: {
58
+ type: 'boolean'
59
+ }
60
+ },
61
+ edit({attributes, className, setAttributes, isSelected}) {
62
+ const getImageButton = (openEvent) => {
63
+ if(attributes.imageUrl) {
64
+ return (
65
+ <>
66
+ { isSelected &&
67
+ <Button
68
+ onClick={ openEvent }
69
+ className="button"
70
+ >
71
+ Edit
72
+ </Button>
73
+ }
74
+ <img
75
+ src={ attributes.imageUrl }
76
+ className="card-img-top"
77
+ />
78
+ </>
79
+ );
80
+ }
81
+ else {
82
+ return (
83
+ <div className="block-editor-image-placeholder">
84
+ <Button
85
+ onClick={ openEvent }
86
+ className="button button-large"
87
+ >
88
+ Pick an image
89
+ </Button>
90
+ </div>
91
+ );
92
+ }
93
+ };
94
+ return ([
95
+ <InspectorControls>
96
+ <PanelBody title='Card settings'>
97
+ <TextControl
98
+ label="URL"
99
+ value={ attributes.url }
100
+ onChange={ content => setAttributes({ url: content }) }
101
+ />
102
+ { attributes.url && (
103
+ <ToggleControl
104
+ label="Display Call To Action"
105
+ checked={ attributes.hasCallToAction }
106
+ onChange={ content => setAttributes({ hasCallToAction: content }) }
107
+ />
108
+ )}
109
+ { attributes.url && (
110
+ <ToggleControl
111
+ label="Open in new Tab?"
112
+ checked={ attributes.openInNewTab }
113
+ onChange={ content => setAttributes({ openInNewTab: content }) }
114
+ />
115
+ )}
116
+ </PanelBody>
117
+ </InspectorControls>,
118
+ <div className={ 'card ' + className }>
119
+ <MediaUpload
120
+ onSelect={ media => { setAttributes({ imageAlt: media.alt, imageUrl: media.url }); } }
121
+ type="image"
122
+ value={ attributes.imageID }
123
+ render={ ({ open }) => getImageButton(open) }
124
+ />
125
+ <div className='card-body'>
126
+ <PlainText
127
+ onChange={ content => setAttributes({ title: content }) }
128
+ value={ attributes.title }
129
+ placeholder="Your card title"
130
+ className="card-title h2"
131
+ />
132
+ <RichText
133
+ onChange={ content => setAttributes({ body: content }) }
134
+ value={ attributes.body }
135
+ multiline="p"
136
+ placeholder="Your card text"
137
+ />
138
+ </div>
139
+ { attributes.hasCallToAction && attributes.url &&
140
+ <PlainText
141
+ onChange={ content => setAttributes({ callToAction: content }) }
142
+ value={ attributes.callToAction }
143
+ placeholder="Your Call To Action"
144
+ className="card-link"
145
+ />
146
+ }
147
+ </div>
148
+ ]);
149
+ },
150
+ save({ attributes }) {
151
+ const linkTarget = (attributes.openInNewTab) ? '_blank' : '_self';
152
+ const cardImage = (src, alt) => {
153
+ if(!src) return null;
154
+
155
+ return (
156
+ <img
157
+ className="card-img-top"
158
+ src={ src }
159
+ alt={ alt }
160
+ />
161
+ );
162
+ }
163
+
164
+ return (
165
+ <div className="card">
166
+ { attributes.url ? (
167
+ <a
168
+ href={ attributes.url }
169
+ target= { linkTarget }
170
+ >
171
+ { cardImage(attributes.imageUrl, attributes.imageAlt) }
172
+ </a>
173
+ ) : (
174
+ cardImage(attributes.imageUrl, attributes.imageAlt)
175
+ )}
176
+ <div className="card-body">
177
+ <h3 className="card-title">
178
+ { attributes.url ? (
179
+ <a
180
+ href={ attributes.url }
181
+ target= { linkTarget }
182
+ >
183
+ { attributes.title }
184
+ </a>
185
+ ) : (
186
+ attributes.title
187
+ )}
188
+ </h3>
189
+ <div className='card-content'>
190
+ { attributes.body }
191
+ </div>
192
+ </div>
193
+ { attributes.hasCallToAction && attributes.url &&
194
+ <RichText.Content
195
+ tagName="a"
196
+ className='card-link'
197
+ href={ attributes.url }
198
+ target= { linkTarget }
199
+ value={ attributes.callToAction }
200
+ />
201
+ }
202
+ </div>
203
+ );
204
+ }
205
+ };