@themarioga/grid-editor 7.2.0 → 7.3.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.
- package/CHANGELOG.md +41 -0
- package/README.md +83 -14
- package/UPGRADING.md +31 -0
- package/dist/grideditor.bundle.min.js +2 -2
- package/dist/grideditor.css +102 -0
- package/dist/grideditor.d.ts +18 -0
- package/dist/grideditor.esm.js +291 -31
- package/dist/grideditor.js +291 -31
- package/dist/grideditor.min.css +1 -1
- package/dist/grideditor.min.css.map +1 -1
- package/dist/grideditor.min.js +1 -1
- package/dist/grideditor.min.js.map +3 -3
- package/dist/locales/grideditor.es.esm.js +67 -0
- package/dist/locales/grideditor.es.js +67 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +2 -2
- package/dist/plugins/grideditor.float.esm.js +10 -1
- package/dist/plugins/grideditor.float.js +8 -2
- package/dist/plugins/grideditor.float.min.js +1 -1
- package/dist/plugins/grideditor.float.min.js.map +4 -4
- package/dist/plugins/grideditor.spacing.esm.js +12 -3
- package/dist/plugins/grideditor.spacing.js +9 -3
- package/dist/plugins/grideditor.spacing.min.js +1 -1
- package/dist/plugins/grideditor.spacing.min.js.map +4 -4
- package/dist/plugins/grideditor.style.esm.js +1593 -0
- package/dist/plugins/grideditor.style.js +1592 -0
- package/dist/plugins/grideditor.style.min.js +2 -0
- package/dist/plugins/grideditor.style.min.js.map +7 -0
- package/dist/plugins/grideditor.textalign.esm.js +10 -1
- package/dist/plugins/grideditor.textalign.js +8 -2
- package/dist/plugins/grideditor.textalign.min.js +1 -1
- package/dist/plugins/grideditor.textalign.min.js.map +4 -4
- package/dist/plugins/grideditor.visibility.esm.js +12 -3
- package/dist/plugins/grideditor.visibility.js +9 -3
- package/dist/plugins/grideditor.visibility.min.js +1 -1
- package/dist/plugins/grideditor.visibility.min.js.map +4 -4
- package/docs/locale-keys.md +86 -7
- package/docs/plugins.md +49 -5
- package/example/index.html +14 -0
- package/example/style.html +151 -0
- package/example/utilities.html +15 -11
- package/package.json +1 -1
- package/src/js/grideditor.js +365 -27
- package/src/js/locales/grideditor.es.js +67 -0
- package/src/js/plugins/grideditor.float.js +8 -33
- package/src/js/plugins/grideditor.spacing.js +8 -273
- package/src/js/plugins/grideditor.style.js +179 -0
- package/src/js/plugins/grideditor.textalign.js +8 -39
- package/src/js/plugins/grideditor.visibility.js +8 -147
- package/src/js/style/accordion.js +157 -0
- package/src/js/style/catalog.js +76 -0
- package/src/js/style/custom.js +84 -0
- package/src/js/style/fields.js +382 -0
- package/src/js/style/float.js +46 -0
- package/src/js/style/options.js +75 -0
- package/src/js/style/sections.js +271 -0
- package/src/js/style/spacing.js +286 -0
- package/src/js/style/textalign.js +52 -0
- package/src/js/style/visibility.js +160 -0
- package/src/less/grideditor.less +111 -0
- package/types/grideditor.d.ts +18 -0
|
@@ -0,0 +1,271 @@
|
|
|
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
|
+
|
|
13
|
+
function each(prefix, values, suffix) {
|
|
14
|
+
return values.map(function(value) { return prefix + value + (suffix || ''); });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A catalog group: the classes it offers and whether they exclude each
|
|
19
|
+
* other, so choosing one takes the others off. `notOn` names the kinds of
|
|
20
|
+
* node it is never offered on.
|
|
21
|
+
*/
|
|
22
|
+
function group(classes, exclusive, notOn) {
|
|
23
|
+
return { classes: classes, exclusive: exclusive !== false, notOn: notOn || [] };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A property's field. `type` is the widget: text for any css value, select
|
|
28
|
+
* for a fixed list, color, url for background-image, shadow for
|
|
29
|
+
* box-shadow and text-shadow. `notOn` names the kinds of node it is never
|
|
30
|
+
* offered on.
|
|
31
|
+
*/
|
|
32
|
+
function prop(name, options) {
|
|
33
|
+
return {
|
|
34
|
+
name: name,
|
|
35
|
+
labelKey: options.labelKey,
|
|
36
|
+
type: options.type || 'text',
|
|
37
|
+
values: options.values || null,
|
|
38
|
+
notOn: options.notOn || [],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var NOT_ON_COLUMN = ['column'];
|
|
43
|
+
|
|
44
|
+
export var SECTIONS = [
|
|
45
|
+
{
|
|
46
|
+
key: 'size',
|
|
47
|
+
labelKey: 'style.section_size',
|
|
48
|
+
properties: [
|
|
49
|
+
prop('width', { labelKey: 'style.prop_width', notOn: NOT_ON_COLUMN }),
|
|
50
|
+
prop('height', { labelKey: 'style.prop_height', notOn: NOT_ON_COLUMN }),
|
|
51
|
+
prop('min-width', { labelKey: 'style.prop_min_width' }),
|
|
52
|
+
prop('min-height', { labelKey: 'style.prop_min_height' }),
|
|
53
|
+
prop('max-width', { labelKey: 'style.prop_max_width' }),
|
|
54
|
+
prop('max-height', { labelKey: 'style.prop_max_height' }),
|
|
55
|
+
],
|
|
56
|
+
catalog: [
|
|
57
|
+
group(each('w-', ['25', '50', '75', '100', 'auto']), true, NOT_ON_COLUMN),
|
|
58
|
+
group(each('h-', ['25', '50', '75', '100', 'auto']), true, NOT_ON_COLUMN),
|
|
59
|
+
group(['mw-100', 'mh-100', 'vw-100', 'vh-100', 'min-vw-100', 'min-vh-100'], false, NOT_ON_COLUMN),
|
|
60
|
+
],
|
|
61
|
+
parts: [],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: 'spacing',
|
|
65
|
+
labelKey: 'style.section_spacing',
|
|
66
|
+
properties: [
|
|
67
|
+
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' }),
|
|
68
|
+
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' }),
|
|
69
|
+
],
|
|
70
|
+
catalog: [],
|
|
71
|
+
parts: ['spacing'],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
key: 'border',
|
|
75
|
+
labelKey: 'style.section_border',
|
|
76
|
+
properties: [
|
|
77
|
+
prop('border-width', { labelKey: 'style.prop_border_width' }),
|
|
78
|
+
prop('border-style', { labelKey: 'style.prop_border_style', type: 'select', values: ['none', 'solid', 'dashed', 'dotted', 'double', 'groove', 'ridge', 'inset', 'outset'] }),
|
|
79
|
+
prop('border-color', { labelKey: 'style.prop_border_color', type: 'color' }),
|
|
80
|
+
prop('border-radius', { labelKey: 'style.prop_border_radius' }),
|
|
81
|
+
prop('box-shadow', { labelKey: 'style.prop_box_shadow', type: 'shadow' }),
|
|
82
|
+
],
|
|
83
|
+
catalog: [
|
|
84
|
+
group(['border', 'border-0'].concat(each('border-', SIDES), each('border-', SIDES, '-0')), false),
|
|
85
|
+
group(each('border-', ['1', '2', '3', '4', '5'])),
|
|
86
|
+
group(each('border-', COLORS.concat(['black', 'white']))),
|
|
87
|
+
group(['rounded'].concat(each('rounded-', ['0', '1', '2', '3', '4', '5', 'circle', 'pill']))),
|
|
88
|
+
group(each('rounded-', SIDES), false),
|
|
89
|
+
group(['shadow-none', 'shadow-sm', 'shadow', 'shadow-lg']),
|
|
90
|
+
],
|
|
91
|
+
parts: [],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
key: 'background',
|
|
95
|
+
labelKey: 'style.section_background',
|
|
96
|
+
properties: [
|
|
97
|
+
prop('background-color', { labelKey: 'style.prop_background_color', type: 'color' }),
|
|
98
|
+
prop('background-image', { labelKey: 'style.prop_background_image', type: 'url' }),
|
|
99
|
+
prop('background-size', { labelKey: 'style.prop_background_size' }),
|
|
100
|
+
prop('background-position', { labelKey: 'style.prop_background_position' }),
|
|
101
|
+
prop('background-repeat', { labelKey: 'style.prop_background_repeat', type: 'select', values: ['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'space', 'round'] }),
|
|
102
|
+
],
|
|
103
|
+
catalog: [
|
|
104
|
+
group(each('bg-', COLORS.concat(['body', 'body-secondary', 'body-tertiary', 'white', 'black', 'transparent']))),
|
|
105
|
+
group(['bg-gradient'], false),
|
|
106
|
+
],
|
|
107
|
+
parts: [],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
key: 'text',
|
|
111
|
+
labelKey: 'style.section_text',
|
|
112
|
+
properties: [
|
|
113
|
+
prop('color', { labelKey: 'style.prop_color', type: 'color' }),
|
|
114
|
+
prop('font-size', { labelKey: 'style.prop_font_size' }),
|
|
115
|
+
prop('text-align', { labelKey: 'style.prop_text_align', type: 'select', values: ['start', 'center', 'end', 'left', 'right', 'justify'] }),
|
|
116
|
+
prop('text-shadow', { labelKey: 'style.prop_text_shadow', type: 'shadow' }),
|
|
117
|
+
],
|
|
118
|
+
catalog: [
|
|
119
|
+
group(each('text-', COLORS.concat(['body', 'body-secondary', 'body-tertiary', 'white', 'black']))),
|
|
120
|
+
group(each('fs-', ['1', '2', '3', '4', '5', '6'])),
|
|
121
|
+
group(each('text-decoration-', ['none', 'underline', 'line-through'])),
|
|
122
|
+
],
|
|
123
|
+
parts: ['textalign'],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: 'typography',
|
|
127
|
+
labelKey: 'style.section_typography',
|
|
128
|
+
properties: [
|
|
129
|
+
prop('font-family', { labelKey: 'style.prop_font_family' }),
|
|
130
|
+
prop('font-weight', { labelKey: 'style.prop_font_weight', type: 'select', values: ['100', '200', '300', '400', '500', '600', '700', '800', '900', 'normal', 'bold', 'lighter', 'bolder'] }),
|
|
131
|
+
prop('font-style', { labelKey: 'style.prop_font_style', type: 'select', values: ['normal', 'italic', 'oblique'] }),
|
|
132
|
+
prop('line-height', { labelKey: 'style.prop_line_height' }),
|
|
133
|
+
prop('letter-spacing', { labelKey: 'style.prop_letter_spacing' }),
|
|
134
|
+
prop('text-transform', { labelKey: 'style.prop_text_transform', type: 'select', values: ['none', 'uppercase', 'lowercase', 'capitalize'] }),
|
|
135
|
+
prop('text-decoration', { labelKey: 'style.prop_text_decoration', type: 'select', values: ['none', 'underline', 'line-through', 'overline'] }),
|
|
136
|
+
],
|
|
137
|
+
catalog: [
|
|
138
|
+
group(each('fw-', ['lighter', 'light', 'normal', 'medium', 'semibold', 'bold', 'bolder'])),
|
|
139
|
+
group(each('fst-', ['italic', 'normal'])),
|
|
140
|
+
group(each('lh-', ['1', 'sm', 'base', 'lg'])),
|
|
141
|
+
group(each('text-', ['lowercase', 'uppercase', 'capitalize'])),
|
|
142
|
+
group(['font-monospace'], false),
|
|
143
|
+
group(['text-wrap', 'text-nowrap']),
|
|
144
|
+
group(['text-break'], false),
|
|
145
|
+
],
|
|
146
|
+
parts: [],
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
key: 'display',
|
|
150
|
+
labelKey: 'style.section_display',
|
|
151
|
+
properties: [
|
|
152
|
+
prop('display', { labelKey: 'style.prop_display', type: 'select', values: ['none', 'block', 'inline', 'inline-block', 'flex', 'inline-flex', 'grid', 'inline-grid'] }),
|
|
153
|
+
prop('opacity', { labelKey: 'style.prop_opacity' }),
|
|
154
|
+
prop('overflow', { labelKey: 'style.prop_overflow', type: 'select', values: ['visible', 'hidden', 'auto', 'scroll', 'clip'] }),
|
|
155
|
+
prop('visibility', { labelKey: 'style.prop_visibility', type: 'select', values: ['visible', 'hidden'] }),
|
|
156
|
+
],
|
|
157
|
+
catalog: [
|
|
158
|
+
group(each('opacity-', ['0', '25', '50', '75', '100'])),
|
|
159
|
+
group(each('overflow-', ['auto', 'hidden', 'visible', 'scroll'])),
|
|
160
|
+
group(['visible', 'invisible']),
|
|
161
|
+
],
|
|
162
|
+
parts: ['visibility'],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
key: 'position',
|
|
166
|
+
labelKey: 'style.section_position',
|
|
167
|
+
properties: [
|
|
168
|
+
prop('position', { labelKey: 'style.prop_position', type: 'select', values: ['static', 'relative', 'absolute', 'fixed', 'sticky'] }),
|
|
169
|
+
prop('top', { labelKey: 'style.prop_top', notOn: NOT_ON_COLUMN }),
|
|
170
|
+
prop('right', { labelKey: 'style.prop_right', notOn: NOT_ON_COLUMN }),
|
|
171
|
+
prop('bottom', { labelKey: 'style.prop_bottom', notOn: NOT_ON_COLUMN }),
|
|
172
|
+
prop('left', { labelKey: 'style.prop_left', notOn: NOT_ON_COLUMN }),
|
|
173
|
+
prop('z-index', { labelKey: 'style.prop_z_index' }),
|
|
174
|
+
],
|
|
175
|
+
catalog: [
|
|
176
|
+
group(each('position-', ['static', 'relative', 'absolute', 'fixed', 'sticky'])),
|
|
177
|
+
group(each('top-', ['0', '50', '100'])),
|
|
178
|
+
group(each('bottom-', ['0', '50', '100'])),
|
|
179
|
+
group(each('start-', ['0', '50', '100'])),
|
|
180
|
+
group(each('end-', ['0', '50', '100'])),
|
|
181
|
+
group(['translate-middle', 'translate-middle-x', 'translate-middle-y']),
|
|
182
|
+
group(['z-n1', 'z-0', 'z-1', 'z-2', 'z-3']),
|
|
183
|
+
],
|
|
184
|
+
parts: ['float'],
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
key: 'custom',
|
|
188
|
+
labelKey: 'style.section_custom',
|
|
189
|
+
properties: [],
|
|
190
|
+
catalog: [],
|
|
191
|
+
parts: [],
|
|
192
|
+
custom: true,
|
|
193
|
+
},
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
export function section(key) {
|
|
197
|
+
return SECTIONS.filter(function(each_) { return each_.key === key; })[0] || null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Whether a property or a catalog group is offered on this kind of node. */
|
|
201
|
+
export function offeredOn(item, kind) {
|
|
202
|
+
return item.notOn.indexOf(kind) === -1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
var BREAKPOINT = '(?:(?:sm|md|lg|xl|xxl)-)?';
|
|
206
|
+
var SPACER = '(?:[0-5]|auto)';
|
|
207
|
+
var COLOR = '(?:' + COLORS.join('|') + '|black|white)';
|
|
208
|
+
var BG = '(?:' + COLORS.join('|') + '|body|body-secondary|body-tertiary|white|black|transparent)';
|
|
209
|
+
var TEXT_COLOR = '(?:' + COLORS.join('|') + '|body|body-secondary|body-tertiary|white|black|muted|black-50|white-50)';
|
|
210
|
+
var BORDER = 'border(?:-(?:top|end|bottom|start))?(?:-0)?';
|
|
211
|
+
|
|
212
|
+
function spacing(key, side) {
|
|
213
|
+
var sides = { top: '[ty]?', bottom: '[by]?', left: '[sx]?', right: '[ex]?' }[side];
|
|
214
|
+
return new RegExp('^' + key + sides + '-' + BREAKPOINT + SPACER + '$');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The Bootstrap classes that set each property. Every one of Bootstrap's
|
|
219
|
+
* utilities is !important, so a node that carries one of them for a
|
|
220
|
+
* property shows the class, whatever its inline style says.
|
|
221
|
+
*/
|
|
222
|
+
var SETS = {
|
|
223
|
+
'width': /^(?:w-(?:25|50|75|100|auto)|vw-100)$/,
|
|
224
|
+
'height': /^(?:h-(?:25|50|75|100|auto)|vh-100)$/,
|
|
225
|
+
'max-width': /^mw-100$/,
|
|
226
|
+
'max-height': /^mh-100$/,
|
|
227
|
+
'min-width': /^min-vw-100$/,
|
|
228
|
+
'min-height': /^min-vh-100$/,
|
|
229
|
+
'margin-top': spacing('m', 'top'),
|
|
230
|
+
'margin-right': spacing('m', 'right'),
|
|
231
|
+
'margin-bottom': spacing('m', 'bottom'),
|
|
232
|
+
'margin-left': spacing('m', 'left'),
|
|
233
|
+
'padding-top': spacing('p', 'top'),
|
|
234
|
+
'padding-right': spacing('p', 'right'),
|
|
235
|
+
'padding-bottom': spacing('p', 'bottom'),
|
|
236
|
+
'padding-left': spacing('p', 'left'),
|
|
237
|
+
'border-width': new RegExp('^(?:' + BORDER + '|border-[1-5])$'),
|
|
238
|
+
'border-style': new RegExp('^' + BORDER + '$'),
|
|
239
|
+
'border-color': new RegExp('^(?:' + BORDER + '|border-' + COLOR + ')$'),
|
|
240
|
+
'border-radius': /^rounded(?:-(?:[0-5]|circle|pill|top|end|bottom|start))?$/,
|
|
241
|
+
'box-shadow': /^shadow(?:-(?:none|sm|lg))?$/,
|
|
242
|
+
'background-color': new RegExp('^bg-' + BG + '$'),
|
|
243
|
+
'background-image': /^bg-gradient$/,
|
|
244
|
+
'color': new RegExp('^text-' + TEXT_COLOR + '$'),
|
|
245
|
+
'font-size': /^fs-[1-6]$/,
|
|
246
|
+
'text-align': new RegExp('^text-' + BREAKPOINT + '(?:start|center|end)$'),
|
|
247
|
+
'text-decoration': /^text-decoration-(?:none|underline|line-through)$/,
|
|
248
|
+
'font-family': /^font-monospace$/,
|
|
249
|
+
'font-weight': /^fw-(?:lighter|light|normal|medium|semibold|bold|bolder)$/,
|
|
250
|
+
'font-style': /^fst-(?:italic|normal)$/,
|
|
251
|
+
'line-height': /^lh-(?:1|sm|base|lg)$/,
|
|
252
|
+
'text-transform': /^text-(?:lowercase|uppercase|capitalize)$/,
|
|
253
|
+
'display': new RegExp('^d-' + BREAKPOINT + '(?:none|inline|inline-block|block|grid|inline-grid|table|table-row|table-cell|flex|inline-flex)$'),
|
|
254
|
+
'opacity': /^opacity-(?:0|25|50|75|100)$/,
|
|
255
|
+
'overflow': /^overflow-(?:auto|hidden|visible|scroll)$/,
|
|
256
|
+
'visibility': /^(?:visible|invisible)$/,
|
|
257
|
+
'position': /^position-(?:static|relative|absolute|fixed|sticky)$/,
|
|
258
|
+
'top': /^top-(?:0|50|100)$/,
|
|
259
|
+
'bottom': /^bottom-(?:0|50|100)$/,
|
|
260
|
+
'left': /^start-(?:0|50|100)$/,
|
|
261
|
+
'right': /^end-(?:0|50|100)$/,
|
|
262
|
+
'z-index': /^z-(?:n1|[0-3])$/,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/** The first of these classes that sets the property, or null. */
|
|
266
|
+
export function overriding(property, classes) {
|
|
267
|
+
var pattern = SETS[property];
|
|
268
|
+
if (!pattern) { return null; }
|
|
269
|
+
|
|
270
|
+
return classes.filter(function(name) { return pattern.test(name); })[0] || null;
|
|
271
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
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.
|
|
4
|
+
*
|
|
5
|
+
* The part is what the spacing plugin was up to 7.2 - its families, and
|
|
6
|
+
* whatever it did on the canvas - as a function of the handle and its options.
|
|
7
|
+
* grideditor.style.js puts it in its sections; the deprecated
|
|
8
|
+
* grideditor.spacing.js still registers it on its own, as it always did.
|
|
9
|
+
*/
|
|
10
|
+
import { GridEditor } from '../grideditor.js';
|
|
11
|
+
import * as dom from '../dom.js';
|
|
12
|
+
|
|
13
|
+
Object.assign(GridEditor.locales.en, {
|
|
14
|
+
'utility.padding': 'Padding',
|
|
15
|
+
'utility.margin': 'Margin',
|
|
16
|
+
'utility.side_all': 'All sides',
|
|
17
|
+
'utility.side_x': 'Left and right',
|
|
18
|
+
'utility.side_y': 'Top and bottom',
|
|
19
|
+
'utility.side_t': 'Top',
|
|
20
|
+
'utility.side_b': 'Bottom',
|
|
21
|
+
'utility.side_s': 'Start',
|
|
22
|
+
'utility.side_e': 'End',
|
|
23
|
+
'utility.spacing_gutter': 'A column\'s side padding is its gutter: changing it changes the gutter',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
var VALUES = ['0', '1', '2', '3', '4', '5'];
|
|
27
|
+
|
|
28
|
+
/** Bootstrap's $spacers. */
|
|
29
|
+
var SCALE = ['0', '.25rem', '.5rem', '1rem', '1.5rem', '3rem'];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The sides, in the order Bootstrap's css writes their rules: within one
|
|
33
|
+
* breakpoint a later rule wins, so p-3 pt-1 has a top of .25rem.
|
|
34
|
+
*/
|
|
35
|
+
var SIDES = ['', 'x', 'y', 't', 'e', 'b', 's'];
|
|
36
|
+
|
|
37
|
+
/** What each side sets. Start and end are left and right: Bootstrap's css is left to right. */
|
|
38
|
+
var SET = {
|
|
39
|
+
'': ['top', 'right', 'bottom', 'left'],
|
|
40
|
+
x: ['left', 'right'],
|
|
41
|
+
y: ['top', 'bottom'],
|
|
42
|
+
t: ['top'],
|
|
43
|
+
e: ['right'],
|
|
44
|
+
b: ['bottom'],
|
|
45
|
+
s: ['left'],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
var INFIXES = ['', 'sm', 'md', 'lg', 'xl', 'xxl'];
|
|
49
|
+
|
|
50
|
+
var PROPERTIES = { p: 'padding', m: 'margin' };
|
|
51
|
+
|
|
52
|
+
/** Every class of the plugin's, padding or margin. */
|
|
53
|
+
function pattern(key) {
|
|
54
|
+
return new RegExp('^' + key + '[xytbse]?-(?:(?:sm|md|lg|xl|xxl)-)?(?:[0-5]|auto)$');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function spacingPart(ge, given) {
|
|
58
|
+
|
|
59
|
+
var options = Object.assign({ values: VALUES, scale: SCALE }, given);
|
|
60
|
+
var patterns = { p: pattern('p'), m: pattern('m') };
|
|
61
|
+
|
|
62
|
+
function applies(node, kind) {
|
|
63
|
+
return kind === 'row' || kind === 'column' || kind === 'element' ||
|
|
64
|
+
dom.is(node, '[data-ge-container]');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function classes(node) {
|
|
68
|
+
return (node.getAttribute('class') || '').split(/\s+/);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function carries(node, key) {
|
|
72
|
+
return classes(node).some(function(name) { return patterns[key].test(name); });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The class of one family that decides a side at a breakpoint: the
|
|
77
|
+
* widest breakpoint up to it that has one, as { tier, value }.
|
|
78
|
+
*/
|
|
79
|
+
function source(node, family, tier) {
|
|
80
|
+
var names = classes(node);
|
|
81
|
+
var values = family.charAt(0) === 'm' ? VALUES.concat(['auto']) : VALUES;
|
|
82
|
+
|
|
83
|
+
for (var i = tier; i >= 0; i--) {
|
|
84
|
+
for (var v = 0; v < values.length; v++) {
|
|
85
|
+
var name = family + (INFIXES[i] ? '-' + INFIXES[i] : '') + '-' + values[v];
|
|
86
|
+
if (names.indexOf(name) !== -1) { return { tier: i, value: values[v] }; }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* What padding or margin is on each side with none of the plugin's
|
|
95
|
+
* classes: the editor's frame for a row or a column, the host's css
|
|
96
|
+
* for anything else. Read by taking the classes off for a moment,
|
|
97
|
+
* since that is the only way to ask the browser.
|
|
98
|
+
*/
|
|
99
|
+
function without(node, key) {
|
|
100
|
+
var original = node.getAttribute('class');
|
|
101
|
+
var style;
|
|
102
|
+
var bare = {};
|
|
103
|
+
|
|
104
|
+
node.setAttribute('class', classes(node).filter(function(name) { return !patterns[key].test(name); }).join(' '));
|
|
105
|
+
style = getComputedStyle(node);
|
|
106
|
+
['top', 'right', 'bottom', 'left'].forEach(function(side) {
|
|
107
|
+
bare[side] = style.getPropertyValue(PROPERTIES[key] + '-' + side);
|
|
108
|
+
});
|
|
109
|
+
if (original === null) { node.removeAttribute('class'); } else { node.setAttribute('class', original); }
|
|
110
|
+
|
|
111
|
+
return bare;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Each side the way Bootstrap's css settles it: the class from the
|
|
116
|
+
* widest breakpoint wins, and within one breakpoint the side written
|
|
117
|
+
* later in the css. A side no class reaches shows what it is without
|
|
118
|
+
* any, over a wider breakpoint's class that is live in a wide window.
|
|
119
|
+
*/
|
|
120
|
+
function sides(node, key, breakpoint) {
|
|
121
|
+
var tier = ge.breakpoints.indexOf(breakpoint);
|
|
122
|
+
var winners = {};
|
|
123
|
+
var styles = {};
|
|
124
|
+
var neutral = null;
|
|
125
|
+
|
|
126
|
+
SIDES.forEach(function(side, order) {
|
|
127
|
+
var found = source(node, key + side, tier);
|
|
128
|
+
if (!found) { return; }
|
|
129
|
+
|
|
130
|
+
SET[side].forEach(function(set) {
|
|
131
|
+
var current = winners[set];
|
|
132
|
+
if (!current || found.tier > current.tier || (found.tier === current.tier && order > current.order)) {
|
|
133
|
+
winners[set] = { tier: found.tier, order: order, value: found.value };
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
['top', 'right', 'bottom', 'left'].forEach(function(set) {
|
|
139
|
+
var winner = winners[set];
|
|
140
|
+
|
|
141
|
+
if (!winner) {
|
|
142
|
+
neutral = neutral || without(node, key);
|
|
143
|
+
styles[PROPERTIES[key] + '-' + set] = neutral[set];
|
|
144
|
+
} else {
|
|
145
|
+
styles[PROPERTIES[key] + '-' + set] = winner.value === 'auto' ? 'auto' : options.scale[winner.value];
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return styles;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** The side a group's select starts on: the first that has a class, or all. */
|
|
153
|
+
function startingSide(node, key) {
|
|
154
|
+
var names = classes(node).filter(function(name) { return patterns[key].test(name); });
|
|
155
|
+
var found = SIDES.filter(function(side) {
|
|
156
|
+
return names.some(function(name) { return name.indexOf(key + side + '-') === 0; });
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return found.length ? found[0] : '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function sideLabel(side) {
|
|
163
|
+
switch (side) {
|
|
164
|
+
case 'x': return ge.t('utility.side_x');
|
|
165
|
+
case 'y': return ge.t('utility.side_y');
|
|
166
|
+
case 't': return ge.t('utility.side_t');
|
|
167
|
+
case 'b': return ge.t('utility.side_b');
|
|
168
|
+
case 's': return ge.t('utility.side_s');
|
|
169
|
+
case 'e': return ge.t('utility.side_e');
|
|
170
|
+
default: return ge.t('utility.side_all');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** A padding or margin group: its name, the side, and the field of that side's family. */
|
|
175
|
+
function group(node, key, labelText) {
|
|
176
|
+
var box = dom.element('div', { 'class': 'ge-spacing-group', 'data-ge-spacing': key });
|
|
177
|
+
var side = dom.element('select', { 'class': 'ge-spacing-side form-select form-select-sm' });
|
|
178
|
+
|
|
179
|
+
box.appendChild(dom.element('span', { 'class': 'ge-utility-label' }, labelText));
|
|
180
|
+
|
|
181
|
+
SIDES.forEach(function(value) {
|
|
182
|
+
side.appendChild(dom.element('option', { value: value }, sideLabel(value)));
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
var field = ge.utilityField(node, key + startingSide(node, key));
|
|
186
|
+
|
|
187
|
+
side.value = field.getAttribute('data-ge-family').slice(1);
|
|
188
|
+
side.addEventListener('change', function() {
|
|
189
|
+
var next = ge.utilityField(node, key + this.value);
|
|
190
|
+
field.replaceWith(next);
|
|
191
|
+
field = next;
|
|
192
|
+
});
|
|
193
|
+
box.appendChild(side);
|
|
194
|
+
box.appendChild(field);
|
|
195
|
+
|
|
196
|
+
return box;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
var NODES = '.row, .column, .ge-element, [data-ge-container]';
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Keep each drawer on its node's edges. A drawer is pulled out over the
|
|
203
|
+
* editor's frame by as much as the frame pads the node, and a padding
|
|
204
|
+
* class replaces the frame, so a padded node's drawer is pulled out by
|
|
205
|
+
* its real padding instead. And a column padded at the sides gets a word
|
|
206
|
+
* about what that does to its gutter.
|
|
207
|
+
*/
|
|
208
|
+
function mark(scope) {
|
|
209
|
+
dom.selfAndAll(scope, NODES).forEach(function(node) {
|
|
210
|
+
var drawer = dom.child(node, '.ge-tools-drawer');
|
|
211
|
+
|
|
212
|
+
if (!drawer || !applies(node, ge.kindOf(node))) { return; }
|
|
213
|
+
|
|
214
|
+
if (carries(node, 'p')) {
|
|
215
|
+
var style = getComputedStyle(node);
|
|
216
|
+
|
|
217
|
+
dom.css(drawer, {
|
|
218
|
+
'margin-top': '-' + style.paddingTop,
|
|
219
|
+
'margin-left': '-' + style.paddingLeft,
|
|
220
|
+
'margin-right': '-' + style.paddingRight,
|
|
221
|
+
width: 'calc(100% + ' + style.paddingLeft + ' + ' + style.paddingRight + ')',
|
|
222
|
+
});
|
|
223
|
+
} else {
|
|
224
|
+
dom.css(drawer, { 'margin-top': '', 'margin-left': '', 'margin-right': '', width: '' });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (dom.hasClass(node, 'column')) {
|
|
228
|
+
var padded = classes(node).some(function(name) {
|
|
229
|
+
return /^p[xse]?-/.test(name) && patterns.p.test(name);
|
|
230
|
+
});
|
|
231
|
+
dom.all(drawer, '.ge-spacing-gutter').forEach(function(note) { dom.toggle(note, padded); });
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function families(key, labelKey) {
|
|
237
|
+
var values = key === 'm' ? VALUES.concat(['auto']) : VALUES;
|
|
238
|
+
var offered = options.values.concat(key === 'm' ? ['auto'] : []);
|
|
239
|
+
|
|
240
|
+
return SIDES.map(function(side) {
|
|
241
|
+
return {
|
|
242
|
+
name: key + side,
|
|
243
|
+
prefix: key + side,
|
|
244
|
+
values: values,
|
|
245
|
+
appliesTo: ['row', 'column', 'text', 'element', 'container'],
|
|
246
|
+
labelKey: labelKey,
|
|
247
|
+
panel: false,
|
|
248
|
+
choices: function() {
|
|
249
|
+
return values.filter(function(value) { return offered.indexOf(value) !== -1; });
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
families: families('p', 'utility.padding').concat(families('m', 'utility.margin')),
|
|
257
|
+
|
|
258
|
+
panel: function(node, kind) {
|
|
259
|
+
if (!applies(node, kind)) { return null; }
|
|
260
|
+
|
|
261
|
+
var box = dom.element('div', { 'class': 'ge-spacing' });
|
|
262
|
+
box.appendChild(group(node, 'p', ge.t('utility.padding')));
|
|
263
|
+
box.appendChild(group(node, 'm', ge.t('utility.margin')));
|
|
264
|
+
|
|
265
|
+
if (kind === 'column') {
|
|
266
|
+
box.appendChild(dom.element('small', { 'class': 'ge-spacing-gutter' }, ge.t('utility.spacing_gutter')));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return box;
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
preview: function(node, kind, breakpoint) {
|
|
273
|
+
if (!applies(node, kind)) { return {}; }
|
|
274
|
+
|
|
275
|
+
var styles = {};
|
|
276
|
+
|
|
277
|
+
['p', 'm'].forEach(function(key) {
|
|
278
|
+
if (carries(node, key)) { Object.assign(styles, sides(node, key, breakpoint)); }
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return styles;
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
onRefresh: mark,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text alignment, a part of the style plugin: text alignment per breakpoint, with Bootstrap's text-{breakpoint}-start,
|
|
3
|
+
* -center and -end classes.
|
|
4
|
+
*
|
|
5
|
+
* The part is what the textalign plugin was up to 7.2 - its families, and
|
|
6
|
+
* whatever it did on the canvas - as a function of the handle.
|
|
7
|
+
* grideditor.style.js puts it in its sections; the deprecated
|
|
8
|
+
* grideditor.textalign.js still registers it on its own, as it always did.
|
|
9
|
+
*/
|
|
10
|
+
import { GridEditor } from '../grideditor.js';
|
|
11
|
+
|
|
12
|
+
Object.assign(GridEditor.locales.en, {
|
|
13
|
+
'utility.text_align': 'Text alignment',
|
|
14
|
+
'utility.text_start': 'Start',
|
|
15
|
+
'utility.text_center': 'Center',
|
|
16
|
+
'utility.text_end': 'End',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/** Start and end are left and right: Bootstrap's css is left to right. */
|
|
20
|
+
var CSS = { start: 'left', center: 'center', end: 'right' };
|
|
21
|
+
|
|
22
|
+
export function textalignPart(ge) {
|
|
23
|
+
|
|
24
|
+
function label(value) {
|
|
25
|
+
if (value === 'start') { return ge.t('utility.text_start'); }
|
|
26
|
+
if (value === 'center') { return ge.t('utility.text_center'); }
|
|
27
|
+
|
|
28
|
+
return ge.t('utility.text_end');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
families: [{
|
|
33
|
+
name: 'text-align',
|
|
34
|
+
prefix: 'text',
|
|
35
|
+
values: ['start', 'center', 'end'],
|
|
36
|
+
appliesTo: ['row', 'column', 'text', 'element', 'container'],
|
|
37
|
+
labelKey: 'utility.text_align',
|
|
38
|
+
label: label,
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* With no class applying here, the node aligns as its parent
|
|
42
|
+
* does - or as the host's css says - which only the browser can
|
|
43
|
+
* tell, so it is asked with the classes out of the way. Parents
|
|
44
|
+
* are previewed before their children, so the parent's answer is
|
|
45
|
+
* already the view's.
|
|
46
|
+
*/
|
|
47
|
+
preview: function(value, node) {
|
|
48
|
+
return { 'text-align': value === null ? ge.bareStyle(node, 'text-align', 'text-align') : CSS[value] };
|
|
49
|
+
},
|
|
50
|
+
}],
|
|
51
|
+
};
|
|
52
|
+
}
|