@acusti/dropdown 1.0.0-alpha.5 → 1.0.0-alpha.7

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/README.md CHANGED
@@ -524,7 +524,11 @@ Placement is best customized in CSS instead of props. The component exposes
524
524
  CSS custom properties for the most common low-level placement controls:
525
525
 
526
526
  - `--uktdd-body-position-area`
527
- - `--uktdd-body-position-try-fallbacks`
527
+ - `--uktdd-body-position-try-fallback-1` and
528
+ `--uktdd-body-position-try-fallback-2` (the two author fallbacks, tried
529
+ in order after the primary placement)
530
+ - `--uktdd-body-fill-fallbacks` (the last-resort fill placements, tried
531
+ when the body fits nowhere at its natural size)
528
532
  - `--uktdd-body-gap` (space between the trigger and the body)
529
533
  - `--uktdd-body-min-height`
530
534
  - `--uktdd-body-min-width`
@@ -536,8 +540,8 @@ Example:
536
540
  ```css
537
541
  .settings-dropdown {
538
542
  --uktdd-body-position-area: block-end span-inline-start;
539
- --uktdd-body-position-try-fallbacks:
540
- --uktdd-top-end, --uktdd-bottom-start, --uktdd-top-start;
543
+ --uktdd-body-position-try-fallback-1: --uktdd-top-end;
544
+ --uktdd-body-position-try-fallback-2: --uktdd-bottom-start;
541
545
  --uktdd-body-gap: 8px;
542
546
  }
543
547
 
@@ -551,15 +555,17 @@ placement and sizing control when a product surface needs it.
551
555
 
552
556
  ### Changing the Default Direction
553
557
 
554
- `--uktdd-body-position-area` and `--uktdd-body-position-try-fallbacks`
555
- always change together. `--uktdd-body-position-area` is the primary
556
- placement, used whenever it fits in the viewport — that’s what actually
557
- determines the direction a dropdown opens by default. The fallbacks list is
558
- only consulted when the primary placement doesn’t fit, so overriding it
559
- alone changes nothing in the common case where the primary already fits.
560
- Overriding the primary alone works, but leaves behind a fallback cascade
561
- tuned for the old primary — in a cramped viewport, the dropdown can fall
562
- back toward the direction you just moved away from.
558
+ `--uktdd-body-position-area` and its two fallback slots
559
+ (`--uktdd-body-position-try-fallback-1`,
560
+ `--uktdd-body-position-try-fallback-2`) always change together.
561
+ `--uktdd-body-position-area` is the primary placement, used whenever it
562
+ fits in the viewport — that’s what actually determines the direction a
563
+ dropdown opens by default. The fallback slots are tried in order only when
564
+ the primary placement doesn’t fit. Set all three together to ensure the
565
+ menu behaves the way you want it to in all possible contexts. If the new
566
+ direction has only one meaningful fallback (a centered menu, say), put it
567
+ in slot 1 and set slot 2 to the shipped no-op `--uktdd-noop` so it doesn’t
568
+ inherit that flip.
563
569
 
564
570
  The four `@position-try` blocks the component ships (`--uktdd-top-start`,
565
571
  `--uktdd-top-end`, `--uktdd-bottom-start`, `--uktdd-bottom-end`) are named
@@ -574,15 +580,21 @@ physical keyword on one axis with a logical one on the other — though
574
580
  `block-start`/`block-end` read as `top`/`bottom` in the near-universal
575
581
  horizontal-tb writing mode.
576
582
 
577
- Pick the row matching the direction you want, and set both variables to its
578
- pair:
583
+ Pick the row matching the direction you want, and set the three CSS custom
584
+ properties to the corresponding values:
579
585
 
580
- | Direction | `--uktdd-body-position-area` | `--uktdd-body-position-try-fallbacks` |
581
- | ----------------------------------- | ------------------------------- | ------------------------------------------------------------- |
582
- | Bottom, start-aligned (the default) | `block-end span-inline-end` | `--uktdd-top-start, --uktdd-bottom-end, --uktdd-top-end` |
583
- | Bottom, end-aligned | `block-end span-inline-start` | `--uktdd-top-end, --uktdd-bottom-start, --uktdd-top-start` |
584
- | Top, start-aligned | `block-start span-inline-end` | `--uktdd-bottom-start, --uktdd-top-end, --uktdd-bottom-end` |
585
- | Top, end-aligned | `block-start span-inline-start` | `--uktdd-bottom-end, --uktdd-top-start, --uktdd-bottom-start` |
586
+ | Direction | `--uktdd-body-position-area` | `…try-fallback-1` | `…try-fallback-2` |
587
+ | ----------------------------------- | ------------------------------- | ---------------------- | ---------------------- |
588
+ | Bottom, start-aligned (the default) | `block-end span-inline-end` | `--uktdd-top-start` | `--uktdd-bottom-end` |
589
+ | Bottom, end-aligned | `block-end span-inline-start` | `--uktdd-top-end` | `--uktdd-bottom-start` |
590
+ | Top, start-aligned | `block-start span-inline-end` | `--uktdd-bottom-start` | `--uktdd-top-end` |
591
+ | Top, end-aligned | `block-start span-inline-start` | `--uktdd-bottom-end` | `--uktdd-top-start` |
592
+
593
+ (The `…try-fallback-N` columns are `--uktdd-body-position-try-fallback-1`
594
+ and `-2`.)
595
+
596
+ The two Top rows should also flip the last-resort fill pair to match:
597
+ `--uktdd-body-fill-fallbacks: --uktdd-fill-top, --uktdd-fill-bottom`.
586
598
 
587
599
  For example, to make a dropdown open upward and end-aligned (useful for a
588
600
  trigger pinned to the bottom of the viewport, near the inline-end edge):
@@ -590,11 +602,17 @@ trigger pinned to the bottom of the viewport, near the inline-end edge):
590
602
  ```css
591
603
  .bottom-toolbar-dropdown {
592
604
  --uktdd-body-position-area: block-start span-inline-start;
593
- --uktdd-body-position-try-fallbacks:
594
- --uktdd-bottom-end, --uktdd-top-start, --uktdd-bottom-start;
605
+ --uktdd-body-position-try-fallback-1: --uktdd-bottom-end;
606
+ --uktdd-body-position-try-fallback-2: --uktdd-top-start;
607
+ --uktdd-body-fill-fallbacks: --uktdd-fill-top, --uktdd-fill-bottom;
595
608
  }
596
609
  ```
597
610
 
611
+ The last line flips the last-resort fill pair to match the recipe’s
612
+ direction: when the body is too tall to fit anywhere at its natural size,
613
+ it fills and scrolls on the upward side first (more on the fill pair
614
+ below).
615
+
598
616
  See the [`DirectionRecipes` story][] for a live demo of all four.
599
617
 
600
618
  [`DirectionRecipes` story]:
@@ -604,9 +622,77 @@ The primary placement wins whenever the body fits there at its natural
604
622
  size, then the fallbacks are tried in order — the body opens in the
605
623
  direction you asked for as long as that side can hold it, and never flips
606
624
  to the opposite side just because the viewport happens to have more empty
607
- space there. Only when the body fits in none of those placements does it
608
- size itself to the block-axis space its preferred side has and let the
609
- content scroll, so it never overflows the viewport or covers the trigger.
625
+ space there. Only when the body fits in none of those placements do the
626
+ `--uktdd-body-fill-fallbacks` placements
627
+ (`--uktdd-fill-bottom, --uktdd-fill-top` by default) take over: the body
628
+ sizes itself to the block-axis space below the trigger — or above it,
629
+ whichever the pair lists first that has room — and lets the content scroll,
630
+ so it never overflows the viewport or covers the trigger. A dropdown that
631
+ opens upward should flip the pair
632
+ (`--uktdd-body-fill-fallbacks: --uktdd-fill-top, --uktdd-fill-bottom`) so
633
+ the last-resort fill also prefers the upward side. In these fill placements
634
+ the body spans the trigger (centered over it, shifted inward as needed to
635
+ stay on-screen) rather than keeping the primary placement’s edge alignment.
636
+ Submenus have their own last-resort fills
637
+ ([`--uktdd-submenu-fill-fallbacks`](#submenu-placement-and-styling)) that
638
+ keep them beside the parent rather than covering it, so this pair applies
639
+ to the body alone.
640
+
641
+ In the fills, `--uktdd-body-min-height` marks a side as too cramped to
642
+ bother with: a fill whose side is shorter than it is rejected so the
643
+ roomier opposite side is tried. That floor is capped at the worst-case side
644
+ — half the viewport minus the trigger, the most a vertically centered
645
+ trigger can guarantee — so a min-height above half the viewport (honored in
646
+ full by the named placements) can’t reject both fills: the body fills the
647
+ roomier side and scrolls rather than overflowing.
648
+
649
+ There are exactly two author fallback slots by design. The
650
+ [CSS spec](https://drafts.csswg.org/css-anchor-position-1/#fallback-apply)
651
+ requires implementations to support at least five position options,
652
+ including the element’s base position, and `@acusti/dropdown` appends two
653
+ last-resort placements to the end, so that leaves two fallbacks that you
654
+ can specify, hence why they are exposed as two separate custom properties.
655
+ The two default slots are the single-axis flips of the primary (a block
656
+ flip and an inline flip); the mirror opposite diagonal is intentionally not
657
+ a slot, so that a trigger crammed into the corner diagonal to the primary
658
+ opening direction lands in a fill rather than a natural placement. See the
659
+ [recipes above](#changing-the-default-direction) for different common
660
+ placement scenarios. For a recipe with a single meaningful fallback (a
661
+ centered menu, say), set slot 1 and leave slot 2 as the shipped no-op
662
+ `--uktdd-noop`, so it doesn’t inherit the default’s flip.
663
+
664
+ ### Trading Trigger Coverage for a Full-Height Menu
665
+
666
+ The block-side fills never cover the trigger, which bounds their height by
667
+ where the trigger sits. When the body already fits horizontally, the opt-in
668
+ `--uktdd-fill-cover` placement (in no default list) can trade that
669
+ guarantee away: it keeps the strict start-aligned inline edge (compose
670
+ `--uktdd-fill-cover flip-inline` for end alignment) and loosens the block
671
+ axis instead, sizing the body to the viewport’s full block size — covering
672
+ the trigger — so a too-tall menu gets the whole viewport to scroll in
673
+ rather than one side of it.
674
+
675
+ ```css
676
+ .tall-menu {
677
+ --uktdd-body-position-try-fallback-1: --uktdd-top-start;
678
+ --uktdd-body-position-try-fallback-2: --uktdd-bottom-end;
679
+ --uktdd-body-fill-fallbacks:
680
+ --uktdd-fill-cover, --uktdd-fill-bottom, --uktdd-fill-top;
681
+ }
682
+ ```
683
+
684
+ The cover fill is rejected whenever the body is too wide for the region
685
+ between the trigger’s inline-start edge and the viewport edge, so the
686
+ guaranteed pair still rescues corner triggers — but the pair must stay
687
+ within the evaluation budget: with three fills you get at most two author
688
+ fallback slots, for six position options total. That’s the ceiling every
689
+ current engine clears (Chromium evaluates exactly six; Safari and Firefox
690
+ go well beyond), though only five are spec-guaranteed — drop to one author
691
+ fallback if you want the whole list within that floor. Two caveats: don’t
692
+ use it on searchable dropdowns, since the body overlays the trigger’s input
693
+ while open; and while the body covers the trigger, clicking the trigger’s
694
+ position hits the body instead — dismiss with Escape or a click elsewhere
695
+ outside.
610
696
 
611
697
  Use `--uktdd-body-gap` for the space between the trigger and the body. It
612
698
  is applied as a symmetric `margin-block`, so the gap lands on whichever
@@ -629,8 +715,8 @@ the menu size itself from its contents.
629
715
  ```css
630
716
  .avatar-menu {
631
717
  --uktdd-body-position-area: block-end span-inline-start;
632
- --uktdd-body-position-try-fallbacks:
633
- --uktdd-top-end, --uktdd-top-start, --uktdd-bottom-end;
718
+ --uktdd-body-position-try-fallback-1: --uktdd-top-end;
719
+ --uktdd-body-position-try-fallback-2: --uktdd-top-start;
634
720
  }
635
721
  ```
636
722
 
@@ -651,13 +737,17 @@ the trigger always overflows it — and `position-try` refuses to select a
651
737
  fallback that overflows, so a `bottom center` → `top center` setup never
652
738
  flips. `span-all` centers over the trigger identically but spans the full
653
739
  width, so it flips cleanly and clamps to the viewport near an edge. The
654
- menu opens below by default and flips above only when it doesn’t fit below;
655
- list the flipped fallback so that flip is available:
740
+ menu opens below by default and flips above only when it doesn’t fit below.
741
+ It has one meaningful fallback (the flipped centered placement), so set it
742
+ in slot 1 and leave slot 2 as the no-op — otherwise slot 2 keeps the
743
+ default’s corner flip and the menu can land off-center in a cramped
744
+ viewport:
656
745
 
657
746
  ```css
658
747
  .centered-menu {
659
748
  --uktdd-body-position-area: bottom span-all;
660
- --uktdd-body-position-try-fallbacks: --centered-menu-top;
749
+ --uktdd-body-position-try-fallback-1: --centered-menu-top;
750
+ --uktdd-body-position-try-fallback-2: --uktdd-noop;
661
751
  }
662
752
 
663
753
  /* define the flipped fallback in your own CSS */
@@ -778,7 +868,19 @@ it flush to the parent item’s edge across browsers. Placement custom
778
868
  properties follow the established naming scheme:
779
869
 
780
870
  - `--uktdd-submenu-position-area` (default: `inline-end span-block-end`)
781
- - `--uktdd-submenu-position-try-fallbacks`
871
+ - `--uktdd-submenu-position-try-fallback` (default:
872
+ `--uktdd-submenu-inline-start`; a single slot, not a list)
873
+ - `--uktdd-submenu-fill-fallbacks` (the last-resort fills for a submenu too
874
+ tall to open beside its parent at natural size; default
875
+ `--uktdd-submenu-fill, --uktdd-submenu-fill flip-inline` — a full-height
876
+ fill on each inline side that anchor-centers on the block axis, so the
877
+ submenu fills the viewport height beside the parent and scrolls rather
878
+ than covering the parent menu, the way macOS never covers a parent with
879
+ its submenu. Flip the pair for a submenu that opens `inline-start` by
880
+ default. A submenu wider than the space on either side of its parent is
881
+ the one case this default doesn’t handle; append
882
+ `--uktdd-fill-bottom, --uktdd-fill-top` here to restore the
883
+ parent-covering rescue if you need it)
782
884
  - `--uktdd-submenu-gap` (space between the parent item and the submenu;
783
885
  applied as a symmetric `margin-inline`, the inline-axis counterpart to
784
886
  `--uktdd-body-gap`, so it auto-reverses when the submenu flips to the