neo.mjs 6.3.11 → 6.4.1
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/apps/ServiceWorker.mjs +2 -2
- package/examples/ConfigurationViewport.mjs +21 -9
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/container/dialog/MainContainerController.mjs +20 -16
- package/examples/dialog/DemoDialog.mjs +24 -3
- package/examples/form/field/select/MainContainer.mjs +28 -6
- package/package.json +1 -1
- package/resources/scss/src/component/Base.scss +26 -0
- package/resources/scss/src/form/field/Picker.scss +0 -3
- package/resources/scss/src/menu/List.scss +4 -8
- package/resources/scss/theme-dark/menu/List.scss +2 -1
- package/resources/scss/theme-light/menu/List.scss +1 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/button/Base.mjs +41 -6
- package/src/component/Base.mjs +236 -44
- package/src/container/Dialog.mjs +3 -3
- package/src/core/Base.mjs +20 -0
- package/src/form/Container.mjs +2 -0
- package/src/form/field/Picker.mjs +30 -47
- package/src/form/field/Time.mjs +8 -8
- package/src/form/field/trigger/Base.mjs +1 -1
- package/src/form/field/trigger/CopyToClipboard.mjs +5 -1
- package/src/grid/View.mjs +5 -2
- package/src/grid/header/Button.mjs +10 -10
- package/src/list/Base.mjs +17 -14
- package/src/list/plugin/Animate.mjs +3 -3
- package/src/main/DomAccess.mjs +272 -28
- package/src/menu/List.mjs +35 -90
- package/src/table/Container.mjs +2 -2
- package/src/table/header/Button.mjs +21 -23
- package/src/tree/Accordion.mjs +1 -1
- package/src/util/Array.mjs +4 -18
- package/src/util/Css.mjs +6 -8
- package/src/util/HashHistory.mjs +10 -3
- package/src/util/Rectangle.mjs +444 -7
- package/test/siesta/siesta-node.js +2 -1
- package/test/siesta/siesta.js +1 -0
- package/test/siesta/tests/Rectangle.mjs +409 -0
@@ -0,0 +1,409 @@
|
|
1
|
+
import Rectangle from '../../../src/util/Rectangle.mjs';
|
2
|
+
|
3
|
+
// Maintainer:
|
4
|
+
// A good technique for debugging Rectangle code is to use the show(<colour>) method
|
5
|
+
// to visualize the Rectangles in the DOM.
|
6
|
+
//
|
7
|
+
// The following statements will reveal the state of the Rectangles used
|
8
|
+
// constrainingRect.show('#f1f1f1')
|
9
|
+
// target.show('red')
|
10
|
+
// subject.show('yellow')
|
11
|
+
// result.show('green')
|
12
|
+
|
13
|
+
StartTest(t => {
|
14
|
+
let constrainTo, subject, target, result;
|
15
|
+
|
16
|
+
t.it('contains', t => {
|
17
|
+
t.ok(new Rectangle(0, 0, 100, 100).contains(new Rectangle(10, 10, 80, 80)));
|
18
|
+
t.notOk(new Rectangle(0, 0, 100, 100).contains(new Rectangle(10, 10, 80, 110)));
|
19
|
+
t.notOk(new Rectangle(0, 0, 100, 100).contains(new Rectangle(10, 10, 110, 80)));
|
20
|
+
t.notOk(new Rectangle(0, 0, 100, 100).contains(new Rectangle(10, 10, 110, 110)));
|
21
|
+
t.notOk(new Rectangle(0, 0, 100, 100).contains(new Rectangle(-10, 10, 80, 80)));
|
22
|
+
t.notOk(new Rectangle(0, 0, 100, 100).contains(new Rectangle(10, -10, 80, 80)));
|
23
|
+
});
|
24
|
+
|
25
|
+
t.describe('constrain', t => {
|
26
|
+
t.describe('Should constrain fitting subject rectangle', t => {
|
27
|
+
constrainTo = new Rectangle(0, 0, 200, 200);
|
28
|
+
|
29
|
+
// Subject rect is below and to the right
|
30
|
+
result = new Rectangle(1000, 1000, 10, 10).constrainTo(constrainTo);
|
31
|
+
t.ok(result.equals(new Rectangle(190, 190, 10, 10)));
|
32
|
+
|
33
|
+
// Subject rect is to the right
|
34
|
+
result = new Rectangle(1000, 0, 10, 10).constrainTo(constrainTo);
|
35
|
+
t.ok(result.equals(new Rectangle(190, 0, 10, 10)));
|
36
|
+
|
37
|
+
// Subject rect is above and right
|
38
|
+
result = new Rectangle(1000, -1000, 10, 10).constrainTo(constrainTo);
|
39
|
+
t.ok(result.equals(new Rectangle(190, 0, 10, 10)));
|
40
|
+
|
41
|
+
// Subject rect is above
|
42
|
+
result = new Rectangle(0, -1000, 10, 10).constrainTo(constrainTo);
|
43
|
+
t.ok(result.equals(new Rectangle(0, 0, 10, 10)));
|
44
|
+
|
45
|
+
// Subject rect is above and to the left
|
46
|
+
result = new Rectangle(-1000, -1000, 10, 10).constrainTo(constrainTo);
|
47
|
+
t.ok(result.equals(new Rectangle(0, 0, 10, 10)));
|
48
|
+
|
49
|
+
// Subject rect is to the left
|
50
|
+
result = new Rectangle(-1000, 0, 10, 10).constrainTo(constrainTo);
|
51
|
+
t.ok(result.equals(new Rectangle(0, 0, 10, 10)));
|
52
|
+
|
53
|
+
// Subject rect is below and to the left
|
54
|
+
result = new Rectangle(-1000, 1000, 10, 10).constrainTo(constrainTo);
|
55
|
+
t.ok(result.equals(new Rectangle(0, 190, 10, 10)));
|
56
|
+
|
57
|
+
// Subject rect is below
|
58
|
+
result = new Rectangle(0, 1000, 10, 10).constrainTo(constrainTo);
|
59
|
+
t.ok(result.equals(new Rectangle(0, 190, 10, 10)));
|
60
|
+
});
|
61
|
+
|
62
|
+
t.describe('Should constrain non-fitting subject rectangle when minima allow', t => {
|
63
|
+
constrainTo = new Rectangle(0, 0, 200, 200);
|
64
|
+
subject = new Rectangle(1000, 1000, 210, 210);
|
65
|
+
|
66
|
+
// Subject Rectangle is willing to shrink to 200x200
|
67
|
+
subject.minWidth = subject.minHeight = 200;
|
68
|
+
|
69
|
+
// Subject rect is below and to the right
|
70
|
+
result = subject.constrainTo(constrainTo);
|
71
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
72
|
+
|
73
|
+
// Subject rect is to the right
|
74
|
+
subject.x = 1000; subject.y = 0;
|
75
|
+
result = subject.constrainTo(constrainTo);
|
76
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
77
|
+
|
78
|
+
// Subject rect is above and right
|
79
|
+
subject.x = 1000; subject.y = -1000;
|
80
|
+
result = subject.constrainTo(constrainTo);
|
81
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
82
|
+
|
83
|
+
// Subject rect is above
|
84
|
+
subject.x = 0; subject.y = -1000;
|
85
|
+
result = subject.constrainTo(constrainTo);
|
86
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
87
|
+
|
88
|
+
// Subject rect is above and to the left
|
89
|
+
subject.x = 1000; subject.y = -1000;
|
90
|
+
result = subject.constrainTo(constrainTo);
|
91
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
92
|
+
|
93
|
+
// Subject rect is to the left
|
94
|
+
subject.x = -1000; subject.y = 0;
|
95
|
+
result = subject.constrainTo(constrainTo);
|
96
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
97
|
+
|
98
|
+
// Subject rect is below and to the left
|
99
|
+
subject.x = -1000; subject.y = 1000;
|
100
|
+
result = subject.constrainTo(constrainTo);
|
101
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
102
|
+
|
103
|
+
// Subject rect is below
|
104
|
+
subject.x = 0; subject.y = 1000;
|
105
|
+
result = subject.constrainTo(constrainTo);
|
106
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
107
|
+
});
|
108
|
+
|
109
|
+
t.describe('Should constrain non-fitting subject rectangle when minima allow', t => {
|
110
|
+
constrainTo = new Rectangle(0, 0, 200, 200);
|
111
|
+
subject = new Rectangle(1000, 1000, 210, 210);
|
112
|
+
|
113
|
+
// Subject Rectangle is willing to shrink to 200x200
|
114
|
+
subject.minWidth = subject.minHeight = 200;
|
115
|
+
|
116
|
+
// Subject rect is below and to the right
|
117
|
+
result = subject.constrainTo(constrainTo);
|
118
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
119
|
+
|
120
|
+
// Subject rect is to the right
|
121
|
+
subject.x = 1000; subject.y = 0;
|
122
|
+
result = subject.constrainTo(constrainTo);
|
123
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
124
|
+
|
125
|
+
// Subject rect is above and right
|
126
|
+
subject.x = 1000; subject.y = -1000;
|
127
|
+
result = subject.constrainTo(constrainTo);
|
128
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
129
|
+
|
130
|
+
// Subject rect is above
|
131
|
+
subject.x = 0; subject.y = -1000;
|
132
|
+
result = subject.constrainTo(constrainTo);
|
133
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
134
|
+
|
135
|
+
// Subject rect is above and to the left
|
136
|
+
subject.x = 1000; subject.y = -1000;
|
137
|
+
result = subject.constrainTo(constrainTo);
|
138
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
139
|
+
|
140
|
+
// Subject rect is to the left
|
141
|
+
subject.x = -1000; subject.y = 0;
|
142
|
+
result = subject.constrainTo(constrainTo);
|
143
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
144
|
+
|
145
|
+
// Subject rect is below and to the left
|
146
|
+
subject.x = -1000; subject.y = 1000;
|
147
|
+
result = subject.constrainTo(constrainTo);
|
148
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
149
|
+
|
150
|
+
// Subject rect is below
|
151
|
+
subject.x = 0; subject.y = 1000;
|
152
|
+
result = subject.constrainTo(constrainTo);
|
153
|
+
t.ok(result.equals(new Rectangle(0, 0, 200, 200)));
|
154
|
+
});
|
155
|
+
});
|
156
|
+
|
157
|
+
t.it('expand should work', t => {
|
158
|
+
t.ok(new Rectangle(10, 10, 10, 10).expand(5).equals(new Rectangle(5, 5, 20, 20)));
|
159
|
+
t.ok(new Rectangle(10, 10, 10, 10).expand([5, 6]).equals(new Rectangle(4, 5, 22, 20)));
|
160
|
+
t.ok(new Rectangle(10, 10, 10, 10).expand([5, 6, 7]).equals(new Rectangle(4, 5, 22, 22)));
|
161
|
+
t.ok(new Rectangle(10, 10, 10, 10).expand([5, 6, 7, 8]).equals(new Rectangle(2, 5, 24, 22)));
|
162
|
+
});
|
163
|
+
|
164
|
+
t.describe('alignTo', t => {
|
165
|
+
t.describe('unconstrained', t => {
|
166
|
+
target = new Rectangle(100, 100, 100, 100);
|
167
|
+
|
168
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
169
|
+
target,
|
170
|
+
edgeAlign : 't-b'
|
171
|
+
});
|
172
|
+
t.ok(result.equals(new Rectangle(125, 200, 50, 50)));
|
173
|
+
|
174
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
175
|
+
target,
|
176
|
+
edgeAlign : 't0-b0'
|
177
|
+
});
|
178
|
+
t.ok(result.equals(new Rectangle(100, 200, 50, 50)));
|
179
|
+
|
180
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
181
|
+
target,
|
182
|
+
edgeAlign : 't100-b100'
|
183
|
+
});
|
184
|
+
t.ok(result.equals(new Rectangle(150, 200, 50, 50)));
|
185
|
+
|
186
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
187
|
+
target,
|
188
|
+
edgeAlign : 'b-t'
|
189
|
+
});
|
190
|
+
t.ok(result.equals(new Rectangle(125, 50, 50, 50)));
|
191
|
+
|
192
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
193
|
+
target,
|
194
|
+
edgeAlign : 'b0-t0'
|
195
|
+
});
|
196
|
+
t.ok(result.equals(new Rectangle(100, 50, 50, 50)));
|
197
|
+
|
198
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
199
|
+
target,
|
200
|
+
edgeAlign : 'b100-t100'
|
201
|
+
});
|
202
|
+
t.ok(result.equals(new Rectangle(150, 50, 50, 50)));
|
203
|
+
|
204
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
205
|
+
target,
|
206
|
+
edgeAlign : 'l-r'
|
207
|
+
});
|
208
|
+
t.ok(result.equals(new Rectangle(200, 125, 50, 50)));
|
209
|
+
|
210
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
211
|
+
target,
|
212
|
+
edgeAlign : 'l0-r0'
|
213
|
+
});
|
214
|
+
t.ok(result.equals(new Rectangle(200, 100, 50, 50)));
|
215
|
+
|
216
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
217
|
+
target,
|
218
|
+
edgeAlign : 'l100-r100'
|
219
|
+
});
|
220
|
+
t.ok(result.equals(new Rectangle(200, 150, 50, 50)));
|
221
|
+
|
222
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
223
|
+
target,
|
224
|
+
edgeAlign : 'r-l'
|
225
|
+
});
|
226
|
+
t.ok(result.equals(new Rectangle(50, 125, 50, 50)));
|
227
|
+
|
228
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
229
|
+
target,
|
230
|
+
edgeAlign : 'r0-l0'
|
231
|
+
});
|
232
|
+
t.ok(result.equals(new Rectangle(50, 100, 50, 50)));
|
233
|
+
|
234
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
235
|
+
target,
|
236
|
+
edgeAlign : 'r100-l100'
|
237
|
+
});
|
238
|
+
t.ok(result.equals(new Rectangle(50, 150, 50, 50)));
|
239
|
+
});
|
240
|
+
|
241
|
+
// The aligned edge of the subject must match the size of the edge of the target that it aligns to
|
242
|
+
t.describe('unconstrained width matchSize', t => {
|
243
|
+
target = new Rectangle(100, 100, 100, 100);
|
244
|
+
|
245
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
246
|
+
target,
|
247
|
+
edgeAlign : 't-b',
|
248
|
+
matchSize : true
|
249
|
+
});
|
250
|
+
t.ok(result.equals(new Rectangle(100, 200, 100, 50)));
|
251
|
+
|
252
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
253
|
+
target,
|
254
|
+
edgeAlign : 'b-t',
|
255
|
+
matchSize : true
|
256
|
+
});
|
257
|
+
t.ok(result.equals(new Rectangle(100, 50, 100, 50)));
|
258
|
+
|
259
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
260
|
+
target,
|
261
|
+
edgeAlign : 'l-r',
|
262
|
+
matchSize : true
|
263
|
+
});
|
264
|
+
t.ok(result.equals(new Rectangle(200, 100, 50, 100)));
|
265
|
+
|
266
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
267
|
+
target,
|
268
|
+
edgeAlign : 'r-l',
|
269
|
+
matchSize : true
|
270
|
+
});
|
271
|
+
t.ok(result.equals(new Rectangle(50, 100, 50, 100)));
|
272
|
+
});
|
273
|
+
|
274
|
+
// The subject must be pushed away from the target by the correct targetMargin
|
275
|
+
t.describe('unconstrained with targetMargin', async t => {
|
276
|
+
target = new Rectangle(110, 110, 80, 80);
|
277
|
+
|
278
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
279
|
+
target,
|
280
|
+
targetMargin : 10,
|
281
|
+
edgeAlign : 't-b'
|
282
|
+
});
|
283
|
+
t.ok(result.equals(new Rectangle(125, 200, 50, 50)));
|
284
|
+
|
285
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
286
|
+
target,
|
287
|
+
targetMargin : 10,
|
288
|
+
edgeAlign : 't0-b0'
|
289
|
+
});
|
290
|
+
t.ok(result.equals(new Rectangle(110, 200, 50, 50)));
|
291
|
+
|
292
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
293
|
+
target,
|
294
|
+
targetMargin : 10,
|
295
|
+
edgeAlign : 't100-b100'
|
296
|
+
});
|
297
|
+
t.ok(result.equals(new Rectangle(140, 200, 50, 50)));
|
298
|
+
|
299
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
300
|
+
target,
|
301
|
+
targetMargin : 10,
|
302
|
+
edgeAlign : 'b-t'
|
303
|
+
});
|
304
|
+
t.ok(result.equals(new Rectangle(125, 50, 50, 50)));
|
305
|
+
|
306
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
307
|
+
target,
|
308
|
+
targetMargin : 10,
|
309
|
+
edgeAlign : 'b0-t0'
|
310
|
+
});
|
311
|
+
t.ok(result.equals(new Rectangle(110, 50, 50, 50)));
|
312
|
+
|
313
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
314
|
+
target,
|
315
|
+
targetMargin : 10,
|
316
|
+
edgeAlign : 'b100-t100'
|
317
|
+
});
|
318
|
+
t.ok(result.equals(new Rectangle(140, 50, 50, 50)));
|
319
|
+
|
320
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
321
|
+
target,
|
322
|
+
targetMargin : 10,
|
323
|
+
edgeAlign : 'l-r'
|
324
|
+
});
|
325
|
+
t.ok(result.equals(new Rectangle(200, 125, 50, 50)));
|
326
|
+
|
327
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
328
|
+
target,
|
329
|
+
targetMargin : 10,
|
330
|
+
edgeAlign : 'l0-r0'
|
331
|
+
});
|
332
|
+
t.ok(result.equals(new Rectangle(200, 110, 50, 50)));
|
333
|
+
|
334
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
335
|
+
target,
|
336
|
+
targetMargin : 10,
|
337
|
+
edgeAlign : 'l100-r100'
|
338
|
+
});
|
339
|
+
t.ok(result.equals(new Rectangle(200, 140, 50, 50)));
|
340
|
+
|
341
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
342
|
+
target,
|
343
|
+
targetMargin : 10,
|
344
|
+
edgeAlign : 'r-l'
|
345
|
+
});
|
346
|
+
t.ok(result.equals(new Rectangle(50, 125, 50, 50)));
|
347
|
+
|
348
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
349
|
+
target,
|
350
|
+
targetMargin : 10,
|
351
|
+
edgeAlign : 'r0-l0'
|
352
|
+
});
|
353
|
+
t.ok(result.equals(new Rectangle(50, 110, 50, 50)));
|
354
|
+
|
355
|
+
result = new Rectangle(0, 0, 50, 50).alignTo({
|
356
|
+
target,
|
357
|
+
targetMargin : 10,
|
358
|
+
edgeAlign : 'r100-l100'
|
359
|
+
});
|
360
|
+
t.ok(result.equals(new Rectangle(50, 140, 50, 50)));
|
361
|
+
});
|
362
|
+
|
363
|
+
// Test the adaptation scenarios for the requested position being below the target.
|
364
|
+
// TODO: test constrain adaptation for all four edge alignment zones
|
365
|
+
t.describe('constrained, edgeAlign : "t-b"', t => {
|
366
|
+
constrainTo = new Rectangle(0, 0, 500, 500);
|
367
|
+
target = new Rectangle(200, 200, 100, 100);
|
368
|
+
subject = new Rectangle(0, 0, 10, 1000);
|
369
|
+
|
370
|
+
t.it('Subject shrinks to fit', t => {
|
371
|
+
subject.minHeight = 100;
|
372
|
+
result = subject.alignTo({
|
373
|
+
target,
|
374
|
+
constrainTo,
|
375
|
+
edgeAlign : 't-b'
|
376
|
+
});
|
377
|
+
t.ok(result.equals(new Rectangle(245, 300, 10, 200)));
|
378
|
+
});
|
379
|
+
|
380
|
+
subject = new Rectangle(0, 0, 10, 1000);
|
381
|
+
subject.minHeight = 100;
|
382
|
+
|
383
|
+
t.it('Subject shrinks to fit, cannot fit in first choice zone, flips edge and matches aligned edge size', t => {
|
384
|
+
result = subject.alignTo({
|
385
|
+
target,
|
386
|
+
constrainTo,
|
387
|
+
matchSize : true,
|
388
|
+
edgeAlign : 't-b'
|
389
|
+
});
|
390
|
+
t.ok(result.equals(new Rectangle(200, 300, 100, 200)));
|
391
|
+
});
|
392
|
+
|
393
|
+
t.it('Subject cannot shrink enough to fit at first choice moves to closest fitting zone', t => {
|
394
|
+
// Only 50px below. Should flip to top
|
395
|
+
target = new Rectangle(200, 350, 100, 100),
|
396
|
+
subject = new Rectangle(0, 0, 50, 200);
|
397
|
+
subject.minHeight = 100;
|
398
|
+
|
399
|
+
result = subject.alignTo({
|
400
|
+
target,
|
401
|
+
constrainTo,
|
402
|
+
matchSize : true,
|
403
|
+
edgeAlign : 't-b'
|
404
|
+
});
|
405
|
+
t.ok(result.equals(new Rectangle(150, 300, 50, 200)));
|
406
|
+
});
|
407
|
+
});
|
408
|
+
});
|
409
|
+
});
|