@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.
@@ -70,25 +70,37 @@ describe('_shared', () => {
70
70
  });
71
71
 
72
72
  test('wraps a single ComponentNode in an array', () => {
73
- const node = Text({ content: 'hello' });
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({ content: 'a' });
80
- const b = Text({ content: 'b' });
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({ content: 'a' });
86
- const b = Text({ content: 'b' });
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({ content: 'a' });
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: { ns: 'plugin:weather', key: 'stats.humidity', params: undefined },
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: { count: 7 },
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: { ns: 'plugin:weather', key: 'ui.dayForecast', params: { count: 7 } },
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({ content: 'plain' });
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: { ns: 'plugin:x', key: 'hello', params: undefined },
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: { dateStyle: 'medium' },
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({ content: 'plain' });
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((result[1] as { i18n: unknown }).i18n).toBeDefined();
195
- expect((result[2] as { intl: unknown }).intl).toBe(intl);
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(isI18nRef({ __i18n: true, ns: 'plugin:x', key: 'k' })).toBe(true);
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(isI18nRef({ __i18n: true, ns: 'n', key: 'k', params: { a: 1 } })).toBe(true);
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(isI18nRef({ ns: 'x', key: 'k' })).toBe(false);
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(isI18nRef({ __i18n: false, ns: 'x', key: 'k' })).toBe(false);
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(isIntlRef({ __intl: true, type: 'dateTime', value: 0 })).toBe(true);
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(isIntlRef({ __intl: true, type: 'number', value: 42 })).toBe(true);
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(isIntlRef({ __intl: true, type: 'relativeTime', value: -1, unit: 'day' })).toBe(true);
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(isIntlRef({ __intl: true, type: 'list', value: ['a', 'b'] })).toBe(true);
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(isIntlRef({ __i18n: true, ns: 'x', key: 'k' })).toBe(false);
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(isIntlRef({ type: 'number', value: 42 })).toBe(false);
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(isIntlRef({ __intl: false, type: 'number', value: 42 })).toBe(false);
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({ content: 'Hello' });
326
- expect(node).toEqual({ type: 'text', content: 'Hello' });
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({ content: 'Title', variant: 'heading' });
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({ content: 'red', color: '#ff0000' });
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(Text({ content: '', variant: v }).variant).toBe(v);
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({ content: ref });
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({ ns: 'plugin:weather', key: 'stats.humidity', params: undefined });
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: { count: 7 },
496
+ params: {
497
+ count: 7,
498
+ },
361
499
  };
362
- const node = Text({ content: ref, variant: 'heading', weight: 'bold' });
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: { count: 7 },
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({ content: 'plain 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: { minimumFractionDigits: 2 },
529
+ options: {
530
+ minimumFractionDigits: 2,
531
+ },
384
532
  };
385
- const node = Text({ content: ref });
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({ content: ref });
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({ content: ref });
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({ content: ref, variant: 'heading', weight: 'bold' });
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({ label: 'New' });
418
- expect(node).toEqual({ type: 'badge', label: 'New' });
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({ label: 'OK', variant: 'success' });
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({ label: 'Warn', icon: 'alert-triangle', color: '#f00' });
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(Badge({ label: '', variant: v }).variant).toBe(v);
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
- { ts: 1000, value: 10 },
450
- { ts: 2000, value: 20 },
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({ variant: 'line', data: sampleData });
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(Chart({ variant: v, data: [] }).variant).toBe(v);
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(Divider({ direction: 'horizontal' }).direction).toBe('horizontal');
488
- expect(Divider({ direction: 'vertical' }).direction).toBe('vertical');
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({ color: '#ccc' });
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({ name: 'star' });
500
- expect(node).toEqual({ type: 'icon', name: 'star' });
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({ name: 'heart', size: 'lg', color: 'red' });
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(Icon({ name: 'x', size: s }).size).toBe(s);
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({ src: 'https://img.example.com/a.png' });
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({ src: 'a', width: 200, height: 100 });
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({ src: 'a', width: '30%', height: '50%' });
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({ value: 42 });
557
- expect(node).toEqual({ type: 'progress', value: 42 });
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(Progress({ value: 0 }).value).toBe(0);
574
- expect(Progress({ value: 100 }).value).toBe(100);
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(Spacer({ size: s }).size).toBe(s);
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({ label: 'Temp', value: 21.5 });
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({ label: 'Status', value: 'OK' });
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(Stat({ label: '', value: 0, trend: t }).trend).toBe(t);
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({ label: 'Server', status: 'online' });
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({ label: 'DB', status: 'error', icon: 'database', color: '#f00' });
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(Status({ label: '', status: s }).status).toBe(s);
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({ src: 'https://stream.example.com/live.m3u8', format: 'hls' });
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(Video({ src: '', format: 'hls' }).format).toBe('hls');
675
- expect(Video({ src: '', format: 'mjpeg' }).format).toBe('mjpeg');
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({ content: 'hi' });
692
- const node = Box({ children: child });
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({ content: 'a' });
698
- const b = Text({ content: 'b' });
699
- const node = Box({ children: [a, b] });
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({ content: 'a' });
705
- const node = Box({ children: [a, null, false, undefined] });
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({ children: Text({ content: 'x' }), padding: 'sm' });
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({ content: 'a' });
749
- const b = Text({ content: 'b' });
750
- const node = Grid({ children: [a, b] });
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({ content: 'a' });
769
- const node = Grid({ children: [a, null, false] });
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({ title: 'Settings' });
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({ content: 'hello' });
784
- const node = Section({ title: 'Main', children: child });
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({ content: 'a' });
790
- const node = Section({ title: 'S', children: [a, null, false] });
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({ content: 'a' });
808
- const b = Text({ content: 'b' });
809
- const node = Row({ children: [a, b] });
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({ onPress: () => {} });
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({ content: 'a' });
835
- const node = Row({ children: [a, null, undefined, false] });
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({ content: 'a' });
853
- const b = Text({ content: 'b' });
854
- const node = Column({ children: [a, b] });
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({ onPress: () => {} });
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({ content: 'a' });
880
- const node = Column({ children: [a, null, undefined, false] });
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({ label: 'Click me' });
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({ label: 'Go', onPress: handler });
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({ label: 'Go', onPress: () => {} });
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({ label: 'Link', url: 'https://example.com' });
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(Button({ variant: v }).variant).toBe(v);
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({ value: 50, min: 0, max: 100, onChange: handler });
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({ value: 10, min: 0, max: 20, onChange: () => {} });
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({ label: 'Dark mode', checked: false, onToggle: handler });
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({ label: 'On', checked: true, onToggle: () => {} });
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({ label: 'LED', checked: true, onToggle: () => {} });
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({ label: 'Off', checked: false, onToggle: () => {}, disabled: true });
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({ content: 'hi', align: 'center', weight: 'bold' });
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({ content: 'long', maxLines: 3 });
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(Text({ content: '', size: s }).size).toBe(s);
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({ content: 'click', onPress: () => {} });
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({ content: 'plain' });
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({ children: 'hello' });
1062
- expect(node).toEqual({ type: 'text', content: 'hello' });
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({ children: ref });
1474
+ const node = Text({
1475
+ children: ref,
1476
+ });
1068
1477
  expect(node.content).toBe('greeting');
1069
- expect(node.i18n).toEqual({ ns: 'plugin:test', key: 'greeting' });
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({ content: 'from-content', children: 'from-children' });
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({ label: 'Go', disabled: true, loading: true });
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({ label: 'Big', size: 'lg', fullWidth: true });
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({ label: 'Rev', value: 100, trendValue: '+5.2%', description: 'Monthly' });
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({ label: 'OR' });
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({ label: 'Tag', onPress: () => {} });
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({ label: 'Static' });
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({ name: 'star', onPress: () => {} });
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({ name: 'star' });
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({ value: 5, min: 0, max: 10, onChange: () => {}, disabled: true });
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({ title: 'Info', gap: 'lg', icon: 'settings' });
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({ src: 'test.m3u8', format: 'hls', controls: true, loop: true });
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({ value: 50, size: 'lg', variant: 'ring' });
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(Progress({ value: 50, size: s }).size).toBe(s);
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
- { key: 'temp', data: [{ ts: 1, value: 20 }], color: 'red' },
1193
- { key: 'humidity', label: 'Humid', data: [{ ts: 1, value: 60 }] },
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({ variant: 'line', data: [], series });
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({ variant: 'info', message: 'Hello' });
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(Callout({ variant: v, message: '' }).variant).toBe(v);
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({ value: 'hello', onChange: () => {} });
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({ value: '', onChange: () => {}, onSubmit: () => {} });
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({ value: '', onChange: () => {} });
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(TextInput({ value: '', onChange: () => {}, inputType: t }).inputType).toBe(t);
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
- { value: 'a', label: 'Alpha' },
1298
- { value: 'b', label: 'Beta' },
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({ value: 'a', options: opts, onChange: () => {} });
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({ value: 'a', options: opts, onChange: () => {} });
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
- { key: 'name', label: 'Name' },
1339
- { key: 'age', label: 'Age', align: 'right' as const },
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
- { name: 'Alice', age: 30 },
1343
- { name: 'Bob', age: 25 },
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({ columns: cols, rows });
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({ columns: cols, rows, striped: true, compact: true, maxRows: 5 });
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({ columns: cols, rows, onRowPress: () => {} });
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
- { label: 'Host', value: 'localhost' },
1370
- { label: 'Port', value: 8080 },
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({ items });
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({ items, layout: 'stacked', dividers: true, compact: true });
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: [{ label: 'IP', value: '127.0.0.1', icon: 'globe', color: '#0f0', copyable: true }],
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({ onPress: () => {} });
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(Avatar({ status: s }).status).toBe(s);
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({ label: 'Docs', url: 'https://docs.example.com' });
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(Link({ label: '', url: '', variant: v }).variant).toBe(v);
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
- { key: 'a', label: 'Tab A' },
1474
- { key: 'b', label: 'Tab B' },
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({ content: 'content' });
2077
+ const child = Text({
2078
+ content: 'content',
2079
+ });
1486
2080
  const node = Tabs({
1487
2081
  value: 'a',
1488
- tabs: [{ key: 'a', label: 'Tab', children: child }],
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: [{ key: 'a', label: 'Tab', icon: 'star' }],
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({ code: 'console.log("hi")' });
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({ label: 'Accept terms', checked: false, onToggle: () => {} });
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({ variant: 'text' });
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({ variant: 'rect', width: '100px', height: '50px', lines: 3 });
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(Skeleton({ variant: v }).variant).toBe(v);
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({ value: '', onChange: () => {}, multiline: true, rows: 5 });
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({ value: '', onChange: () => {} });
2219
+ const node = TextInput({
2220
+ value: '',
2221
+ onChange: () => {},
2222
+ });
1592
2223
  expect(node.multiline).toBeUndefined();
1593
2224
  expect(node.rows).toBeUndefined();
1594
2225
  });