@themarioga/grid-editor 7.2.0 → 8.0.0-beta.2

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 (97) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +96 -30
  3. package/UPGRADING.md +86 -0
  4. package/dist/grideditor.bundle.min.js +3 -3
  5. package/dist/grideditor.css +149 -6
  6. package/dist/grideditor.d.ts +18 -0
  7. package/dist/grideditor.esm.js +257 -48
  8. package/dist/grideditor.jquery.js +0 -13
  9. package/dist/grideditor.jquery.min.js +1 -1
  10. package/dist/grideditor.jquery.min.js.map +3 -3
  11. package/dist/grideditor.js +257 -48
  12. package/dist/grideditor.min.css +1 -1
  13. package/dist/grideditor.min.css.map +1 -1
  14. package/dist/grideditor.min.js +2 -2
  15. package/dist/grideditor.min.js.map +3 -3
  16. package/dist/locales/grideditor.es.esm.js +80 -6
  17. package/dist/locales/grideditor.es.js +80 -6
  18. package/dist/locales/grideditor.es.min.js +1 -1
  19. package/dist/locales/grideditor.es.min.js.map +2 -2
  20. package/dist/plugins/grideditor.accordion.min.js.map +2 -2
  21. package/dist/plugins/grideditor.alignment.esm.js +11 -38
  22. package/dist/plugins/grideditor.alignment.js +11 -38
  23. package/dist/plugins/grideditor.alignment.min.js +1 -1
  24. package/dist/plugins/grideditor.alignment.min.js.map +3 -3
  25. package/dist/plugins/grideditor.card.min.js.map +1 -1
  26. package/dist/plugins/grideditor.ckeditor.esm.js +0 -5
  27. package/dist/plugins/grideditor.ckeditor.js +0 -5
  28. package/dist/plugins/grideditor.ckeditor.min.js +1 -1
  29. package/dist/plugins/grideditor.ckeditor.min.js.map +3 -3
  30. package/dist/plugins/grideditor.clipboard.min.js.map +1 -1
  31. package/dist/plugins/grideditor.codemirror-inline.min.js.map +1 -1
  32. package/dist/plugins/grideditor.codemirror.min.js.map +1 -1
  33. package/dist/plugins/grideditor.elements.min.js.map +2 -2
  34. package/dist/plugins/grideditor.gutters.min.js.map +1 -1
  35. package/dist/plugins/grideditor.order.min.js.map +1 -1
  36. package/dist/plugins/grideditor.popup.min.js.map +1 -1
  37. package/dist/plugins/grideditor.sections.min.js.map +2 -2
  38. package/dist/plugins/grideditor.style.esm.js +1926 -0
  39. package/dist/plugins/grideditor.style.js +1923 -0
  40. package/dist/plugins/grideditor.style.min.js +4 -0
  41. package/dist/plugins/grideditor.style.min.js.map +7 -0
  42. package/dist/plugins/grideditor.summernote.min.js.map +2 -2
  43. package/dist/plugins/grideditor.tabs.min.js.map +2 -2
  44. package/dist/plugins/grideditor.tinymce.esm.js +1 -8
  45. package/dist/plugins/grideditor.tinymce.js +1 -8
  46. package/dist/plugins/grideditor.tinymce.min.js +1 -1
  47. package/dist/plugins/grideditor.tinymce.min.js.map +3 -3
  48. package/docs/events.md +4 -6
  49. package/docs/locale-keys.md +99 -15
  50. package/docs/plugins.md +47 -23
  51. package/example/ckeditor.html +0 -5
  52. package/example/index.html +17 -2
  53. package/example/style.html +163 -0
  54. package/example/utilities.html +21 -16
  55. package/package.json +1 -1
  56. package/src/js/dom.js +1 -2
  57. package/src/js/grideditor.jquery.js +7 -28
  58. package/src/js/grideditor.js +336 -67
  59. package/src/js/locales/grideditor.es.js +80 -6
  60. package/src/js/plugins/grideditor.alignment.js +21 -50
  61. package/src/js/plugins/grideditor.ckeditor.js +10 -23
  62. package/src/js/plugins/grideditor.style.js +185 -0
  63. package/src/js/plugins/grideditor.summernote.js +4 -5
  64. package/src/js/plugins/grideditor.tinymce.js +4 -17
  65. package/src/js/style/accordion.js +168 -0
  66. package/src/js/style/catalog.js +76 -0
  67. package/src/js/style/custom.js +84 -0
  68. package/src/js/style/display.js +229 -0
  69. package/src/js/style/drawerflow.js +118 -0
  70. package/src/js/style/fields.js +382 -0
  71. package/src/js/style/flex.js +156 -0
  72. package/src/js/{plugins/grideditor.float.js → style/float.js} +6 -16
  73. package/src/js/style/options.js +60 -0
  74. package/src/js/style/sections.js +298 -0
  75. package/src/js/{plugins/grideditor.spacing.js → style/spacing.js} +7 -19
  76. package/src/js/style/sticky.js +39 -0
  77. package/src/js/{plugins/grideditor.textalign.js → style/textalign.js} +6 -14
  78. package/src/js/text/grideditor.text.js +1 -1
  79. package/src/less/grideditor.less +151 -10
  80. package/types/grideditor.d.ts +18 -0
  81. package/dist/plugins/grideditor.float.esm.js +0 -34
  82. package/dist/plugins/grideditor.float.js +0 -41
  83. package/dist/plugins/grideditor.float.min.js +0 -1
  84. package/dist/plugins/grideditor.float.min.js.map +0 -7
  85. package/dist/plugins/grideditor.spacing.esm.js +0 -318
  86. package/dist/plugins/grideditor.spacing.js +0 -323
  87. package/dist/plugins/grideditor.spacing.min.js +0 -1
  88. package/dist/plugins/grideditor.spacing.min.js.map +0 -7
  89. package/dist/plugins/grideditor.textalign.esm.js +0 -40
  90. package/dist/plugins/grideditor.textalign.js +0 -47
  91. package/dist/plugins/grideditor.textalign.min.js +0 -1
  92. package/dist/plugins/grideditor.textalign.min.js.map +0 -7
  93. package/dist/plugins/grideditor.visibility.esm.js +0 -158
  94. package/dist/plugins/grideditor.visibility.js +0 -163
  95. package/dist/plugins/grideditor.visibility.min.js +0 -1
  96. package/dist/plugins/grideditor.visibility.min.js.map +0 -7
  97. package/src/js/plugins/grideditor.visibility.js +0 -171
@@ -0,0 +1,298 @@
1
+ /**
2
+ * What the style plugin's sections are made of: for each, its inline
3
+ * properties and the field each one gets, the Bootstrap 5.3 classes its
4
+ * catalog offers, and which of the merged utility parts it shows.
5
+ *
6
+ * Data, and the few questions asked of it: which classes set a property,
7
+ * which properties a kind of node is offered.
8
+ */
9
+
10
+ var COLORS = ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark'];
11
+ var SIDES = ['top', 'end', 'bottom', 'start'];
12
+ var OPACITIES = ['10', '25', '50', '75', '100'];
13
+
14
+ function each(prefix, values, suffix) {
15
+ return values.map(function(value) { return prefix + value + (suffix || ''); });
16
+ }
17
+
18
+ /**
19
+ * A catalog group: the classes it offers and whether they exclude each
20
+ * other, so choosing one takes the others off. `notOn` names the kinds of
21
+ * node it is never offered on, `onlyOn` the only ones it is.
22
+ */
23
+ function group(classes, exclusive, notOn, onlyOn) {
24
+ return { classes: classes, exclusive: exclusive !== false, notOn: notOn || [], onlyOn: onlyOn || null };
25
+ }
26
+
27
+ /**
28
+ * A property's field. `type` is the widget: text for any css value, select
29
+ * for a fixed list, color, url for background-image, shadow for
30
+ * box-shadow and text-shadow. `notOn` names the kinds of node it is never
31
+ * offered on.
32
+ */
33
+ function prop(name, options) {
34
+ return {
35
+ name: name,
36
+ labelKey: options.labelKey,
37
+ type: options.type || 'text',
38
+ values: options.values || null,
39
+ notOn: options.notOn || [],
40
+ };
41
+ }
42
+
43
+ var NOT_ON_COLUMN = ['column'];
44
+
45
+ /** The image classes are for the markup an element holds. */
46
+ var ONLY_ON_ELEMENT = ['element'];
47
+
48
+ export var SECTIONS = [
49
+ {
50
+ key: 'size',
51
+ labelKey: 'style.section_size',
52
+ properties: [
53
+ prop('width', { labelKey: 'style.prop_width', notOn: NOT_ON_COLUMN }),
54
+ prop('height', { labelKey: 'style.prop_height', notOn: NOT_ON_COLUMN }),
55
+ prop('min-width', { labelKey: 'style.prop_min_width' }),
56
+ prop('min-height', { labelKey: 'style.prop_min_height' }),
57
+ prop('max-width', { labelKey: 'style.prop_max_width' }),
58
+ prop('max-height', { labelKey: 'style.prop_max_height' }),
59
+ ],
60
+ catalog: [
61
+ group(each('w-', ['25', '50', '75', '100', 'auto']), true, NOT_ON_COLUMN),
62
+ group(each('h-', ['25', '50', '75', '100', 'auto']), true, NOT_ON_COLUMN),
63
+ group(['mw-100', 'mh-100', 'vw-100', 'vh-100', 'min-vw-100', 'min-vh-100'], false, NOT_ON_COLUMN),
64
+ group(['img-fluid', 'img-thumbnail'], false, [], ONLY_ON_ELEMENT),
65
+ group(each('object-fit-', ['contain', 'cover', 'fill', 'scale', 'none']), true, [], ONLY_ON_ELEMENT),
66
+ ],
67
+ parts: [],
68
+ },
69
+ {
70
+ key: 'spacing',
71
+ labelKey: 'style.section_spacing',
72
+ properties: [
73
+ prop('margin-top', { labelKey: 'style.prop_margin_top' }), prop('margin-right', { labelKey: 'style.prop_margin_right' }), prop('margin-bottom', { labelKey: 'style.prop_margin_bottom' }), prop('margin-left', { labelKey: 'style.prop_margin_left' }),
74
+ prop('padding-top', { labelKey: 'style.prop_padding_top' }), prop('padding-right', { labelKey: 'style.prop_padding_right' }), prop('padding-bottom', { labelKey: 'style.prop_padding_bottom' }), prop('padding-left', { labelKey: 'style.prop_padding_left' }),
75
+ ],
76
+ catalog: [],
77
+ parts: ['spacing'],
78
+ },
79
+ {
80
+ key: 'border',
81
+ labelKey: 'style.section_border',
82
+ properties: [
83
+ prop('border-width', { labelKey: 'style.prop_border_width' }),
84
+ prop('border-style', { labelKey: 'style.prop_border_style', type: 'select', values: ['none', 'solid', 'dashed', 'dotted', 'double', 'groove', 'ridge', 'inset', 'outset'] }),
85
+ prop('border-color', { labelKey: 'style.prop_border_color', type: 'color' }),
86
+ prop('border-radius', { labelKey: 'style.prop_border_radius' }),
87
+ prop('box-shadow', { labelKey: 'style.prop_box_shadow', type: 'shadow' }),
88
+ ],
89
+ catalog: [
90
+ group(['border', 'border-0'].concat(each('border-', SIDES), each('border-', SIDES, '-0')), false),
91
+ group(each('border-', ['1', '2', '3', '4', '5'])),
92
+ group(each('border-', COLORS.concat(['black', 'white'])).concat(each('border-', COLORS, '-subtle'))),
93
+ group(each('border-opacity-', OPACITIES)),
94
+ group(['rounded'].concat(each('rounded-', ['0', '1', '2', '3', '4', '5', 'circle', 'pill']))),
95
+ group(each('rounded-', SIDES), false),
96
+ group(['shadow-none', 'shadow-sm', 'shadow', 'shadow-lg']),
97
+ ],
98
+ parts: [],
99
+ },
100
+ {
101
+ key: 'background',
102
+ labelKey: 'style.section_background',
103
+ properties: [
104
+ prop('background-color', { labelKey: 'style.prop_background_color', type: 'color' }),
105
+ prop('background-image', { labelKey: 'style.prop_background_image', type: 'url' }),
106
+ prop('background-size', { labelKey: 'style.prop_background_size' }),
107
+ prop('background-position', { labelKey: 'style.prop_background_position' }),
108
+ prop('background-repeat', { labelKey: 'style.prop_background_repeat', type: 'select', values: ['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'space', 'round'] }),
109
+ ],
110
+ catalog: [
111
+ group(each('bg-', COLORS.concat(['body', 'body-secondary', 'body-tertiary', 'white', 'black', 'transparent']))
112
+ .concat(each('bg-', COLORS, '-subtle'), each('text-bg-', COLORS))),
113
+ group(['bg-gradient'], false),
114
+ group(each('bg-opacity-', OPACITIES)),
115
+ ],
116
+ parts: [],
117
+ },
118
+ {
119
+ key: 'text',
120
+ labelKey: 'style.section_text',
121
+ properties: [
122
+ prop('color', { labelKey: 'style.prop_color', type: 'color' }),
123
+ prop('font-size', { labelKey: 'style.prop_font_size' }),
124
+ prop('text-align', { labelKey: 'style.prop_text_align', type: 'select', values: ['start', 'center', 'end', 'left', 'right', 'justify'] }),
125
+ prop('text-shadow', { labelKey: 'style.prop_text_shadow', type: 'shadow' }),
126
+ ],
127
+ catalog: [
128
+ group(each('text-', COLORS.concat(['body', 'body-secondary', 'body-tertiary', 'white', 'black']))
129
+ .concat(each('text-', COLORS, '-emphasis'), ['text-body-emphasis'])),
130
+ group(each('text-opacity-', ['25', '50', '75', '100'])),
131
+ group(each('fs-', ['1', '2', '3', '4', '5', '6'])),
132
+ group(each('text-decoration-', ['none', 'underline', 'line-through'])),
133
+ ],
134
+ parts: ['textalign'],
135
+ },
136
+ {
137
+ key: 'typography',
138
+ labelKey: 'style.section_typography',
139
+ properties: [
140
+ prop('font-family', { labelKey: 'style.prop_font_family' }),
141
+ prop('font-weight', { labelKey: 'style.prop_font_weight', type: 'select', values: ['100', '200', '300', '400', '500', '600', '700', '800', '900', 'normal', 'bold', 'lighter', 'bolder'] }),
142
+ prop('font-style', { labelKey: 'style.prop_font_style', type: 'select', values: ['normal', 'italic', 'oblique'] }),
143
+ prop('line-height', { labelKey: 'style.prop_line_height' }),
144
+ prop('letter-spacing', { labelKey: 'style.prop_letter_spacing' }),
145
+ prop('text-transform', { labelKey: 'style.prop_text_transform', type: 'select', values: ['none', 'uppercase', 'lowercase', 'capitalize'] }),
146
+ prop('text-decoration', { labelKey: 'style.prop_text_decoration', type: 'select', values: ['none', 'underline', 'line-through', 'overline'] }),
147
+ ],
148
+ catalog: [
149
+ group(each('fw-', ['lighter', 'light', 'normal', 'medium', 'semibold', 'bold', 'bolder'])),
150
+ group(each('fst-', ['italic', 'normal'])),
151
+ group(each('lh-', ['1', 'sm', 'base', 'lg'])),
152
+ group(each('text-', ['lowercase', 'uppercase', 'capitalize'])),
153
+ group(['font-monospace'], false),
154
+ group(['text-wrap', 'text-nowrap']),
155
+ group(['text-break'], false),
156
+ ],
157
+ parts: [],
158
+ },
159
+ {
160
+ key: 'display',
161
+ labelKey: 'style.section_display',
162
+ properties: [
163
+ prop('display', { labelKey: 'style.prop_display', type: 'select', values: ['none', 'block', 'inline', 'inline-block', 'flex', 'inline-flex', 'grid', 'inline-grid'] }),
164
+ prop('opacity', { labelKey: 'style.prop_opacity' }),
165
+ prop('overflow', { labelKey: 'style.prop_overflow', type: 'select', values: ['visible', 'hidden', 'auto', 'scroll', 'clip'] }),
166
+ prop('visibility', { labelKey: 'style.prop_visibility', type: 'select', values: ['visible', 'hidden'] }),
167
+ ],
168
+ catalog: [
169
+ group(each('opacity-', ['0', '25', '50', '75', '100'])),
170
+ group(each('overflow-', ['auto', 'hidden', 'visible', 'scroll'])),
171
+ group(['visible', 'invisible']),
172
+ ],
173
+ parts: ['display'],
174
+ },
175
+ {
176
+ key: 'flex',
177
+ labelKey: 'style.section_flex',
178
+ properties: [],
179
+ catalog: [
180
+ group(['vstack', 'hstack'], true, ['row']),
181
+ ],
182
+ parts: ['flex'],
183
+ },
184
+ {
185
+ key: 'position',
186
+ labelKey: 'style.section_position',
187
+ properties: [
188
+ prop('position', { labelKey: 'style.prop_position', type: 'select', values: ['static', 'relative', 'absolute', 'fixed', 'sticky'] }),
189
+ prop('top', { labelKey: 'style.prop_top', notOn: NOT_ON_COLUMN }),
190
+ prop('right', { labelKey: 'style.prop_right', notOn: NOT_ON_COLUMN }),
191
+ prop('bottom', { labelKey: 'style.prop_bottom', notOn: NOT_ON_COLUMN }),
192
+ prop('left', { labelKey: 'style.prop_left', notOn: NOT_ON_COLUMN }),
193
+ prop('z-index', { labelKey: 'style.prop_z_index' }),
194
+ ],
195
+ catalog: [
196
+ group(each('position-', ['static', 'relative', 'absolute', 'fixed', 'sticky'])),
197
+ group(each('top-', ['0', '50', '100'])),
198
+ group(each('bottom-', ['0', '50', '100'])),
199
+ group(each('start-', ['0', '50', '100'])),
200
+ group(each('end-', ['0', '50', '100'])),
201
+ group(['translate-middle', 'translate-middle-x', 'translate-middle-y']),
202
+ group(['z-n1', 'z-0', 'z-1', 'z-2', 'z-3']),
203
+ group(['fixed-top', 'fixed-bottom']),
204
+ ],
205
+ parts: ['float', 'sticky'],
206
+ },
207
+ {
208
+ key: 'custom',
209
+ labelKey: 'style.section_custom',
210
+ properties: [],
211
+ catalog: [],
212
+ parts: [],
213
+ custom: true,
214
+ },
215
+ ];
216
+
217
+ export function section(key) {
218
+ return SECTIONS.filter(function(each_) { return each_.key === key; })[0] || null;
219
+ }
220
+
221
+ /** Whether a property or a catalog group is offered on this kind of node. */
222
+ export function offeredOn(item, kind) {
223
+ if (item.onlyOn && item.onlyOn.indexOf(kind) === -1) { return false; }
224
+
225
+ return item.notOn.indexOf(kind) === -1;
226
+ }
227
+
228
+ var BREAKPOINT = '(?:(?:sm|md|lg|xl|xxl)-)?';
229
+ var SPACER = '(?:[0-5]|auto)';
230
+ var COLOR = '(?:' + COLORS.join('|') + '|black|white)';
231
+ var BG = '(?:' + COLORS.join('|') + '|body|body-secondary|body-tertiary|white|black|transparent)';
232
+ var TEXT_COLOR = '(?:' + COLORS.join('|') + '|body|body-secondary|body-tertiary|white|black|muted|black-50|white-50)';
233
+ var BORDER = 'border(?:-(?:top|end|bottom|start))?(?:-0)?';
234
+ var SUBTLE = '(?:' + COLORS.join('|') + ')-subtle';
235
+ var EMPHASIS = '(?:' + COLORS.join('|') + '|body)-emphasis';
236
+ var TEXT_BG = 'text-bg-(?:' + COLORS.join('|') + ')';
237
+ var STICKY = 'sticky-' + BREAKPOINT;
238
+
239
+ function spacing(key, side) {
240
+ var sides = { top: '[ty]?', bottom: '[by]?', left: '[sx]?', right: '[ex]?' }[side];
241
+ return new RegExp('^' + key + sides + '-' + BREAKPOINT + SPACER + '$');
242
+ }
243
+
244
+ /**
245
+ * The Bootstrap classes that set each property. Every one of Bootstrap's
246
+ * utilities is !important, so a node that carries one of them for a
247
+ * property shows the class, whatever its inline style says.
248
+ */
249
+ var SETS = {
250
+ 'width': /^(?:w-(?:25|50|75|100|auto)|vw-100)$/,
251
+ 'height': /^(?:h-(?:25|50|75|100|auto)|vh-100)$/,
252
+ 'max-width': /^mw-100$/,
253
+ 'max-height': /^mh-100$/,
254
+ 'min-width': /^min-vw-100$/,
255
+ 'min-height': /^min-vh-100$/,
256
+ 'margin-top': spacing('m', 'top'),
257
+ 'margin-right': spacing('m', 'right'),
258
+ 'margin-bottom': spacing('m', 'bottom'),
259
+ 'margin-left': spacing('m', 'left'),
260
+ 'padding-top': spacing('p', 'top'),
261
+ 'padding-right': spacing('p', 'right'),
262
+ 'padding-bottom': spacing('p', 'bottom'),
263
+ 'padding-left': spacing('p', 'left'),
264
+ 'border-width': new RegExp('^(?:' + BORDER + '|border-[1-5])$'),
265
+ 'border-style': new RegExp('^' + BORDER + '$'),
266
+ 'border-color': new RegExp('^(?:' + BORDER + '|border-' + COLOR + '|border-' + SUBTLE + ')$'),
267
+ 'border-radius': /^rounded(?:-(?:[0-5]|circle|pill|top|end|bottom|start))?$/,
268
+ 'box-shadow': /^shadow(?:-(?:none|sm|lg))?$/,
269
+ 'background-color': new RegExp('^(?:bg-' + BG + '|bg-' + SUBTLE + '|' + TEXT_BG + ')$'),
270
+ 'background-image': /^bg-gradient$/,
271
+ 'color': new RegExp('^(?:text-' + TEXT_COLOR + '|text-' + EMPHASIS + '|' + TEXT_BG + ')$'),
272
+ 'font-size': /^fs-[1-6]$/,
273
+ 'text-align': new RegExp('^text-' + BREAKPOINT + '(?:start|center|end)$'),
274
+ 'text-decoration': /^text-decoration-(?:none|underline|line-through)$/,
275
+ 'font-family': /^font-monospace$/,
276
+ 'font-weight': /^fw-(?:lighter|light|normal|medium|semibold|bold|bolder)$/,
277
+ 'font-style': /^fst-(?:italic|normal)$/,
278
+ 'line-height': /^lh-(?:1|sm|base|lg)$/,
279
+ 'text-transform': /^text-(?:lowercase|uppercase|capitalize)$/,
280
+ 'display': new RegExp('^(?:d-' + BREAKPOINT + '(?:none|inline|inline-block|block|grid|inline-grid|table|table-row|table-cell|flex|inline-flex)|vstack|hstack)$'),
281
+ 'opacity': /^opacity-(?:0|25|50|75|100)$/,
282
+ 'overflow': /^overflow-(?:auto|hidden|visible|scroll)$/,
283
+ 'visibility': /^(?:visible|invisible)$/,
284
+ 'position': new RegExp('^(?:position-(?:static|relative|absolute|fixed|sticky)|fixed-(?:top|bottom)|' + STICKY + '(?:top|bottom))$'),
285
+ 'top': new RegExp('^(?:top-(?:0|50|100)|fixed-top|' + STICKY + 'top)$'),
286
+ 'bottom': new RegExp('^(?:bottom-(?:0|50|100)|fixed-bottom|' + STICKY + 'bottom)$'),
287
+ 'left': /^start-(?:0|50|100)$/,
288
+ 'right': /^end-(?:0|50|100)$/,
289
+ 'z-index': /^z-(?:n1|[0-3])$/,
290
+ };
291
+
292
+ /** The first of these classes that sets the property, or null. */
293
+ export function overriding(property, classes) {
294
+ var pattern = SETS[property];
295
+ if (!pattern) { return null; }
296
+
297
+ return classes.filter(function(name) { return pattern.test(name); })[0] || null;
298
+ }
@@ -1,21 +1,9 @@
1
1
  /**
2
- * Spacing for grid-editor.
2
+ * Spacing, a part of the style plugin: padding and margin per breakpoint, with Bootstrap's p-{breakpoint}-*,
3
+ * pt-, px- … and m-{breakpoint}-*, mt-, mx- … classes.
3
4
  *
4
- * A utility plugin: load this file after the editor and every row, column,
5
- * element and container can have its padding and margin set per breakpoint,
6
- * with Bootstrap's p-{breakpoint}-*, pt-, px- … and m-{breakpoint}-*, mt-, mx-
7
- * … classes. What it can ask the editor for is the handle its factory is
8
- * called with, described in docs/plugins.md.
9
- *
10
- * <script src="dist/grideditor.min.js"></script>
11
- * <script src="dist/plugins/grideditor.spacing.min.js"></script>
12
- *
13
- * Fourteen families would be fourteen fields, so the panel has two, padding
14
- * and margin, each a choice of side and a value for that side.
15
- *
16
- * utilities.spacing.values narrows the values offered, and
17
- * utilities.spacing.scale is what 0 to 5 come to, for a page that changed
18
- * Bootstrap's $spacers.
5
+ * Its families, and whatever it does on the canvas, as a function of the
6
+ * handle and its options: grideditor.style.js puts them in its sections.
19
7
  */
20
8
  import { GridEditor } from '../grideditor.js';
21
9
  import * as dom from '../dom.js';
@@ -64,9 +52,9 @@ function pattern(key) {
64
52
  return new RegExp('^' + key + '[xytbse]?-(?:(?:sm|md|lg|xl|xxl)-)?(?:[0-5]|auto)$');
65
53
  }
66
54
 
67
- GridEditor.utilities.spacing = function(ge) {
55
+ export function spacingPart(ge, given) {
68
56
 
69
- var options = Object.assign({ values: VALUES, scale: SCALE }, ge.settings.utilities.spacing);
57
+ var options = Object.assign({ values: VALUES, scale: SCALE }, given);
70
58
  var patterns = { p: pattern('p'), m: pattern('m') };
71
59
 
72
60
  function applies(node, kind) {
@@ -293,4 +281,4 @@ GridEditor.utilities.spacing = function(ge) {
293
281
 
294
282
  onRefresh: mark,
295
283
  };
296
- };
284
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Sticky, a part of the style plugin: sticking a node to the top or the
3
+ * bottom of the page as it scrolls, per breakpoint, with Bootstrap's
4
+ * sticky-{breakpoint}-top and -bottom classes.
5
+ *
6
+ * Its families, and whatever it does on the canvas, as a function of the
7
+ * handle: grideditor.style.js puts them in its sections.
8
+ */
9
+ import { GridEditor } from '../grideditor.js';
10
+
11
+ Object.assign(GridEditor.locales.en, {
12
+ 'utility.sticky': 'Sticky',
13
+ });
14
+
15
+ /** What Bootstrap's sticky-top and sticky-bottom are. */
16
+ var STUCK = {
17
+ top: { position: 'sticky', top: '0', 'z-index': '1020' },
18
+ bottom: { position: 'sticky', bottom: '0', 'z-index': '1020' },
19
+ };
20
+
21
+ export function stickyPart(ge) {
22
+ return {
23
+ families: [{
24
+ name: 'sticky',
25
+ prefix: 'sticky',
26
+ values: ['top', 'bottom'],
27
+ appliesTo: ['row', 'column', 'element', 'container'],
28
+ labelKey: 'utility.sticky',
29
+ panel: false,
30
+
31
+ /** With no class applying here, where the node is without one. */
32
+ preview: function(value, node) {
33
+ if (value !== null) { return STUCK[value]; }
34
+
35
+ return { position: ge.bareStyle(node, 'sticky', 'position') };
36
+ },
37
+ }],
38
+ };
39
+ }
@@ -1,17 +1,9 @@
1
1
  /**
2
- * Text alignment for grid-editor.
2
+ * Text alignment, a part of the style plugin: text alignment per breakpoint, with Bootstrap's text-{breakpoint}-start,
3
+ * -center and -end classes.
3
4
  *
4
- * A utility plugin: load this file after the editor and a row, column,
5
- * element or container can align its text per breakpoint, with Bootstrap's
6
- * text-{breakpoint}-start, -center and -end classes. What it can ask the
7
- * editor for is the handle its factory is called with, described in
8
- * docs/plugins.md.
9
- *
10
- * <script src="dist/grideditor.min.js"></script>
11
- * <script src="dist/plugins/grideditor.textalign.min.js"></script>
12
- *
13
- * The class aligns everything inside the node that does not align itself: a
14
- * paragraph the rich text editor gave its own text-align keeps it.
5
+ * Its families, and whatever it does on the canvas, as a function of the
6
+ * handle: grideditor.style.js puts them in its sections.
15
7
  */
16
8
  import { GridEditor } from '../grideditor.js';
17
9
 
@@ -25,7 +17,7 @@ Object.assign(GridEditor.locales.en, {
25
17
  /** Start and end are left and right: Bootstrap's css is left to right. */
26
18
  var CSS = { start: 'left', center: 'center', end: 'right' };
27
19
 
28
- GridEditor.utilities.textalign = function(ge) {
20
+ export function textalignPart(ge) {
29
21
 
30
22
  function label(value) {
31
23
  if (value === 'start') { return ge.t('utility.text_start'); }
@@ -55,4 +47,4 @@ GridEditor.utilities.textalign = function(ge) {
55
47
  },
56
48
  }],
57
49
  };
58
- };
50
+ }
@@ -210,7 +210,7 @@ if (!GridEditor.features.text) {
210
210
  var before = readBefore.get(block);
211
211
  var open = before ? attributesOf(block) : null;
212
212
 
213
- // Every content area is told, as in 5.x: one whose editor never
213
+ // Every content area is told: one whose editor never
214
214
  // started is the plugin's to ignore
215
215
  if (text) { text.stop([block]); }
216
216
 
@@ -330,6 +330,117 @@
330
330
  }
331
331
  }
332
332
 
333
+ /* A settings panel the dialog was opened from waits under its backdrop:
334
+ Bootstrap's popover would sit over the modal */
335
+ .ge-settings-panel.ge-under-dialog {
336
+ z-index: 1040;
337
+ }
338
+
339
+ /* What plugins add to a panel, between its general fields and Responsive.
340
+ In a popover or inline, a button that opens it in the dialog. */
341
+ .ge-details .ge-panel-section {
342
+ margin-top: 10px;
343
+ }
344
+
345
+ /* The style plugin's accordion: in a panel, or in the dialog, which is
346
+ outside any panel, so it carries the look of the fields it shares. */
347
+ .ge-style {
348
+ font-size: 0.8125rem;
349
+
350
+ .accordion-button {
351
+ padding: 6px 10px;
352
+ font-size: 0.8125rem;
353
+ font-weight: 500;
354
+ }
355
+ .accordion-body {
356
+ display: flex;
357
+ flex-direction: column;
358
+ gap: 10px;
359
+ padding: 8px 10px;
360
+ }
361
+
362
+ .ge-style-label,
363
+ .ge-utility-label,
364
+ .ge-style-shadow-label {
365
+ color: var(--bs-secondary-color, #6c757d);
366
+ font-size: 0.75rem;
367
+ }
368
+ .ge-style-note,
369
+ .ge-utility-note,
370
+ .ge-spacing-gutter {
371
+ color: var(--bs-secondary-color, #666);
372
+ font-size: 0.6875rem;
373
+ }
374
+
375
+ .ge-style-fields,
376
+ .ge-spacing {
377
+ display: grid;
378
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
379
+ gap: 8px 10px;
380
+ }
381
+ .ge-style-field,
382
+ .ge-utility,
383
+ .ge-spacing-group {
384
+ display: flex;
385
+ flex-direction: column;
386
+ gap: 2px;
387
+ margin: 0;
388
+ }
389
+ .ge-spacing-group .ge-utility > .ge-utility-label {
390
+ display: none;
391
+ }
392
+ .ge-spacing-gutter {
393
+ grid-column: 1 / -1;
394
+ }
395
+
396
+ .ge-style-color .form-control-color {
397
+ flex: 0 0 2.25rem;
398
+ padding: 2px;
399
+ }
400
+
401
+ .ge-style-shadow,
402
+ .ge-style-field:has(.ge-style-shadow) {
403
+ grid-column: 1 / -1;
404
+ }
405
+ .ge-style-shadow-builder {
406
+ display: grid;
407
+ grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
408
+ gap: 4px 8px;
409
+ align-items: end;
410
+ }
411
+ .ge-style-shadow-part {
412
+ display: flex;
413
+ flex-direction: column;
414
+ gap: 2px;
415
+ margin: 0;
416
+ }
417
+ .ge-style-shadow-color {
418
+ grid-column: span 2;
419
+ }
420
+ .ge-style-shadow-mode {
421
+ display: inline-block;
422
+ margin-top: 2px;
423
+ font-size: 0.6875rem;
424
+ }
425
+
426
+ .ge-style-catalog {
427
+ display: flex;
428
+ flex-direction: column;
429
+ gap: 4px;
430
+ }
431
+ .ge-style-chips {
432
+ display: flex;
433
+ flex-wrap: wrap;
434
+ gap: 3px;
435
+ }
436
+ .ge-style-chip {
437
+ --bs-btn-padding-y: 0;
438
+ --bs-btn-padding-x: 6px;
439
+ --bs-btn-font-size: 0.6875rem;
440
+ font-family: var(--bs-font-monospace, monospace);
441
+ }
442
+ }
443
+
333
444
  /* In a drawer it is part of the drawer, compact */
334
445
  .ge-tools-drawer > .ge-details {
335
446
  font-size: 11px;
@@ -363,6 +474,14 @@
363
474
  width: 360px;
364
475
  max-width: calc(100vw - 16px);
365
476
 
477
+ /* Bootstrap's css leaves the arrow's position to Popper, which puts it on
478
+ as an inline style. Without it the arrow stays in the flow, a strip as
479
+ tall as the arrow above the header; out of it, the top or bottom of
480
+ .bs-popover-bottom and .bs-popover-top hang it outside the edge */
481
+ > .popover-arrow {
482
+ position: absolute;
483
+ }
484
+
366
485
  > .popover-header {
367
486
  display: flex;
368
487
  align-items: center;
@@ -996,18 +1115,19 @@
996
1115
  .ge-layout-modes();
997
1116
 
998
1117
  /*
999
- * The visibility plugin. A node Bootstrap would hide is kept on the canvas -
1000
- * there would be nothing left to click to show it again - and shown the way
1001
- * the view sees it instead. The selectors outweigh Bootstrap's d-* classes,
1002
- * which are !important too.
1118
+ * The style plugin's display. A node Bootstrap would hide is kept on the
1119
+ * canvas - there would be nothing left to click to show it again - and shown
1120
+ * as it would be if it were not hidden, which data-ge-display says. The
1121
+ * selectors outweigh Bootstrap's d-* classes, which are !important too.
1003
1122
  */
1123
+ @ge-displays: inline, inline-block, block, grid, inline-grid, flex, inline-flex;
1124
+
1004
1125
  .ge-canvas.ge-editing {
1005
- .ge-visibility {
1006
- display: block !important;
1007
- }
1008
- .row.ge-visibility {
1009
- display: flex !important;
1010
- }
1126
+ each(@ge-displays, {
1127
+ [data-ge-display="@{value}"] {
1128
+ display: @value !important;
1129
+ }
1130
+ });
1011
1131
 
1012
1132
  .ge-hidden-in-view {
1013
1133
  opacity: .45;
@@ -1037,6 +1157,27 @@
1037
1157
  }
1038
1158
  }
1039
1159
 
1160
+ /*
1161
+ * The style plugin's drawer on a flex or grid node: out of the flow, on top
1162
+ * and as wide as the node, over a transparent top border as tall as it is.
1163
+ * The border's width comes with the node's data-ge-drawer-out, from a rule
1164
+ * per height the plugin writes. The selectors outweigh Bootstrap's border
1165
+ * classes and the drawer's own margins, which the spacing part sets inline.
1166
+ */
1167
+ .ge-canvas.ge-editing .ge-drawer-out {
1168
+ position: relative;
1169
+ border-top-style: solid !important;
1170
+ border-top-color: transparent !important;
1171
+
1172
+ > .ge-tools-drawer {
1173
+ position: absolute;
1174
+ left: 0;
1175
+ right: 0;
1176
+ width: auto !important;
1177
+ margin: 0 !important;
1178
+ }
1179
+ }
1180
+
1040
1181
  /* The order plugin: a column ordered by class in this view says where */
1041
1182
  .ge-canvas.ge-editing .column[data-ge-order]::before {
1042
1183
  content: attr(data-ge-order);
@@ -53,6 +53,22 @@ export interface PresetClass {
53
53
  }
54
54
 
55
55
  /** A content filter: run on init and deinit with the canvas. A string names a function on window. */
56
+ /** A section of the style plugin's accordion. */
57
+ export type StyleSectionKey = 'size' | 'spacing' | 'border' | 'background' | 'text' | 'typography' | 'display' | 'flex' | 'position' | 'custom';
58
+
59
+ /** A section on or off, or on with some of its properties and without its catalog. */
60
+ export type StyleSection = boolean | { properties?: string[]; catalog?: boolean };
61
+
62
+ /** The style plugin's settings. */
63
+ export interface StyleOptions {
64
+ /** Every section is on unless it is turned off here. */
65
+ sections?: Partial<Record<StyleSectionKey, StyleSection>>;
66
+ /** The spacing section: the values offered, and what 0 to 5 come to - for the gaps too. */
67
+ spacing?: { values?: string[]; scale?: string[] };
68
+ /** The eye that hides and shows a node, the display family's: false leaves it out of the drawers. */
69
+ visibility?: { drawer?: boolean };
70
+ }
71
+
56
72
  export type CustomFilter = ((canvas: HTMLElement, isInit: boolean) => void) | string;
57
73
 
58
74
  /** The settings. Every one is optional. */
@@ -79,6 +95,8 @@ export interface GridEditorOptions {
79
95
  content_types?: string[];
80
96
  row_cols?: boolean;
81
97
  utilities?: Record<string, unknown>;
98
+ /** The style plugin's sections, and the options of the utilities it carries. */
99
+ style?: StyleOptions;
82
100
  elements?: { enabled?: boolean | 'auto'; selector?: string; auto?: boolean };
83
101
  custom_filter?: CustomFilter | CustomFilter[] | '';
84
102
  valid_col_sizes?: ColumnSize[];