@ckeditor/ckeditor5-style 34.0.0 → 35.0.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 (95) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/LICENSE.md +2 -2
  3. package/build/style.js +1 -1
  4. package/build/translations/ar.js +1 -0
  5. package/build/translations/bg.js +1 -0
  6. package/build/translations/bn.js +1 -0
  7. package/build/translations/ca.js +1 -0
  8. package/build/translations/cs.js +1 -0
  9. package/build/translations/da.js +1 -0
  10. package/build/translations/de.js +1 -0
  11. package/build/translations/el.js +1 -0
  12. package/build/translations/en-au.js +1 -0
  13. package/build/translations/es.js +1 -0
  14. package/build/translations/et.js +1 -0
  15. package/build/translations/fi.js +1 -0
  16. package/build/translations/fr.js +1 -0
  17. package/build/translations/gl.js +1 -0
  18. package/build/translations/he.js +1 -0
  19. package/build/translations/hi.js +1 -0
  20. package/build/translations/hr.js +1 -0
  21. package/build/translations/hu.js +1 -0
  22. package/build/translations/id.js +1 -0
  23. package/build/translations/it.js +1 -0
  24. package/build/translations/ja.js +1 -0
  25. package/build/translations/ko.js +1 -0
  26. package/build/translations/lt.js +1 -0
  27. package/build/translations/lv.js +1 -0
  28. package/build/translations/ms.js +1 -0
  29. package/build/translations/nl.js +1 -0
  30. package/build/translations/no.js +1 -0
  31. package/build/translations/pl.js +1 -0
  32. package/build/translations/pt-br.js +1 -0
  33. package/build/translations/pt.js +1 -0
  34. package/build/translations/ro.js +1 -0
  35. package/build/translations/ru.js +1 -0
  36. package/build/translations/sk.js +1 -0
  37. package/build/translations/sr-latn.js +1 -0
  38. package/build/translations/sr.js +1 -0
  39. package/build/translations/sv.js +1 -0
  40. package/build/translations/th.js +1 -0
  41. package/build/translations/tr.js +1 -0
  42. package/build/translations/uk.js +1 -0
  43. package/build/translations/vi.js +1 -0
  44. package/build/translations/zh-cn.js +1 -0
  45. package/build/translations/zh.js +1 -0
  46. package/ckeditor5-metadata.json +3 -0
  47. package/lang/translations/ar.po +33 -0
  48. package/lang/translations/bg.po +33 -0
  49. package/lang/translations/bn.po +33 -0
  50. package/lang/translations/ca.po +33 -0
  51. package/lang/translations/cs.po +33 -0
  52. package/lang/translations/da.po +33 -0
  53. package/lang/translations/de.po +33 -0
  54. package/lang/translations/el.po +33 -0
  55. package/lang/translations/en-au.po +33 -0
  56. package/lang/translations/es.po +33 -0
  57. package/lang/translations/et.po +33 -0
  58. package/lang/translations/fi.po +33 -0
  59. package/lang/translations/fr.po +33 -0
  60. package/lang/translations/gl.po +33 -0
  61. package/lang/translations/he.po +33 -0
  62. package/lang/translations/hi.po +33 -0
  63. package/lang/translations/hr.po +33 -0
  64. package/lang/translations/hu.po +33 -0
  65. package/lang/translations/id.po +33 -0
  66. package/lang/translations/it.po +33 -0
  67. package/lang/translations/ja.po +33 -0
  68. package/lang/translations/ko.po +33 -0
  69. package/lang/translations/lt.po +33 -0
  70. package/lang/translations/lv.po +33 -0
  71. package/lang/translations/ms.po +33 -0
  72. package/lang/translations/nl.po +33 -0
  73. package/lang/translations/no.po +33 -0
  74. package/lang/translations/pl.po +33 -0
  75. package/lang/translations/pt-br.po +33 -0
  76. package/lang/translations/pt.po +33 -0
  77. package/lang/translations/ro.po +33 -0
  78. package/lang/translations/ru.po +33 -0
  79. package/lang/translations/sk.po +33 -0
  80. package/lang/translations/sr-latn.po +33 -0
  81. package/lang/translations/sr.po +33 -0
  82. package/lang/translations/sv.po +33 -0
  83. package/lang/translations/th.po +33 -0
  84. package/lang/translations/tr.po +33 -0
  85. package/lang/translations/uk.po +33 -0
  86. package/lang/translations/vi.po +33 -0
  87. package/lang/translations/zh-cn.po +33 -0
  88. package/lang/translations/zh.po +33 -0
  89. package/package.json +36 -34
  90. package/src/stylecommand.js +150 -153
  91. package/src/styleediting.js +1 -85
  92. package/src/styleui.js +6 -3
  93. package/src/ui/stylegridbuttonview.js +1 -1
  94. package/src/utils.js +13 -6
  95. package/theme/stylegrid.css +1 -0
@@ -18,29 +18,28 @@ import { logWarning, first } from 'ckeditor5/src/utils';
18
18
  * @extends module:core/command~Command
19
19
  */
20
20
  export default class StyleCommand extends Command {
21
- constructor( editor, styles ) {
21
+ /**
22
+ * Creates an instance of the command.
23
+ *
24
+ * @param {module:core/editor/editor~Editor} editor Editor on which this command will be used.
25
+ * @param {Object} styleDefinitions Normalized definitions of the styles.
26
+ * @param {Array.<module:style/style~StyleDefinition>} styleDefinitions.block Definitions of block styles.
27
+ * @param {Array.<module:style/style~StyleDefinition>} styleDefinitions.inline Definitions of inline styles.
28
+ */
29
+ constructor( editor, styleDefinitions ) {
22
30
  super( editor );
23
31
 
24
32
  /**
25
- * Set of currently applied styles on current selection.
33
+ * Set of currently applied styles on the current selection.
26
34
  *
27
35
  * Names of styles correspond to the `name` property of
28
36
  * {@link module:style/style~StyleDefinition configured definitions}.
29
37
  *
30
- * @observable
31
38
  * @readonly
32
- * @member {Boolean|String} #value
33
- */
34
-
35
- /**
36
- * Styles object. Helps in getting styles definitions by
37
- * class name, style name and model element name.
38
- *
39
- * @private
40
- * @readonly
41
- * @member {module:style/styleediting~Styles}
39
+ * @observable
40
+ * @member {Array.<String>} #value
42
41
  */
43
- this.styles = styles;
42
+ this.set( 'value', [] );
44
43
 
45
44
  /**
46
45
  * Names of enabled styles (styles that can be applied to the current selection).
@@ -55,33 +54,80 @@ export default class StyleCommand extends Command {
55
54
  this.set( 'enabledStyles', [] );
56
55
 
57
56
  /**
58
- * Refresh state.
57
+ * Normalized definitions of the styles.
58
+ *
59
+ * @private
60
+ * @readonly
61
+ * @member {Object} #styleDefinitions
59
62
  */
60
- this.refresh();
63
+ this._styleDefinitions = styleDefinitions;
61
64
  }
62
65
 
63
66
  /**
64
67
  * @inheritDoc
65
68
  */
66
69
  refresh() {
67
- let value = [];
68
- const editor = this.editor;
69
- const selection = editor.model.document.selection;
70
- const block = first( selection.getSelectedBlocks() );
70
+ const model = this.editor.model;
71
+ const selection = model.document.selection;
71
72
 
72
- this.enabledStyles = [];
73
+ const value = new Set();
74
+ const enabledStyles = new Set();
73
75
 
74
- if ( !block || !editor.model.schema.isObject( block ) ) {
75
- value = this._prepareNewInlineElementValue( value, selection );
76
- this.enabledStyles = this.styles.getInlineElementsNames();
76
+ // Inline styles.
77
+ for ( const definition of this._styleDefinitions.inline ) {
78
+ for ( const ghsAttributeName of definition.ghsAttributes ) {
79
+ // Check if this inline style is enabled.
80
+ if ( model.schema.checkAttributeInSelection( selection, ghsAttributeName ) ) {
81
+ enabledStyles.add( definition.name );
82
+ }
77
83
 
78
- if ( block ) {
79
- value = this._prepareNewBlockElementValue( value, block );
84
+ // Check if this inline style is active.
85
+ const ghsAttributeValue = this._getValueFromFirstAllowedNode( ghsAttributeName );
86
+
87
+ if ( hasAllClasses( ghsAttributeValue, definition.classes ) ) {
88
+ value.add( definition.name );
89
+ }
80
90
  }
81
91
  }
82
92
 
93
+ // Block styles.
94
+ const firstBlock = first( selection.getSelectedBlocks() );
95
+
96
+ if ( firstBlock ) {
97
+ const ancestorBlocks = firstBlock.getAncestors( { includeSelf: true, parentFirst: true } );
98
+
99
+ for ( const block of ancestorBlocks ) {
100
+ // E.g. reached a model table when the selection is in a cell. The command should not modify
101
+ // ancestors of a table.
102
+ if ( model.schema.isLimit( block ) ) {
103
+ break;
104
+ }
105
+
106
+ if ( !model.schema.checkAttribute( block, 'htmlAttributes' ) ) {
107
+ continue;
108
+ }
109
+
110
+ for ( const definition of this._styleDefinitions.block ) {
111
+ // Check if this block style is enabled.
112
+ if ( !definition.modelElements.includes( block.name ) ) {
113
+ continue;
114
+ }
115
+
116
+ enabledStyles.add( definition.name );
117
+
118
+ // Check if this block style is active.
119
+ const ghsAttributeValue = block.getAttribute( 'htmlAttributes' );
120
+
121
+ if ( hasAllClasses( ghsAttributeValue, definition.classes ) ) {
122
+ value.add( definition.name );
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ this.enabledStyles = Array.from( enabledStyles ).sort();
83
129
  this.isEnabled = this.enabledStyles.length > 0;
84
- this.value = this.isEnabled ? value : [];
130
+ this.value = this.isEnabled ? Array.from( value ).sort() : [];
85
131
  }
86
132
 
87
133
  /**
@@ -95,145 +141,74 @@ export default class StyleCommand extends Command {
95
141
  * * When applying inline styles:
96
142
  * * If the selection is on a range, the command applies the style classes to all nodes in that range.
97
143
  * * If the selection is collapsed in a non-empty node, the command applies the style classes to the
98
- * {@link module:engine/model/document~Document#selection} itself (note that typed characters copy style classes from the selection).
144
+ * {@link module:engine/model/document~Document#selection}.
99
145
  *
100
146
  * * When applying block styles:
101
147
  * * If the selection is on a range, the command applies the style classes to the nearest block parent element.
102
148
  *
103
- * * When selection is set on a widget object:
104
- * * Do nothing. Widgets are not yet supported by the style command.
105
- *
106
149
  * @fires execute
107
- * @param {String} styleName Style name matching the one defined in the config.
150
+ * @param {Object} [options] Command options.
151
+ * @param {String} options.styleName Style name matching the one defined in the
152
+ * {@link module:style/style~StyleConfig#definitions configuration}.
153
+ * @param {Boolean} [options.forceValue] Whether the command should add given style (`true`) or remove it (`false`) from the selection.
154
+ * If not set (default), the command will toggle the style basing on the first selected node. Note, that this will not force
155
+ * setting a style on an element that cannot receive given style.
108
156
  */
109
- execute( styleName ) {
157
+ execute( { styleName, forceValue } ) {
110
158
  if ( !this.enabledStyles.includes( styleName ) ) {
111
159
  /**
112
- * Style command can be executed only on a correct style name.
113
- * This warning may be caused by passing name that it not specified in any of the
114
- * definitions in the styles config, when trying to apply style that is not allowed
115
- * on given element or passing class name instead of the style name.
160
+ * Style command can be executed only with a correct style name.
161
+ *
162
+ * This warning may be caused by:
163
+ *
164
+ * * passing a name that is not specified in the {@link module:style/style~StyleConfig#definitions configuration}
165
+ * (e.g. a CSS class name),
166
+ * * when trying to apply a style that is not allowed on a given element.
116
167
  *
117
168
  * @error style-command-executed-with-incorrect-style-name
118
169
  */
119
170
  logWarning( 'style-command-executed-with-incorrect-style-name' );
120
- return;
121
- }
122
-
123
- const editor = this.editor;
124
- const model = editor.model;
125
- const doc = model.document;
126
- const selection = doc.selection;
127
-
128
- const selectedBlockElement = first( selection.getSelectedBlocks() );
129
- const definition = this.styles.getDefinitionsByName( styleName );
130
171
 
131
- if ( selectedBlockElement && definition.isBlock ) {
132
- this._handleStyleUpdate( definition, selectedBlockElement );
133
- } else {
134
- this._handleStyleUpdate( definition, selection );
172
+ return;
135
173
  }
136
- }
137
174
 
138
- /**
139
- * Adds or removes classes to element, range or selection.
140
- *
141
- * @private
142
- * @param {Object} definition Style definition object.
143
- * @param {module:engine/model/selection~Selectable} selectable Selection, range or element to update the style on.
144
- */
145
- _handleStyleUpdate( definition, selectable ) {
146
- const { name, element, classes } = definition;
175
+ const model = this.editor.model;
176
+ const selection = model.document.selection;
147
177
  const htmlSupport = this.editor.plugins.get( 'GeneralHtmlSupport' );
148
178
 
149
- if ( this.value.includes( name ) ) {
150
- htmlSupport.removeModelHtmlClass( element, classes, selectable );
151
- } else {
152
- htmlSupport.addModelHtmlClass( element, classes, selectable );
153
- }
154
- }
155
-
156
- /**
157
- * Returns inline element value.
158
- *
159
- * @private
160
- * @param {Array} value
161
- * @param {module:engine/model/selection~Selection} selection
162
- */
163
- _prepareNewInlineElementValue( value, selection ) {
164
- let newValue = [ ...value ];
165
-
166
- const attributes = selection.getAttributes();
167
-
168
- for ( const [ attribute ] of attributes ) {
169
- newValue = [ ...newValue, ...this._getAttributeValue( attribute ) ];
170
- }
171
-
172
- return newValue;
173
- }
174
-
175
- /**
176
- * Returns element value and sets enabled styles.
177
- *
178
- * @private
179
- * @param {Array} value
180
- * @param {Object|null} element
181
- * @return {Array} Current block element styles value.
182
- */
183
- _prepareNewBlockElementValue( value, element ) {
184
- const availableDefinitions = this.styles.getDefinitionsByElementName( element.name );
185
-
186
- if ( availableDefinitions ) {
187
- const blockStyleNames = availableDefinitions.map( ( { name } ) => name );
188
- this.enabledStyles = [ ...this.enabledStyles, ...blockStyleNames ];
189
- }
179
+ const definition = [
180
+ ...this._styleDefinitions.inline,
181
+ ...this._styleDefinitions.block
182
+ ].find( ( { name } ) => name == styleName );
190
183
 
191
- return [ ...value, ...this._getAttributeValue( 'htmlAttributes' ) ];
192
- }
184
+ const shouldAddStyle = forceValue === undefined ? !this.value.includes( definition.name ) : forceValue;
193
185
 
194
- /**
195
- * Get classes attribute value.
196
- *
197
- * @private
198
- * @param {String} attribute
199
- */
200
- _getAttributeValue( attribute ) {
201
- const value = [];
202
- const classes = attribute === 'htmlAttributes' ?
203
- this._getValueFromBlockElement() :
204
- this._getValueFromFirstAllowedNode( attribute );
186
+ model.change( () => {
187
+ let selectables;
205
188
 
206
- for ( const htmlClass of classes ) {
207
- const { name } = this.styles.getDefinitionsByClassName( htmlClass ) || {};
208
-
209
- value.push( name );
210
- }
211
-
212
- return value;
213
- }
214
-
215
- /**
216
- * Gets classes from currently selected block element.
217
- *
218
- * @private
219
- */
220
- _getValueFromBlockElement() {
221
- const selection = this.editor.model.document.selection;
222
- const block = first( selection.getSelectedBlocks() );
223
- const attributes = block.getAttribute( 'htmlAttributes' );
224
-
225
- if ( attributes ) {
226
- return attributes.classes;
227
- }
189
+ if ( definition.isBlock ) {
190
+ selectables = getAffectedBlocks( selection.getSelectedBlocks(), definition.modelElements, model.schema );
191
+ } else {
192
+ selectables = [ selection ];
193
+ }
228
194
 
229
- return [];
195
+ for ( const selectable of selectables ) {
196
+ if ( shouldAddStyle ) {
197
+ htmlSupport.addModelHtmlClass( definition.element, definition.classes, selectable );
198
+ } else {
199
+ htmlSupport.removeModelHtmlClass( definition.element, definition.classes, selectable );
200
+ }
201
+ }
202
+ } );
230
203
  }
231
204
 
232
205
  /**
233
- * Gets classes from currently selected text element.
206
+ * Checks the attribute value of the first node in the selection that allows the attribute.
207
+ * For the collapsed selection, returns the selection attribute.
234
208
  *
235
209
  * @private
236
- * @param {String} attributeName Text attribute name.
210
+ * @param {String} attributeName Name of the GHS attribute.
211
+ * @returns {Object|null} The attribute value.
237
212
  */
238
213
  _getValueFromFirstAllowedNode( attributeName ) {
239
214
  const model = this.editor.model;
@@ -241,27 +216,49 @@ export default class StyleCommand extends Command {
241
216
  const selection = model.document.selection;
242
217
 
243
218
  if ( selection.isCollapsed ) {
244
- /* istanbul ignore next */
245
- const { classes } = selection.getAttribute( attributeName ) || {};
246
-
247
- /* istanbul ignore next */
248
- return classes || [];
219
+ return selection.getAttribute( attributeName );
249
220
  }
250
221
 
251
222
  for ( const range of selection.getRanges() ) {
252
223
  for ( const item of range.getItems() ) {
253
- /* istanbul ignore else */
254
224
  if ( schema.checkAttribute( item, attributeName ) ) {
255
- /* istanbul ignore next */
256
- const { classes } = item.getAttribute( attributeName ) || {};
257
-
258
- /* istanbul ignore next */
259
- return classes || [];
225
+ return item.getAttribute( attributeName );
260
226
  }
261
227
  }
262
228
  }
263
229
 
264
- /* istanbul ignore next */
265
- return [];
230
+ return null;
231
+ }
232
+ }
233
+
234
+ // Verifies if all classes are present in the given GHS attribute.
235
+ function hasAllClasses( ghsAttributeValue, classes ) {
236
+ if ( !ghsAttributeValue || !ghsAttributeValue.classes ) {
237
+ return false;
266
238
  }
239
+
240
+ return classes.every( className => ghsAttributeValue.classes.includes( className ) );
241
+ }
242
+
243
+ // Returns a set of elements that should be affected by the block-style change.
244
+ function getAffectedBlocks( selectedBlocks, elementNames, schema ) {
245
+ const blocks = new Set();
246
+
247
+ for ( const selectedBlock of selectedBlocks ) {
248
+ const ancestorBlocks = selectedBlock.getAncestors( { includeSelf: true, parentFirst: true } );
249
+
250
+ for ( const block of ancestorBlocks ) {
251
+ if ( schema.isLimit( block ) ) {
252
+ break;
253
+ }
254
+
255
+ if ( elementNames.includes( block.name ) ) {
256
+ blocks.add( block );
257
+
258
+ break;
259
+ }
260
+ }
261
+ }
262
+
263
+ return blocks;
267
264
  }
@@ -43,9 +43,8 @@ export default class StyleEditing extends Plugin {
43
43
  const editor = this.editor;
44
44
  const dataSchema = editor.plugins.get( 'DataSchema' );
45
45
  const normalizedStyleDefinitions = normalizeConfig( dataSchema, editor.config.get( 'style.definitions' ) );
46
- const styles = new Styles( normalizedStyleDefinitions );
47
46
 
48
- editor.commands.add( 'style', new StyleCommand( editor, styles ) );
47
+ editor.commands.add( 'style', new StyleCommand( editor, normalizedStyleDefinitions ) );
49
48
 
50
49
  this._configureGHSDataFilter( normalizedStyleDefinitions );
51
50
  }
@@ -66,89 +65,6 @@ export default class StyleEditing extends Plugin {
66
65
  }
67
66
  }
68
67
 
69
- /**
70
- * The helper class storing various mappings based on
71
- * {@link module:style/style~StyleConfig#definitions configured style definitions}. Used internally by
72
- * {@link module:style/stylecommand~StyleCommand}.
73
- *
74
- * @private
75
- */
76
- class Styles {
77
- /**
78
- * @param {Object} An object with normalized style definitions grouped into `block` and `inline` categories (arrays).
79
- */
80
- constructor( styleDefinitions ) {
81
- this.styleTypes = [ 'inline', 'block' ];
82
- this.styleDefinitions = styleDefinitions;
83
- this.elementToDefinition = new Map();
84
- this.classToDefinition = new Map();
85
- this.nameToDefinition = new Map();
86
-
87
- this._prepareDefinitionsMapping();
88
- }
89
-
90
- /**
91
- * Populates various maps to simplify getting config definitions
92
- * by model name,class name and style name.
93
- *
94
- * @private
95
- */
96
- _prepareDefinitionsMapping() {
97
- for ( const type of this.styleTypes ) {
98
- for ( const { modelElements, name, element, classes, isBlock } of this.styleDefinitions[ type ] ) {
99
- for ( const modelElement of modelElements ) {
100
- const currentValue = this.elementToDefinition.get( modelElement ) || [];
101
- const newValue = [ ...currentValue, { name, element, classes } ];
102
- this.elementToDefinition.set( modelElement, newValue );
103
- }
104
-
105
- this.classToDefinition.set( classes.join( ' ' ), { name, element, classes } );
106
- this.nameToDefinition.set( name, { name, element, classes, isBlock } );
107
- }
108
- }
109
- }
110
-
111
- /**
112
- * Returns all inline definitions elements names.
113
- *
114
- * @protected
115
- * @return {Array.<String>} Inline elements names.
116
- */
117
- getInlineElementsNames() {
118
- return this.styleDefinitions.inline.map( ( { name } ) => name );
119
- }
120
-
121
- /**
122
- * Returns the style config definitions by the model element name.
123
- *
124
- * @protected
125
- * @return {Object} Style config definition.
126
- */
127
- getDefinitionsByElementName( elementName ) {
128
- return this.elementToDefinition.get( elementName );
129
- }
130
-
131
- /**
132
- * Returns the style config definitions by the style name.
133
- *
134
- * @protected
135
- * @return {Object} Style config definition.
136
- */
137
- getDefinitionsByName( name ) {
138
- return this.nameToDefinition.get( name );
139
- }
140
-
141
- /**
142
- * Returns the style config definitions by the style name.
143
- *
144
- * @protected
145
- * @return {Object} Style config definition.
146
- */
147
- getDefinitionsByClassName( className ) {
148
- return this.classToDefinition.get( className );
149
- }
150
- }
151
-
152
68
  // Translates a normalized style definition to a view matcher pattern.
153
69
  //
154
70
  // @param {Object} definition A normalized style definition.
package/src/styleui.js CHANGED
@@ -39,7 +39,7 @@ export default class StyleUI extends Plugin {
39
39
  const dataSchema = editor.plugins.get( 'DataSchema' );
40
40
  const normalizedStyleDefinitions = normalizeConfig( dataSchema, editor.config.get( 'style.definitions' ) );
41
41
 
42
- // Add the dropdown fo the component factory.
42
+ // Add the dropdown to the component factory.
43
43
  editor.ui.componentFactory.add( 'style', locale => {
44
44
  const t = locale.t;
45
45
  const dropdown = createDropdown( locale );
@@ -85,8 +85,11 @@ export default class StyleUI extends Plugin {
85
85
  panelView.delegate( 'execute' ).to( dropdown );
86
86
 
87
87
  // Execute the command when a style is selected in the styles panel.
88
- panelView.on( 'execute', evt => {
89
- editor.execute( 'style', evt.source.styleDefinition.name );
88
+ // Also focus the editable after executing the command.
89
+ // It overrides a default behaviour where the focus is moved to the dropdown button (#12125).
90
+ dropdown.on( 'execute', evt => {
91
+ editor.execute( 'style', { styleName: evt.source.styleDefinition.name } );
92
+ editor.editing.view.focus();
90
93
  } );
91
94
 
92
95
  // Bind the state of the styles panel to the command.
@@ -109,7 +109,7 @@ export default class StyleGridButtonView extends ButtonView {
109
109
  * be used instead. This avoids previewing a standalone `<td>`, `<li>`, etc. without a parent.
110
110
  *
111
111
  * @private
112
- * @param {module:style/style~StyleDefinition} styleDefinition
112
+ * @param {String} elementName
113
113
  * @returns {Boolean} `true` when the element can be rendered. `false` otherwise.
114
114
  */
115
115
  _isPreviewable( elementName ) {
package/src/utils.js CHANGED
@@ -36,14 +36,21 @@ export function normalizeConfig( dataSchema, styleDefinitions = [] ) {
36
36
  };
37
37
 
38
38
  for ( const definition of styleDefinitions ) {
39
- const matchingDefinitions = Array.from( dataSchema.getDefinitionsForView( definition.element ) );
40
- const modelElements = matchingDefinitions.map( ( { model } ) => model );
41
- const isBlock = matchingDefinitions.some( ( { isBlock } ) => isBlock );
39
+ const modelElements = [];
40
+ const ghsAttributes = [];
42
41
 
43
- if ( isBlock ) {
44
- normalizedDefinitions.block.push( { isBlock, modelElements, ...definition } );
42
+ for ( const ghsDefinition of dataSchema.getDefinitionsForView( definition.element ) ) {
43
+ if ( ghsDefinition.isBlock ) {
44
+ modelElements.push( ghsDefinition.model );
45
+ } else {
46
+ ghsAttributes.push( ghsDefinition.model );
47
+ }
48
+ }
49
+
50
+ if ( modelElements.length ) {
51
+ normalizedDefinitions.block.push( { ...definition, modelElements, isBlock: true } );
45
52
  } else {
46
- normalizedDefinitions.inline.push( { isBlock, modelElements, ...definition } );
53
+ normalizedDefinitions.inline.push( { ...definition, ghsAttributes } );
47
54
  }
48
55
  }
49
56
  return normalizedDefinitions;
@@ -10,6 +10,7 @@
10
10
  .ck.ck-style-panel .ck-style-grid {
11
11
  display: grid;
12
12
  grid-template-columns: repeat(var(--ck-style-panel-columns),auto);
13
+ justify-content: start;
13
14
 
14
15
  & .ck-style-grid__button {
15
16
  display: flex;