@brika/ui-kit 0.3.0 → 0.3.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/package.json +9 -9
- package/src/__tests__/nodes.test.ts +811 -180
- package/src/descriptors.ts +0 -8
- package/src/index.ts +2 -24
- package/src/nodes/_shared.ts +30 -9
- package/src/nodes/avatar.ts +8 -2
- package/src/nodes/badge.ts +8 -2
- package/src/nodes/button.ts +5 -1
- package/src/nodes/callout.ts +4 -1
- package/src/nodes/chart.ts +4 -1
- package/src/nodes/checkbox.ts +8 -2
- package/src/nodes/code-block.ts +4 -1
- package/src/nodes/divider.ts +4 -1
- package/src/nodes/icon.ts +8 -2
- package/src/nodes/image.ts +8 -2
- package/src/nodes/key-value.ts +4 -1
- package/src/nodes/link.ts +4 -1
- package/src/nodes/markdown.ts +4 -1
- package/src/nodes/progress.ts +4 -1
- package/src/nodes/select.ts +5 -1
- package/src/nodes/skeleton.ts +4 -1
- package/src/nodes/slider.ts +5 -1
- package/src/nodes/spacer.ts +4 -1
- package/src/nodes/stat-value.ts +4 -1
- package/src/nodes/status.ts +4 -1
- package/src/nodes/table.ts +8 -2
- package/src/nodes/tabs.ts +6 -1
- package/src/nodes/text.ts +16 -3
- package/src/nodes/toggle.ts +5 -1
- package/src/nodes/video.ts +4 -1
- package/tailwind-theme.css +115 -0
- package/src/__tests__/define-brick.test.ts +0 -125
- package/src/__tests__/mutations.test.ts +0 -211
- package/src/define-brick.ts +0 -92
- package/src/jsx-dev-runtime.ts +0 -3
- package/src/jsx-runtime.ts +0 -60
- package/src/mutations.ts +0 -79
|
@@ -70,25 +70,37 @@ describe('_shared', () => {
|
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
test('wraps a single ComponentNode in an array', () => {
|
|
73
|
-
const node = Text({
|
|
73
|
+
const node = Text({
|
|
74
|
+
content: 'hello',
|
|
75
|
+
});
|
|
74
76
|
const result = normalizeChildren(node);
|
|
75
77
|
expect(result).toEqual([node]);
|
|
76
78
|
});
|
|
77
79
|
|
|
78
80
|
test('returns flat array from array of nodes', () => {
|
|
79
|
-
const a = Text({
|
|
80
|
-
|
|
81
|
+
const a = Text({
|
|
82
|
+
content: 'a',
|
|
83
|
+
});
|
|
84
|
+
const b = Text({
|
|
85
|
+
content: 'b',
|
|
86
|
+
});
|
|
81
87
|
expect(normalizeChildren([a, b])).toEqual([a, b]);
|
|
82
88
|
});
|
|
83
89
|
|
|
84
90
|
test('flattens nested arrays', () => {
|
|
85
|
-
const a = Text({
|
|
86
|
-
|
|
91
|
+
const a = Text({
|
|
92
|
+
content: 'a',
|
|
93
|
+
});
|
|
94
|
+
const b = Text({
|
|
95
|
+
content: 'b',
|
|
96
|
+
});
|
|
87
97
|
expect(normalizeChildren([[a], [b]])).toEqual([a, b]);
|
|
88
98
|
});
|
|
89
99
|
|
|
90
100
|
test('filters out null, undefined, and false from arrays', () => {
|
|
91
|
-
const a = Text({
|
|
101
|
+
const a = Text({
|
|
102
|
+
content: 'a',
|
|
103
|
+
});
|
|
92
104
|
const result = normalizeChildren([a, null, undefined, false]);
|
|
93
105
|
expect(result).toEqual([a]);
|
|
94
106
|
});
|
|
@@ -108,7 +120,11 @@ describe('_shared', () => {
|
|
|
108
120
|
{
|
|
109
121
|
type: 'text',
|
|
110
122
|
content: 'stats.humidity',
|
|
111
|
-
i18n: {
|
|
123
|
+
i18n: {
|
|
124
|
+
ns: 'plugin:weather',
|
|
125
|
+
key: 'stats.humidity',
|
|
126
|
+
params: undefined,
|
|
127
|
+
},
|
|
112
128
|
},
|
|
113
129
|
]);
|
|
114
130
|
});
|
|
@@ -118,20 +134,30 @@ describe('_shared', () => {
|
|
|
118
134
|
__i18n: true,
|
|
119
135
|
ns: 'plugin:weather',
|
|
120
136
|
key: 'ui.dayForecast',
|
|
121
|
-
params: {
|
|
137
|
+
params: {
|
|
138
|
+
count: 7,
|
|
139
|
+
},
|
|
122
140
|
};
|
|
123
141
|
const result = normalizeChildren(ref);
|
|
124
142
|
expect(result).toEqual([
|
|
125
143
|
{
|
|
126
144
|
type: 'text',
|
|
127
145
|
content: 'ui.dayForecast',
|
|
128
|
-
i18n: {
|
|
146
|
+
i18n: {
|
|
147
|
+
ns: 'plugin:weather',
|
|
148
|
+
key: 'ui.dayForecast',
|
|
149
|
+
params: {
|
|
150
|
+
count: 7,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
129
153
|
},
|
|
130
154
|
]);
|
|
131
155
|
});
|
|
132
156
|
|
|
133
157
|
test('handles mixed I18nRef and ComponentNode in array', () => {
|
|
134
|
-
const textNode = Text({
|
|
158
|
+
const textNode = Text({
|
|
159
|
+
content: 'plain',
|
|
160
|
+
});
|
|
135
161
|
const ref = i18nRef('plugin:x', 'hello');
|
|
136
162
|
const result = normalizeChildren([textNode, ref, null, false]);
|
|
137
163
|
expect(result).toHaveLength(2);
|
|
@@ -139,7 +165,11 @@ describe('_shared', () => {
|
|
|
139
165
|
expect(result[1]).toEqual({
|
|
140
166
|
type: 'text',
|
|
141
167
|
content: 'hello',
|
|
142
|
-
i18n: {
|
|
168
|
+
i18n: {
|
|
169
|
+
ns: 'plugin:x',
|
|
170
|
+
key: 'hello',
|
|
171
|
+
params: undefined,
|
|
172
|
+
},
|
|
143
173
|
});
|
|
144
174
|
});
|
|
145
175
|
|
|
@@ -160,7 +190,9 @@ describe('_shared', () => {
|
|
|
160
190
|
__intl: true,
|
|
161
191
|
type: 'dateTime',
|
|
162
192
|
value: 0,
|
|
163
|
-
options: {
|
|
193
|
+
options: {
|
|
194
|
+
dateStyle: 'medium',
|
|
195
|
+
},
|
|
164
196
|
};
|
|
165
197
|
const result = normalizeChildren(ref);
|
|
166
198
|
expect(result).toEqual([
|
|
@@ -185,24 +217,53 @@ describe('_shared', () => {
|
|
|
185
217
|
});
|
|
186
218
|
|
|
187
219
|
test('handles mixed IntlRef, I18nRef, and ComponentNode in array', () => {
|
|
188
|
-
const textNode = Text({
|
|
220
|
+
const textNode = Text({
|
|
221
|
+
content: 'plain',
|
|
222
|
+
});
|
|
189
223
|
const i18n = i18nRef('plugin:x', 'hello');
|
|
190
224
|
const intl = intlRef.number(42);
|
|
191
225
|
const result = normalizeChildren([textNode, i18n, intl, null]);
|
|
192
226
|
expect(result).toHaveLength(3);
|
|
193
227
|
expect(result[0]).toBe(textNode);
|
|
194
|
-
expect(
|
|
195
|
-
|
|
228
|
+
expect(
|
|
229
|
+
(
|
|
230
|
+
result[1] as {
|
|
231
|
+
i18n: unknown;
|
|
232
|
+
}
|
|
233
|
+
).i18n
|
|
234
|
+
).toBeDefined();
|
|
235
|
+
expect(
|
|
236
|
+
(
|
|
237
|
+
result[2] as {
|
|
238
|
+
intl: unknown;
|
|
239
|
+
}
|
|
240
|
+
).intl
|
|
241
|
+
).toBe(intl);
|
|
196
242
|
});
|
|
197
243
|
});
|
|
198
244
|
|
|
199
245
|
describe('isI18nRef', () => {
|
|
200
246
|
test('returns true for valid I18nRef', () => {
|
|
201
|
-
expect(
|
|
247
|
+
expect(
|
|
248
|
+
isI18nRef({
|
|
249
|
+
__i18n: true,
|
|
250
|
+
ns: 'plugin:x',
|
|
251
|
+
key: 'k',
|
|
252
|
+
})
|
|
253
|
+
).toBe(true);
|
|
202
254
|
});
|
|
203
255
|
|
|
204
256
|
test('returns true for I18nRef with params', () => {
|
|
205
|
-
expect(
|
|
257
|
+
expect(
|
|
258
|
+
isI18nRef({
|
|
259
|
+
__i18n: true,
|
|
260
|
+
ns: 'n',
|
|
261
|
+
key: 'k',
|
|
262
|
+
params: {
|
|
263
|
+
a: 1,
|
|
264
|
+
},
|
|
265
|
+
})
|
|
266
|
+
).toBe(true);
|
|
206
267
|
});
|
|
207
268
|
|
|
208
269
|
test('returns false for null', () => {
|
|
@@ -222,29 +283,65 @@ describe('_shared', () => {
|
|
|
222
283
|
});
|
|
223
284
|
|
|
224
285
|
test('returns false for object without __i18n', () => {
|
|
225
|
-
expect(
|
|
286
|
+
expect(
|
|
287
|
+
isI18nRef({
|
|
288
|
+
ns: 'x',
|
|
289
|
+
key: 'k',
|
|
290
|
+
})
|
|
291
|
+
).toBe(false);
|
|
226
292
|
});
|
|
227
293
|
|
|
228
294
|
test('returns false for object with __i18n = false', () => {
|
|
229
|
-
expect(
|
|
295
|
+
expect(
|
|
296
|
+
isI18nRef({
|
|
297
|
+
__i18n: false,
|
|
298
|
+
ns: 'x',
|
|
299
|
+
key: 'k',
|
|
300
|
+
})
|
|
301
|
+
).toBe(false);
|
|
230
302
|
});
|
|
231
303
|
});
|
|
232
304
|
|
|
233
305
|
describe('isIntlRef', () => {
|
|
234
306
|
test('returns true for dateTime ref', () => {
|
|
235
|
-
expect(
|
|
307
|
+
expect(
|
|
308
|
+
isIntlRef({
|
|
309
|
+
__intl: true,
|
|
310
|
+
type: 'dateTime',
|
|
311
|
+
value: 0,
|
|
312
|
+
})
|
|
313
|
+
).toBe(true);
|
|
236
314
|
});
|
|
237
315
|
|
|
238
316
|
test('returns true for number ref', () => {
|
|
239
|
-
expect(
|
|
317
|
+
expect(
|
|
318
|
+
isIntlRef({
|
|
319
|
+
__intl: true,
|
|
320
|
+
type: 'number',
|
|
321
|
+
value: 42,
|
|
322
|
+
})
|
|
323
|
+
).toBe(true);
|
|
240
324
|
});
|
|
241
325
|
|
|
242
326
|
test('returns true for relativeTime ref', () => {
|
|
243
|
-
expect(
|
|
327
|
+
expect(
|
|
328
|
+
isIntlRef({
|
|
329
|
+
__intl: true,
|
|
330
|
+
type: 'relativeTime',
|
|
331
|
+
value: -1,
|
|
332
|
+
unit: 'day',
|
|
333
|
+
})
|
|
334
|
+
).toBe(true);
|
|
244
335
|
});
|
|
245
336
|
|
|
246
337
|
test('returns true for list ref', () => {
|
|
247
|
-
expect(
|
|
338
|
+
expect(
|
|
339
|
+
isIntlRef({
|
|
340
|
+
__intl: true,
|
|
341
|
+
type: 'list',
|
|
342
|
+
value: ['a', 'b'],
|
|
343
|
+
})
|
|
344
|
+
).toBe(true);
|
|
248
345
|
});
|
|
249
346
|
|
|
250
347
|
test('returns false for null', () => {
|
|
@@ -260,15 +357,32 @@ describe('_shared', () => {
|
|
|
260
357
|
});
|
|
261
358
|
|
|
262
359
|
test('returns false for I18nRef', () => {
|
|
263
|
-
expect(
|
|
360
|
+
expect(
|
|
361
|
+
isIntlRef({
|
|
362
|
+
__i18n: true,
|
|
363
|
+
ns: 'x',
|
|
364
|
+
key: 'k',
|
|
365
|
+
})
|
|
366
|
+
).toBe(false);
|
|
264
367
|
});
|
|
265
368
|
|
|
266
369
|
test('returns false for object without __intl', () => {
|
|
267
|
-
expect(
|
|
370
|
+
expect(
|
|
371
|
+
isIntlRef({
|
|
372
|
+
type: 'number',
|
|
373
|
+
value: 42,
|
|
374
|
+
})
|
|
375
|
+
).toBe(false);
|
|
268
376
|
});
|
|
269
377
|
|
|
270
378
|
test('returns false for object with __intl = false', () => {
|
|
271
|
-
expect(
|
|
379
|
+
expect(
|
|
380
|
+
isIntlRef({
|
|
381
|
+
__intl: false,
|
|
382
|
+
type: 'number',
|
|
383
|
+
value: 42,
|
|
384
|
+
})
|
|
385
|
+
).toBe(false);
|
|
272
386
|
});
|
|
273
387
|
});
|
|
274
388
|
|
|
@@ -322,34 +436,56 @@ describe('_shared', () => {
|
|
|
322
436
|
|
|
323
437
|
describe('Text', () => {
|
|
324
438
|
test('creates text node with required content', () => {
|
|
325
|
-
const node = Text({
|
|
326
|
-
|
|
439
|
+
const node = Text({
|
|
440
|
+
content: 'Hello',
|
|
441
|
+
});
|
|
442
|
+
expect(node).toEqual({
|
|
443
|
+
type: 'text',
|
|
444
|
+
content: 'Hello',
|
|
445
|
+
});
|
|
327
446
|
});
|
|
328
447
|
|
|
329
448
|
test('includes optional variant', () => {
|
|
330
|
-
const node = Text({
|
|
449
|
+
const node = Text({
|
|
450
|
+
content: 'Title',
|
|
451
|
+
variant: 'heading',
|
|
452
|
+
});
|
|
331
453
|
expect(node.type).toBe('text');
|
|
332
454
|
expect(node.content).toBe('Title');
|
|
333
455
|
expect(node.variant).toBe('heading');
|
|
334
456
|
});
|
|
335
457
|
|
|
336
458
|
test('includes optional color', () => {
|
|
337
|
-
const node = Text({
|
|
459
|
+
const node = Text({
|
|
460
|
+
content: 'red',
|
|
461
|
+
color: '#ff0000',
|
|
462
|
+
});
|
|
338
463
|
expect(node.color).toBe('#ff0000');
|
|
339
464
|
});
|
|
340
465
|
|
|
341
466
|
test('all variant values work', () => {
|
|
342
467
|
for (const v of ['body', 'caption', 'heading'] as const) {
|
|
343
|
-
expect(
|
|
468
|
+
expect(
|
|
469
|
+
Text({
|
|
470
|
+
content: '',
|
|
471
|
+
variant: v,
|
|
472
|
+
}).variant
|
|
473
|
+
).toBe(v);
|
|
344
474
|
}
|
|
345
475
|
});
|
|
346
476
|
|
|
347
477
|
test('accepts I18nRef as content and sets i18n field', () => {
|
|
348
478
|
const ref = i18nRef('plugin:weather', 'stats.humidity');
|
|
349
|
-
const node = Text({
|
|
479
|
+
const node = Text({
|
|
480
|
+
content: ref,
|
|
481
|
+
});
|
|
350
482
|
expect(node.type).toBe('text');
|
|
351
483
|
expect(node.content).toBe('stats.humidity');
|
|
352
|
-
expect(node.i18n).toEqual({
|
|
484
|
+
expect(node.i18n).toEqual({
|
|
485
|
+
ns: 'plugin:weather',
|
|
486
|
+
key: 'stats.humidity',
|
|
487
|
+
params: undefined,
|
|
488
|
+
});
|
|
353
489
|
});
|
|
354
490
|
|
|
355
491
|
test('I18nRef with params preserves params in i18n field', () => {
|
|
@@ -357,21 +493,31 @@ describe('Text', () => {
|
|
|
357
493
|
__i18n: true,
|
|
358
494
|
ns: 'plugin:weather',
|
|
359
495
|
key: 'ui.dayForecast',
|
|
360
|
-
params: {
|
|
496
|
+
params: {
|
|
497
|
+
count: 7,
|
|
498
|
+
},
|
|
361
499
|
};
|
|
362
|
-
const node = Text({
|
|
500
|
+
const node = Text({
|
|
501
|
+
content: ref,
|
|
502
|
+
variant: 'heading',
|
|
503
|
+
weight: 'bold',
|
|
504
|
+
});
|
|
363
505
|
expect(node.content).toBe('ui.dayForecast');
|
|
364
506
|
expect(node.i18n).toEqual({
|
|
365
507
|
ns: 'plugin:weather',
|
|
366
508
|
key: 'ui.dayForecast',
|
|
367
|
-
params: {
|
|
509
|
+
params: {
|
|
510
|
+
count: 7,
|
|
511
|
+
},
|
|
368
512
|
});
|
|
369
513
|
expect(node.variant).toBe('heading');
|
|
370
514
|
expect(node.weight).toBe('bold');
|
|
371
515
|
});
|
|
372
516
|
|
|
373
517
|
test('string content does not set i18n field', () => {
|
|
374
|
-
const node = Text({
|
|
518
|
+
const node = Text({
|
|
519
|
+
content: 'plain text',
|
|
520
|
+
});
|
|
375
521
|
expect(node.i18n).toBeUndefined();
|
|
376
522
|
});
|
|
377
523
|
|
|
@@ -380,9 +526,13 @@ describe('Text', () => {
|
|
|
380
526
|
__intl: true,
|
|
381
527
|
type: 'number',
|
|
382
528
|
value: 1234.5,
|
|
383
|
-
options: {
|
|
529
|
+
options: {
|
|
530
|
+
minimumFractionDigits: 2,
|
|
531
|
+
},
|
|
384
532
|
};
|
|
385
|
-
const node = Text({
|
|
533
|
+
const node = Text({
|
|
534
|
+
content: ref,
|
|
535
|
+
});
|
|
386
536
|
expect(node.type).toBe('text');
|
|
387
537
|
expect(node.content).toBe('1234.5');
|
|
388
538
|
expect(node.intl).toBe(ref);
|
|
@@ -391,21 +541,29 @@ describe('Text', () => {
|
|
|
391
541
|
|
|
392
542
|
test('accepts IntlRef dateTime as content', () => {
|
|
393
543
|
const ref = intlRef.dateTime(1700000000000);
|
|
394
|
-
const node = Text({
|
|
544
|
+
const node = Text({
|
|
545
|
+
content: ref,
|
|
546
|
+
});
|
|
395
547
|
expect(node.content).toBe('1700000000000');
|
|
396
548
|
expect(node.intl).toBe(ref);
|
|
397
549
|
});
|
|
398
550
|
|
|
399
551
|
test('accepts IntlRef list as content with joined fallback', () => {
|
|
400
552
|
const ref = intlRef.list(['apples', 'oranges']);
|
|
401
|
-
const node = Text({
|
|
553
|
+
const node = Text({
|
|
554
|
+
content: ref,
|
|
555
|
+
});
|
|
402
556
|
expect(node.content).toBe('apples, oranges');
|
|
403
557
|
expect(node.intl).toBe(ref);
|
|
404
558
|
});
|
|
405
559
|
|
|
406
560
|
test('IntlRef preserves other props', () => {
|
|
407
561
|
const ref = intlRef.number(99);
|
|
408
|
-
const node = Text({
|
|
562
|
+
const node = Text({
|
|
563
|
+
content: ref,
|
|
564
|
+
variant: 'heading',
|
|
565
|
+
weight: 'bold',
|
|
566
|
+
});
|
|
409
567
|
expect(node.variant).toBe('heading');
|
|
410
568
|
expect(node.weight).toBe('bold');
|
|
411
569
|
expect(node.intl).toBe(ref);
|
|
@@ -414,18 +572,30 @@ describe('Text', () => {
|
|
|
414
572
|
|
|
415
573
|
describe('Badge', () => {
|
|
416
574
|
test('creates badge node with required label', () => {
|
|
417
|
-
const node = Badge({
|
|
418
|
-
|
|
575
|
+
const node = Badge({
|
|
576
|
+
label: 'New',
|
|
577
|
+
});
|
|
578
|
+
expect(node).toEqual({
|
|
579
|
+
type: 'badge',
|
|
580
|
+
label: 'New',
|
|
581
|
+
});
|
|
419
582
|
});
|
|
420
583
|
|
|
421
584
|
test('includes optional variant', () => {
|
|
422
|
-
const node = Badge({
|
|
585
|
+
const node = Badge({
|
|
586
|
+
label: 'OK',
|
|
587
|
+
variant: 'success',
|
|
588
|
+
});
|
|
423
589
|
expect(node.type).toBe('badge');
|
|
424
590
|
expect(node.variant).toBe('success');
|
|
425
591
|
});
|
|
426
592
|
|
|
427
593
|
test('includes optional icon and color', () => {
|
|
428
|
-
const node = Badge({
|
|
594
|
+
const node = Badge({
|
|
595
|
+
label: 'Warn',
|
|
596
|
+
icon: 'alert-triangle',
|
|
597
|
+
color: '#f00',
|
|
598
|
+
});
|
|
429
599
|
expect(node.icon).toBe('alert-triangle');
|
|
430
600
|
expect(node.color).toBe('#f00');
|
|
431
601
|
});
|
|
@@ -439,19 +609,33 @@ describe('Badge', () => {
|
|
|
439
609
|
'warning',
|
|
440
610
|
'destructive',
|
|
441
611
|
] as const) {
|
|
442
|
-
expect(
|
|
612
|
+
expect(
|
|
613
|
+
Badge({
|
|
614
|
+
label: '',
|
|
615
|
+
variant: v,
|
|
616
|
+
}).variant
|
|
617
|
+
).toBe(v);
|
|
443
618
|
}
|
|
444
619
|
});
|
|
445
620
|
});
|
|
446
621
|
|
|
447
622
|
describe('Chart', () => {
|
|
448
623
|
const sampleData = [
|
|
449
|
-
{
|
|
450
|
-
|
|
624
|
+
{
|
|
625
|
+
ts: 1000,
|
|
626
|
+
value: 10,
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
ts: 2000,
|
|
630
|
+
value: 20,
|
|
631
|
+
},
|
|
451
632
|
];
|
|
452
633
|
|
|
453
634
|
test('creates chart node with required fields', () => {
|
|
454
|
-
const node = Chart({
|
|
635
|
+
const node = Chart({
|
|
636
|
+
variant: 'line',
|
|
637
|
+
data: sampleData,
|
|
638
|
+
});
|
|
455
639
|
expect(node.type).toBe('chart');
|
|
456
640
|
expect(node.variant).toBe('line');
|
|
457
641
|
expect(node.data).toEqual(sampleData);
|
|
@@ -472,7 +656,12 @@ describe('Chart', () => {
|
|
|
472
656
|
|
|
473
657
|
test('all variant values work', () => {
|
|
474
658
|
for (const v of ['line', 'area', 'bar'] as const) {
|
|
475
|
-
expect(
|
|
659
|
+
expect(
|
|
660
|
+
Chart({
|
|
661
|
+
variant: v,
|
|
662
|
+
data: [],
|
|
663
|
+
}).variant
|
|
664
|
+
).toBe(v);
|
|
476
665
|
}
|
|
477
666
|
});
|
|
478
667
|
});
|
|
@@ -484,38 +673,64 @@ describe('Divider', () => {
|
|
|
484
673
|
});
|
|
485
674
|
|
|
486
675
|
test('accepts direction', () => {
|
|
487
|
-
expect(
|
|
488
|
-
|
|
676
|
+
expect(
|
|
677
|
+
Divider({
|
|
678
|
+
direction: 'horizontal',
|
|
679
|
+
}).direction
|
|
680
|
+
).toBe('horizontal');
|
|
681
|
+
expect(
|
|
682
|
+
Divider({
|
|
683
|
+
direction: 'vertical',
|
|
684
|
+
}).direction
|
|
685
|
+
).toBe('vertical');
|
|
489
686
|
});
|
|
490
687
|
|
|
491
688
|
test('accepts color', () => {
|
|
492
|
-
const node = Divider({
|
|
689
|
+
const node = Divider({
|
|
690
|
+
color: '#ccc',
|
|
691
|
+
});
|
|
493
692
|
expect(node.color).toBe('#ccc');
|
|
494
693
|
});
|
|
495
694
|
});
|
|
496
695
|
|
|
497
696
|
describe('Icon', () => {
|
|
498
697
|
test('creates icon node with required name', () => {
|
|
499
|
-
const node = Icon({
|
|
500
|
-
|
|
698
|
+
const node = Icon({
|
|
699
|
+
name: 'star',
|
|
700
|
+
});
|
|
701
|
+
expect(node).toEqual({
|
|
702
|
+
type: 'icon',
|
|
703
|
+
name: 'star',
|
|
704
|
+
});
|
|
501
705
|
});
|
|
502
706
|
|
|
503
707
|
test('includes optional size and color', () => {
|
|
504
|
-
const node = Icon({
|
|
708
|
+
const node = Icon({
|
|
709
|
+
name: 'heart',
|
|
710
|
+
size: 'lg',
|
|
711
|
+
color: 'red',
|
|
712
|
+
});
|
|
505
713
|
expect(node.size).toBe('lg');
|
|
506
714
|
expect(node.color).toBe('red');
|
|
507
715
|
});
|
|
508
716
|
|
|
509
717
|
test('all size values work', () => {
|
|
510
718
|
for (const s of ['sm', 'md', 'lg'] as const) {
|
|
511
|
-
expect(
|
|
719
|
+
expect(
|
|
720
|
+
Icon({
|
|
721
|
+
name: 'x',
|
|
722
|
+
size: s,
|
|
723
|
+
}).size
|
|
724
|
+
).toBe(s);
|
|
512
725
|
}
|
|
513
726
|
});
|
|
514
727
|
});
|
|
515
728
|
|
|
516
729
|
describe('Image', () => {
|
|
517
730
|
test('creates image node with required src', () => {
|
|
518
|
-
const node = Image({
|
|
731
|
+
const node = Image({
|
|
732
|
+
src: 'https://img.example.com/a.png',
|
|
733
|
+
});
|
|
519
734
|
expect(node.type).toBe('image');
|
|
520
735
|
expect(node.src).toBe('https://img.example.com/a.png');
|
|
521
736
|
});
|
|
@@ -541,11 +756,19 @@ describe('Image', () => {
|
|
|
541
756
|
});
|
|
542
757
|
|
|
543
758
|
test('width/height accept both number and string', () => {
|
|
544
|
-
const n1 = Image({
|
|
759
|
+
const n1 = Image({
|
|
760
|
+
src: 'a',
|
|
761
|
+
width: 200,
|
|
762
|
+
height: 100,
|
|
763
|
+
});
|
|
545
764
|
expect(n1.width).toBe(200);
|
|
546
765
|
expect(n1.height).toBe(100);
|
|
547
766
|
|
|
548
|
-
const n2 = Image({
|
|
767
|
+
const n2 = Image({
|
|
768
|
+
src: 'a',
|
|
769
|
+
width: '30%',
|
|
770
|
+
height: '50%',
|
|
771
|
+
});
|
|
549
772
|
expect(n2.width).toBe('30%');
|
|
550
773
|
expect(n2.height).toBe('50%');
|
|
551
774
|
});
|
|
@@ -553,8 +776,13 @@ describe('Image', () => {
|
|
|
553
776
|
|
|
554
777
|
describe('Progress', () => {
|
|
555
778
|
test('creates progress node with required value', () => {
|
|
556
|
-
const node = Progress({
|
|
557
|
-
|
|
779
|
+
const node = Progress({
|
|
780
|
+
value: 42,
|
|
781
|
+
});
|
|
782
|
+
expect(node).toEqual({
|
|
783
|
+
type: 'progress',
|
|
784
|
+
value: 42,
|
|
785
|
+
});
|
|
558
786
|
});
|
|
559
787
|
|
|
560
788
|
test('includes optional fields', () => {
|
|
@@ -570,8 +798,16 @@ describe('Progress', () => {
|
|
|
570
798
|
});
|
|
571
799
|
|
|
572
800
|
test('handles boundary values', () => {
|
|
573
|
-
expect(
|
|
574
|
-
|
|
801
|
+
expect(
|
|
802
|
+
Progress({
|
|
803
|
+
value: 0,
|
|
804
|
+
}).value
|
|
805
|
+
).toBe(0);
|
|
806
|
+
expect(
|
|
807
|
+
Progress({
|
|
808
|
+
value: 100,
|
|
809
|
+
}).value
|
|
810
|
+
).toBe(100);
|
|
575
811
|
});
|
|
576
812
|
});
|
|
577
813
|
|
|
@@ -583,7 +819,11 @@ describe('Spacer', () => {
|
|
|
583
819
|
|
|
584
820
|
test('accepts size', () => {
|
|
585
821
|
for (const s of ['sm', 'md', 'lg'] as const) {
|
|
586
|
-
expect(
|
|
822
|
+
expect(
|
|
823
|
+
Spacer({
|
|
824
|
+
size: s,
|
|
825
|
+
}).size
|
|
826
|
+
).toBe(s);
|
|
587
827
|
}
|
|
588
828
|
});
|
|
589
829
|
|
|
@@ -595,14 +835,20 @@ describe('Spacer', () => {
|
|
|
595
835
|
|
|
596
836
|
describe('Stat', () => {
|
|
597
837
|
test('creates stat-value node with required label and value', () => {
|
|
598
|
-
const node = Stat({
|
|
838
|
+
const node = Stat({
|
|
839
|
+
label: 'Temp',
|
|
840
|
+
value: 21.5,
|
|
841
|
+
});
|
|
599
842
|
expect(node.type).toBe('stat-value');
|
|
600
843
|
expect(node.label).toBe('Temp');
|
|
601
844
|
expect(node.value).toBe(21.5);
|
|
602
845
|
});
|
|
603
846
|
|
|
604
847
|
test('value can be a string', () => {
|
|
605
|
-
const node = Stat({
|
|
848
|
+
const node = Stat({
|
|
849
|
+
label: 'Status',
|
|
850
|
+
value: 'OK',
|
|
851
|
+
});
|
|
606
852
|
expect(node.value).toBe('OK');
|
|
607
853
|
});
|
|
608
854
|
|
|
@@ -623,35 +869,57 @@ describe('Stat', () => {
|
|
|
623
869
|
|
|
624
870
|
test('all trend values work', () => {
|
|
625
871
|
for (const t of ['up', 'down', 'flat'] as const) {
|
|
626
|
-
expect(
|
|
872
|
+
expect(
|
|
873
|
+
Stat({
|
|
874
|
+
label: '',
|
|
875
|
+
value: 0,
|
|
876
|
+
trend: t,
|
|
877
|
+
}).trend
|
|
878
|
+
).toBe(t);
|
|
627
879
|
}
|
|
628
880
|
});
|
|
629
881
|
});
|
|
630
882
|
|
|
631
883
|
describe('Status', () => {
|
|
632
884
|
test('creates status node with required label and status', () => {
|
|
633
|
-
const node = Status({
|
|
885
|
+
const node = Status({
|
|
886
|
+
label: 'Server',
|
|
887
|
+
status: 'online',
|
|
888
|
+
});
|
|
634
889
|
expect(node.type).toBe('status');
|
|
635
890
|
expect(node.label).toBe('Server');
|
|
636
891
|
expect(node.status).toBe('online');
|
|
637
892
|
});
|
|
638
893
|
|
|
639
894
|
test('includes optional icon and color', () => {
|
|
640
|
-
const node = Status({
|
|
895
|
+
const node = Status({
|
|
896
|
+
label: 'DB',
|
|
897
|
+
status: 'error',
|
|
898
|
+
icon: 'database',
|
|
899
|
+
color: '#f00',
|
|
900
|
+
});
|
|
641
901
|
expect(node.icon).toBe('database');
|
|
642
902
|
expect(node.color).toBe('#f00');
|
|
643
903
|
});
|
|
644
904
|
|
|
645
905
|
test('all status values work', () => {
|
|
646
906
|
for (const s of ['online', 'offline', 'warning', 'error', 'idle'] as const) {
|
|
647
|
-
expect(
|
|
907
|
+
expect(
|
|
908
|
+
Status({
|
|
909
|
+
label: '',
|
|
910
|
+
status: s,
|
|
911
|
+
}).status
|
|
912
|
+
).toBe(s);
|
|
648
913
|
}
|
|
649
914
|
});
|
|
650
915
|
});
|
|
651
916
|
|
|
652
917
|
describe('Video', () => {
|
|
653
918
|
test('creates video node with required fields', () => {
|
|
654
|
-
const node = Video({
|
|
919
|
+
const node = Video({
|
|
920
|
+
src: 'https://stream.example.com/live.m3u8',
|
|
921
|
+
format: 'hls',
|
|
922
|
+
});
|
|
655
923
|
expect(node.type).toBe('video');
|
|
656
924
|
expect(node.src).toBe('https://stream.example.com/live.m3u8');
|
|
657
925
|
expect(node.format).toBe('hls');
|
|
@@ -671,8 +939,18 @@ describe('Video', () => {
|
|
|
671
939
|
});
|
|
672
940
|
|
|
673
941
|
test('both format values work', () => {
|
|
674
|
-
expect(
|
|
675
|
-
|
|
942
|
+
expect(
|
|
943
|
+
Video({
|
|
944
|
+
src: '',
|
|
945
|
+
format: 'hls',
|
|
946
|
+
}).format
|
|
947
|
+
).toBe('hls');
|
|
948
|
+
expect(
|
|
949
|
+
Video({
|
|
950
|
+
src: '',
|
|
951
|
+
format: 'mjpeg',
|
|
952
|
+
}).format
|
|
953
|
+
).toBe('mjpeg');
|
|
676
954
|
});
|
|
677
955
|
});
|
|
678
956
|
|
|
@@ -688,21 +966,35 @@ describe('Box', () => {
|
|
|
688
966
|
});
|
|
689
967
|
|
|
690
968
|
test('normalizes single child', () => {
|
|
691
|
-
const child = Text({
|
|
692
|
-
|
|
969
|
+
const child = Text({
|
|
970
|
+
content: 'hi',
|
|
971
|
+
});
|
|
972
|
+
const node = Box({
|
|
973
|
+
children: child,
|
|
974
|
+
});
|
|
693
975
|
expect(node.children).toEqual([child]);
|
|
694
976
|
});
|
|
695
977
|
|
|
696
978
|
test('normalizes array children', () => {
|
|
697
|
-
const a = Text({
|
|
698
|
-
|
|
699
|
-
|
|
979
|
+
const a = Text({
|
|
980
|
+
content: 'a',
|
|
981
|
+
});
|
|
982
|
+
const b = Text({
|
|
983
|
+
content: 'b',
|
|
984
|
+
});
|
|
985
|
+
const node = Box({
|
|
986
|
+
children: [a, b],
|
|
987
|
+
});
|
|
700
988
|
expect(node.children).toEqual([a, b]);
|
|
701
989
|
});
|
|
702
990
|
|
|
703
991
|
test('filters out falsy children', () => {
|
|
704
|
-
const a = Text({
|
|
705
|
-
|
|
992
|
+
const a = Text({
|
|
993
|
+
content: 'a',
|
|
994
|
+
});
|
|
995
|
+
const node = Box({
|
|
996
|
+
children: [a, null, false, undefined],
|
|
997
|
+
});
|
|
706
998
|
expect(node.children).toEqual([a]);
|
|
707
999
|
});
|
|
708
1000
|
|
|
@@ -730,7 +1022,12 @@ describe('Box', () => {
|
|
|
730
1022
|
});
|
|
731
1023
|
|
|
732
1024
|
test('does not leak children into rest props', () => {
|
|
733
|
-
const node = Box({
|
|
1025
|
+
const node = Box({
|
|
1026
|
+
children: Text({
|
|
1027
|
+
content: 'x',
|
|
1028
|
+
}),
|
|
1029
|
+
padding: 'sm',
|
|
1030
|
+
});
|
|
734
1031
|
// The children key should be the normalized array, not the raw input
|
|
735
1032
|
expect(Array.isArray(node.children)).toBe(true);
|
|
736
1033
|
expect(node.padding).toBe('sm');
|
|
@@ -745,9 +1042,15 @@ describe('Grid', () => {
|
|
|
745
1042
|
});
|
|
746
1043
|
|
|
747
1044
|
test('normalizes children', () => {
|
|
748
|
-
const a = Text({
|
|
749
|
-
|
|
750
|
-
|
|
1045
|
+
const a = Text({
|
|
1046
|
+
content: 'a',
|
|
1047
|
+
});
|
|
1048
|
+
const b = Text({
|
|
1049
|
+
content: 'b',
|
|
1050
|
+
});
|
|
1051
|
+
const node = Grid({
|
|
1052
|
+
children: [a, b],
|
|
1053
|
+
});
|
|
751
1054
|
expect(node.children).toEqual([a, b]);
|
|
752
1055
|
});
|
|
753
1056
|
|
|
@@ -765,29 +1068,45 @@ describe('Grid', () => {
|
|
|
765
1068
|
});
|
|
766
1069
|
|
|
767
1070
|
test('filters falsy children', () => {
|
|
768
|
-
const a = Text({
|
|
769
|
-
|
|
1071
|
+
const a = Text({
|
|
1072
|
+
content: 'a',
|
|
1073
|
+
});
|
|
1074
|
+
const node = Grid({
|
|
1075
|
+
children: [a, null, false],
|
|
1076
|
+
});
|
|
770
1077
|
expect(node.children).toEqual([a]);
|
|
771
1078
|
});
|
|
772
1079
|
});
|
|
773
1080
|
|
|
774
1081
|
describe('Section', () => {
|
|
775
1082
|
test('creates section node with title and empty children', () => {
|
|
776
|
-
const node = Section({
|
|
1083
|
+
const node = Section({
|
|
1084
|
+
title: 'Settings',
|
|
1085
|
+
});
|
|
777
1086
|
expect(node.type).toBe('section');
|
|
778
1087
|
expect(node.title).toBe('Settings');
|
|
779
1088
|
expect(node.children).toEqual([]);
|
|
780
1089
|
});
|
|
781
1090
|
|
|
782
1091
|
test('normalizes children', () => {
|
|
783
|
-
const child = Text({
|
|
784
|
-
|
|
1092
|
+
const child = Text({
|
|
1093
|
+
content: 'hello',
|
|
1094
|
+
});
|
|
1095
|
+
const node = Section({
|
|
1096
|
+
title: 'Main',
|
|
1097
|
+
children: child,
|
|
1098
|
+
});
|
|
785
1099
|
expect(node.children).toEqual([child]);
|
|
786
1100
|
});
|
|
787
1101
|
|
|
788
1102
|
test('normalizes array children with falsy values', () => {
|
|
789
|
-
const a = Text({
|
|
790
|
-
|
|
1103
|
+
const a = Text({
|
|
1104
|
+
content: 'a',
|
|
1105
|
+
});
|
|
1106
|
+
const node = Section({
|
|
1107
|
+
title: 'S',
|
|
1108
|
+
children: [a, null, false],
|
|
1109
|
+
});
|
|
791
1110
|
expect(node.children).toEqual([a]);
|
|
792
1111
|
});
|
|
793
1112
|
});
|
|
@@ -804,9 +1123,15 @@ describe('Row', () => {
|
|
|
804
1123
|
});
|
|
805
1124
|
|
|
806
1125
|
test('normalizes children', () => {
|
|
807
|
-
const a = Text({
|
|
808
|
-
|
|
809
|
-
|
|
1126
|
+
const a = Text({
|
|
1127
|
+
content: 'a',
|
|
1128
|
+
});
|
|
1129
|
+
const b = Text({
|
|
1130
|
+
content: 'b',
|
|
1131
|
+
});
|
|
1132
|
+
const node = Row({
|
|
1133
|
+
children: [a, b],
|
|
1134
|
+
});
|
|
810
1135
|
expect(node.children).toEqual([a, b]);
|
|
811
1136
|
});
|
|
812
1137
|
|
|
@@ -826,13 +1151,19 @@ describe('Row', () => {
|
|
|
826
1151
|
});
|
|
827
1152
|
|
|
828
1153
|
test('resolves onPress to action ID', () => {
|
|
829
|
-
const node = Row({
|
|
1154
|
+
const node = Row({
|
|
1155
|
+
onPress: () => {},
|
|
1156
|
+
});
|
|
830
1157
|
expect(node.onPress).toMatch(/^__action_\d+$/);
|
|
831
1158
|
});
|
|
832
1159
|
|
|
833
1160
|
test('filters falsy children', () => {
|
|
834
|
-
const a = Text({
|
|
835
|
-
|
|
1161
|
+
const a = Text({
|
|
1162
|
+
content: 'a',
|
|
1163
|
+
});
|
|
1164
|
+
const node = Row({
|
|
1165
|
+
children: [a, null, undefined, false],
|
|
1166
|
+
});
|
|
836
1167
|
expect(node.children).toEqual([a]);
|
|
837
1168
|
});
|
|
838
1169
|
});
|
|
@@ -849,9 +1180,15 @@ describe('Column', () => {
|
|
|
849
1180
|
});
|
|
850
1181
|
|
|
851
1182
|
test('normalizes children', () => {
|
|
852
|
-
const a = Text({
|
|
853
|
-
|
|
854
|
-
|
|
1183
|
+
const a = Text({
|
|
1184
|
+
content: 'a',
|
|
1185
|
+
});
|
|
1186
|
+
const b = Text({
|
|
1187
|
+
content: 'b',
|
|
1188
|
+
});
|
|
1189
|
+
const node = Column({
|
|
1190
|
+
children: [a, b],
|
|
1191
|
+
});
|
|
855
1192
|
expect(node.children).toEqual([a, b]);
|
|
856
1193
|
});
|
|
857
1194
|
|
|
@@ -871,13 +1208,19 @@ describe('Column', () => {
|
|
|
871
1208
|
});
|
|
872
1209
|
|
|
873
1210
|
test('resolves onPress to action ID', () => {
|
|
874
|
-
const node = Column({
|
|
1211
|
+
const node = Column({
|
|
1212
|
+
onPress: () => {},
|
|
1213
|
+
});
|
|
875
1214
|
expect(node.onPress).toMatch(/^__action_\d+$/);
|
|
876
1215
|
});
|
|
877
1216
|
|
|
878
1217
|
test('filters falsy children', () => {
|
|
879
|
-
const a = Text({
|
|
880
|
-
|
|
1218
|
+
const a = Text({
|
|
1219
|
+
content: 'a',
|
|
1220
|
+
});
|
|
1221
|
+
const node = Column({
|
|
1222
|
+
children: [a, null, undefined, false],
|
|
1223
|
+
});
|
|
881
1224
|
expect(node.children).toEqual([a]);
|
|
882
1225
|
});
|
|
883
1226
|
});
|
|
@@ -892,7 +1235,9 @@ describe('Button', () => {
|
|
|
892
1235
|
});
|
|
893
1236
|
|
|
894
1237
|
test('creates button node with label only', () => {
|
|
895
|
-
const node = Button({
|
|
1238
|
+
const node = Button({
|
|
1239
|
+
label: 'Click me',
|
|
1240
|
+
});
|
|
896
1241
|
expect(node.type).toBe('button');
|
|
897
1242
|
expect(node.label).toBe('Click me');
|
|
898
1243
|
expect(node.onPress).toBeUndefined();
|
|
@@ -900,19 +1245,28 @@ describe('Button', () => {
|
|
|
900
1245
|
|
|
901
1246
|
test('resolves onPress handler to an action ID', () => {
|
|
902
1247
|
const handler = () => {};
|
|
903
|
-
const node = Button({
|
|
1248
|
+
const node = Button({
|
|
1249
|
+
label: 'Go',
|
|
1250
|
+
onPress: handler,
|
|
1251
|
+
});
|
|
904
1252
|
expect(node.type).toBe('button');
|
|
905
1253
|
expect(node.onPress).toMatch(/^__action_\d+$/);
|
|
906
1254
|
});
|
|
907
1255
|
|
|
908
1256
|
test('uses custom registrar for onPress', () => {
|
|
909
1257
|
_setActionRegistrar(() => 'btn-action-1');
|
|
910
|
-
const node = Button({
|
|
1258
|
+
const node = Button({
|
|
1259
|
+
label: 'Go',
|
|
1260
|
+
onPress: () => {},
|
|
1261
|
+
});
|
|
911
1262
|
expect(node.onPress).toBe('btn-action-1');
|
|
912
1263
|
});
|
|
913
1264
|
|
|
914
1265
|
test('includes url without onPress', () => {
|
|
915
|
-
const node = Button({
|
|
1266
|
+
const node = Button({
|
|
1267
|
+
label: 'Link',
|
|
1268
|
+
url: 'https://example.com',
|
|
1269
|
+
});
|
|
916
1270
|
expect(node.url).toBe('https://example.com');
|
|
917
1271
|
expect(node.onPress).toBeUndefined();
|
|
918
1272
|
});
|
|
@@ -932,7 +1286,11 @@ describe('Button', () => {
|
|
|
932
1286
|
|
|
933
1287
|
test('all variant values work', () => {
|
|
934
1288
|
for (const v of ['default', 'secondary', 'outline', 'ghost', 'destructive', 'link'] as const) {
|
|
935
|
-
expect(
|
|
1289
|
+
expect(
|
|
1290
|
+
Button({
|
|
1291
|
+
variant: v,
|
|
1292
|
+
}).variant
|
|
1293
|
+
).toBe(v);
|
|
936
1294
|
}
|
|
937
1295
|
});
|
|
938
1296
|
});
|
|
@@ -944,7 +1302,12 @@ describe('Slider', () => {
|
|
|
944
1302
|
|
|
945
1303
|
test('creates slider node with required fields', () => {
|
|
946
1304
|
const handler = () => {};
|
|
947
|
-
const node = Slider({
|
|
1305
|
+
const node = Slider({
|
|
1306
|
+
value: 50,
|
|
1307
|
+
min: 0,
|
|
1308
|
+
max: 100,
|
|
1309
|
+
onChange: handler,
|
|
1310
|
+
});
|
|
948
1311
|
expect(node.type).toBe('slider');
|
|
949
1312
|
expect(node.value).toBe(50);
|
|
950
1313
|
expect(node.min).toBe(0);
|
|
@@ -954,7 +1317,12 @@ describe('Slider', () => {
|
|
|
954
1317
|
|
|
955
1318
|
test('uses custom registrar for onChange', () => {
|
|
956
1319
|
_setActionRegistrar(() => 'slider-action-1');
|
|
957
|
-
const node = Slider({
|
|
1320
|
+
const node = Slider({
|
|
1321
|
+
value: 10,
|
|
1322
|
+
min: 0,
|
|
1323
|
+
max: 20,
|
|
1324
|
+
onChange: () => {},
|
|
1325
|
+
});
|
|
958
1326
|
expect(node.onChange).toBe('slider-action-1');
|
|
959
1327
|
});
|
|
960
1328
|
|
|
@@ -985,7 +1353,11 @@ describe('Toggle', () => {
|
|
|
985
1353
|
|
|
986
1354
|
test('creates toggle node with required fields', () => {
|
|
987
1355
|
const handler = () => {};
|
|
988
|
-
const node = Toggle({
|
|
1356
|
+
const node = Toggle({
|
|
1357
|
+
label: 'Dark mode',
|
|
1358
|
+
checked: false,
|
|
1359
|
+
onToggle: handler,
|
|
1360
|
+
});
|
|
989
1361
|
expect(node.type).toBe('toggle');
|
|
990
1362
|
expect(node.label).toBe('Dark mode');
|
|
991
1363
|
expect(node.checked).toBe(false);
|
|
@@ -993,13 +1365,21 @@ describe('Toggle', () => {
|
|
|
993
1365
|
});
|
|
994
1366
|
|
|
995
1367
|
test('checked can be true', () => {
|
|
996
|
-
const node = Toggle({
|
|
1368
|
+
const node = Toggle({
|
|
1369
|
+
label: 'On',
|
|
1370
|
+
checked: true,
|
|
1371
|
+
onToggle: () => {},
|
|
1372
|
+
});
|
|
997
1373
|
expect(node.checked).toBe(true);
|
|
998
1374
|
});
|
|
999
1375
|
|
|
1000
1376
|
test('uses custom registrar for onToggle', () => {
|
|
1001
1377
|
_setActionRegistrar(() => 'toggle-action-1');
|
|
1002
|
-
const node = Toggle({
|
|
1378
|
+
const node = Toggle({
|
|
1379
|
+
label: 'LED',
|
|
1380
|
+
checked: true,
|
|
1381
|
+
onToggle: () => {},
|
|
1382
|
+
});
|
|
1003
1383
|
expect(node.onToggle).toBe('toggle-action-1');
|
|
1004
1384
|
});
|
|
1005
1385
|
|
|
@@ -1016,7 +1396,12 @@ describe('Toggle', () => {
|
|
|
1016
1396
|
});
|
|
1017
1397
|
|
|
1018
1398
|
test('includes disabled prop', () => {
|
|
1019
|
-
const node = Toggle({
|
|
1399
|
+
const node = Toggle({
|
|
1400
|
+
label: 'Off',
|
|
1401
|
+
checked: false,
|
|
1402
|
+
onToggle: () => {},
|
|
1403
|
+
disabled: true,
|
|
1404
|
+
});
|
|
1020
1405
|
expect(node.disabled).toBe(true);
|
|
1021
1406
|
});
|
|
1022
1407
|
});
|
|
@@ -1031,46 +1416,76 @@ describe('Text (new props)', () => {
|
|
|
1031
1416
|
});
|
|
1032
1417
|
|
|
1033
1418
|
test('includes align and weight', () => {
|
|
1034
|
-
const node = Text({
|
|
1419
|
+
const node = Text({
|
|
1420
|
+
content: 'hi',
|
|
1421
|
+
align: 'center',
|
|
1422
|
+
weight: 'bold',
|
|
1423
|
+
});
|
|
1035
1424
|
expect(node.align).toBe('center');
|
|
1036
1425
|
expect(node.weight).toBe('bold');
|
|
1037
1426
|
});
|
|
1038
1427
|
|
|
1039
1428
|
test('includes maxLines', () => {
|
|
1040
|
-
const node = Text({
|
|
1429
|
+
const node = Text({
|
|
1430
|
+
content: 'long',
|
|
1431
|
+
maxLines: 3,
|
|
1432
|
+
});
|
|
1041
1433
|
expect(node.maxLines).toBe(3);
|
|
1042
1434
|
});
|
|
1043
1435
|
|
|
1044
1436
|
test('includes size', () => {
|
|
1045
1437
|
for (const s of ['xs', 'sm', 'md', 'lg', 'xl'] as const) {
|
|
1046
|
-
expect(
|
|
1438
|
+
expect(
|
|
1439
|
+
Text({
|
|
1440
|
+
content: '',
|
|
1441
|
+
size: s,
|
|
1442
|
+
}).size
|
|
1443
|
+
).toBe(s);
|
|
1047
1444
|
}
|
|
1048
1445
|
});
|
|
1049
1446
|
|
|
1050
1447
|
test('resolves onPress to action ID', () => {
|
|
1051
|
-
const node = Text({
|
|
1448
|
+
const node = Text({
|
|
1449
|
+
content: 'click',
|
|
1450
|
+
onPress: () => {},
|
|
1451
|
+
});
|
|
1052
1452
|
expect(node.onPress).toMatch(/^__action_\d+$/);
|
|
1053
1453
|
});
|
|
1054
1454
|
|
|
1055
1455
|
test('omits onPress when not provided', () => {
|
|
1056
|
-
const node = Text({
|
|
1456
|
+
const node = Text({
|
|
1457
|
+
content: 'plain',
|
|
1458
|
+
});
|
|
1057
1459
|
expect(node.onPress).toBeUndefined();
|
|
1058
1460
|
});
|
|
1059
1461
|
|
|
1060
1462
|
test('accepts children as alias for content', () => {
|
|
1061
|
-
const node = Text({
|
|
1062
|
-
|
|
1463
|
+
const node = Text({
|
|
1464
|
+
children: 'hello',
|
|
1465
|
+
});
|
|
1466
|
+
expect(node).toEqual({
|
|
1467
|
+
type: 'text',
|
|
1468
|
+
content: 'hello',
|
|
1469
|
+
});
|
|
1063
1470
|
});
|
|
1064
1471
|
|
|
1065
1472
|
test('children works with I18nRef', () => {
|
|
1066
1473
|
const ref = i18nRef('plugin:test', 'greeting');
|
|
1067
|
-
const node = Text({
|
|
1474
|
+
const node = Text({
|
|
1475
|
+
children: ref,
|
|
1476
|
+
});
|
|
1068
1477
|
expect(node.content).toBe('greeting');
|
|
1069
|
-
expect(node.i18n).toEqual({
|
|
1478
|
+
expect(node.i18n).toEqual({
|
|
1479
|
+
ns: 'plugin:test',
|
|
1480
|
+
key: 'greeting',
|
|
1481
|
+
});
|
|
1070
1482
|
});
|
|
1071
1483
|
|
|
1072
1484
|
test('content takes precedence over children', () => {
|
|
1073
|
-
const node = Text({
|
|
1485
|
+
const node = Text({
|
|
1486
|
+
content: 'from-content',
|
|
1487
|
+
children: 'from-children',
|
|
1488
|
+
});
|
|
1074
1489
|
expect(node.content).toBe('from-content');
|
|
1075
1490
|
});
|
|
1076
1491
|
|
|
@@ -1086,13 +1501,21 @@ describe('Button (new props)', () => {
|
|
|
1086
1501
|
});
|
|
1087
1502
|
|
|
1088
1503
|
test('includes disabled and loading', () => {
|
|
1089
|
-
const node = Button({
|
|
1504
|
+
const node = Button({
|
|
1505
|
+
label: 'Go',
|
|
1506
|
+
disabled: true,
|
|
1507
|
+
loading: true,
|
|
1508
|
+
});
|
|
1090
1509
|
expect(node.disabled).toBe(true);
|
|
1091
1510
|
expect(node.loading).toBe(true);
|
|
1092
1511
|
});
|
|
1093
1512
|
|
|
1094
1513
|
test('includes size and fullWidth', () => {
|
|
1095
|
-
const node = Button({
|
|
1514
|
+
const node = Button({
|
|
1515
|
+
label: 'Big',
|
|
1516
|
+
size: 'lg',
|
|
1517
|
+
fullWidth: true,
|
|
1518
|
+
});
|
|
1096
1519
|
expect(node.size).toBe('lg');
|
|
1097
1520
|
expect(node.fullWidth).toBe(true);
|
|
1098
1521
|
});
|
|
@@ -1100,7 +1523,12 @@ describe('Button (new props)', () => {
|
|
|
1100
1523
|
|
|
1101
1524
|
describe('Stat (new props)', () => {
|
|
1102
1525
|
test('includes trendValue and description', () => {
|
|
1103
|
-
const node = Stat({
|
|
1526
|
+
const node = Stat({
|
|
1527
|
+
label: 'Rev',
|
|
1528
|
+
value: 100,
|
|
1529
|
+
trendValue: '+5.2%',
|
|
1530
|
+
description: 'Monthly',
|
|
1531
|
+
});
|
|
1104
1532
|
expect(node.trendValue).toBe('+5.2%');
|
|
1105
1533
|
expect(node.description).toBe('Monthly');
|
|
1106
1534
|
});
|
|
@@ -1108,7 +1536,9 @@ describe('Stat (new props)', () => {
|
|
|
1108
1536
|
|
|
1109
1537
|
describe('Divider (new props)', () => {
|
|
1110
1538
|
test('includes label', () => {
|
|
1111
|
-
const node = Divider({
|
|
1539
|
+
const node = Divider({
|
|
1540
|
+
label: 'OR',
|
|
1541
|
+
});
|
|
1112
1542
|
expect(node.label).toBe('OR');
|
|
1113
1543
|
});
|
|
1114
1544
|
});
|
|
@@ -1119,12 +1549,17 @@ describe('Badge (onPress)', () => {
|
|
|
1119
1549
|
});
|
|
1120
1550
|
|
|
1121
1551
|
test('resolves onPress to action ID', () => {
|
|
1122
|
-
const node = Badge({
|
|
1552
|
+
const node = Badge({
|
|
1553
|
+
label: 'Tag',
|
|
1554
|
+
onPress: () => {},
|
|
1555
|
+
});
|
|
1123
1556
|
expect(node.onPress).toMatch(/^__action_\d+$/);
|
|
1124
1557
|
});
|
|
1125
1558
|
|
|
1126
1559
|
test('omits onPress when not provided', () => {
|
|
1127
|
-
const node = Badge({
|
|
1560
|
+
const node = Badge({
|
|
1561
|
+
label: 'Static',
|
|
1562
|
+
});
|
|
1128
1563
|
expect(node.onPress).toBeUndefined();
|
|
1129
1564
|
});
|
|
1130
1565
|
});
|
|
@@ -1135,12 +1570,17 @@ describe('Icon (onPress)', () => {
|
|
|
1135
1570
|
});
|
|
1136
1571
|
|
|
1137
1572
|
test('resolves onPress to action ID', () => {
|
|
1138
|
-
const node = Icon({
|
|
1573
|
+
const node = Icon({
|
|
1574
|
+
name: 'star',
|
|
1575
|
+
onPress: () => {},
|
|
1576
|
+
});
|
|
1139
1577
|
expect(node.onPress).toMatch(/^__action_\d+$/);
|
|
1140
1578
|
});
|
|
1141
1579
|
|
|
1142
1580
|
test('omits onPress when not provided', () => {
|
|
1143
|
-
const node = Icon({
|
|
1581
|
+
const node = Icon({
|
|
1582
|
+
name: 'star',
|
|
1583
|
+
});
|
|
1144
1584
|
expect(node.onPress).toBeUndefined();
|
|
1145
1585
|
});
|
|
1146
1586
|
});
|
|
@@ -1151,14 +1591,24 @@ describe('Slider (disabled)', () => {
|
|
|
1151
1591
|
});
|
|
1152
1592
|
|
|
1153
1593
|
test('includes disabled prop', () => {
|
|
1154
|
-
const node = Slider({
|
|
1594
|
+
const node = Slider({
|
|
1595
|
+
value: 5,
|
|
1596
|
+
min: 0,
|
|
1597
|
+
max: 10,
|
|
1598
|
+
onChange: () => {},
|
|
1599
|
+
disabled: true,
|
|
1600
|
+
});
|
|
1155
1601
|
expect(node.disabled).toBe(true);
|
|
1156
1602
|
});
|
|
1157
1603
|
});
|
|
1158
1604
|
|
|
1159
1605
|
describe('Section (new props)', () => {
|
|
1160
1606
|
test('includes gap and icon', () => {
|
|
1161
|
-
const node = Section({
|
|
1607
|
+
const node = Section({
|
|
1608
|
+
title: 'Info',
|
|
1609
|
+
gap: 'lg',
|
|
1610
|
+
icon: 'settings',
|
|
1611
|
+
});
|
|
1162
1612
|
expect(node.gap).toBe('lg');
|
|
1163
1613
|
expect(node.icon).toBe('settings');
|
|
1164
1614
|
});
|
|
@@ -1166,7 +1616,12 @@ describe('Section (new props)', () => {
|
|
|
1166
1616
|
|
|
1167
1617
|
describe('Video (new props)', () => {
|
|
1168
1618
|
test('includes controls and loop', () => {
|
|
1169
|
-
const node = Video({
|
|
1619
|
+
const node = Video({
|
|
1620
|
+
src: 'test.m3u8',
|
|
1621
|
+
format: 'hls',
|
|
1622
|
+
controls: true,
|
|
1623
|
+
loop: true,
|
|
1624
|
+
});
|
|
1170
1625
|
expect(node.controls).toBe(true);
|
|
1171
1626
|
expect(node.loop).toBe(true);
|
|
1172
1627
|
});
|
|
@@ -1174,14 +1629,23 @@ describe('Video (new props)', () => {
|
|
|
1174
1629
|
|
|
1175
1630
|
describe('Progress (new props)', () => {
|
|
1176
1631
|
test('includes size and variant', () => {
|
|
1177
|
-
const node = Progress({
|
|
1632
|
+
const node = Progress({
|
|
1633
|
+
value: 50,
|
|
1634
|
+
size: 'lg',
|
|
1635
|
+
variant: 'ring',
|
|
1636
|
+
});
|
|
1178
1637
|
expect(node.size).toBe('lg');
|
|
1179
1638
|
expect(node.variant).toBe('ring');
|
|
1180
1639
|
});
|
|
1181
1640
|
|
|
1182
1641
|
test('all size values work', () => {
|
|
1183
1642
|
for (const s of ['sm', 'md', 'lg'] as const) {
|
|
1184
|
-
expect(
|
|
1643
|
+
expect(
|
|
1644
|
+
Progress({
|
|
1645
|
+
value: 50,
|
|
1646
|
+
size: s,
|
|
1647
|
+
}).size
|
|
1648
|
+
).toBe(s);
|
|
1185
1649
|
}
|
|
1186
1650
|
});
|
|
1187
1651
|
});
|
|
@@ -1189,10 +1653,32 @@ describe('Progress (new props)', () => {
|
|
|
1189
1653
|
describe('Chart (new props)', () => {
|
|
1190
1654
|
test('includes series', () => {
|
|
1191
1655
|
const series = [
|
|
1192
|
-
{
|
|
1193
|
-
|
|
1656
|
+
{
|
|
1657
|
+
key: 'temp',
|
|
1658
|
+
data: [
|
|
1659
|
+
{
|
|
1660
|
+
ts: 1,
|
|
1661
|
+
value: 20,
|
|
1662
|
+
},
|
|
1663
|
+
],
|
|
1664
|
+
color: 'red',
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
key: 'humidity',
|
|
1668
|
+
label: 'Humid',
|
|
1669
|
+
data: [
|
|
1670
|
+
{
|
|
1671
|
+
ts: 1,
|
|
1672
|
+
value: 60,
|
|
1673
|
+
},
|
|
1674
|
+
],
|
|
1675
|
+
},
|
|
1194
1676
|
];
|
|
1195
|
-
const node = Chart({
|
|
1677
|
+
const node = Chart({
|
|
1678
|
+
variant: 'line',
|
|
1679
|
+
data: [],
|
|
1680
|
+
series,
|
|
1681
|
+
});
|
|
1196
1682
|
expect(node.series).toEqual(series);
|
|
1197
1683
|
});
|
|
1198
1684
|
|
|
@@ -1218,7 +1704,10 @@ describe('Chart (new props)', () => {
|
|
|
1218
1704
|
|
|
1219
1705
|
describe('Callout', () => {
|
|
1220
1706
|
test('creates callout with required fields', () => {
|
|
1221
|
-
const node = Callout({
|
|
1707
|
+
const node = Callout({
|
|
1708
|
+
variant: 'info',
|
|
1709
|
+
message: 'Hello',
|
|
1710
|
+
});
|
|
1222
1711
|
expect(node.type).toBe('callout');
|
|
1223
1712
|
expect(node.variant).toBe('info');
|
|
1224
1713
|
expect(node.message).toBe('Hello');
|
|
@@ -1237,7 +1726,12 @@ describe('Callout', () => {
|
|
|
1237
1726
|
|
|
1238
1727
|
test('all variant values work', () => {
|
|
1239
1728
|
for (const v of ['info', 'warning', 'error', 'success'] as const) {
|
|
1240
|
-
expect(
|
|
1729
|
+
expect(
|
|
1730
|
+
Callout({
|
|
1731
|
+
variant: v,
|
|
1732
|
+
message: '',
|
|
1733
|
+
}).variant
|
|
1734
|
+
).toBe(v);
|
|
1241
1735
|
}
|
|
1242
1736
|
});
|
|
1243
1737
|
});
|
|
@@ -1248,19 +1742,29 @@ describe('TextInput', () => {
|
|
|
1248
1742
|
});
|
|
1249
1743
|
|
|
1250
1744
|
test('creates text-input with required fields', () => {
|
|
1251
|
-
const node = TextInput({
|
|
1745
|
+
const node = TextInput({
|
|
1746
|
+
value: 'hello',
|
|
1747
|
+
onChange: () => {},
|
|
1748
|
+
});
|
|
1252
1749
|
expect(node.type).toBe('text-input');
|
|
1253
1750
|
expect(node.value).toBe('hello');
|
|
1254
1751
|
expect(node.onChange).toMatch(/^__action_\d+$/);
|
|
1255
1752
|
});
|
|
1256
1753
|
|
|
1257
1754
|
test('resolves onSubmit when provided', () => {
|
|
1258
|
-
const node = TextInput({
|
|
1755
|
+
const node = TextInput({
|
|
1756
|
+
value: '',
|
|
1757
|
+
onChange: () => {},
|
|
1758
|
+
onSubmit: () => {},
|
|
1759
|
+
});
|
|
1259
1760
|
expect(node.onSubmit).toMatch(/^__action_\d+$/);
|
|
1260
1761
|
});
|
|
1261
1762
|
|
|
1262
1763
|
test('omits onSubmit when not provided', () => {
|
|
1263
|
-
const node = TextInput({
|
|
1764
|
+
const node = TextInput({
|
|
1765
|
+
value: '',
|
|
1766
|
+
onChange: () => {},
|
|
1767
|
+
});
|
|
1264
1768
|
expect(node.onSubmit).toBeUndefined();
|
|
1265
1769
|
});
|
|
1266
1770
|
|
|
@@ -1283,7 +1787,13 @@ describe('TextInput', () => {
|
|
|
1283
1787
|
|
|
1284
1788
|
test('all inputType values work', () => {
|
|
1285
1789
|
for (const t of ['text', 'password', 'email', 'number'] as const) {
|
|
1286
|
-
expect(
|
|
1790
|
+
expect(
|
|
1791
|
+
TextInput({
|
|
1792
|
+
value: '',
|
|
1793
|
+
onChange: () => {},
|
|
1794
|
+
inputType: t,
|
|
1795
|
+
}).inputType
|
|
1796
|
+
).toBe(t);
|
|
1287
1797
|
}
|
|
1288
1798
|
});
|
|
1289
1799
|
});
|
|
@@ -1294,12 +1804,22 @@ describe('Select', () => {
|
|
|
1294
1804
|
});
|
|
1295
1805
|
|
|
1296
1806
|
const opts = [
|
|
1297
|
-
{
|
|
1298
|
-
|
|
1807
|
+
{
|
|
1808
|
+
value: 'a',
|
|
1809
|
+
label: 'Alpha',
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
value: 'b',
|
|
1813
|
+
label: 'Beta',
|
|
1814
|
+
},
|
|
1299
1815
|
];
|
|
1300
1816
|
|
|
1301
1817
|
test('creates select with required fields', () => {
|
|
1302
|
-
const node = Select({
|
|
1818
|
+
const node = Select({
|
|
1819
|
+
value: 'a',
|
|
1820
|
+
options: opts,
|
|
1821
|
+
onChange: () => {},
|
|
1822
|
+
});
|
|
1303
1823
|
expect(node.type).toBe('select');
|
|
1304
1824
|
expect(node.value).toBe('a');
|
|
1305
1825
|
expect(node.options).toEqual(opts);
|
|
@@ -1324,7 +1844,11 @@ describe('Select', () => {
|
|
|
1324
1844
|
|
|
1325
1845
|
test('uses custom registrar for onChange', () => {
|
|
1326
1846
|
_setActionRegistrar(() => 'sel-action');
|
|
1327
|
-
const node = Select({
|
|
1847
|
+
const node = Select({
|
|
1848
|
+
value: 'a',
|
|
1849
|
+
options: opts,
|
|
1850
|
+
onChange: () => {},
|
|
1851
|
+
});
|
|
1328
1852
|
expect(node.onChange).toBe('sel-action');
|
|
1329
1853
|
});
|
|
1330
1854
|
});
|
|
@@ -1335,23 +1859,45 @@ describe('Select', () => {
|
|
|
1335
1859
|
|
|
1336
1860
|
describe('Table', () => {
|
|
1337
1861
|
const cols = [
|
|
1338
|
-
{
|
|
1339
|
-
|
|
1862
|
+
{
|
|
1863
|
+
key: 'name',
|
|
1864
|
+
label: 'Name',
|
|
1865
|
+
},
|
|
1866
|
+
{
|
|
1867
|
+
key: 'age',
|
|
1868
|
+
label: 'Age',
|
|
1869
|
+
align: 'right' as const,
|
|
1870
|
+
},
|
|
1340
1871
|
];
|
|
1341
1872
|
const rows = [
|
|
1342
|
-
{
|
|
1343
|
-
|
|
1873
|
+
{
|
|
1874
|
+
name: 'Alice',
|
|
1875
|
+
age: 30,
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
name: 'Bob',
|
|
1879
|
+
age: 25,
|
|
1880
|
+
},
|
|
1344
1881
|
];
|
|
1345
1882
|
|
|
1346
1883
|
test('creates table with required fields', () => {
|
|
1347
|
-
const node = Table({
|
|
1884
|
+
const node = Table({
|
|
1885
|
+
columns: cols,
|
|
1886
|
+
rows,
|
|
1887
|
+
});
|
|
1348
1888
|
expect(node.type).toBe('table');
|
|
1349
1889
|
expect(node.columns).toEqual(cols);
|
|
1350
1890
|
expect(node.rows).toEqual(rows);
|
|
1351
1891
|
});
|
|
1352
1892
|
|
|
1353
1893
|
test('includes optional props', () => {
|
|
1354
|
-
const node = Table({
|
|
1894
|
+
const node = Table({
|
|
1895
|
+
columns: cols,
|
|
1896
|
+
rows,
|
|
1897
|
+
striped: true,
|
|
1898
|
+
compact: true,
|
|
1899
|
+
maxRows: 5,
|
|
1900
|
+
});
|
|
1355
1901
|
expect(node.striped).toBe(true);
|
|
1356
1902
|
expect(node.compact).toBe(true);
|
|
1357
1903
|
expect(node.maxRows).toBe(5);
|
|
@@ -1359,25 +1905,42 @@ describe('Table', () => {
|
|
|
1359
1905
|
|
|
1360
1906
|
test('resolves onRowPress', () => {
|
|
1361
1907
|
_setActionRegistrar(null);
|
|
1362
|
-
const node = Table({
|
|
1908
|
+
const node = Table({
|
|
1909
|
+
columns: cols,
|
|
1910
|
+
rows,
|
|
1911
|
+
onRowPress: () => {},
|
|
1912
|
+
});
|
|
1363
1913
|
expect(node.onRowPress).toMatch(/^__action_\d+$/);
|
|
1364
1914
|
});
|
|
1365
1915
|
});
|
|
1366
1916
|
|
|
1367
1917
|
describe('KeyValue', () => {
|
|
1368
1918
|
const items = [
|
|
1369
|
-
{
|
|
1370
|
-
|
|
1919
|
+
{
|
|
1920
|
+
label: 'Host',
|
|
1921
|
+
value: 'localhost',
|
|
1922
|
+
},
|
|
1923
|
+
{
|
|
1924
|
+
label: 'Port',
|
|
1925
|
+
value: 8080,
|
|
1926
|
+
},
|
|
1371
1927
|
];
|
|
1372
1928
|
|
|
1373
1929
|
test('creates key-value with required fields', () => {
|
|
1374
|
-
const node = KeyValue({
|
|
1930
|
+
const node = KeyValue({
|
|
1931
|
+
items,
|
|
1932
|
+
});
|
|
1375
1933
|
expect(node.type).toBe('key-value');
|
|
1376
1934
|
expect(node.items).toEqual(items);
|
|
1377
1935
|
});
|
|
1378
1936
|
|
|
1379
1937
|
test('includes optional props', () => {
|
|
1380
|
-
const node = KeyValue({
|
|
1938
|
+
const node = KeyValue({
|
|
1939
|
+
items,
|
|
1940
|
+
layout: 'stacked',
|
|
1941
|
+
dividers: true,
|
|
1942
|
+
compact: true,
|
|
1943
|
+
});
|
|
1381
1944
|
expect(node.layout).toBe('stacked');
|
|
1382
1945
|
expect(node.dividers).toBe(true);
|
|
1383
1946
|
expect(node.compact).toBe(true);
|
|
@@ -1385,7 +1948,15 @@ describe('KeyValue', () => {
|
|
|
1385
1948
|
|
|
1386
1949
|
test('items support icon, color, copyable', () => {
|
|
1387
1950
|
const node = KeyValue({
|
|
1388
|
-
items: [
|
|
1951
|
+
items: [
|
|
1952
|
+
{
|
|
1953
|
+
label: 'IP',
|
|
1954
|
+
value: '127.0.0.1',
|
|
1955
|
+
icon: 'globe',
|
|
1956
|
+
color: '#0f0',
|
|
1957
|
+
copyable: true,
|
|
1958
|
+
},
|
|
1959
|
+
],
|
|
1389
1960
|
});
|
|
1390
1961
|
const item = node.items[0];
|
|
1391
1962
|
expect(item?.icon).toBe('globe');
|
|
@@ -1422,20 +1993,29 @@ describe('Avatar', () => {
|
|
|
1422
1993
|
});
|
|
1423
1994
|
|
|
1424
1995
|
test('resolves onPress', () => {
|
|
1425
|
-
const node = Avatar({
|
|
1996
|
+
const node = Avatar({
|
|
1997
|
+
onPress: () => {},
|
|
1998
|
+
});
|
|
1426
1999
|
expect(node.onPress).toMatch(/^__action_\d+$/);
|
|
1427
2000
|
});
|
|
1428
2001
|
|
|
1429
2002
|
test('all status values work', () => {
|
|
1430
2003
|
for (const s of ['online', 'offline', 'busy', 'away'] as const) {
|
|
1431
|
-
expect(
|
|
2004
|
+
expect(
|
|
2005
|
+
Avatar({
|
|
2006
|
+
status: s,
|
|
2007
|
+
}).status
|
|
2008
|
+
).toBe(s);
|
|
1432
2009
|
}
|
|
1433
2010
|
});
|
|
1434
2011
|
});
|
|
1435
2012
|
|
|
1436
2013
|
describe('Link', () => {
|
|
1437
2014
|
test('creates link with required fields', () => {
|
|
1438
|
-
const node = Link({
|
|
2015
|
+
const node = Link({
|
|
2016
|
+
label: 'Docs',
|
|
2017
|
+
url: 'https://docs.example.com',
|
|
2018
|
+
});
|
|
1439
2019
|
expect(node.type).toBe('link');
|
|
1440
2020
|
expect(node.label).toBe('Docs');
|
|
1441
2021
|
expect(node.url).toBe('https://docs.example.com');
|
|
@@ -1456,7 +2036,13 @@ describe('Link', () => {
|
|
|
1456
2036
|
|
|
1457
2037
|
test('all variant values work', () => {
|
|
1458
2038
|
for (const v of ['default', 'muted', 'underline'] as const) {
|
|
1459
|
-
expect(
|
|
2039
|
+
expect(
|
|
2040
|
+
Link({
|
|
2041
|
+
label: '',
|
|
2042
|
+
url: '',
|
|
2043
|
+
variant: v,
|
|
2044
|
+
}).variant
|
|
2045
|
+
).toBe(v);
|
|
1460
2046
|
}
|
|
1461
2047
|
});
|
|
1462
2048
|
});
|
|
@@ -1470,8 +2056,14 @@ describe('Tabs', () => {
|
|
|
1470
2056
|
const node = Tabs({
|
|
1471
2057
|
value: 'a',
|
|
1472
2058
|
tabs: [
|
|
1473
|
-
{
|
|
1474
|
-
|
|
2059
|
+
{
|
|
2060
|
+
key: 'a',
|
|
2061
|
+
label: 'Tab A',
|
|
2062
|
+
},
|
|
2063
|
+
{
|
|
2064
|
+
key: 'b',
|
|
2065
|
+
label: 'Tab B',
|
|
2066
|
+
},
|
|
1475
2067
|
],
|
|
1476
2068
|
onChange: () => {},
|
|
1477
2069
|
});
|
|
@@ -1482,10 +2074,18 @@ describe('Tabs', () => {
|
|
|
1482
2074
|
});
|
|
1483
2075
|
|
|
1484
2076
|
test('normalizes tab children', () => {
|
|
1485
|
-
const child = Text({
|
|
2077
|
+
const child = Text({
|
|
2078
|
+
content: 'content',
|
|
2079
|
+
});
|
|
1486
2080
|
const node = Tabs({
|
|
1487
2081
|
value: 'a',
|
|
1488
|
-
tabs: [
|
|
2082
|
+
tabs: [
|
|
2083
|
+
{
|
|
2084
|
+
key: 'a',
|
|
2085
|
+
label: 'Tab',
|
|
2086
|
+
children: child,
|
|
2087
|
+
},
|
|
2088
|
+
],
|
|
1489
2089
|
onChange: () => {},
|
|
1490
2090
|
});
|
|
1491
2091
|
expect(node.tabs[0]?.children).toEqual([child]);
|
|
@@ -1494,7 +2094,13 @@ describe('Tabs', () => {
|
|
|
1494
2094
|
test('includes optional variant and icon', () => {
|
|
1495
2095
|
const node = Tabs({
|
|
1496
2096
|
value: 'a',
|
|
1497
|
-
tabs: [
|
|
2097
|
+
tabs: [
|
|
2098
|
+
{
|
|
2099
|
+
key: 'a',
|
|
2100
|
+
label: 'Tab',
|
|
2101
|
+
icon: 'star',
|
|
2102
|
+
},
|
|
2103
|
+
],
|
|
1498
2104
|
onChange: () => {},
|
|
1499
2105
|
variant: 'pills',
|
|
1500
2106
|
});
|
|
@@ -1505,7 +2111,9 @@ describe('Tabs', () => {
|
|
|
1505
2111
|
|
|
1506
2112
|
describe('CodeBlock', () => {
|
|
1507
2113
|
test('creates code-block with required fields', () => {
|
|
1508
|
-
const node = CodeBlock({
|
|
2114
|
+
const node = CodeBlock({
|
|
2115
|
+
code: 'console.log("hi")',
|
|
2116
|
+
});
|
|
1509
2117
|
expect(node.type).toBe('code-block');
|
|
1510
2118
|
expect(node.code).toBe('console.log("hi")');
|
|
1511
2119
|
});
|
|
@@ -1533,7 +2141,11 @@ describe('Checkbox', () => {
|
|
|
1533
2141
|
});
|
|
1534
2142
|
|
|
1535
2143
|
test('creates checkbox with required fields', () => {
|
|
1536
|
-
const node = Checkbox({
|
|
2144
|
+
const node = Checkbox({
|
|
2145
|
+
label: 'Accept terms',
|
|
2146
|
+
checked: false,
|
|
2147
|
+
onToggle: () => {},
|
|
2148
|
+
});
|
|
1537
2149
|
expect(node.type).toBe('checkbox');
|
|
1538
2150
|
expect(node.label).toBe('Accept terms');
|
|
1539
2151
|
expect(node.checked).toBe(false);
|
|
@@ -1557,13 +2169,20 @@ describe('Checkbox', () => {
|
|
|
1557
2169
|
|
|
1558
2170
|
describe('Skeleton', () => {
|
|
1559
2171
|
test('creates skeleton with required variant', () => {
|
|
1560
|
-
const node = Skeleton({
|
|
2172
|
+
const node = Skeleton({
|
|
2173
|
+
variant: 'text',
|
|
2174
|
+
});
|
|
1561
2175
|
expect(node.type).toBe('skeleton');
|
|
1562
2176
|
expect(node.variant).toBe('text');
|
|
1563
2177
|
});
|
|
1564
2178
|
|
|
1565
2179
|
test('includes optional props', () => {
|
|
1566
|
-
const node = Skeleton({
|
|
2180
|
+
const node = Skeleton({
|
|
2181
|
+
variant: 'rect',
|
|
2182
|
+
width: '100px',
|
|
2183
|
+
height: '50px',
|
|
2184
|
+
lines: 3,
|
|
2185
|
+
});
|
|
1567
2186
|
expect(node.width).toBe('100px');
|
|
1568
2187
|
expect(node.height).toBe('50px');
|
|
1569
2188
|
expect(node.lines).toBe(3);
|
|
@@ -1571,7 +2190,11 @@ describe('Skeleton', () => {
|
|
|
1571
2190
|
|
|
1572
2191
|
test('all variant values work', () => {
|
|
1573
2192
|
for (const v of ['text', 'circle', 'rect'] as const) {
|
|
1574
|
-
expect(
|
|
2193
|
+
expect(
|
|
2194
|
+
Skeleton({
|
|
2195
|
+
variant: v,
|
|
2196
|
+
}).variant
|
|
2197
|
+
).toBe(v);
|
|
1575
2198
|
}
|
|
1576
2199
|
});
|
|
1577
2200
|
});
|
|
@@ -1582,13 +2205,21 @@ describe('TextInput (multiline)', () => {
|
|
|
1582
2205
|
});
|
|
1583
2206
|
|
|
1584
2207
|
test('includes multiline and rows', () => {
|
|
1585
|
-
const node = TextInput({
|
|
2208
|
+
const node = TextInput({
|
|
2209
|
+
value: '',
|
|
2210
|
+
onChange: () => {},
|
|
2211
|
+
multiline: true,
|
|
2212
|
+
rows: 5,
|
|
2213
|
+
});
|
|
1586
2214
|
expect(node.multiline).toBe(true);
|
|
1587
2215
|
expect(node.rows).toBe(5);
|
|
1588
2216
|
});
|
|
1589
2217
|
|
|
1590
2218
|
test('multiline defaults are omitted when not set', () => {
|
|
1591
|
-
const node = TextInput({
|
|
2219
|
+
const node = TextInput({
|
|
2220
|
+
value: '',
|
|
2221
|
+
onChange: () => {},
|
|
2222
|
+
});
|
|
1592
2223
|
expect(node.multiline).toBeUndefined();
|
|
1593
2224
|
expect(node.rows).toBeUndefined();
|
|
1594
2225
|
});
|