rei-kit 2.23.0 → 2.24.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/styles.css CHANGED
@@ -246,72 +246,99 @@
246
246
  }
247
247
  }
248
248
 
249
- .rk-scroll[data-v-4c21cdc9] {
249
+ /*
250
+ * A flex column, so a height written on this box reaches the box that
251
+ * scrolls.
252
+ *
253
+ * The caller's class lands here, on the wrapper, because that is the
254
+ * element the component renders outermost — so `class="max-h-56"` is the
255
+ * obvious and only thing to write. It used to do nothing. The viewport
256
+ * carried `max-height: 100%`, and a percentage height resolves against the
257
+ * parent's *height*, which is `auto` here; a parent with only a
258
+ * `max-height` gives it nothing to resolve against, so the rule was inert
259
+ * and the viewport grew to the full height of its contents.
260
+ *
261
+ * Visually that spills. For `VirtualList` it is worse than spilling: the
262
+ * window is sized from `clientHeight`, so an unconstrained viewport reports
263
+ * the height of the whole list, every row is "near the viewport", and five
264
+ * thousand of them render at once. That is the component's whole purpose,
265
+ * inverted, by the one line every caller writes.
266
+ *
267
+ * `flex: 1 1 auto` with `min-height: 0` is what lets the item shrink below
268
+ * its content, which is the part that is easy to leave out: a flex item's
269
+ * default `min-height: auto` refuses to go below its content and the box
270
+ * spills exactly as before.
271
+ */
272
+ .rk-scroll[data-v-383954d8] {
250
273
  position: relative;
274
+ display: flex;
275
+ flex-direction: column;
251
276
  min-width: 0;
252
277
  min-height: 0;
253
278
  }
254
- .rk-scroll-viewport[data-v-4c21cdc9] {
279
+ .rk-scroll-viewport[data-v-383954d8] {
280
+ flex: 1 1 auto;
281
+ min-width: 0;
282
+ min-height: 0;
255
283
  max-width: 100%;
256
- max-height: 100%;
257
284
  }
258
- .rk-scroll-viewport.is-x[data-v-4c21cdc9] {
285
+ .rk-scroll-viewport.is-x[data-v-383954d8] {
259
286
  overflow-x: auto;
260
287
  overflow-y: hidden;
261
288
  }
262
- .rk-scroll-viewport.is-y[data-v-4c21cdc9] {
289
+ .rk-scroll-viewport.is-y[data-v-383954d8] {
263
290
  overflow-x: hidden;
264
291
  overflow-y: auto;
265
292
  }
266
- .rk-scroll-viewport.is-both[data-v-4c21cdc9] {
293
+ .rk-scroll-viewport.is-both[data-v-383954d8] {
267
294
  overflow: auto;
268
295
  }
269
- .rk-scroll-viewport[data-v-4c21cdc9]:focus-visible {
296
+ .rk-scroll-viewport[data-v-383954d8]:focus-visible {
270
297
  outline: 2px solid var(--color-primary);
271
298
  outline-offset: 2px;
272
299
  }
273
300
 
274
301
  /* The fade paints over whatever the box sits on, so the colour is a hook:
275
302
  a scroll area on a card sets it to the card's ground. */
276
- .rk-scroll-fade[data-v-4c21cdc9] {
303
+ .rk-scroll-fade[data-v-383954d8] {
277
304
  position: absolute;
278
305
  z-index: 1;
279
306
  pointer-events: none;
280
307
  --rk-scroll-fade: var(--scroll-fade-color, var(--color-canvas));
281
308
  }
282
- .rk-scroll-fade.is-start-x[data-v-4c21cdc9],
283
- .rk-scroll-fade.is-end-x[data-v-4c21cdc9] {
309
+ .rk-scroll-fade.is-start-x[data-v-383954d8],
310
+ .rk-scroll-fade.is-end-x[data-v-383954d8] {
284
311
  inset-block: 0;
285
312
  width: 1.5rem;
286
313
  }
287
- .rk-scroll-fade.is-start-y[data-v-4c21cdc9],
288
- .rk-scroll-fade.is-end-y[data-v-4c21cdc9] {
314
+ .rk-scroll-fade.is-start-y[data-v-383954d8],
315
+ .rk-scroll-fade.is-end-y[data-v-383954d8] {
289
316
  inset-inline: 0;
290
317
  height: 1.5rem;
291
318
  }
292
- .rk-scroll-fade.is-start-x[data-v-4c21cdc9] {
319
+ .rk-scroll-fade.is-start-x[data-v-383954d8] {
293
320
  inset-inline-start: 0;
294
321
  background: linear-gradient(to right, var(--rk-scroll-fade), transparent);
295
322
  }
296
- .rk-scroll-fade.is-end-x[data-v-4c21cdc9] {
323
+ .rk-scroll-fade.is-end-x[data-v-383954d8] {
297
324
  inset-inline-end: 0;
298
325
  background: linear-gradient(to left, var(--rk-scroll-fade), transparent);
299
326
  }
300
- .rk-scroll-fade.is-start-y[data-v-4c21cdc9] {
327
+ .rk-scroll-fade.is-start-y[data-v-383954d8] {
301
328
  inset-block-start: 0;
302
329
  background: linear-gradient(to bottom, var(--rk-scroll-fade), transparent);
303
330
  }
304
- .rk-scroll-fade.is-end-y[data-v-4c21cdc9] {
331
+ .rk-scroll-fade.is-end-y[data-v-383954d8] {
305
332
  inset-block-end: 0;
306
333
  background: linear-gradient(to top, var(--rk-scroll-fade), transparent);
307
334
  }
308
335
 
309
336
  /* The insets are logical, so they land on the correct side on their own.
310
337
  A gradient has no logical direction, so these two flip by hand. */
311
- [dir='rtl'] .rk-scroll-fade.is-start-x[data-v-4c21cdc9] {
338
+ [dir='rtl'] .rk-scroll-fade.is-start-x[data-v-383954d8] {
312
339
  background: linear-gradient(to left, var(--rk-scroll-fade), transparent);
313
340
  }
314
- [dir='rtl'] .rk-scroll-fade.is-end-x[data-v-4c21cdc9] {
341
+ [dir='rtl'] .rk-scroll-fade.is-end-x[data-v-383954d8] {
315
342
  background: linear-gradient(to right, var(--rk-scroll-fade), transparent);
316
343
  }
317
344
 
@@ -414,37 +441,45 @@
414
441
  height: 65%;
415
442
  }
416
443
 
417
- .rk-menu[data-v-eaeecb75] {
444
+ .rk-menu[data-v-657b2528] {
418
445
  position: relative;
419
446
  display: inline-flex;
420
447
  }
421
- .rk-menu-trigger[data-v-eaeecb75] {
448
+ .rk-menu-trigger[data-v-657b2528] {
422
449
  display: inline-flex;
423
450
  border-radius: var(--radius-cell);
424
451
  }
425
- .rk-menu-trigger[data-v-eaeecb75]:focus-visible {
452
+ .rk-menu-trigger[data-v-657b2528]:focus-visible {
426
453
  outline: 2px solid var(--color-primary);
427
454
  outline-offset: 2px;
428
455
  }
429
- .rk-menu-panel[data-v-eaeecb75] {
456
+ .rk-menu-panel[data-v-657b2528] {
430
457
  position: absolute;
431
- top: calc(100% + 0.5rem);
432
458
  z-index: 50;
459
+ /* The slide is a translate rather than an inset, so it composes with the
460
+ `is-start`/`is-end` edge the caller asked for instead of replacing it. */
461
+ transform: translateX(var(--rk-menu-shift, 0px));
433
462
  min-width: 12rem;
434
463
  overflow: hidden;
435
464
  border-radius: var(--radius-card);
436
465
  padding: 0.375rem;
437
466
  }
438
- .rk-menu-panel.is-end[data-v-eaeecb75] {
467
+ .rk-menu-panel.is-bottom[data-v-657b2528] {
468
+ top: calc(100% + 0.5rem);
469
+ }
470
+ .rk-menu-panel.is-top[data-v-657b2528] {
471
+ bottom: calc(100% + 0.5rem);
472
+ }
473
+ .rk-menu-panel.is-end[data-v-657b2528] {
439
474
  inset-inline-end: 0;
440
475
  }
441
- .rk-menu-panel.is-start[data-v-eaeecb75] {
476
+ .rk-menu-panel.is-start[data-v-657b2528] {
442
477
  inset-inline-start: 0;
443
478
  }
444
479
 
445
480
  /* The items belong to the caller, so this styles them by role rather than by
446
481
  class: whatever they render, it lines up. */
447
- .rk-menu-panel[data-v-eaeecb75] [role='menuitem'] {
482
+ .rk-menu-panel[data-v-657b2528] [role='menuitem'] {
448
483
  display: block;
449
484
  width: 100%;
450
485
  border-radius: var(--radius-cell);
@@ -454,32 +489,32 @@
454
489
  color: var(--color-ink);
455
490
  transition: background-color var(--duration-fast);
456
491
  }
457
- .rk-menu-panel[data-v-eaeecb75] [role='menuitem']:hover {
492
+ .rk-menu-panel[data-v-657b2528] [role='menuitem']:hover {
458
493
  background: var(--color-muted);
459
494
  }
460
- .rk-menu-panel[data-v-eaeecb75] [role='menuitem']:focus-visible {
495
+ .rk-menu-panel[data-v-657b2528] [role='menuitem']:focus-visible {
461
496
  outline: 2px solid var(--color-primary);
462
497
  outline-offset: -2px;
463
498
  }
464
- .rk-menu-panel[data-v-eaeecb75] hr {
499
+ .rk-menu-panel[data-v-657b2528] hr {
465
500
  margin: 0.375rem 0;
466
501
  height: 1px;
467
502
  border: 0;
468
503
  background: color-mix(in srgb, var(--color-hair) 70%, transparent);
469
504
  }
470
505
 
471
- .rk-combo[data-v-0ae3b425] {
506
+ .rk-combo[data-v-f02a0924] {
472
507
  position: relative;
473
508
  display: flex;
474
509
  flex-direction: column;
475
510
  gap: 0.375rem;
476
511
  }
477
- .rk-combo-label[data-v-0ae3b425] {
512
+ .rk-combo-label[data-v-f02a0924] {
478
513
  font-size: 0.875rem;
479
514
  font-weight: 500;
480
515
  color: var(--color-ink);
481
516
  }
482
- .rk-combo-field[data-v-0ae3b425] {
517
+ .rk-combo-field[data-v-f02a0924] {
483
518
  position: relative;
484
519
  display: flex;
485
520
  align-items: center;
@@ -487,14 +522,14 @@
487
522
 
488
523
  /* With chips the field is a box that wraps, and the input is one item in it
489
524
  that grows into whatever is left. */
490
- .rk-combo-field.is-multiple[data-v-0ae3b425] {
525
+ .rk-combo-field.is-multiple[data-v-f02a0924] {
491
526
  flex-wrap: wrap;
492
527
  gap: 0.25rem;
493
528
  min-height: 2.75rem;
494
529
  border-radius: var(--radius-card);
495
530
  padding: 0.3125rem 2rem 0.3125rem 0.375rem;
496
531
  }
497
- .rk-combo-chip[data-v-0ae3b425] {
532
+ .rk-combo-chip[data-v-f02a0924] {
498
533
  display: inline-flex;
499
534
  align-items: center;
500
535
  gap: 0.25rem;
@@ -504,7 +539,7 @@
504
539
  font-size: 0.8125rem;
505
540
  color: var(--color-ink);
506
541
  }
507
- .rk-combo-chip-x[data-v-0ae3b425] {
542
+ .rk-combo-chip-x[data-v-f02a0924] {
508
543
  display: grid;
509
544
  width: 1.125rem;
510
545
  height: 1.125rem;
@@ -513,13 +548,13 @@
513
548
  color: var(--color-ink-soft);
514
549
  line-height: 1;
515
550
  }
516
- .rk-combo-chip-x[data-v-0ae3b425]:hover {
551
+ .rk-combo-chip-x[data-v-f02a0924]:hover {
517
552
  color: var(--color-ink);
518
553
  }
519
554
 
520
555
  /* 16px, like every other text control here: iOS zooms the viewport when it
521
556
  focuses a field under 16px and never zooms back. */
522
- .rk-combo-input[data-v-0ae3b425] {
557
+ .rk-combo-input[data-v-f02a0924] {
523
558
  width: 100%;
524
559
  height: 2.75rem;
525
560
  border-radius: var(--radius-card);
@@ -527,7 +562,7 @@
527
562
  font-size: 1rem;
528
563
  color: var(--color-ink);
529
564
  }
530
- .is-multiple .rk-combo-input[data-v-0ae3b425] {
565
+ .is-multiple .rk-combo-input[data-v-f02a0924] {
531
566
  width: auto;
532
567
  height: 1.75rem;
533
568
  min-width: 6rem;
@@ -538,39 +573,45 @@
538
573
  background: transparent;
539
574
  box-shadow: none;
540
575
  }
541
- .rk-combo-input[data-v-0ae3b425]:focus-visible {
576
+ .rk-combo-input[data-v-f02a0924]:focus-visible {
542
577
  outline: 2px solid var(--color-primary);
543
578
  outline-offset: -1px;
544
579
  }
545
- .is-multiple .rk-combo-input[data-v-0ae3b425]:focus-visible {
580
+ .is-multiple .rk-combo-input[data-v-f02a0924]:focus-visible {
546
581
  outline: none;
547
582
  }
548
583
 
549
584
  /* The ring belongs to the whole box once the box is the control. */
550
- .rk-combo-field.is-multiple[data-v-0ae3b425]:focus-within {
585
+ .rk-combo-field.is-multiple[data-v-f02a0924]:focus-within {
551
586
  outline: 2px solid var(--color-primary);
552
587
  outline-offset: -1px;
553
588
  }
554
- .rk-combo-input[data-v-0ae3b425]:disabled {
589
+ .rk-combo-input[data-v-f02a0924]:disabled {
555
590
  opacity: 0.5;
556
591
  }
557
- .rk-combo-toggle[data-v-0ae3b425] {
592
+ .rk-combo-toggle[data-v-f02a0924] {
558
593
  position: absolute;
559
594
  inset-inline-end: 0.5rem;
560
595
  color: var(--color-ink-soft);
561
596
  font-size: 0.75rem;
562
597
  }
563
- .rk-combo-list[data-v-0ae3b425] {
598
+ .rk-combo-list[data-v-f02a0924] {
564
599
  position: absolute;
565
- top: calc(100% - 1.25rem);
566
600
  z-index: 50;
601
+ transform: translateX(var(--rk-combo-shift, 0px));
567
602
  max-height: 14rem;
568
603
  width: 100%;
569
604
  overflow-y: auto;
570
605
  border-radius: var(--radius-card);
571
606
  padding: 0.25rem;
572
607
  }
573
- .rk-combo-option[data-v-0ae3b425] {
608
+ .rk-combo-list.is-bottom[data-v-f02a0924] {
609
+ top: calc(100% - 1.25rem);
610
+ }
611
+ .rk-combo-list.is-top[data-v-f02a0924] {
612
+ bottom: calc(100% - 1.25rem);
613
+ }
614
+ .rk-combo-option[data-v-f02a0924] {
574
615
  cursor: pointer;
575
616
  border-radius: var(--radius-cell);
576
617
  padding: 0.5rem 0.625rem;
@@ -580,38 +621,38 @@
580
621
 
581
622
  /* A virtual row's height is the arithmetic the spacers are built on, so it
582
623
  cannot be left to the text inside it. */
583
- .rk-combo-option[style][data-v-0ae3b425] {
624
+ .rk-combo-option[style][data-v-f02a0924] {
584
625
  display: flex;
585
626
  align-items: center;
586
627
  padding-block: 0;
587
628
  }
588
- .rk-combo-option.is-highlighted[data-v-0ae3b425] {
629
+ .rk-combo-option.is-highlighted[data-v-f02a0924] {
589
630
  background: var(--color-muted);
590
631
  }
591
- .rk-combo-option.is-selected[data-v-0ae3b425] {
632
+ .rk-combo-option.is-selected[data-v-f02a0924] {
592
633
  font-weight: 600;
593
634
  }
594
- .rk-combo-empty[data-v-0ae3b425],
595
- .rk-combo-status[data-v-0ae3b425] {
635
+ .rk-combo-empty[data-v-f02a0924],
636
+ .rk-combo-status[data-v-f02a0924] {
596
637
  padding: 0.75rem 0.625rem;
597
638
  font-size: 0.875rem;
598
639
  color: var(--color-ink-soft);
599
640
  }
600
- .rk-combo-status[data-v-0ae3b425] {
641
+ .rk-combo-status[data-v-f02a0924] {
601
642
  display: flex;
602
643
  flex-direction: column;
603
644
  gap: 0.5rem;
604
645
  }
605
- .rk-combo-status-rows[data-v-0ae3b425] {
646
+ .rk-combo-status-rows[data-v-f02a0924] {
606
647
  display: flex;
607
648
  flex-direction: column;
608
649
  gap: 0.5rem;
609
650
  }
610
- .rk-combo-error[data-v-0ae3b425] {
651
+ .rk-combo-error[data-v-f02a0924] {
611
652
  font-size: 0.75rem;
612
653
  color: var(--color-negative);
613
654
  }
614
- .rk-combo-hint[data-v-0ae3b425] {
655
+ .rk-combo-hint[data-v-f02a0924] {
615
656
  font-size: 0.75rem;
616
657
  color: var(--color-ink-soft);
617
658
  }
@@ -1189,12 +1230,88 @@ to {
1189
1230
  outline-offset: 1px;
1190
1231
  }
1191
1232
 
1192
- .rk-vlist-rows[data-v-936ed40c] {
1233
+ .rk-bars[data-v-12682ed6] {
1234
+ width: 100%;
1235
+ border-collapse: collapse;
1236
+ }
1237
+ .rk-bars-label[data-v-12682ed6] {
1238
+ padding-block: 0.3125rem;
1239
+ padding-inline-end: 0.75rem;
1240
+ color: var(--color-ink);
1241
+ font-size: 0.8125rem;
1242
+ font-weight: 500;
1243
+ text-align: start;
1244
+ white-space: nowrap;
1245
+ }
1246
+ .rk-bars-track[data-v-12682ed6] {
1247
+ width: 100%;
1248
+ padding-block: 0.3125rem;
1249
+ }
1250
+ .rk-bars-fill[data-v-12682ed6] {
1251
+ display: block;
1252
+ height: 0.625rem;
1253
+ border-radius: 9999px;
1254
+ transition: width var(--duration-slower) var(--ease-standard);
1255
+ }
1256
+ .rk-bars-value[data-v-12682ed6] {
1257
+ padding-block: 0.3125rem;
1258
+ padding-inline-start: 0.75rem;
1259
+ color: var(--color-ink-soft);
1260
+ font-size: 0.8125rem;
1261
+ font-variant-numeric: tabular-nums;
1262
+ text-align: end;
1263
+ white-space: nowrap;
1264
+ }
1265
+
1266
+ .rk-donut[data-v-4ee6aaa6] {
1267
+ display: flex;
1268
+ flex-wrap: wrap;
1269
+ align-items: center;
1270
+ gap: 1.25rem;
1271
+ }
1272
+ .rk-donut-ring[data-v-4ee6aaa6] {
1273
+ width: 8.5rem;
1274
+ height: 8.5rem;
1275
+ flex: none;
1276
+ }
1277
+ .rk-donut-legend[data-v-4ee6aaa6] {
1278
+ margin: 0;
1279
+ padding: 0;
1280
+ min-width: 0;
1281
+ flex: 1 1 12rem;
1282
+ list-style: none;
1283
+ }
1284
+ .rk-donut-item[data-v-4ee6aaa6] {
1285
+ display: flex;
1286
+ align-items: center;
1287
+ gap: 0.5rem;
1288
+ padding-block: 0.1875rem;
1289
+ font-size: 0.8125rem;
1290
+ }
1291
+ .rk-donut-swatch[data-v-4ee6aaa6] {
1292
+ width: 0.625rem;
1293
+ height: 0.625rem;
1294
+ flex: none;
1295
+ border-radius: 9999px;
1296
+ background: currentColor;
1297
+ }
1298
+ .rk-donut-name[data-v-4ee6aaa6] {
1299
+ min-width: 0;
1300
+ flex: 1 1 auto;
1301
+ color: var(--color-ink);
1302
+ }
1303
+ .rk-donut-value[data-v-4ee6aaa6] {
1304
+ color: var(--color-ink-soft);
1305
+ font-variant-numeric: tabular-nums;
1306
+ white-space: nowrap;
1307
+ }
1308
+
1309
+ .rk-vlist-rows[data-v-5fea77fd] {
1193
1310
  margin: 0;
1194
1311
  padding: 0;
1195
1312
  list-style: none;
1196
1313
  }
1197
- .rk-vlist-row[data-v-936ed40c] {
1314
+ .rk-vlist-row[data-v-5fea77fd] {
1198
1315
  box-sizing: border-box;
1199
1316
  overflow: hidden;
1200
1317
  }
@@ -1956,11 +2073,11 @@ to {
1956
2073
  outline: none;
1957
2074
  }
1958
2075
 
1959
- .rk-popover[data-v-22d8f397] {
2076
+ .rk-popover[data-v-86915db6] {
1960
2077
  position: relative;
1961
2078
  display: inline-flex;
1962
2079
  }
1963
- .rk-popover-panel[data-v-22d8f397] {
2080
+ .rk-popover-panel[data-v-86915db6] {
1964
2081
  position: absolute;
1965
2082
  z-index: 50;
1966
2083
  min-width: 14rem;
@@ -1969,39 +2086,39 @@ to {
1969
2086
  padding: 0.75rem;
1970
2087
  translate: var(--rk-popover-shift, 0) 0;
1971
2088
  }
1972
- .rk-popover-panel[data-v-22d8f397]:focus-visible {
2089
+ .rk-popover-panel[data-v-86915db6]:focus-visible {
1973
2090
  outline: 2px solid var(--color-primary);
1974
2091
  outline-offset: 2px;
1975
2092
  }
1976
- .rk-popover-panel.is-bottom[data-v-22d8f397] {
2093
+ .rk-popover-panel.is-bottom[data-v-86915db6] {
1977
2094
  top: calc(100% + 0.5rem);
1978
2095
  }
1979
- .rk-popover-panel.is-top[data-v-22d8f397] {
2096
+ .rk-popover-panel.is-top[data-v-86915db6] {
1980
2097
  bottom: calc(100% + 0.5rem);
1981
2098
  }
1982
- .rk-popover-panel.is-start[data-v-22d8f397] {
2099
+ .rk-popover-panel.is-start[data-v-86915db6] {
1983
2100
  inset-inline-start: 0;
1984
2101
  }
1985
- .rk-popover-panel.is-end[data-v-22d8f397] {
2102
+ .rk-popover-panel.is-end[data-v-86915db6] {
1986
2103
  inset-inline-end: 0;
1987
2104
  }
1988
- .rk-popover-panel.is-center[data-v-22d8f397] {
2105
+ .rk-popover-panel.is-center[data-v-86915db6] {
1989
2106
  left: 50%;
1990
2107
  translate: calc(-50% + var(--rk-popover-shift, 0px)) 0;
1991
2108
  }
1992
- .rk-popover-enter-active[data-v-22d8f397],
1993
- .rk-popover-leave-active[data-v-22d8f397] {
2109
+ .rk-popover-enter-active[data-v-86915db6],
2110
+ .rk-popover-leave-active[data-v-86915db6] {
1994
2111
  transition:
1995
2112
  opacity var(--duration-fast) var(--ease-standard),
1996
2113
  transform var(--duration-fast) var(--ease-standard);
1997
2114
  }
1998
- .rk-popover-enter-from[data-v-22d8f397],
1999
- .rk-popover-leave-to[data-v-22d8f397] {
2115
+ .rk-popover-enter-from[data-v-86915db6],
2116
+ .rk-popover-leave-to[data-v-86915db6] {
2000
2117
  opacity: 0;
2001
2118
  transform: translateY(-4px) scale(0.98);
2002
2119
  }
2003
- .rk-popover-panel.is-top.rk-popover-enter-from[data-v-22d8f397],
2004
- .rk-popover-panel.is-top.rk-popover-leave-to[data-v-22d8f397] {
2120
+ .rk-popover-panel.is-top.rk-popover-enter-from[data-v-86915db6],
2121
+ .rk-popover-panel.is-top.rk-popover-leave-to[data-v-86915db6] {
2005
2122
  transform: translateY(4px) scale(0.98);
2006
2123
  }
2007
2124
 
@@ -2960,12 +3077,13 @@ to {
2960
3077
  }
2961
3078
  }
2962
3079
 
2963
- .rk-hovercard[data-v-70c09916] {
3080
+ .rk-hovercard[data-v-d3c3b40f] {
2964
3081
  position: relative;
2965
3082
  display: inline-flex;
2966
3083
  }
2967
- .rk-hovercard-panel[data-v-70c09916] {
3084
+ .rk-hovercard-panel[data-v-d3c3b40f] {
2968
3085
  position: absolute;
3086
+ transform: translateX(var(--rk-hovercard-shift, 0px));
2969
3087
  z-index: 40;
2970
3088
  inset-inline-start: 0;
2971
3089
  width: max-content;
@@ -2985,23 +3103,23 @@ to {
2985
3103
  * because the failure it prevents -- a card whose contents cannot be
2986
3104
  * reached -- is total rather than cosmetic.
2987
3105
  */
2988
- .rk-hovercard-panel[data-v-70c09916]::before {
3106
+ .rk-hovercard-panel[data-v-d3c3b40f]::before {
2989
3107
  content: '';
2990
3108
  position: absolute;
2991
3109
  inset-inline: 0;
2992
3110
  height: 0.5rem;
2993
3111
  }
2994
- .rk-hovercard-panel.is-bottom[data-v-70c09916]::before {
3112
+ .rk-hovercard-panel.is-bottom[data-v-d3c3b40f]::before {
2995
3113
  top: -0.5rem;
2996
3114
  }
2997
- .rk-hovercard-panel.is-top[data-v-70c09916]::before {
3115
+ .rk-hovercard-panel.is-top[data-v-d3c3b40f]::before {
2998
3116
  bottom: -0.5rem;
2999
3117
  }
3000
- .rk-hovercard-panel.is-bottom[data-v-70c09916] {
3118
+ .rk-hovercard-panel.is-bottom[data-v-d3c3b40f] {
3001
3119
  top: 100%;
3002
3120
  margin-block-start: 0.5rem;
3003
3121
  }
3004
- .rk-hovercard-panel.is-top[data-v-70c09916] {
3122
+ .rk-hovercard-panel.is-top[data-v-d3c3b40f] {
3005
3123
  bottom: 100%;
3006
3124
  margin-block-end: 0.5rem;
3007
3125
  }
@@ -3547,12 +3665,12 @@ to {
3547
3665
  background: var(--color-primary);
3548
3666
  }
3549
3667
 
3550
- .rk-toolbar[data-v-d49198bf] {
3668
+ .rk-toolbar[data-v-ad876ad1] {
3551
3669
  display: flex;
3552
3670
  align-items: center;
3553
3671
  gap: 0.375rem;
3554
3672
  }
3555
- .rk-toolbar.is-vertical[data-v-d49198bf] {
3673
+ .rk-toolbar.is-vertical[data-v-ad876ad1] {
3556
3674
  flex-direction: column;
3557
3675
  align-items: stretch;
3558
3676
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * What the keyboard can reach, as one selector.
3
+ *
4
+ * Three parts of the kit ask this question and each had written its own
5
+ * answer, which is how three answers came to differ: the dialog trap and
6
+ * the popover agreed, and `ScrollArea` left out `:not([disabled])`, so a
7
+ * box holding nothing but disabled buttons counted as reachable and was
8
+ * denied the focus stop that would have been its only way in.
9
+ *
10
+ * `summary` belongs here for the same reason it belonged in `ScrollArea`:
11
+ * a `<details>` heading takes focus, and a dialog whose trap skipped one
12
+ * would let Tab out of itself.
13
+ *
14
+ * Two things it deliberately does not do. It does not check whether an
15
+ * element is visible or inside an `inert` subtree — a selector cannot, and
16
+ * every caller here is already scoped to something on screen. And it is
17
+ * not what a roving-tabindex container should use to find its own
18
+ * controls: `[tabindex]:not([tabindex="-1"])` matches exactly the one
19
+ * control such a container has already put in the tab order, so it would
20
+ * find one item and then stop. `BaseToolbar` says so where it keeps its
21
+ * own.
22
+ */
23
+ export declare const FOCUSABLE = "a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, [tabindex]:not([tabindex=\"-1\"])";
24
+ /** The reachable elements inside `root`, in document order. */
25
+ export declare function focusableWithin(root: Element | null | undefined): HTMLElement[];
@@ -43,6 +43,7 @@ type __VLS_Props = {
43
43
  openDelay?: number | undefined;
44
44
  /** How long it survives the pointer leaving, so the card can be reached. */
45
45
  closeDelay?: number | undefined;
46
+ /** Which side it prefers. It opens on the other when there is more room there. */
46
47
  placement?: 'top' | 'bottom' | undefined;
47
48
  };
48
49
  type __VLS_Slots = {
package/dist/web.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as BaseCheckbox_default, c as useBoundValue, d as ensureSheetRoot, n as elementDirection, o as BaseSheet_default, r as horizontalStep, s as inertOutside, t as focusTarget } from "./focus-target-DRgd8UnQ.js";
2
- import { a as useMediaQuery, i as useMenuKeys, n as ScrollArea_default, r as BaseSkeleton_default, t as BaseListbox_default } from "./BaseListbox-BrIZxUmx.js";
2
+ import { a as BaseSkeleton_default, c as useMediaQuery, i as focusableWithin, n as ScrollArea_default, o as useMenuKeys, s as useAnchoredPanel, t as BaseListbox_default } from "./BaseListbox-BQoSwYdJ.js";
3
3
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BOaGB7Aw.js";
4
4
  import { t as BaseButton_default } from "./BaseButton-RN2an975.js";
5
5
  import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeModels, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, unref, useId, useModel, useTemplateRef, vModelText, vShow, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
@@ -310,6 +310,14 @@ var BaseHoverCard_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @
310
310
  setup(__props) {
311
311
  const id = useId();
312
312
  const open = ref(false);
313
+ const root = ref(null);
314
+ const panel = ref(null);
315
+ const { placed, shift } = useAnchoredPanel({
316
+ root,
317
+ panel,
318
+ open,
319
+ side: __props.placement
320
+ });
313
321
  let timer;
314
322
  function clear() {
315
323
  if (timer !== void 0) clearTimeout(timer);
@@ -349,6 +357,8 @@ var BaseHoverCard_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @
349
357
  onBeforeUnmount(clear);
350
358
  return (_ctx, _cache) => {
351
359
  return openBlock(), createElementBlock("div", {
360
+ ref_key: "root",
361
+ ref: root,
352
362
  class: "rk-hovercard",
353
363
  onPointerenter: show,
354
364
  onPointerleave: hide,
@@ -358,37 +368,22 @@ var BaseHoverCard_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @
358
368
  }, [renderSlot(_ctx.$slots, "default", { props: triggerProps.value }, void 0, true), open.value ? (openBlock(), createElementBlock("div", {
359
369
  key: 0,
360
370
  id: unref(id),
361
- class: normalizeClass(["rk-hovercard-panel surface-raised", `is-${__props.placement}`]),
371
+ ref_key: "panel",
372
+ ref: panel,
373
+ class: normalizeClass(["rk-hovercard-panel surface-raised", `is-${unref(placed)}`]),
374
+ style: normalizeStyle(unref(shift) ? { "--rk-hovercard-shift": `${unref(shift)}px` } : void 0),
362
375
  role: "group",
363
376
  "aria-label": __props.label
364
- }, [renderSlot(_ctx.$slots, "card", {}, void 0, true)], 10, _hoisted_1$15)) : createCommentVNode("", true)], 32);
377
+ }, [renderSlot(_ctx.$slots, "card", {}, void 0, true)], 14, _hoisted_1$15)) : createCommentVNode("", true)], 544);
365
378
  };
366
379
  }
367
- }), [["__scopeId", "data-v-70c09916"]]);
380
+ }), [["__scopeId", "data-v-d3c3b40f"]]);
368
381
  //#endregion
369
382
  //#region src/composables/use-dialog-shell.ts
370
- /**
371
- * What every modal surface has to do, in one place.
372
- *
373
- * A dialog, a drawer and anything else that takes the whole page share a
374
- * list that is easy to get nearly right: trap Tab, stop Escape, make the
375
- * rest of the page inert, stop it scrolling underneath, and hand focus back
376
- * to whatever opened it. Each of those has an order that matters, and the
377
- * orders are not obvious — releasing `inert` *after* restoring focus drops
378
- * it on the body, because an inert element cannot take focus. That was
379
- * written once, correctly, in `BaseModal`; a drawer that copied it would be
380
- * a second copy to keep correct.
381
- *
382
- * The Tab wrap has to be done by hand: the browser's own Tab order is the
383
- * whole document, and a dialog is only part of it. `inert` is what also
384
- * stops a screen reader's virtual cursor, which walks straight past a
385
- * keydown handler.
386
- */
387
- var FOCUSABLE$1 = "a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
388
383
  function useDialogShell(open, panel, { dismissible = () => true, onClose }) {
389
384
  let releaseInert = null;
390
385
  let restoreTo = null;
391
- const focusable = () => panel.value ? Array.from(panel.value.querySelectorAll(FOCUSABLE$1)) : [];
386
+ const focusable = () => panel.value ? focusableWithin(panel.value) : [];
392
387
  function onKeydown(event) {
393
388
  if (event.key === "Escape" && dismissible()) {
394
389
  event.stopPropagation();
@@ -1271,7 +1266,7 @@ var BaseToolbar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
1271
1266
  }, [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 42, _hoisted_1$8);
1272
1267
  };
1273
1268
  }
1274
- }), [["__scopeId", "data-v-d49198bf"]]);
1269
+ }), [["__scopeId", "data-v-ad876ad1"]]);
1275
1270
  //#endregion
1276
1271
  //#region src/web/BaseTree.vue?vue&type=script&setup=true&lang.ts
1277
1272
  var _hoisted_1$7 = ["aria-label", "aria-multiselectable"];