@fairfox/polly 0.86.0 → 0.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gallery/gallery.css +146 -43
- package/dist/gallery/gallery.js +17 -12
- package/dist/src/polly-ui/Button.d.ts +6 -2
- package/dist/src/polly-ui/Tabs.d.ts +3 -1
- package/dist/src/polly-ui/index.css +120 -38
- package/dist/src/polly-ui/index.js +19 -14
- package/dist/src/polly-ui/index.js.map +5 -5
- package/dist/src/polly-ui/styles.css +120 -38
- package/dist/src/polly-ui/theme.css +42 -4
- package/dist/tools/test/src/browser/index.js +15 -4
- package/dist/tools/test/src/browser/index.js.map +3 -3
- package/dist/tools/test/src/browser/run.d.ts +10 -3
- package/dist/tools/test/src/browser/run.js +313 -31
- package/dist/tools/test/src/browser/run.js.map +6 -5
- package/dist/tools/test/src/browser/runner-core.d.ts +64 -0
- package/dist/tools/test/src/browser/source-map.d.ts +31 -0
- package/package.json +1 -1
|
@@ -203,23 +203,27 @@
|
|
|
203
203
|
@layer polly-components {
|
|
204
204
|
.root_-n6UrQ {
|
|
205
205
|
box-sizing: border-box;
|
|
206
|
-
|
|
206
|
+
min-block-size: var(--polly-control-height-md);
|
|
207
|
+
padding-block-start: 0;
|
|
208
|
+
padding-block-end: 0;
|
|
209
|
+
padding-inline: var(--polly-field-padding);
|
|
207
210
|
font: inherit;
|
|
208
211
|
font-family: var(--polly-font-sans);
|
|
209
212
|
color: var(--polly-text);
|
|
210
213
|
line-height: var(--polly-line-height-base);
|
|
211
214
|
border: var(--polly-border-width-default) solid transparent;
|
|
212
|
-
border-radius: var(--polly-radius
|
|
213
|
-
min-block-size: calc(1.5em + 2 * var(--polly-space-sm) + 2 * var(--polly-border-width-default));
|
|
215
|
+
border-radius: var(--polly-control-radius);
|
|
214
216
|
inline-size: 100%;
|
|
215
217
|
}
|
|
216
218
|
|
|
217
219
|
.view_-n6UrQ {
|
|
220
|
+
display: flex;
|
|
218
221
|
cursor: text;
|
|
219
222
|
white-space: pre-wrap;
|
|
220
223
|
word-break: break-word;
|
|
221
224
|
transition: background var(--polly-motion-fast) ease, border-color var(--polly-motion-fast) ease;
|
|
222
225
|
background: none;
|
|
226
|
+
align-items: center;
|
|
223
227
|
}
|
|
224
228
|
|
|
225
229
|
.view_-n6UrQ:hover {
|
|
@@ -238,7 +242,9 @@
|
|
|
238
242
|
}
|
|
239
243
|
|
|
240
244
|
.root_-n6UrQ[data-variant="multi"] {
|
|
245
|
+
display: block;
|
|
241
246
|
field-sizing: content;
|
|
247
|
+
padding-block: calc((var(--polly-control-height-md) - 1.5em - 2 * var(--polly-border-width-default)) / 2);
|
|
242
248
|
resize: vertical;
|
|
243
249
|
max-block-size: 40em;
|
|
244
250
|
}
|
|
@@ -252,7 +258,8 @@
|
|
|
252
258
|
}
|
|
253
259
|
|
|
254
260
|
.trigger_HX48zA {
|
|
255
|
-
display: inline-
|
|
261
|
+
display: inline-flex;
|
|
262
|
+
align-items: center;
|
|
256
263
|
}
|
|
257
264
|
|
|
258
265
|
.menu_HX48zA {
|
|
@@ -349,10 +356,13 @@
|
|
|
349
356
|
display: inline-flex;
|
|
350
357
|
align-items: center;
|
|
351
358
|
gap: var(--polly-space-sm);
|
|
359
|
+
min-block-size: var(--polly-control-height-md);
|
|
352
360
|
max-width: min(100%, var(--polly-control-max-width));
|
|
353
|
-
padding
|
|
361
|
+
padding-block-start: 0;
|
|
362
|
+
padding-block-end: 0;
|
|
363
|
+
padding-inline: var(--polly-field-padding);
|
|
354
364
|
border: var(--polly-border-width-default) solid var(--polly-border);
|
|
355
|
-
border-radius: var(--polly-radius
|
|
365
|
+
border-radius: var(--polly-control-radius);
|
|
356
366
|
background-color: var(--polly-surface);
|
|
357
367
|
font-family: inherit;
|
|
358
368
|
font-size: var(--polly-text-md);
|
|
@@ -406,7 +416,7 @@
|
|
|
406
416
|
}
|
|
407
417
|
|
|
408
418
|
.actionBtn_daofbw {
|
|
409
|
-
display:
|
|
419
|
+
display: block;
|
|
410
420
|
padding: var(--polly-space-xs) var(--polly-space-sm);
|
|
411
421
|
border-radius: var(--polly-radius-sm);
|
|
412
422
|
font-family: inherit;
|
|
@@ -449,6 +459,8 @@
|
|
|
449
459
|
|
|
450
460
|
.optionCheck_daofbw {
|
|
451
461
|
accent-color: var(--polly-accent);
|
|
462
|
+
inline-size: var(--polly-checkbox-size);
|
|
463
|
+
block-size: var(--polly-checkbox-size);
|
|
452
464
|
vertical-align: middle;
|
|
453
465
|
pointer-events: none;
|
|
454
466
|
margin-inline-end: var(--polly-space-sm);
|
|
@@ -494,20 +506,26 @@
|
|
|
494
506
|
/* src/polly-ui/Button.module.css */
|
|
495
507
|
@layer polly-components {
|
|
496
508
|
.btn_c4HKfA {
|
|
497
|
-
display: inline-
|
|
498
|
-
|
|
509
|
+
display: inline-flex;
|
|
510
|
+
justify-content: center;
|
|
511
|
+
align-items: center;
|
|
512
|
+
gap: var(--polly-space-sm);
|
|
513
|
+
min-block-size: var(--polly-control-height-md);
|
|
514
|
+
padding-block-start: 0;
|
|
515
|
+
padding-block-end: 0;
|
|
516
|
+
padding-inline: var(--polly-control-padding-md);
|
|
499
517
|
border: var(--polly-border-width-default) solid transparent;
|
|
500
|
-
border-radius: var(--polly-radius
|
|
518
|
+
border-radius: var(--polly-control-radius);
|
|
501
519
|
font-family: inherit;
|
|
502
520
|
font-size: var(--polly-text-md);
|
|
503
521
|
font-weight: var(--polly-weight-medium);
|
|
522
|
+
line-height: var(--polly-line-height-tight);
|
|
504
523
|
text-align: center;
|
|
505
524
|
text-decoration: none;
|
|
506
525
|
cursor: pointer;
|
|
507
526
|
user-select: none;
|
|
508
527
|
box-sizing: border-box;
|
|
509
528
|
transition: background-color var(--polly-motion-fast), border-color var(--polly-motion-fast), color var(--polly-motion-fast);
|
|
510
|
-
line-height: 1.2;
|
|
511
529
|
}
|
|
512
530
|
|
|
513
531
|
.btn_c4HKfA:disabled, .btn_c4HKfA[aria-disabled="true"] {
|
|
@@ -582,20 +600,31 @@
|
|
|
582
600
|
}
|
|
583
601
|
|
|
584
602
|
.btnSmall_c4HKfA {
|
|
585
|
-
|
|
603
|
+
min-block-size: var(--polly-control-height-sm);
|
|
604
|
+
padding-inline: var(--polly-control-padding-sm);
|
|
586
605
|
font-size: var(--polly-text-sm);
|
|
587
606
|
}
|
|
588
607
|
|
|
589
608
|
.btnLarge_c4HKfA {
|
|
590
|
-
|
|
609
|
+
min-block-size: var(--polly-control-height-lg);
|
|
610
|
+
padding-inline: var(--polly-control-padding-lg);
|
|
591
611
|
font-size: var(--polly-text-lg);
|
|
592
612
|
}
|
|
593
613
|
|
|
594
614
|
.btnCircle_c4HKfA {
|
|
595
615
|
border-radius: var(--polly-radius-full);
|
|
596
616
|
aspect-ratio: 1;
|
|
597
|
-
|
|
598
|
-
padding: 0;
|
|
617
|
+
inline-size: var(--polly-control-height-md);
|
|
618
|
+
padding-inline-start: 0;
|
|
619
|
+
padding-inline-end: 0;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.btnSmall_c4HKfA.btnCircle_c4HKfA {
|
|
623
|
+
inline-size: var(--polly-control-height-sm);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.btnLarge_c4HKfA.btnCircle_c4HKfA {
|
|
627
|
+
inline-size: var(--polly-control-height-lg);
|
|
599
628
|
}
|
|
600
629
|
|
|
601
630
|
.btnFullWidth_c4HKfA {
|
|
@@ -608,6 +637,22 @@
|
|
|
608
637
|
text-overflow: ellipsis;
|
|
609
638
|
white-space: nowrap;
|
|
610
639
|
}
|
|
640
|
+
|
|
641
|
+
.icon_c4HKfA {
|
|
642
|
+
display: inline-flex;
|
|
643
|
+
flex: none;
|
|
644
|
+
align-items: center;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.label_c4HKfA {
|
|
648
|
+
min-inline-size: 0;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.btnBounded_c4HKfA .label_c4HKfA {
|
|
652
|
+
overflow: hidden;
|
|
653
|
+
text-overflow: ellipsis;
|
|
654
|
+
white-space: nowrap;
|
|
655
|
+
}
|
|
611
656
|
}
|
|
612
657
|
|
|
613
658
|
/* src/polly-ui/Surface.module.css */
|
|
@@ -691,7 +736,11 @@
|
|
|
691
736
|
/* src/polly-ui/Checkbox.module.css */
|
|
692
737
|
@layer polly-components {
|
|
693
738
|
.checkbox_EKE5sg {
|
|
694
|
-
display: inline-
|
|
739
|
+
display: inline-flex;
|
|
740
|
+
align-items: center;
|
|
741
|
+
gap: var(--polly-space-sm);
|
|
742
|
+
box-sizing: border-box;
|
|
743
|
+
min-block-size: var(--polly-control-height-md);
|
|
695
744
|
cursor: pointer;
|
|
696
745
|
font-family: inherit;
|
|
697
746
|
font-size: var(--polly-text-md);
|
|
@@ -706,14 +755,15 @@
|
|
|
706
755
|
|
|
707
756
|
.input_EKE5sg {
|
|
708
757
|
accent-color: var(--polly-accent);
|
|
709
|
-
|
|
758
|
+
inline-size: var(--polly-checkbox-size);
|
|
759
|
+
block-size: var(--polly-checkbox-size);
|
|
710
760
|
cursor: inherit;
|
|
761
|
+
flex: none;
|
|
711
762
|
margin: 0;
|
|
712
763
|
}
|
|
713
764
|
|
|
714
765
|
.label_EKE5sg {
|
|
715
|
-
|
|
716
|
-
margin-inline-start: var(--polly-space-sm);
|
|
766
|
+
min-inline-size: 0;
|
|
717
767
|
}
|
|
718
768
|
}
|
|
719
769
|
|
|
@@ -831,13 +881,19 @@
|
|
|
831
881
|
|
|
832
882
|
.cancel_ZfTX4A, .confirm_ZfTX4A, .confirmDanger_ZfTX4A {
|
|
833
883
|
appearance: none;
|
|
834
|
-
|
|
884
|
+
display: inline-flex;
|
|
885
|
+
min-block-size: var(--polly-control-height-md);
|
|
886
|
+
padding-block-start: 0;
|
|
887
|
+
padding-block-end: 0;
|
|
888
|
+
padding-inline: var(--polly-control-padding-md);
|
|
835
889
|
font: inherit;
|
|
836
890
|
font-weight: var(--polly-weight-medium);
|
|
837
891
|
border: var(--polly-border-width-default) solid var(--polly-border);
|
|
838
|
-
border-radius: var(--polly-radius
|
|
892
|
+
border-radius: var(--polly-control-radius);
|
|
839
893
|
cursor: pointer;
|
|
840
894
|
transition: background var(--polly-motion-fast) ease;
|
|
895
|
+
justify-content: center;
|
|
896
|
+
align-items: center;
|
|
841
897
|
}
|
|
842
898
|
|
|
843
899
|
.cancel_ZfTX4A {
|
|
@@ -918,14 +974,20 @@
|
|
|
918
974
|
|
|
919
975
|
.close_fLMrWA {
|
|
920
976
|
appearance: none;
|
|
977
|
+
display: inline-flex;
|
|
978
|
+
min-block-size: var(--polly-control-height-md);
|
|
921
979
|
color: var(--polly-text);
|
|
922
980
|
border: var(--polly-border-width-default) solid transparent;
|
|
923
|
-
border-radius: var(--polly-radius
|
|
924
|
-
padding
|
|
981
|
+
border-radius: var(--polly-control-radius);
|
|
982
|
+
padding-block-start: 0;
|
|
983
|
+
padding-block-end: 0;
|
|
984
|
+
padding-inline: var(--polly-field-padding);
|
|
925
985
|
font: inherit;
|
|
926
986
|
cursor: pointer;
|
|
927
987
|
transition: background var(--polly-motion-fast) ease, border-color var(--polly-motion-fast) ease;
|
|
928
988
|
background: none;
|
|
989
|
+
justify-content: center;
|
|
990
|
+
align-items: center;
|
|
929
991
|
}
|
|
930
992
|
|
|
931
993
|
.close_fLMrWA:hover {
|
|
@@ -949,10 +1011,13 @@
|
|
|
949
1011
|
display: inline-flex;
|
|
950
1012
|
align-items: center;
|
|
951
1013
|
gap: var(--polly-space-sm);
|
|
1014
|
+
box-sizing: border-box;
|
|
952
1015
|
min-block-size: var(--polly-control-height-md);
|
|
953
|
-
padding
|
|
1016
|
+
padding-block-start: 0;
|
|
1017
|
+
padding-block-end: 0;
|
|
1018
|
+
padding-inline: var(--polly-control-padding-md);
|
|
954
1019
|
border: var(--polly-border-width-default) solid var(--polly-border);
|
|
955
|
-
border-radius: var(--polly-radius
|
|
1020
|
+
border-radius: var(--polly-control-radius);
|
|
956
1021
|
background-color: var(--polly-surface);
|
|
957
1022
|
font-family: inherit;
|
|
958
1023
|
font-size: var(--polly-text-md);
|
|
@@ -1083,8 +1148,11 @@
|
|
|
1083
1148
|
}
|
|
1084
1149
|
|
|
1085
1150
|
.tab_xKO6GA {
|
|
1086
|
-
display: inline-
|
|
1087
|
-
|
|
1151
|
+
display: inline-flex;
|
|
1152
|
+
min-block-size: var(--polly-control-height-md);
|
|
1153
|
+
padding-block-start: 0;
|
|
1154
|
+
padding-block-end: 0;
|
|
1155
|
+
padding-inline: var(--polly-control-padding-md);
|
|
1088
1156
|
border: none;
|
|
1089
1157
|
border-bottom: var(--polly-border-width-medium) solid transparent;
|
|
1090
1158
|
font-family: inherit;
|
|
@@ -1095,6 +1163,8 @@
|
|
|
1095
1163
|
white-space: nowrap;
|
|
1096
1164
|
transition: color var(--polly-motion-fast), border-color var(--polly-motion-fast);
|
|
1097
1165
|
background: none;
|
|
1166
|
+
justify-content: center;
|
|
1167
|
+
align-items: center;
|
|
1098
1168
|
}
|
|
1099
1169
|
|
|
1100
1170
|
.tab_xKO6GA:hover:not(:disabled) {
|
|
@@ -1192,13 +1262,16 @@
|
|
|
1192
1262
|
@layer polly-components {
|
|
1193
1263
|
.input_ez4_Vg {
|
|
1194
1264
|
box-sizing: border-box;
|
|
1195
|
-
|
|
1265
|
+
min-block-size: var(--polly-control-height-md);
|
|
1266
|
+
padding-block-start: 0;
|
|
1267
|
+
padding-block-end: 0;
|
|
1268
|
+
padding-inline: var(--polly-field-padding);
|
|
1196
1269
|
font: inherit;
|
|
1197
1270
|
font-family: var(--polly-font-sans);
|
|
1198
1271
|
color: var(--polly-text);
|
|
1199
1272
|
background: var(--polly-surface);
|
|
1200
1273
|
border: var(--polly-border-width-default) solid var(--polly-border);
|
|
1201
|
-
border-radius: var(--polly-radius
|
|
1274
|
+
border-radius: var(--polly-control-radius);
|
|
1202
1275
|
transition: border-color var(--polly-motion-fast) ease, background var(--polly-motion-fast) ease;
|
|
1203
1276
|
inline-size: 100%;
|
|
1204
1277
|
}
|
|
@@ -1218,7 +1291,8 @@
|
|
|
1218
1291
|
|
|
1219
1292
|
.input_ez4_Vg[data-polly-input-variant="multi"] {
|
|
1220
1293
|
field-sizing: content;
|
|
1221
|
-
|
|
1294
|
+
padding-block: calc((var(--polly-control-height-md) - 1.5em - 2 * var(--polly-border-width-default)) / 2);
|
|
1295
|
+
min-block-size: var(--polly-control-height-md);
|
|
1222
1296
|
resize: vertical;
|
|
1223
1297
|
max-block-size: 40em;
|
|
1224
1298
|
}
|
|
@@ -1266,13 +1340,19 @@
|
|
|
1266
1340
|
|
|
1267
1341
|
.close_xVzRuA {
|
|
1268
1342
|
appearance: none;
|
|
1343
|
+
display: inline-flex;
|
|
1344
|
+
min-block-size: var(--polly-control-height-sm);
|
|
1269
1345
|
color: inherit;
|
|
1270
1346
|
border: var(--polly-border-width-default) solid transparent;
|
|
1271
|
-
border-radius: var(--polly-radius
|
|
1272
|
-
padding
|
|
1347
|
+
border-radius: var(--polly-control-radius);
|
|
1348
|
+
padding-block-start: 0;
|
|
1349
|
+
padding-block-end: 0;
|
|
1350
|
+
padding-inline: var(--polly-space-sm);
|
|
1273
1351
|
font: inherit;
|
|
1274
1352
|
cursor: pointer;
|
|
1275
1353
|
background: none;
|
|
1354
|
+
justify-content: center;
|
|
1355
|
+
align-items: center;
|
|
1276
1356
|
}
|
|
1277
1357
|
|
|
1278
1358
|
.close_xVzRuA:hover {
|
|
@@ -1283,13 +1363,16 @@
|
|
|
1283
1363
|
/* src/polly-ui/Toggle.module.css */
|
|
1284
1364
|
@layer polly-components {
|
|
1285
1365
|
.toggle_rnf-SQ {
|
|
1286
|
-
display: inline-
|
|
1366
|
+
display: inline-flex;
|
|
1367
|
+
align-items: center;
|
|
1368
|
+
gap: var(--polly-space-sm);
|
|
1369
|
+
box-sizing: border-box;
|
|
1370
|
+
min-block-size: var(--polly-control-height-md);
|
|
1287
1371
|
cursor: pointer;
|
|
1288
1372
|
font-family: inherit;
|
|
1289
1373
|
font-size: var(--polly-text-md);
|
|
1290
1374
|
color: var(--polly-text);
|
|
1291
1375
|
user-select: none;
|
|
1292
|
-
vertical-align: middle;
|
|
1293
1376
|
}
|
|
1294
1377
|
|
|
1295
1378
|
.disabled_rnf-SQ {
|
|
@@ -1310,12 +1393,12 @@
|
|
|
1310
1393
|
}
|
|
1311
1394
|
|
|
1312
1395
|
.track_rnf-SQ {
|
|
1313
|
-
display:
|
|
1396
|
+
display: block;
|
|
1314
1397
|
position: relative;
|
|
1315
1398
|
border-radius: var(--polly-radius-full);
|
|
1316
1399
|
background-color: var(--polly-border);
|
|
1317
|
-
vertical-align: middle;
|
|
1318
1400
|
transition: background-color var(--polly-motion-fast);
|
|
1401
|
+
flex: none;
|
|
1319
1402
|
width: 36px;
|
|
1320
1403
|
height: 20px;
|
|
1321
1404
|
}
|
|
@@ -1350,7 +1433,6 @@
|
|
|
1350
1433
|
}
|
|
1351
1434
|
|
|
1352
1435
|
.label_rnf-SQ {
|
|
1353
|
-
|
|
1354
|
-
margin-inline-start: var(--polly-space-sm);
|
|
1436
|
+
min-inline-size: 0;
|
|
1355
1437
|
}
|
|
1356
1438
|
}
|
|
@@ -14,6 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
@layer polly-defaults {
|
|
16
16
|
:root {
|
|
17
|
+
/* Tell the UA which schemes the page supports, so native controls —
|
|
18
|
+
* date and time pickers, the checkbox box, scrollbars, autofill —
|
|
19
|
+
* follow the palette instead of staying light on a dark page
|
|
20
|
+
* (polly#179). The media query below asks what the user prefers;
|
|
21
|
+
* this property answers what the page can render. */
|
|
22
|
+
color-scheme: light dark;
|
|
23
|
+
|
|
17
24
|
/* Surfaces */
|
|
18
25
|
--polly-surface: #ffffff;
|
|
19
26
|
--polly-surface-raised: #ffffff;
|
|
@@ -75,10 +82,39 @@
|
|
|
75
82
|
--polly-measure-prose: 68ch;
|
|
76
83
|
--polly-measure-page: 1040px;
|
|
77
84
|
|
|
78
|
-
/* Control heights —
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
/* Control heights — the single source of truth for how tall an
|
|
86
|
+
* interactive control is. Button, TextInput, ActionInput, Select,
|
|
87
|
+
* FileInput, Dropdown, Checkbox, Toggle and Tabs all set
|
|
88
|
+
* `min-block-size` from this ladder, so a row of mixed controls
|
|
89
|
+
* lines up without the consumer measuring anything. The ladder used to
|
|
90
|
+
* exist without anything reading it, and the same row held five different
|
|
91
|
+
* heights (37.19 / 40 / 42 / 42 / 54 px).
|
|
92
|
+
*
|
|
93
|
+
* Control text is centred by the flex/native box rather than by
|
|
94
|
+
* vertical padding, so changing a height here moves every control
|
|
95
|
+
* together and never re-cuts the text position. */
|
|
96
|
+
--polly-control-height-sm: 2rem;
|
|
97
|
+
--polly-control-height-md: 2.5rem;
|
|
98
|
+
--polly-control-height-lg: 3rem;
|
|
99
|
+
|
|
100
|
+
/* Control corner — one radius for every control, so a Button beside
|
|
101
|
+
* a TextInput has the same corner. Containers (Collapsible, the
|
|
102
|
+
* Dropdown menu, Output, a code block) keep --polly-radius-md
|
|
103
|
+
* independently; this token exists so a consumer can re-cut control
|
|
104
|
+
* corners without touching container corners. */
|
|
105
|
+
--polly-control-radius: var(--polly-radius-md);
|
|
106
|
+
|
|
107
|
+
/* Control inline padding — buttons carry more air than fields, and
|
|
108
|
+
* the ladder tracks the height ladder. */
|
|
109
|
+
--polly-control-padding-sm: var(--polly-space-md);
|
|
110
|
+
--polly-control-padding-md: var(--polly-space-lg);
|
|
111
|
+
--polly-control-padding-lg: var(--polly-space-xl);
|
|
112
|
+
--polly-field-padding: var(--polly-space-md);
|
|
113
|
+
|
|
114
|
+
/* Native checkbox box. The UA default is 13x13, which reads small
|
|
115
|
+
* beside 16px text; Checkbox and the Select option check both size
|
|
116
|
+
* from this. */
|
|
117
|
+
--polly-checkbox-size: 1.125rem;
|
|
82
118
|
|
|
83
119
|
/* Control widths — caps and floors for Button, Select, Dropdown
|
|
84
120
|
* triggers so semi-dynamic labels (multi-select joins, user-
|
|
@@ -194,6 +230,7 @@
|
|
|
194
230
|
|
|
195
231
|
/* Explicit mode override — wins over prefers-color-scheme. */
|
|
196
232
|
[data-polly-theme="light"] {
|
|
233
|
+
color-scheme: light;
|
|
197
234
|
--polly-surface: #ffffff;
|
|
198
235
|
--polly-surface-raised: #ffffff;
|
|
199
236
|
--polly-surface-sunken: #f4f5f7;
|
|
@@ -225,6 +262,7 @@
|
|
|
225
262
|
}
|
|
226
263
|
|
|
227
264
|
[data-polly-theme="dark"] {
|
|
265
|
+
color-scheme: dark;
|
|
228
266
|
--polly-surface: #14171c;
|
|
229
267
|
--polly-surface-raised: #1c2027;
|
|
230
268
|
--polly-surface-sunken: #0f1216;
|
|
@@ -72,6 +72,12 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
// tools/test/src/browser/harness.ts
|
|
75
|
+
function reportProgress(event) {
|
|
76
|
+
const fn = window["__pollyProgress"];
|
|
77
|
+
if (typeof fn === "function") {
|
|
78
|
+
fn(event);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
75
81
|
var results = [];
|
|
76
82
|
var suites = [];
|
|
77
83
|
function describe(name, fn) {
|
|
@@ -230,19 +236,24 @@ function cleanup(container) {
|
|
|
230
236
|
container.innerHTML = "";
|
|
231
237
|
}
|
|
232
238
|
async function done() {
|
|
239
|
+
reportProgress({ kind: "plan", total: suites.reduce((n, s) => n + s.tests.length, 0) });
|
|
233
240
|
for (const suite of suites) {
|
|
234
241
|
for (const t of suite.tests) {
|
|
235
242
|
const fullName = `${suite.name} > ${t.name}`;
|
|
243
|
+
reportProgress({ kind: "start", name: fullName });
|
|
244
|
+
let result;
|
|
236
245
|
try {
|
|
237
246
|
await t.fn();
|
|
238
|
-
|
|
247
|
+
result = { name: fullName, passed: true };
|
|
239
248
|
} catch (err) {
|
|
240
|
-
|
|
249
|
+
result = {
|
|
241
250
|
name: fullName,
|
|
242
251
|
passed: false,
|
|
243
252
|
error: err instanceof Error ? err.message : String(err)
|
|
244
|
-
}
|
|
253
|
+
};
|
|
245
254
|
}
|
|
255
|
+
results.push(result);
|
|
256
|
+
reportProgress({ kind: "result", ...result });
|
|
246
257
|
}
|
|
247
258
|
}
|
|
248
259
|
const report = window["__pollyReport"];
|
|
@@ -273,4 +284,4 @@ export {
|
|
|
273
284
|
waitFor
|
|
274
285
|
};
|
|
275
286
|
|
|
276
|
-
//# debugId=
|
|
287
|
+
//# debugId=B042476A041C912A64756E2164756E21
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../tools/test/src/browser/harness.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Browser-side test harness for Polly applications.\n *\n * Provides describe/test/expect/done that run inside a Puppeteer-launched\n * browser tab and record results on window.__testResults for the Node-side\n * runner to collect. Matchers cover both value assertions and DOM element\n * assertions so that Preact component tests and WebRTC adapter tests use\n * the same harness.\n *\n * @example\n * ```typescript\n * import { describe, test, expect, done, flush, cleanup } from \"@fairfox/polly/test/browser\";\n *\n * const app = document.getElementById(\"app\")!;\n *\n * describe(\"my feature\", () => {\n * test(\"renders correctly\", async () => {\n * render(<MyComponent />, app);\n * await flush();\n * expect(app.querySelector(\"h1\")).toHaveTextContent(\"Hello\");\n * cleanup(app);\n * });\n * });\n *\n * done();\n * ```\n */\n\ninterface TestResult {\n name: string;\n passed: boolean;\n error?: string;\n}\n\nconst results: TestResult[] = [];\nconst suites: Array<{\n name: string;\n tests: Array<{ name: string; fn: () => Promise<void> | void }>;\n}> = [];\n\nexport function describe(name: string, fn: () => void): void {\n suites.push({ name, tests: [] });\n fn();\n}\n\nexport function test(name: string, fn: () => Promise<void> | void): void {\n const suite = suites[suites.length - 1];\n if (suite) {\n suite.tests.push({ name, fn });\n }\n}\n\nfunction assertElement(value: unknown): Element {\n if (!(value instanceof Element)) {\n throw new Error(`Expected an Element, got ${typeof value}: ${String(value)}`);\n }\n return value;\n}\n\nexport function expect<T>(actual: T) {\n return {\n // Value matchers\n toBe(expected: T) {\n if (actual !== expected) {\n throw new Error(`Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);\n }\n },\n toEqual(expected: T) {\n if (JSON.stringify(actual) !== JSON.stringify(expected)) {\n throw new Error(`Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);\n }\n },\n toContain(sub: string) {\n if (!String(actual).includes(sub)) {\n throw new Error(`Expected \"${String(actual)}\" to contain \"${sub}\"`);\n }\n },\n toBeTruthy() {\n if (!actual) throw new Error(`Expected truthy, got ${String(actual)}`);\n },\n toBeFalsy() {\n if (actual) throw new Error(`Expected falsy, got ${String(actual)}`);\n },\n toBeNull() {\n if (actual !== null) throw new Error(`Expected null, got ${String(actual)}`);\n },\n toBeDefined() {\n if (actual === undefined || actual === null) {\n throw new Error(`Expected value to be defined, got ${String(actual)}`);\n }\n },\n toBeUndefined() {\n if (actual !== undefined) {\n throw new Error(`Expected undefined, got ${JSON.stringify(actual)}`);\n }\n },\n toBeGreaterThan(expected: number) {\n if (typeof actual !== \"number\" || actual <= expected) {\n throw new Error(`Expected ${String(actual)} to be greater than ${expected}`);\n }\n },\n toHaveLength(expected: number) {\n const obj = actual;\n const len = obj && typeof obj === \"object\" && \"length\" in obj ? Number(obj.length) : -1;\n if (len !== expected) throw new Error(`Expected length ${expected}, got ${len}`);\n },\n toExist() {\n if (actual == null) throw new Error(`Expected value to exist, got ${String(actual)}`);\n },\n\n // DOM element matchers\n toHaveTextContent(expected: string) {\n const el = assertElement(actual);\n if (!el.textContent?.includes(expected)) {\n throw new Error(\n `Expected text content to include ${JSON.stringify(expected)}, got ${JSON.stringify(el.textContent)}`\n );\n }\n },\n toBeChecked() {\n const el = assertElement(actual);\n if (!(el instanceof HTMLInputElement) || !el.checked) {\n throw new Error(\"Expected element to be checked\");\n }\n },\n toBeDisabled() {\n const el = assertElement(actual);\n if (!el.hasAttribute(\"disabled\") && el.getAttribute(\"aria-disabled\") !== \"true\") {\n throw new Error(\"Expected element to be disabled\");\n }\n },\n toHaveValue(expected: string) {\n const el = assertElement(actual);\n const inputEl =\n el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement ? el : null;\n if (!inputEl || inputEl.value !== expected) {\n throw new Error(\n `Expected value ${JSON.stringify(expected)}, got ${JSON.stringify(inputEl?.value ?? \"(not an input)\")}`\n );\n }\n },\n toHaveAttribute(name: string, value?: string) {\n const el = assertElement(actual);\n if (!el.hasAttribute(name)) {\n throw new Error(`Expected element to have attribute \"${name}\"`);\n }\n if (value !== undefined && el.getAttribute(name) !== value) {\n throw new Error(\n `Expected attribute \"${name}\" to be ${JSON.stringify(value)}, got ${JSON.stringify(el.getAttribute(name))}`\n );\n }\n },\n\n // .not variants\n not: {\n toBe(expected: T) {\n if (actual === expected) {\n throw new Error(`Expected value NOT to be ${JSON.stringify(expected)}`);\n }\n },\n toEqual(expected: T) {\n if (JSON.stringify(actual) === JSON.stringify(expected)) {\n throw new Error(`Expected value NOT to equal ${JSON.stringify(expected)}`);\n }\n },\n toContain(sub: string) {\n if (String(actual).includes(sub)) {\n throw new Error(`Expected \"${String(actual)}\" NOT to contain \"${sub}\"`);\n }\n },\n toBeNull() {\n if (actual === null) throw new Error(\"Expected value NOT to be null\");\n },\n toExist() {\n if (actual != null) throw new Error(`Expected value NOT to exist, got ${String(actual)}`);\n },\n toBeChecked() {\n const el = assertElement(actual);\n if (el instanceof HTMLInputElement && el.checked) {\n throw new Error(\"Expected element NOT to be checked\");\n }\n },\n toBeDisabled() {\n const el = assertElement(actual);\n if (el.hasAttribute(\"disabled\") || el.getAttribute(\"aria-disabled\") === \"true\") {\n throw new Error(\"Expected element NOT to be disabled\");\n }\n },\n toHaveAttribute(name: string) {\n const el = assertElement(actual);\n if (el.hasAttribute(name)) {\n throw new Error(`Expected element NOT to have attribute \"${name}\"`);\n }\n },\n },\n };\n}\n\n/**\n * Flush microtasks and pending DOM updates. Call after signal assignments\n * or render calls to give the reactive system and the browser a chance to\n * settle before asserting on the result.\n */\nexport function flush(ms = 50): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Clear a container's rendered content. Call at the end of each test to\n * prevent state leaking between tests. If you use Preact's render(), pass\n * the same container; the function calls render(null, container) if Preact\n * is available, otherwise sets innerHTML to \"\".\n */\nexport function cleanup(container: Element): void {\n container.innerHTML = \"\";\n}\n\n/**\n * Run all registered tests and report the tally to the Node-side runner.\n *\n * The runner injects `window.__pollyReport` (via Puppeteer's\n * `page.exposeFunction`) before navigating, so reporting is a single\n * push from the page to the runner — no polling, no waiting on a long-\n * running CDP call from the Node side. Polled `page.evaluate` was the\n * root cause of the intermittent `Runtime.callFunctionOn` stalls\n * tracked in polly#138.\n *\n * Call this at the end of every .browser.ts test file.\n */\nexport async function done(): Promise<void> {\n for (const suite of suites) {\n for (const t of suite.tests) {\n const fullName = `${suite.name} > ${t.name}`;\n try {\n await t.fn();\n results.push({ name: fullName, passed: true });\n } catch (err) {\n results.push({\n name: fullName,\n passed: false,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n const report = (window as unknown as Record<string, unknown>)[\"__pollyReport\"];\n if (!isReportFunction(report)) {\n throw new Error(\n \"harness.done(): window.__pollyReport is not defined. \" +\n \"This harness must be driven by the Polly browser test runner.\"\n );\n }\n report(results);\n}\n\n/** The runner injects `window.__pollyReport`; all we can check is callability. */\nfunction isReportFunction(value: unknown): value is (r: TestResult[]) => void {\n return typeof value === \"function\";\n}\n\n/**\n * Wait until a predicate returns true, polling every intervalMs. Rejects\n * after timeoutMs.\n */\nexport async function waitFor(\n predicate: () => boolean | Promise<boolean>,\n timeoutMs = 5000,\n intervalMs = 25\n): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await predicate()) return;\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n throw new Error(`waitFor timed out after ${timeoutMs}ms`);\n}\n"
|
|
5
|
+
"/**\n * Browser-side test harness for Polly applications.\n *\n * Provides describe/test/expect/done that run inside a Puppeteer-launched\n * browser tab and record results on window.__testResults for the Node-side\n * runner to collect. Matchers cover both value assertions and DOM element\n * assertions so that Preact component tests and WebRTC adapter tests use\n * the same harness.\n *\n * @example\n * ```typescript\n * import { describe, test, expect, done, flush, cleanup } from \"@fairfox/polly/test/browser\";\n *\n * const app = document.getElementById(\"app\")!;\n *\n * describe(\"my feature\", () => {\n * test(\"renders correctly\", async () => {\n * render(<MyComponent />, app);\n * await flush();\n * expect(app.querySelector(\"h1\")).toHaveTextContent(\"Hello\");\n * cleanup(app);\n * });\n * });\n *\n * done();\n * ```\n */\n\nimport type { ProgressEvent } from \"./runner-core.ts\";\n\ninterface TestResult {\n name: string;\n passed: boolean;\n error?: string;\n}\n\n/**\n * Push one progress event to the runner, if it is listening.\n *\n * The runner binds `window.__pollyProgress` next to `__pollyReport`. Older\n * runners bind only the latter, so a missing binding is not an error — the\n * suite just runs silently, as it always did.\n */\nfunction reportProgress(event: ProgressEvent): void {\n const fn = (window as unknown as Record<string, unknown>)[\"__pollyProgress\"];\n if (typeof fn === \"function\") {\n (fn as (e: ProgressEvent) => void)(event);\n }\n}\n\nconst results: TestResult[] = [];\nconst suites: Array<{\n name: string;\n tests: Array<{ name: string; fn: () => Promise<void> | void }>;\n}> = [];\n\nexport function describe(name: string, fn: () => void): void {\n suites.push({ name, tests: [] });\n fn();\n}\n\nexport function test(name: string, fn: () => Promise<void> | void): void {\n const suite = suites[suites.length - 1];\n if (suite) {\n suite.tests.push({ name, fn });\n }\n}\n\nfunction assertElement(value: unknown): Element {\n if (!(value instanceof Element)) {\n throw new Error(`Expected an Element, got ${typeof value}: ${String(value)}`);\n }\n return value;\n}\n\nexport function expect<T>(actual: T) {\n return {\n // Value matchers\n toBe(expected: T) {\n if (actual !== expected) {\n throw new Error(`Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);\n }\n },\n toEqual(expected: T) {\n if (JSON.stringify(actual) !== JSON.stringify(expected)) {\n throw new Error(`Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);\n }\n },\n toContain(sub: string) {\n if (!String(actual).includes(sub)) {\n throw new Error(`Expected \"${String(actual)}\" to contain \"${sub}\"`);\n }\n },\n toBeTruthy() {\n if (!actual) throw new Error(`Expected truthy, got ${String(actual)}`);\n },\n toBeFalsy() {\n if (actual) throw new Error(`Expected falsy, got ${String(actual)}`);\n },\n toBeNull() {\n if (actual !== null) throw new Error(`Expected null, got ${String(actual)}`);\n },\n toBeDefined() {\n if (actual === undefined || actual === null) {\n throw new Error(`Expected value to be defined, got ${String(actual)}`);\n }\n },\n toBeUndefined() {\n if (actual !== undefined) {\n throw new Error(`Expected undefined, got ${JSON.stringify(actual)}`);\n }\n },\n toBeGreaterThan(expected: number) {\n if (typeof actual !== \"number\" || actual <= expected) {\n throw new Error(`Expected ${String(actual)} to be greater than ${expected}`);\n }\n },\n toHaveLength(expected: number) {\n const obj = actual;\n const len = obj && typeof obj === \"object\" && \"length\" in obj ? Number(obj.length) : -1;\n if (len !== expected) throw new Error(`Expected length ${expected}, got ${len}`);\n },\n toExist() {\n if (actual == null) throw new Error(`Expected value to exist, got ${String(actual)}`);\n },\n\n // DOM element matchers\n toHaveTextContent(expected: string) {\n const el = assertElement(actual);\n if (!el.textContent?.includes(expected)) {\n throw new Error(\n `Expected text content to include ${JSON.stringify(expected)}, got ${JSON.stringify(el.textContent)}`\n );\n }\n },\n toBeChecked() {\n const el = assertElement(actual);\n if (!(el instanceof HTMLInputElement) || !el.checked) {\n throw new Error(\"Expected element to be checked\");\n }\n },\n toBeDisabled() {\n const el = assertElement(actual);\n if (!el.hasAttribute(\"disabled\") && el.getAttribute(\"aria-disabled\") !== \"true\") {\n throw new Error(\"Expected element to be disabled\");\n }\n },\n toHaveValue(expected: string) {\n const el = assertElement(actual);\n const inputEl =\n el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement ? el : null;\n if (!inputEl || inputEl.value !== expected) {\n throw new Error(\n `Expected value ${JSON.stringify(expected)}, got ${JSON.stringify(inputEl?.value ?? \"(not an input)\")}`\n );\n }\n },\n toHaveAttribute(name: string, value?: string) {\n const el = assertElement(actual);\n if (!el.hasAttribute(name)) {\n throw new Error(`Expected element to have attribute \"${name}\"`);\n }\n if (value !== undefined && el.getAttribute(name) !== value) {\n throw new Error(\n `Expected attribute \"${name}\" to be ${JSON.stringify(value)}, got ${JSON.stringify(el.getAttribute(name))}`\n );\n }\n },\n\n // .not variants\n not: {\n toBe(expected: T) {\n if (actual === expected) {\n throw new Error(`Expected value NOT to be ${JSON.stringify(expected)}`);\n }\n },\n toEqual(expected: T) {\n if (JSON.stringify(actual) === JSON.stringify(expected)) {\n throw new Error(`Expected value NOT to equal ${JSON.stringify(expected)}`);\n }\n },\n toContain(sub: string) {\n if (String(actual).includes(sub)) {\n throw new Error(`Expected \"${String(actual)}\" NOT to contain \"${sub}\"`);\n }\n },\n toBeNull() {\n if (actual === null) throw new Error(\"Expected value NOT to be null\");\n },\n toExist() {\n if (actual != null) throw new Error(`Expected value NOT to exist, got ${String(actual)}`);\n },\n toBeChecked() {\n const el = assertElement(actual);\n if (el instanceof HTMLInputElement && el.checked) {\n throw new Error(\"Expected element NOT to be checked\");\n }\n },\n toBeDisabled() {\n const el = assertElement(actual);\n if (el.hasAttribute(\"disabled\") || el.getAttribute(\"aria-disabled\") === \"true\") {\n throw new Error(\"Expected element NOT to be disabled\");\n }\n },\n toHaveAttribute(name: string) {\n const el = assertElement(actual);\n if (el.hasAttribute(name)) {\n throw new Error(`Expected element NOT to have attribute \"${name}\"`);\n }\n },\n },\n };\n}\n\n/**\n * Flush microtasks and pending DOM updates. Call after signal assignments\n * or render calls to give the reactive system and the browser a chance to\n * settle before asserting on the result.\n */\nexport function flush(ms = 50): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Clear a container's rendered content. Call at the end of each test to\n * prevent state leaking between tests. If you use Preact's render(), pass\n * the same container; the function calls render(null, container) if Preact\n * is available, otherwise sets innerHTML to \"\".\n */\nexport function cleanup(container: Element): void {\n container.innerHTML = \"\";\n}\n\n/**\n * Run all registered tests and report the tally to the Node-side runner.\n *\n * The runner injects `window.__pollyReport` (via Puppeteer's\n * `page.exposeFunction`) before navigating, so reporting is a single\n * push from the page to the runner — no polling, no waiting on a long-\n * running CDP call from the Node side. Polled `page.evaluate` was the\n * root cause of the intermittent `Runtime.callFunctionOn` stalls\n * tracked in polly#138.\n *\n * Call this at the end of every .browser.ts test file.\n */\nexport async function done(): Promise<void> {\n // Announce the plan before running anything. A page that stops part-way —\n // a runaway loop, an unsettled promise — has then already told the runner\n // how many tests it owed, so the stalled file reports how many never ran\n // instead of counting as a single failure (polly#177).\n reportProgress({ kind: \"plan\", total: suites.reduce((n, s) => n + s.tests.length, 0) });\n\n for (const suite of suites) {\n for (const t of suite.tests) {\n const fullName = `${suite.name} > ${t.name}`;\n reportProgress({ kind: \"start\", name: fullName });\n let result: TestResult;\n try {\n await t.fn();\n result = { name: fullName, passed: true };\n } catch (err) {\n result = {\n name: fullName,\n passed: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n results.push(result);\n reportProgress({ kind: \"result\", ...result });\n }\n }\n\n const report = (window as unknown as Record<string, unknown>)[\"__pollyReport\"];\n if (!isReportFunction(report)) {\n throw new Error(\n \"harness.done(): window.__pollyReport is not defined. \" +\n \"This harness must be driven by the Polly browser test runner.\"\n );\n }\n report(results);\n}\n\n/** The runner injects `window.__pollyReport`; all we can check is callability. */\nfunction isReportFunction(value: unknown): value is (r: TestResult[]) => void {\n return typeof value === \"function\";\n}\n\n/**\n * Wait until a predicate returns true, polling every intervalMs. Rejects\n * after timeoutMs.\n */\nexport async function waitFor(\n predicate: () => boolean | Promise<boolean>,\n timeoutMs = 5000,\n intervalMs = 25\n): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await predicate()) return;\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n throw new Error(`waitFor timed out after ${timeoutMs}ms`);\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "B042476A041C912A64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -4,9 +4,16 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Finds all *.browser.ts files in a given directory, bundles each with
|
|
6
6
|
* Bun.build for the browser target (with an internal Automerge WASM fix),
|
|
7
|
-
* serves the bundle on an ephemeral port, opens a Puppeteer page
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* serves the bundle on an ephemeral port, and opens a Puppeteer page in its
|
|
8
|
+
* own browser context. The page pushes its results back through bindings the
|
|
9
|
+
* runner exposes (`__pollyReport` for the final tally, `__pollyProgress` per
|
|
10
|
+
* test). Prints pass/fail per test and exits non-zero if any test failed.
|
|
11
|
+
*
|
|
12
|
+
* A file that stops reporting is diagnosed rather than merely timed out: the
|
|
13
|
+
* runner asks the page whether its main thread is still free, so a runaway
|
|
14
|
+
* loop in the code under test reads differently from a suite that never
|
|
15
|
+
* finished, and the tests that never ran are counted (polly#177). Set
|
|
16
|
+
* POLLY_BROWSER_STACK=1 to also print the stack a wedged page is executing.
|
|
10
17
|
*
|
|
11
18
|
* A signalling server for WebRTC tests starts automatically on a random
|
|
12
19
|
* port. The URL is injected into the bundle via process.env.SIGNALING_URL.
|