@reliability-design/web 1.4.3 → 1.4.5

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.
Files changed (48) hide show
  1. package/dist/components/rel-accordion/rel-accordion.ts +13 -1
  2. package/dist/components/rel-autocomplete/README.md +1 -0
  3. package/dist/components/rel-autocomplete/rel-autocomplete.ts +56 -1
  4. package/dist/components/rel-button/rel-button.ts +18 -2
  5. package/dist/components/rel-calendar/rel-calendar.ts +23 -1
  6. package/dist/components/rel-carousel/rel-carousel.ts +20 -0
  7. package/dist/components/rel-checkbox/README.md +69 -22
  8. package/dist/components/rel-checkbox/rel-checkbox.ts +119 -9
  9. package/dist/components/rel-chip/rel-chip.ts +29 -0
  10. package/dist/components/rel-date-picker/rel-date-picker.ts +156 -13
  11. package/dist/components/rel-drawer/rel-drawer.ts +22 -58
  12. package/dist/components/rel-menu/rel-menu.ts +124 -15
  13. package/dist/components/rel-menubar/rel-menubar.ts +221 -63
  14. package/dist/components/rel-nav-menu/rel-nav-menu.ts +39 -3
  15. package/dist/components/rel-otp/rel-otp.ts +3 -3
  16. package/dist/components/rel-pagination/README.md +14 -0
  17. package/dist/components/rel-pagination/rel-pagination.ts +30 -14
  18. package/dist/components/rel-popover/rel-popover.ts +31 -3
  19. package/dist/components/rel-range-picker/rel-range-picker.ts +251 -3
  20. package/dist/components/rel-resizable/rel-resizable-group.ts +20 -0
  21. package/dist/components/rel-segmented-button/rel-segmented-button.ts +50 -12
  22. package/dist/components/rel-select/README.md +1 -0
  23. package/dist/components/rel-select/rel-select.ts +1385 -1170
  24. package/dist/components/rel-sheet/rel-sheet.ts +22 -1
  25. package/dist/components/rel-sidebar/rel-sidebar.ts +43 -39
  26. package/dist/components/rel-stepper/rel-stepper.ts +44 -1
  27. package/dist/components/rel-tab/rel-tab.ts +32 -7
  28. package/dist/components/rel-time-picker/rel-time-picker.ts +338 -206
  29. package/dist/components/rel-tooltip/rel-tooltip.ts +30 -0
  30. package/dist/components/rel-topbar/rel-topbar-actions.ts +1 -1
  31. package/dist/components/rel-topbar/rel-topbar-brand.ts +1 -1
  32. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +1 -1
  33. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +1 -1
  34. package/dist/components/rel-topbar/rel-topbar-item.ts +318 -319
  35. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +1 -1
  36. package/dist/components/rel-topbar/rel-topbar-profile.ts +224 -224
  37. package/dist/components/rel-topbar/rel-topbar-utilities.ts +1 -1
  38. package/dist/components/rel-topbar/rel-topbar.ts +440 -440
  39. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +134 -0
  40. package/dist/components/rel-upload/rel-upload-actions.ts +163 -0
  41. package/dist/components/rel-upload/rel-upload.ts +943 -0
  42. package/dist/index.d.mts +491 -18
  43. package/dist/index.d.ts +491 -18
  44. package/dist/index.js +2748 -410
  45. package/dist/index.js.map +1 -1
  46. package/dist/index.mjs +2953 -627
  47. package/dist/index.mjs.map +1 -1
  48. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -11,6 +11,8 @@ declare class RelAccordion extends LitElement {
11
11
  /** Figma "Style" axis — named appearance because `style` collides with the HTML style attribute. */
12
12
  appearance: "shadow" | "plain";
13
13
  static styles: lit.CSSResult;
14
+ /** Stable id prefix wiring the header to its panel. */
15
+ private accordionId;
14
16
  private toggle;
15
17
  render(): lit_html.TemplateResult<1>;
16
18
  }
@@ -213,6 +215,8 @@ declare class RelAutocomplete extends LitElement {
213
215
  private onPageScroll;
214
216
  private openPanel;
215
217
  private closePanel;
218
+ private showNativePopover;
219
+ private hideNativePopover;
216
220
  private updatePosition;
217
221
  /** Re-evaluates whether the panel should be showing for the current state. */
218
222
  private syncPanel;
@@ -354,6 +358,13 @@ declare class RelCalendar extends LitElement {
354
358
  private nextMonth;
355
359
  private selectDay;
356
360
  private handleKeyDown;
361
+ /**
362
+ * Index of the single grid cell carrying tabindex="0". The old expression
363
+ * (`isSelected || (index === 0 && !focusedDate)`) left the grid with ZERO
364
+ * tab stops once the user arrowed around without a selection — Tab could
365
+ * never re-enter the calendar.
366
+ */
367
+ private getRovingIndex;
357
368
  render(): lit_html.TemplateResult<1>;
358
369
  }
359
370
 
@@ -422,6 +433,8 @@ declare class RelCarousel extends LitElement {
422
433
  private handlePointerMove;
423
434
  private handlePointerUp;
424
435
  private handleKeyDown;
436
+ private handleFocusIn;
437
+ private handleFocusOut;
425
438
  private handleMouseEnter;
426
439
  private handleMouseLeave;
427
440
  updated(changedProperties: Map<string, any>): void;
@@ -443,6 +456,9 @@ declare class RelCardMedia extends LitElement {
443
456
 
444
457
  type CheckboxState = "default" | "error" | "disabled";
445
458
  type CheckboxStatus = "unchecked" | "checked" | "indeterminate";
459
+ type CheckboxSize = "small" | "medium";
460
+ type CheckboxDensity = "compact" | "comfortable";
461
+ type CheckboxAlignment = "leading" | "trailing";
446
462
  declare class RelCheckbox extends LitElement {
447
463
  label: string;
448
464
  /** rel-icon name rendered between the checkbox and the label (label prefix icon). */
@@ -451,11 +467,26 @@ declare class RelCheckbox extends LitElement {
451
467
  state: CheckboxState;
452
468
  status: CheckboxStatus;
453
469
  value: string;
470
+ /** Control scale (Figma Size). `"medium"` (default) = 18px box with body-lg
471
+ * label; `"small"` = 14px box with body-md label. */
472
+ size: CheckboxSize;
473
+ /** Supporting-text layout (Figma Density). `"compact"` (default) puts the
474
+ * supporting text on its own line under the row, indented past the box;
475
+ * `"comfortable"` stacks label + supporting text beside the box. */
476
+ density: CheckboxDensity;
477
+ /** Box position (Figma Alignment). `"leading"` (default) renders the box
478
+ * before the label; `"trailing"` pushes it to the far edge of the row.
479
+ * Trailing has no compact layout in the spec, so it always renders with
480
+ * comfortable density. */
481
+ alignment: CheckboxAlignment;
454
482
  get checked(): boolean;
455
483
  set checked(val: boolean);
456
484
  private _onChange;
457
485
  private _onTouched;
458
486
  static styles: lit.CSSResult;
487
+ protected willUpdate(changed: PropertyValues<this>): void;
488
+ /** Trailing has no compact layout in the spec — trailing wins. */
489
+ private get effectiveDensity();
459
490
  private toggle;
460
491
  registerOnChange(fn: (value: boolean) => void): void;
461
492
  registerOnTouched(fn: () => void): void;
@@ -532,8 +563,17 @@ declare class RelDatePicker extends LitElement {
532
563
  private handleDayKeydown;
533
564
  private toggleMonthDropdown;
534
565
  private toggleYearDropdown;
566
+ private handleDropdownTriggerKeydown;
567
+ private focusOpenDropdownSelection;
568
+ private handleDropdownKeydown;
535
569
  private selectMonth;
536
570
  private selectYear;
571
+ /**
572
+ * Index of the single grid cell carrying tabindex="0". The old expression
573
+ * (`isSelected || (index === 0 && !value)`) left the grid with ZERO tab
574
+ * stops once the user arrowed around without a selection.
575
+ */
576
+ private getRovingIndex;
537
577
  render(): lit_html.TemplateResult<1>;
538
578
  }
539
579
 
@@ -562,11 +602,19 @@ declare class RelRangePicker extends LitElement {
562
602
  private viewMonth;
563
603
  private isSelectingRange;
564
604
  private hoverDate;
605
+ /** ISO date of the cell that owns the grid's single Tab stop (roving tabindex). */
606
+ private focusedDate;
565
607
  private triggerButton?;
608
+ private popoverEl?;
609
+ private backdropEl?;
566
610
  static styles: lit.CSSResult;
567
611
  connectedCallback(): void;
568
612
  disconnectedCallback(): void;
569
- updated(): void;
613
+ updated(changed: Map<string, unknown>): void;
614
+ private showTopLayer;
615
+ private hideTopLayer;
616
+ private onReposition;
617
+ private updatePopoverPosition;
570
618
  private handleClickOutside;
571
619
  private handleGlobalKeydown;
572
620
  private toggleOpen;
@@ -591,6 +639,14 @@ declare class RelRangePicker extends LitElement {
591
639
  private getCalendarDays;
592
640
  private handleDayClick;
593
641
  private handleDayHover;
642
+ /**
643
+ * The cell that carries tabindex="0". Prefers the last roved date, then the
644
+ * draft start, then today, then the first selectable day — always exactly
645
+ * one Tab stop, even after arrowing away with nothing selected.
646
+ */
647
+ private getRovingIso;
648
+ private handleGridKeydown;
649
+ private moveGridFocusTo;
594
650
  render(): lit_html.TemplateResult<1>;
595
651
  }
596
652
  declare global {
@@ -625,6 +681,12 @@ declare class RelChip extends LitElement {
625
681
  static styles: lit.CSSResult;
626
682
  private get classes();
627
683
  private handleRemove;
684
+ /** The chip body is announced as a button, so it must also act on keys:
685
+ * Enter/Space re-dispatch as a host click (consumers' @click handlers
686
+ * fire), Delete/Backspace remove when removable, and arrow keys ask the
687
+ * container to reorder a draggable chip (`chip-move`) — the keyboard
688
+ * alternative to pointer drag-and-drop. */
689
+ private handleKeydown;
628
690
  private onDragStart;
629
691
  private onDragEnd;
630
692
  protected updated(changed: Map<string, unknown>): void;
@@ -697,7 +759,6 @@ declare class RelDrawer extends LitElement {
697
759
  private handleClose;
698
760
  private lockScroll;
699
761
  private unlockScroll;
700
- private getFocusableElements;
701
762
  private handleKeydown;
702
763
  private handleOverlayClick;
703
764
  private handleCloseButtonClick;
@@ -778,6 +839,7 @@ declare class RelStepper extends LitElement {
778
839
  private isProgress;
779
840
  private isDisabled;
780
841
  private getStepClasses;
842
+ private onStepKeyDown;
781
843
  private onStepClick;
782
844
  private renderIndicator;
783
845
  render(): lit_html.TemplateResult<1>;
@@ -837,8 +899,12 @@ declare class RelMenu extends LitElement {
837
899
  type: MenuType;
838
900
  items: MenuItem[];
839
901
  private focusedIndex;
902
+ /** Index inside the open submenu that virtual focus sits on; -1 = main list. */
903
+ private subFocusedIndex;
840
904
  private _items;
841
- static readonly _css = "\n :host {\n color: var(--rel-text-default);\n display: inline-block;\n }\n\n .rel-menu {\n position: relative;\n display: inline-block;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n border-radius: var(--rel-border-radius-md);\n box-shadow: var(--rel-shadows-shadow-300);\n min-width: 220px;\n /* No vertical padding: items fill edge-to-edge so a first/last-item hover\n reaches the menu's top/bottom. NOT overflow:hidden \u2014 that clips the\n type=arrow flyout (position:absolute at left:100%). Instead the first\n and last items carry the outer corner radius so hover backgrounds clip\n to the rounded shape without any overflow. */\n padding: 0;\n outline: none;\n overflow: visible;\n font-family: var(--rel-body-lg-regular-font-family);\n font-weight: var(--rel-body-lg-regular-font-weight);\n font-size: var(--rel-body-lg-regular-font-size);\n line-height: var(--rel-body-lg-regular-line-height);\n letter-spacing: var(--rel-body-lg-regular-letter-spacing);\n }\n\n .rel-menu:focus-visible,\n :host(:focus-visible) .rel-menu {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: 2px;\n }\n\n .rel-menu-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-xs);\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n line-height: var(--rel-body-sm-regular-line-height);\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n }\n\n /* First/last items carry the menu's outer radius so their hover fill clips\n to the rounded corners (replaces the removed overflow:hidden). */\n .rel-menu > .rel-menu-item:first-child {\n border-top-left-radius: var(--rel-border-radius-md);\n border-top-right-radius: var(--rel-border-radius-md);\n }\n\n .rel-menu > .rel-menu-item:last-child {\n border-bottom-left-radius: var(--rel-border-radius-md);\n border-bottom-right-radius: var(--rel-border-radius-md);\n }\n\n .rel-menu-item:hover {\n background: var(--rel-bg-neutral-elevated-1);\n }\n\n .rel-menu-item:active {\n background: var(--rel-bg-neutral-elevated-1);\n }\n\n .rel-menu-item.active {\n background: var(--rel-bg-neutral-elevated-2);\n font-weight: var(--rel-body-lg-medium-font-weight);\n }\n\n .rel-menu-item.disabled {\n background-color: transparent;\n color: var(--rel-text-disabled);\n /* Keep the item pointer-interactive so cursor:not-allowed actually\n renders; clicks are already neutralised by the item.disabled guard in\n onItemClick/onItemEnter. pointer-events:none here would make the row\n transparent to the pointer and suppress the cursor. */\n cursor: not-allowed;\n }\n\n .rel-menu-item[data-focused=\"true\"] {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: -2px;\n }\n\n /* Width modes (Figma Type=Fixed / Type=Fit) */\n .rel-menu.fixed {\n width: var(--rel-menu-width, 300px);\n min-width: 0;\n box-sizing: border-box;\n }\n\n .rel-menu.fit {\n min-width: 0;\n width: max-content;\n }\n\n /* Checkbox (Type=Checkbox) / radio (Type=Select Option) rows render the real\n rel-checkbox / rel-radio. pointer-events:none keeps the whole row the click\n target so onItemClick stays the single source of truth. */\n .menu-control {\n pointer-events: none;\n width: 100%;\n }\n\n .menu-label {\n flex: 1 1 auto;\n }\n\n /* Submenu affordance \u2014 same rel-icon chevron the menubar uses. */\n .submenu-chevron {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n opacity: 0.6;\n pointer-events: none;\n }\n\n /* Shortcut / hint text (Figma body-sm-regular, caption tone) */\n .menu-shortcut,\n ::slotted([slot=\"shortcut\"]) {\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n color: var(--rel-text-caption);\n margin-left: auto;\n padding-left: var(--rel-spacing-md);\n }\n\n \n .rel-submenu {\n border: 1px solid var(--rel-border-subtle);\n position: absolute;\n top: calc(-1 * var(--rel-spacing-3xs));\n /* flush against the trigger (no gap) so moving the pointer into the flyout\n never crosses a dead zone that would fire the trigger's mouseleave */\n left: 100%;\n min-width: 200px;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n border-radius: var(--rel-border-radius-md);\n box-shadow: var(--rel-shadows-shadow-300);\n /* padding:0 + overflow:hidden \u2014 safe here (a submenu has no further nested\n flyout to clip) \u2014 so sub-item hovers fill fully and clip to the corners */\n padding: 0;\n overflow: hidden;\n visibility: hidden;\n pointer-events: none;\n z-index: 20;\n }\n\n .rel-submenu.visible {\n visibility: visible;\n pointer-events: auto;\n }\n\n .rel-submenu .rel-menu-item {\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n }\n ";
905
+ /** Stable id prefix for aria-activedescendant targets. */
906
+ private menuId;
907
+ static readonly _css = "\n :host {\n color: var(--rel-text-default);\n display: inline-block;\n }\n\n .rel-menu {\n position: relative;\n display: inline-block;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n border-radius: var(--rel-border-radius-md);\n box-shadow: var(--rel-shadows-shadow-300);\n min-width: 220px;\n /* No vertical padding: items fill edge-to-edge so a first/last-item hover\n reaches the menu's top/bottom. NOT overflow:hidden \u2014 that clips the\n type=arrow flyout (position:absolute at left:100%). Instead the first\n and last items carry the outer corner radius so hover backgrounds clip\n to the rounded shape without any overflow. */\n padding: 0;\n outline: none;\n overflow: visible;\n font-family: var(--rel-body-lg-regular-font-family);\n font-weight: var(--rel-body-lg-regular-font-weight);\n font-size: var(--rel-body-lg-regular-font-size);\n line-height: var(--rel-body-lg-regular-line-height);\n letter-spacing: var(--rel-body-lg-regular-letter-spacing);\n }\n\n .rel-menu:focus-visible,\n :host(:focus-visible) .rel-menu {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: 2px;\n }\n\n .rel-menu-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-xs);\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n line-height: var(--rel-body-sm-regular-line-height);\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n }\n\n /* First/last items carry the menu's outer radius so their hover fill clips\n to the rounded corners (replaces the removed overflow:hidden). */\n .rel-menu > .rel-menu-item:first-child {\n border-top-left-radius: var(--rel-border-radius-md);\n border-top-right-radius: var(--rel-border-radius-md);\n }\n\n .rel-menu > .rel-menu-item:last-child {\n border-bottom-left-radius: var(--rel-border-radius-md);\n border-bottom-right-radius: var(--rel-border-radius-md);\n }\n\n .rel-menu-item:hover {\n background: var(--rel-bg-neutral-elevated-1);\n }\n\n .rel-menu-item:active {\n background: var(--rel-bg-neutral-elevated-1);\n }\n\n .rel-menu-item.active {\n background: var(--rel-bg-neutral-elevated-2);\n font-weight: var(--rel-body-lg-medium-font-weight);\n }\n\n .rel-menu-item.disabled {\n background-color: transparent;\n color: var(--rel-text-disabled);\n /* Keep the item pointer-interactive so cursor:not-allowed actually\n renders; clicks are already neutralised by the item.disabled guard in\n onItemClick/onItemEnter. pointer-events:none here would make the row\n transparent to the pointer and suppress the cursor. */\n cursor: not-allowed;\n }\n\n /* [data-focused] (presence, not =\"true\"): the ?data-focused boolean\n binding renders the attribute with an EMPTY value, so a =\"true\"\n selector never matches. */\n .rel-menu-item[data-focused] {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: -2px;\n }\n\n /* Width modes (Figma Type=Fixed / Type=Fit) */\n .rel-menu.fixed {\n width: var(--rel-menu-width, 300px);\n min-width: 0;\n box-sizing: border-box;\n }\n\n .rel-menu.fit {\n min-width: 0;\n width: max-content;\n }\n\n /* Checkbox (Type=Checkbox) / radio (Type=Select Option) rows render the real\n rel-checkbox / rel-radio. pointer-events:none keeps the whole row the click\n target so onItemClick stays the single source of truth. */\n .menu-control {\n pointer-events: none;\n width: 100%;\n }\n\n .menu-label {\n flex: 1 1 auto;\n }\n\n /* Submenu affordance \u2014 same rel-icon chevron the menubar uses. */\n .submenu-chevron {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n opacity: 0.6;\n pointer-events: none;\n }\n\n /* Shortcut / hint text (Figma body-sm-regular, caption tone) */\n .menu-shortcut,\n ::slotted([slot=\"shortcut\"]) {\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n color: var(--rel-text-caption);\n margin-left: auto;\n padding-left: var(--rel-spacing-md);\n }\n\n \n .rel-submenu {\n border: 1px solid var(--rel-border-subtle);\n position: absolute;\n top: calc(-1 * var(--rel-spacing-3xs));\n /* flush against the trigger (no gap) so moving the pointer into the flyout\n never crosses a dead zone that would fire the trigger's mouseleave */\n left: 100%;\n min-width: 200px;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n border-radius: var(--rel-border-radius-md);\n box-shadow: var(--rel-shadows-shadow-300);\n /* padding:0 + overflow:hidden \u2014 safe here (a submenu has no further nested\n flyout to clip) \u2014 so sub-item hovers fill fully and clip to the corners */\n padding: 0;\n overflow: hidden;\n visibility: hidden;\n pointer-events: none;\n z-index: 20;\n }\n\n .rel-submenu.visible {\n visibility: visible;\n pointer-events: auto;\n }\n\n .rel-submenu .rel-menu-item {\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n }\n ";
842
908
  createRenderRoot(): this;
843
909
  connectedCallback(): void;
844
910
  disconnectedCallback(): void;
@@ -850,19 +916,35 @@ declare class RelMenu extends LitElement {
850
916
  private onItemLeave;
851
917
  private onItemClick;
852
918
  private onSubClick;
919
+ /** Keyboard-open locks the submenu (no hover-out to close it) and moves
920
+ * virtual focus onto its first entry. */
921
+ private openSubmenuAt;
922
+ private closeSubmenus;
853
923
  private onKeydown;
854
924
  private renderMenuItem;
855
925
  render(): lit_html.TemplateResult<1>;
856
926
  }
857
927
 
858
928
  declare class RelMenubar extends LitElement {
929
+ /**
930
+ * Opt-in: actually BIND the keys declared via data-shortcut (e.g.
931
+ * data-shortcut="Ctrl+Z"), not just display them. "Ctrl" matches Cmd on
932
+ * Apple platforms when written as "Mod". Keystrokes originating in
933
+ * inputs/textareas/contenteditable are ignored.
934
+ */
935
+ bindShortcuts: boolean;
859
936
  private menus;
860
937
  private openMenuIndex;
861
938
  private focusedTriggerIndex;
862
939
  private focusedItemIndex;
940
+ /** Virtual-focus index inside the open submenu; -1 = focus is in the panel. */
941
+ private focusedSubItemIndex;
863
942
  private openSubmenuElement;
864
943
  private hoverSwitchEnabled;
865
944
  private _onScroll?;
945
+ /** Stable id prefix for aria-activedescendant targets (light DOM, so ids
946
+ * must be unique per menubar instance on the page). */
947
+ private menubarId;
866
948
  static readonly _css = "\n /* This component renders into LIGHT DOM (createRenderRoot returns this), so\n :host / <slot> don't work here \u2014 the raw <rel-menubar-menu> definitions\n are data holders that must be hidden with a plain selector. Relying on the\n global rel-menubar-menu.css is not enough: it can't cross a consumer's\n shadow boundary AND it's a no-op in the tsup-built package (css:\"copy\"). */\n rel-menubar {\n color: var(--rel-text-default);\n display: block;\n }\n\n rel-menubar-menu {\n display: none;\n }\n\n .menubar-container {\n display: flex;\n align-items: stretch;\n background: var(--rel-bg-surface-elevated);\n border: var(--rel-stroke-sm) solid var(--rel-border-default);\n border-radius: var(--rel-border-radius-sm);\n overflow: hidden;\n padding: 0;\n gap: var(--rel-spacing-3xs);\n height: 40px;\n width: fit-content;\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n }\n\n .menubar-trigger {\n display: flex;\n align-items: center;\n align-self: stretch;\n height: 100%;\n padding: 0 var(--rel-spacing-sm);\n background: transparent;\n border: none;\n cursor: pointer;\n font-family: inherit;\n font-size: inherit;\n color: var(--rel-text-label);\n transition: background 0.15s ease;\n user-select: none;\n outline: none;\n }\n\n .menubar-trigger:hover,\n .menubar-trigger.active {\n background: var(--rel-bg-neutral-elevated-2);\n }\n\n .menubar-trigger:focus-visible {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: 2px;\n }\n\n .menubar-panel {\n position: fixed;\n min-width: 220px;\n background: var(--rel-bg-surface);\n border: var(--rel-stroke-sm) solid var(--rel-border-default);\n border-radius: var(--rel-border-radius-sm);\n box-shadow: var(--rel-shadows-shadow-300);\n padding: 0;\n overflow: hidden;\n z-index: 1000;\n display: none;\n }\n\n .menubar-panel.open {\n display: block;\n }\n\n .menu-item {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--rel-spacing-sm);\n padding: var(--rel-spacing-xs) var(--rel-spacing-md);\n cursor: pointer;\n transition: background 0.15s ease;\n user-select: none;\n color: var(--rel-text-label);\n line-height: var(--rel-body-sm-regular-line-height);\n }\n\n .menu-item:hover,\n .menu-item.focused {\n background: var(--rel-bg-neutral-elevated-2);\n }\n\n .menu-item[data-disabled=\"true\"] {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .menu-separator {\n height: var(--rel-stroke-sm);\n background: var(--rel-border-default);\n margin: 0;\n padding: 0;\n }\n\n rel-icon {\n display: inline-flex;\n pointer-events: none;\n }\n\n .menu-submenu-trigger {\n position: relative;\n }\n\n .menu-submenu-trigger rel-icon {\n opacity: 0.6;\n }\n\n .submenu-panel {\n position: fixed;\n min-width: 200px;\n background: var(--rel-bg-surface);\n border: var(--rel-stroke-sm) solid var(--rel-border-default);\n border-radius: var(--rel-border-radius-sm);\n box-shadow: var(--rel-shadows-shadow-300);\n padding: 0;\n overflow: hidden;\n z-index: 1001;\n display: none;\n }\n\n .submenu-panel.open {\n display: block;\n }\n\n .menu-shortcut {\n opacity: 0.6;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-3xs);\n font-family: var(--rel-body-xs-regular-font-family);\n font-weight: var(--rel-body-xs-regular-font-weight);\n font-size: var(--rel-body-xs-regular-font-size);\n line-height: var(--rel-body-xs-regular-line-height);\n letter-spacing: var(--rel-body-xs-regular-letter-spacing);\n }\n\n .menubar-panel rel-checkbox {\n display: block;\n width: 100%;\n padding: var(--rel-spacing-xs, 8px) var(--rel-spacing-md, 16px);\n box-sizing: border-box;\n cursor: pointer;\n }\n ";
867
949
  createRenderRoot(): this;
868
950
  connectedCallback(): void;
@@ -870,17 +952,24 @@ declare class RelMenubar extends LitElement {
870
952
  private _repositionOpenSubmenu;
871
953
  private _repositionOpenMenu;
872
954
  private discoverMenus;
955
+ private handleShortcutKeyDown;
873
956
  private handleOutsideClick;
874
957
  private closeAllMenus;
958
+ /** Close everything and put DOM focus back on the trigger that owned the
959
+ * open menu. (Capturing the index BEFORE closing — closeAllMenus resets
960
+ * openMenuIndex to -1, which used to drop focus to <body>.) */
961
+ private closeAllMenusAndRefocusTrigger;
875
962
  private openMenu;
876
963
  private handleTriggerClick;
877
964
  private handleTriggerMouseEnter;
878
965
  private handleTriggerKeyDown;
879
966
  private focusTrigger;
880
967
  private handlePanelKeyDown;
968
+ private getSubmenuItems;
881
969
  private getFocusableItems;
882
970
  private focusMenuItem;
883
971
  private handleItemClick;
972
+ private dispatchSelectEvent;
884
973
  private openSubmenu;
885
974
  private handleSubmenuItemClick;
886
975
  private dispatchChangeEvent;
@@ -912,7 +1001,7 @@ declare class RelNavbar extends LitElement {
912
1001
 
913
1002
  /**
914
1003
  * @deprecated Part of the deprecated rel-topbar family. Use a plain
915
- * `<a>`/logo markup inside the "App Topbar" recipe at /docs/recipes/app-topbar.
1004
+ * `<a>`/logo markup inside the "Navbar" recipe at /docs/recipes/navbar.
916
1005
  */
917
1006
  declare class RelTopbarBrand extends LitElement {
918
1007
  src: string;
@@ -929,7 +1018,7 @@ declare global {
929
1018
 
930
1019
  /**
931
1020
  * @deprecated Part of the deprecated rel-topbar family. Use plain
932
- * `rel-button` elements inside the "App Topbar" recipe at /docs/recipes/app-topbar.
1021
+ * `rel-button` elements inside the "Navbar" recipe at /docs/recipes/navbar.
933
1022
  */
934
1023
  declare class RelTopbarActions extends LitElement {
935
1024
  static styles: lit.CSSResult;
@@ -943,7 +1032,7 @@ declare global {
943
1032
 
944
1033
  /**
945
1034
  * @deprecated Part of the deprecated rel-topbar family. Use plain
946
- * `rel-button` (icon variant) elements inside the "App Topbar" recipe at /docs/recipes/app-topbar.
1035
+ * `rel-button` (icon variant) elements inside the "Navbar" recipe at /docs/recipes/navbar.
947
1036
  */
948
1037
  declare class RelTopbarUtilities extends LitElement {
949
1038
  static styles: lit.CSSResult;
@@ -957,7 +1046,7 @@ declare global {
957
1046
 
958
1047
  /**
959
1048
  * @deprecated Part of the deprecated rel-topbar family. Use `rel-drawer`
960
- * for the mobile nav panel in the "App Topbar" recipe at /docs/recipes/app-topbar.
1049
+ * for the mobile nav panel in the "Navbar" recipe at /docs/recipes/navbar.
961
1050
  */
962
1051
  declare class RelTopbarMobilePanel extends LitElement {
963
1052
  static styles: lit.CSSResult;
@@ -971,7 +1060,7 @@ declare global {
971
1060
 
972
1061
  /**
973
1062
  * @deprecated Part of the deprecated rel-topbar family. Use `rel-menu` or
974
- * `rel-popover` for nav dropdowns in the "App Topbar" recipe at /docs/recipes/app-topbar.
1063
+ * `rel-popover` for nav dropdowns in the "Navbar" recipe at /docs/recipes/navbar.
975
1064
  */
976
1065
  declare class RelTopbarDropdown extends LitElement {
977
1066
  static styles: lit.CSSResult;
@@ -985,7 +1074,7 @@ declare global {
985
1074
 
986
1075
  /**
987
1076
  * @deprecated Part of the deprecated rel-topbar family. Use `rel-menu`'s
988
- * item slots or `rel-popover` content in the "App Topbar" recipe at /docs/recipes/app-topbar.
1077
+ * item slots or `rel-popover` content in the "Navbar" recipe at /docs/recipes/navbar.
989
1078
  */
990
1079
  declare class RelTopbarDropdownItem extends LitElement {
991
1080
  label: string;
@@ -1008,7 +1097,7 @@ type TopbarForceLayout = "auto" | "desktop" | "tablet" | "mobile";
1008
1097
  *
1009
1098
  * @deprecated This component's fixed slot structure, hardcoded breakpoint,
1010
1099
  * and built-in overflow logic are too rigid for most real layouts. Use the
1011
- * "App Topbar" recipe at /docs/recipes/app-topbar instead, composed from
1100
+ * "Navbar" recipe at /docs/recipes/navbar instead, composed from
1012
1101
  * rel-menu/rel-popover, rel-drawer, and rel-button. Still supported, but
1013
1102
  * will be removed in a future major version.
1014
1103
  *
@@ -1061,8 +1150,7 @@ declare class RelTopbar extends LitElement {
1061
1150
  /**
1062
1151
  * `rel-topbar-item` — A navigation item within rel-topbar.
1063
1152
  *
1064
- * @deprecated Part of the deprecated rel-topbar family. Use the "App
1065
- * Topbar" recipe at /docs/recipes/app-topbar, which composes nav links and
1153
+ * @deprecated Part of the deprecated rel-topbar family. Use the "Navbar" recipe at /docs/recipes/navbar, which composes nav links and
1066
1154
  * `rel-menu`/`rel-popover` dropdowns directly instead of a dedicated item component.
1067
1155
  *
1068
1156
  * Renders as an `<a>` when `href` is supplied, otherwise a `<button>`.
@@ -1112,7 +1200,7 @@ type TopbarRewardTier = "gold" | "silver" | "platinum" | "bronze" | "regular";
1112
1200
  * `rel-topbar-profile` — Profile / user tile for the topbar right region.
1113
1201
  *
1114
1202
  * @deprecated Part of the deprecated rel-topbar family. Compose `rel-avatar`
1115
- * directly inside the "App Topbar" recipe at /docs/recipes/app-topbar.
1203
+ * directly inside the "Navbar" recipe at /docs/recipes/navbar.
1116
1204
  *
1117
1205
  * type="avatar" Customer avatar with initials circle + optional name/subtitle.
1118
1206
  * type="carrier" Carrier reward tile with reward-tier badge + name/subtitle.
@@ -1212,6 +1300,9 @@ declare class RelPagination extends LitElement {
1212
1300
  private get activePage();
1213
1301
  private get computedTotalPages();
1214
1302
  private generatePageNumbers;
1303
+ /** Abbreviate large page numbers (368178 → "368k") so buttons stay compact.
1304
+ Exact below 10,000; floored to k up to 1M; then M with one decimal. */
1305
+ private formatPageLabel;
1215
1306
  private handlePageChange;
1216
1307
  private renderChevronLeft;
1217
1308
  private renderChevronRight;
@@ -1250,6 +1341,7 @@ declare class RelPopover extends LitElement {
1250
1341
  private get activeOpen();
1251
1342
  private setOpen;
1252
1343
  private onHostPointerDown;
1344
+ private onHostKeyDown;
1253
1345
  private onOpen;
1254
1346
  private onClose;
1255
1347
  private showNativePopover;
@@ -1377,6 +1469,9 @@ declare class RelSegmentedButton extends LitElement {
1377
1469
  align: SegmentAlign;
1378
1470
  static styles: lit.CSSResult;
1379
1471
  private setActive;
1472
+ /** APG radio-group navigation: arrows move focus AND select, the group is
1473
+ * one Tab stop (roving tabindex on the selected segment). */
1474
+ private onKeyDown;
1380
1475
  private renderSegment;
1381
1476
  render(): lit_html.TemplateResult<1>;
1382
1477
  }
@@ -1430,6 +1525,10 @@ declare class RelSelect extends LitElement {
1430
1525
  noSearch: boolean;
1431
1526
  private open;
1432
1527
  private highlightedIndex;
1528
+ /** Virtual highlight on the Select-All header row (multi mode). */
1529
+ private selectAllHighlighted;
1530
+ private typeaheadBuffer;
1531
+ private typeaheadTimer;
1433
1532
  private panelStyle;
1434
1533
  private searchValue;
1435
1534
  private internalState;
@@ -1474,6 +1573,8 @@ declare class RelSelect extends LitElement {
1474
1573
  private emitChange;
1475
1574
  private openListbox;
1476
1575
  private closeListbox;
1576
+ private showNativePopover;
1577
+ private hideNativePopover;
1477
1578
  private updatePosition;
1478
1579
  private selectSingleOption;
1479
1580
  private toggleMultiOption;
@@ -1484,6 +1585,12 @@ declare class RelSelect extends LitElement {
1484
1585
  private onSearchInput;
1485
1586
  private onSearchKeyDown;
1486
1587
  private handleListNavigation;
1588
+ /** APG typeahead for the no-search mode (with a search field, typing
1589
+ * filters instead). Accumulates printable keys for 500 ms and jumps the
1590
+ * highlight to the next option whose label starts with the buffer. */
1591
+ private handleTypeahead;
1592
+ private activateHighlighted;
1593
+ private scrollHighlightedIntoView;
1487
1594
  private renderChips;
1488
1595
  /**
1489
1596
  * Hidden, unconstrained copy of every selected chip used purely for width
@@ -1533,6 +1640,7 @@ declare class RelModal extends LitElement {
1533
1640
  */
1534
1641
  breakpoint: "responsive" | "web";
1535
1642
  private overlayElement;
1643
+ private panelElement;
1536
1644
  private previousFocus;
1537
1645
  private originalBodyOverflow;
1538
1646
  private originalBodyPaddingRight;
@@ -1675,11 +1783,14 @@ declare class RelTab extends LitElement {
1675
1783
  /** Tab size — styled via :host([size]) rules. */
1676
1784
  size: "sm" | "md" | "lg";
1677
1785
  private _tabItems;
1786
+ /** Stable id prefix linking tabs to the shared tabpanel. */
1787
+ private tabsId;
1678
1788
  static styles: lit.CSSResult;
1679
1789
  private _onSlotChange;
1680
1790
  private get _effectiveTabs();
1681
1791
  private selectTab;
1682
1792
  private onKeyDown;
1793
+ private selectAndFocusTab;
1683
1794
  render(): lit_html.TemplateResult<1>;
1684
1795
  }
1685
1796
 
@@ -1691,19 +1802,27 @@ declare class RelTab extends LitElement {
1691
1802
  * column selections are held in draft state until Apply is clicked; Cancel,
1692
1803
  * Escape, or an outside click discards the draft.
1693
1804
  *
1694
- * The committed `value` is ALWAYS 24-hour "HH:mm" regardless of the display
1695
- * `format`, so consumers get a consistent machine-readable string.
1805
+ * The committed `value` is ALWAYS 24-hour "HH:mm" (or "HH:mm:ss" when
1806
+ * `seconds` is enabled) regardless of the display `format`, so consumers get
1807
+ * a consistent machine-readable string.
1808
+ *
1809
+ * Panel visuals follow the Figma "Time Picker" component (Reliability DS
1810
+ * V1.0, node 8301:3771): fixed panel widths 220/250/280 by size, full-bleed
1811
+ * columns with 1px dividers, neutral selected state, and a Now / Cancel / OK
1812
+ * footer whose buttons are always size S.
1696
1813
  */
1697
1814
  declare class RelTimePicker extends LitElement {
1698
- /** Committed time, 24-hour "HH:mm" (e.g. "09:30", "17:05"). */
1815
+ /** Committed time, 24-hour "HH:mm" or "HH:mm:ss" (e.g. "09:30", "17:05:30"). */
1699
1816
  value: string | null;
1700
1817
  placeholder: string;
1701
1818
  label: string | null;
1702
1819
  disabled: boolean;
1703
1820
  required: boolean;
1704
1821
  readonly: boolean;
1705
- /** Display format of the trigger text and hour column. Value stays "HH:mm". */
1822
+ /** Display format of the trigger text and hour column. Value stays 24-hour. */
1706
1823
  format: "12h" | "24h";
1824
+ /** Shows the seconds column; committed value becomes "HH:mm:ss". */
1825
+ seconds: boolean;
1707
1826
  /** Minute granularity of the minutes column (1, 5, 10, 15, 30, …). */
1708
1827
  minuteStep: number;
1709
1828
  /** Earliest selectable time, "HH:mm" (inclusive). */
@@ -1723,6 +1842,9 @@ declare class RelTimePicker extends LitElement {
1723
1842
  fullWidth: boolean;
1724
1843
  private draftHour;
1725
1844
  private draftMinute;
1845
+ private draftSecond;
1846
+ /** Panel opens above the field when there is no viewport space below. */
1847
+ private openUp;
1726
1848
  private triggerButton?;
1727
1849
  private columnsElement?;
1728
1850
  static styles: lit.CSSResult;
@@ -1731,6 +1853,8 @@ declare class RelTimePicker extends LitElement {
1731
1853
  private handleClickOutside;
1732
1854
  private handleEscapeKey;
1733
1855
  updated(changedProperties: Map<string, any>): void;
1856
+ /** Open upward when the panel doesn't fit below but does fit above. */
1857
+ private updatePanelPlacement;
1734
1858
  private parseTime;
1735
1859
  private formatValue;
1736
1860
  private formatDisplay;
@@ -1746,6 +1870,8 @@ declare class RelTimePicker extends LitElement {
1746
1870
  private isPeriodEnabled;
1747
1871
  /** Hour column entries: display label + the 0–23 hour it maps to. */
1748
1872
  private getHourOptions;
1873
+ /** Seconds shown in the seconds column (always step 1). */
1874
+ private getSecondOptions;
1749
1875
  private get draftPeriod();
1750
1876
  private resetDraftFromValue;
1751
1877
  /** Snap the draft minute to the nearest valid step minute for the hour. */
@@ -1759,7 +1885,14 @@ declare class RelTimePicker extends LitElement {
1759
1885
  private clearValue;
1760
1886
  private selectHour;
1761
1887
  private selectMinute;
1888
+ private selectSecond;
1762
1889
  private selectPeriod;
1890
+ /**
1891
+ * Scrolls the column's own scroll container only. scrollIntoView is off
1892
+ * limits here: it walks ALL scrollable ancestors, so it yanked the page
1893
+ * up/down whenever a column recentred (user-reported jump bug).
1894
+ */
1895
+ private scrollOptionInColumn;
1763
1896
  private scrollColumnsToSelection;
1764
1897
  private handleTriggerKeydown;
1765
1898
  /**
@@ -1804,9 +1937,349 @@ declare class RelTooltip extends LitElement {
1804
1937
  type: TooltipType;
1805
1938
  private uniqueId;
1806
1939
  static styles: lit.CSSResult;
1940
+ connectedCallback(): void;
1941
+ disconnectedCallback(): void;
1942
+ /** APG: Escape dismisses the tooltip. Not swallowed — an enclosing dialog
1943
+ * may legitimately close on the same keystroke. */
1944
+ private onKeydown;
1945
+ private clearDismissed;
1807
1946
  firstUpdated(): void;
1808
1947
  private linkTrigger;
1809
1948
  render(): lit_html.TemplateResult<1>;
1810
1949
  }
1811
1950
 
1812
- export { type AutocompleteFilter, type AutocompleteItem, type AutocompleteSearchFn, type BreadcrumbItem, type ButtonTone, type ButtonVariant, type ChipBorder, type ChipSize, type ChipTone, type ChipVariant, type DrawerCloseReason, type DrawerSide, type FieldLabelStyle, type LabelPlacement, type MenuItem, type MenuType, type ModalSide, type Orientation, type OtpType, type ProgressMode, type RadioOption, RelAccordion, RelAlert, RelAutocomplete, RelAvatar, RelBadge, RelBreadcrumbs, RelButton, RelCalendar, RelCard, RelCardMedia, RelCarousel, RelCheckbox, RelChip, RelContainer, RelDatePicker, RelDivider, RelDrawer, RelDrawerFooter, RelKbd, RelKbdGroup, RelLayout, RelMenu, RelMenuItem, RelMenubar, RelMenubarMenu, RelModal, RelNavbar, RelOtp, RelPagination, RelPopover, RelPopoverContent, RelProgress, RelRadio, RelRangePicker, RelResizableGroup, RelResizableHandle, RelResizablePanel, RelSegmentedButton, RelSelect, RelSkeleton, RelSlider, RelSnackbar, RelStepper, RelSwitch, RelTab, RelTabItem, RelTextfield, RelTimePicker, RelToast, RelTooltip, RelTopbar, RelTopbarActions, RelTopbarBrand, RelTopbarDropdown, RelTopbarDropdownItem, RelTopbarItem, RelTopbarMobilePanel, RelTopbarProfile, RelTopbarUtilities, type SegmentAlign, type SegmentOption, type SegmentSize, type SelectBorder, type SelectLabelStyle, type SelectOption, type SelectOptionObject, type SelectSize, type SelectState, type SkeletonAnimation, type SkeletonShape, type SliderType, type SnackbarLines, type SnackbarType, type Step, type StepStatus, type StepperSize, type StepperType, type TabItem, type TextAlign, type TextFieldSize, type TextFieldState, type TextFieldVariant, type ToastType, type TooltipPosition, type TooltipType, type TopbarForceLayout, type TopbarProfileType, type TopbarRewardTier, type TopbarVariant, type TrackStyle };
1951
+ /** Per-file lifecycle state. Mirrors the Figma "Upload File Row" variants 1:1. */
1952
+ type UploadStatus = "ready" | "uploading" | "success" | "error";
1953
+ /**
1954
+ * Aggregate state, derived from `files` — never set directly. Drives the list
1955
+ * heading, the alert, and the footer button in `<rel-upload-actions>`, and
1956
+ * corresponds to the Figma "Upload Modal" variants.
1957
+ */
1958
+ type UploadPhase = "empty" | "selected" | "uploading" | "delayed" | "failed";
1959
+ interface UploadFile {
1960
+ /** Stable identity for keyed rendering and remove/retry targeting. */
1961
+ id: string;
1962
+ name: string;
1963
+ /** Size in bytes. */
1964
+ size: number;
1965
+ status: UploadStatus;
1966
+ /** 0–100, present while uploading and after success. */
1967
+ progress?: number;
1968
+ /** Bytes transferred so far. */
1969
+ loaded?: number;
1970
+ /** Human-readable failure reason, e.g. "file exceeds the 10 MB limit". */
1971
+ error?: string;
1972
+ /** The underlying File. Absent when the app supplies `files` itself. */
1973
+ file?: File;
1974
+ }
1975
+ interface UploadRejection {
1976
+ name: string;
1977
+ reason: "format" | "size";
1978
+ message: string;
1979
+ }
1980
+ interface UploaderContext {
1981
+ /** The entry being uploaded. */
1982
+ file: UploadFile;
1983
+ /** Aborted when `cancel()` is called. */
1984
+ signal: AbortSignal;
1985
+ /** Report bytes transferred. `total` defaults to the file size. */
1986
+ onProgress: (loaded: number, total?: number) => void;
1987
+ }
1988
+ /** Supply this to let `<rel-upload>` drive the whole lifecycle itself. */
1989
+ type Uploader = (file: File, ctx: UploaderContext) => Promise<void>;
1990
+ /** Snapshot handed to `<rel-upload-actions>` on every `rel-state` event. */
1991
+ interface UploadState {
1992
+ phase: UploadPhase;
1993
+ total: number;
1994
+ failed: number;
1995
+ canUpload: boolean;
1996
+ primaryLabel: string;
1997
+ }
1998
+ /**
1999
+ * `<rel-upload>` — dropzone plus per-file upload list.
2000
+ *
2001
+ * Two modes, chosen by whether `uploader` is set:
2002
+ *
2003
+ * - **Controlled** (default): the component picks and validates files, then
2004
+ * emits intents (`rel-upload`, `rel-retry`, `rel-cancel`, `rel-remove`). The
2005
+ * app performs the transfer and writes progress back onto `files`.
2006
+ * - **Self-driving**: with an `uploader` function the component runs the whole
2007
+ * batch itself — concurrency, progress, the delay warning, abort and retry.
2008
+ *
2009
+ * The Cancel / Upload buttons are NOT rendered here. They live in
2010
+ * `<rel-upload-actions>` so they can sit in `<rel-modal>`'s footer slot and
2011
+ * stay pinned while this body scrolls.
2012
+ *
2013
+ * Emits (bubbling + composed):
2014
+ * - `rel-files-added` — `{ added: UploadFile[], rejected: UploadRejection[] }`
2015
+ * - `rel-invalid` — `{ rejected: UploadRejection[] }`
2016
+ * - `rel-change` — selection changed; `{ files: UploadFile[] }`
2017
+ * - `rel-remove` — row removed; `{ id, file }`
2018
+ * - `rel-upload` — Upload pressed; `{ files: UploadFile[] }`
2019
+ * - `rel-retry` — Retry pressed; `{ files: UploadFile[] }`
2020
+ * - `rel-cancel` — Cancel pressed
2021
+ * - `rel-progress` — `{ id, progress, loaded, total }`
2022
+ * - `rel-file-complete`— `{ id, file }`
2023
+ * - `rel-file-error` — `{ id, file, error }`
2024
+ * - `rel-complete` — batch settled; `{ succeeded, failed }`
2025
+ * - `rel-state` — derived snapshot changed; `detail: UploadState`
2026
+ *
2027
+ * @element rel-upload
2028
+ */
2029
+ declare class RelUpload extends LitElement {
2030
+ /** Comma-separated accept list, e.g. ".pdf,.png,.jpg" or "image/*". */
2031
+ accept: string;
2032
+ /** Max size per file as a human string ("10MB", "500kb"). Empty → no limit. */
2033
+ maxSize: string;
2034
+ /** Allow more than one file. */
2035
+ multiple: boolean;
2036
+ /** Disables the whole control. */
2037
+ disabled: boolean;
2038
+ /** Overrides the derived "PDF, PNG or JPG - up to 10 MB per file" hint. */
2039
+ hint: string;
2040
+ /** Dropzone headline. */
2041
+ dropzoneTitle: string;
2042
+ /** Browse button label. */
2043
+ browseLabel: string;
2044
+ /**
2045
+ * The file list. Set it to drive the component in controlled mode; the
2046
+ * component also maintains it itself as files are added and removed.
2047
+ */
2048
+ files: UploadFile[];
2049
+ /** Supply to run uploads internally. See {@link Uploader}. */
2050
+ uploader?: Uploader;
2051
+ /** Max files transferred at once in self-driving mode. */
2052
+ concurrency: number;
2053
+ /** ms of continuous uploading before the "taking longer than usual" alert. */
2054
+ delayThreshold: number;
2055
+ private dragOver;
2056
+ private delayed;
2057
+ private inputEl;
2058
+ private aborter?;
2059
+ private delayTimer?;
2060
+ private lastSignature;
2061
+ static styles: lit.CSSResult;
2062
+ /**
2063
+ * Aggregate state. Read-only; corresponds to the Figma modal variants.
2064
+ *
2065
+ * `failed` means there is nothing left to send AND something errored — while
2066
+ * any row is still `ready` the primary action is Upload, not Retry.
2067
+ */
2068
+ get phase(): UploadPhase;
2069
+ /** Files still eligible to be sent. */
2070
+ private get pending();
2071
+ private get failedFiles();
2072
+ /**
2073
+ * Failed rows worth sending again. A file rejected by `accept`/`max-size`
2074
+ * will fail validation every time, so retrying it is pointless — re-check
2075
+ * rather than re-queueing it blindly.
2076
+ */
2077
+ private get retryable();
2078
+ get canUpload(): boolean;
2079
+ /** Footer button label — "Upload", "Upload 3 files" or "Retry upload". */
2080
+ get primaryLabel(): string;
2081
+ /** The snapshot `<rel-upload-actions>` renders from. */
2082
+ get state(): UploadState;
2083
+ private get listHeading();
2084
+ private get hintText();
2085
+ private get acceptDisplay();
2086
+ private get alertContent();
2087
+ private parseMaxBytes;
2088
+ private matchesAccept;
2089
+ static fmtSize(bytes: number): string;
2090
+ private static ext;
2091
+ /**
2092
+ * Validate and append. Invalid files are kept as `error` rows rather than
2093
+ * dropped — that is how the Figma Failure state surfaces them.
2094
+ */
2095
+ private ingest;
2096
+ private patch;
2097
+ private startDelayTimer;
2098
+ private stopDelayTimer;
2099
+ private runBatch;
2100
+ /** Start (or resume) the batch. Emits `rel-upload`; runs it when `uploader` is set. */
2101
+ upload(): void;
2102
+ /** Re-queue every retryable failed row and send again. */
2103
+ retry(): void;
2104
+ /** Abort anything in flight and emit `rel-cancel`. Does not clear the list. */
2105
+ cancel(): void;
2106
+ /** Remove one row by id. */
2107
+ removeFile(id: string): void;
2108
+ /** Clear everything and abort in-flight transfers. */
2109
+ reset(): void;
2110
+ private emit;
2111
+ /**
2112
+ * Emit `rel-state` only when the derived snapshot actually changes, so
2113
+ * progress ticks don't spam `<rel-upload-actions>`.
2114
+ */
2115
+ private notify;
2116
+ private openPicker;
2117
+ private onInputChange;
2118
+ private onDragOver;
2119
+ private onDragLeave;
2120
+ private onDrop;
2121
+ connectedCallback(): void;
2122
+ disconnectedCallback(): void;
2123
+ updated(): void;
2124
+ private rowMeta;
2125
+ private renderRow;
2126
+ render(): lit_html.TemplateResult<1>;
2127
+ }
2128
+ declare global {
2129
+ interface HTMLElementTagNameMap {
2130
+ "rel-upload": RelUpload;
2131
+ }
2132
+ }
2133
+
2134
+ /**
2135
+ * `<rel-upload-actions>` — the Cancel / Upload footer for `<rel-upload>`.
2136
+ *
2137
+ * Lives outside `<rel-upload>` so it can sit in `<rel-modal>`'s footer slot and
2138
+ * stay pinned while the upload body scrolls. It mirrors the sibling
2139
+ * `<rel-upload>`'s derived state, so the button label follows the design:
2140
+ * "Upload" → "Upload 3 files" → spinner → "Retry upload".
2141
+ *
2142
+ * ```html
2143
+ * <rel-modal open side="center" title="Upload documents">
2144
+ * <rel-upload multiple .uploader=${fn}></rel-upload>
2145
+ * <rel-upload-actions slot="footer"></rel-upload-actions>
2146
+ * </rel-modal>
2147
+ * ```
2148
+ *
2149
+ * The target is found automatically among its siblings. Use `for` to point at a
2150
+ * specific `<rel-upload>` by id when a container holds more than one.
2151
+ *
2152
+ * @element rel-upload-actions
2153
+ */
2154
+ declare class RelUploadActions extends LitElement {
2155
+ /** Id of the `<rel-upload>` to control. Omit to auto-discover a sibling. */
2156
+ for: string;
2157
+ /** Cancel button label. */
2158
+ cancelLabel: string;
2159
+ /** Hides Cancel for flows that only ever move forward. */
2160
+ noCancel: boolean;
2161
+ private snapshot;
2162
+ private target;
2163
+ static styles: lit.CSSResult;
2164
+ connectedCallback(): void;
2165
+ disconnectedCallback(): void;
2166
+ updated(changed: Map<string, unknown>): void;
2167
+ /**
2168
+ * Listen on our own root rather than `document`: a shared root means no
2169
+ * shadow boundary sits between us and the sibling `<rel-upload>`, so
2170
+ * `event.target` is never retargeted away from it.
2171
+ */
2172
+ private get root();
2173
+ private resolveTarget;
2174
+ private onState;
2175
+ private onCancel;
2176
+ private onPrimary;
2177
+ render(): lit_html.TemplateResult<1>;
2178
+ }
2179
+ declare global {
2180
+ interface HTMLElementTagNameMap {
2181
+ "rel-upload-actions": RelUploadActions;
2182
+ }
2183
+ }
2184
+
2185
+ /**
2186
+ * Shared focus utilities (shadow-DOM aware).
2187
+ *
2188
+ * Most components in this package render into shadow roots, so the classic
2189
+ * `container.querySelectorAll(focusableSelector)` + `document.activeElement`
2190
+ * approach silently fails in two ways:
2191
+ * 1. querySelectorAll never descends into child components' shadow roots,
2192
+ * so slotted rel-buttons etc. are invisible to a focus trap.
2193
+ * 2. document.activeElement retargets to the outermost host, so equality
2194
+ * checks against inner elements never match.
2195
+ * These helpers traverse the *composed* tree and resolve the *deep* active
2196
+ * element instead.
2197
+ */
2198
+ /**
2199
+ * All keyboard-focusable elements under `root`, in composed tree order —
2200
+ * descends into shadow roots and follows slot assignment.
2201
+ */
2202
+ declare function getFocusableElements(root: Element | ShadowRoot): HTMLElement[];
2203
+ /** The actually-focused element, resolved through nested shadow roots. */
2204
+ declare function getDeepActiveElement(): HTMLElement | null;
2205
+ /**
2206
+ * Keep Tab / Shift+Tab cycling inside `container`. Call from a keydown
2207
+ * listener; no-op for non-Tab keys. If focus has already escaped the
2208
+ * container, the next Tab pulls it back in.
2209
+ */
2210
+ declare function trapTabKey(e: KeyboardEvent, container: Element | ShadowRoot): void;
2211
+ /**
2212
+ * Reusable focus trap for dialog-like components (drawer, modal, popover…).
2213
+ *
2214
+ * private trap = new FocusTrap(() => this.panelEl);
2215
+ * onOpen() { this.trap.activate(); }
2216
+ * onClose() { this.trap.deactivate(); }
2217
+ *
2218
+ * activate() records the previously focused element, moves focus to the
2219
+ * first focusable inside the container (or the container itself), and wraps
2220
+ * Tab at the edges. deactivate() restores focus to where it was.
2221
+ */
2222
+ declare class FocusTrap {
2223
+ private getContainer;
2224
+ private previousFocus;
2225
+ private active;
2226
+ constructor(getContainer: () => Element | ShadowRoot | null);
2227
+ activate(options?: {
2228
+ initialFocus?: HTMLElement | null;
2229
+ }): void;
2230
+ deactivate(options?: {
2231
+ restoreFocus?: boolean;
2232
+ }): void;
2233
+ private onKeyDown;
2234
+ }
2235
+
2236
+ /**
2237
+ * Shared keyboard-shortcut utilities.
2238
+ *
2239
+ * Shortcut strings are written as "+"-joined tokens, e.g. "mod+b",
2240
+ * "ctrl+shift+p", "escape". The "mod" token means Cmd on Apple platforms
2241
+ * and Ctrl everywhere else (this is the pattern rel-sidebar's Ctrl/Cmd+B
2242
+ * toggle established). Matching is case-insensitive.
2243
+ */
2244
+ type ShortcutHandler = (e: KeyboardEvent) => void;
2245
+ interface ParsedShortcut {
2246
+ key: string;
2247
+ ctrl: boolean;
2248
+ meta: boolean;
2249
+ alt: boolean;
2250
+ shift: boolean;
2251
+ }
2252
+ declare function isApplePlatform(): boolean;
2253
+ declare function parseShortcut(shortcut: string): ParsedShortcut;
2254
+ /** Does this keydown event match the shortcut string? */
2255
+ declare function matchesShortcut(e: KeyboardEvent, shortcut: string): boolean;
2256
+ /**
2257
+ * True when the event originates from a text-editing context (input,
2258
+ * textarea, select, contenteditable) — global single-key shortcuts should
2259
+ * stay out of the way there. Uses composedPath so it sees through shadow
2260
+ * roots (e.g. the real <input> inside rel-textfield).
2261
+ */
2262
+ declare function isEditableTarget(e: Event): boolean;
2263
+ interface BindShortcutOptions {
2264
+ /** Listen on this target instead of `document`. */
2265
+ target?: EventTarget;
2266
+ /** Fire even when focus is in an input/textarea/contenteditable. */
2267
+ allowInEditable?: boolean;
2268
+ /** preventDefault on match (default true). */
2269
+ preventDefault?: boolean;
2270
+ }
2271
+ /**
2272
+ * Bind a shortcut, returns the unbind function.
2273
+ *
2274
+ * private unbind = bindShortcut("mod+b", () => this.toggle());
2275
+ * disconnectedCallback() { this.unbind(); }
2276
+ */
2277
+ declare function bindShortcut(shortcut: string, handler: ShortcutHandler, options?: BindShortcutOptions): () => void;
2278
+ /**
2279
+ * Display labels for a shortcut, one entry per key — feed straight into
2280
+ * <rel-kbd-group .items=${formatShortcutParts("mod+b")}>.
2281
+ * Platform-aware: "mod+b" → ["⌘","B"] on Apple, ["Ctrl","B"] elsewhere.
2282
+ */
2283
+ declare function formatShortcutParts(shortcut: string): string[];
2284
+
2285
+ export { type AutocompleteFilter, type AutocompleteItem, type AutocompleteSearchFn, type BindShortcutOptions, type BreadcrumbItem, type ButtonTone, type ButtonVariant, type ChipBorder, type ChipSize, type ChipTone, type ChipVariant, type DrawerCloseReason, type DrawerSide, type FieldLabelStyle, FocusTrap, type LabelPlacement, type MenuItem, type MenuType, type ModalSide, type Orientation, type OtpType, type ProgressMode, type RadioOption, RelAccordion, RelAlert, RelAutocomplete, RelAvatar, RelBadge, RelBreadcrumbs, RelButton, RelCalendar, RelCard, RelCardMedia, RelCarousel, RelCheckbox, RelChip, RelContainer, RelDatePicker, RelDivider, RelDrawer, RelDrawerFooter, RelKbd, RelKbdGroup, RelLayout, RelMenu, RelMenuItem, RelMenubar, RelMenubarMenu, RelModal, RelNavbar, RelOtp, RelPagination, RelPopover, RelPopoverContent, RelProgress, RelRadio, RelRangePicker, RelResizableGroup, RelResizableHandle, RelResizablePanel, RelSegmentedButton, RelSelect, RelSkeleton, RelSlider, RelSnackbar, RelStepper, RelSwitch, RelTab, RelTabItem, RelTextfield, RelTimePicker, RelToast, RelTooltip, RelTopbar, RelTopbarActions, RelTopbarBrand, RelTopbarDropdown, RelTopbarDropdownItem, RelTopbarItem, RelTopbarMobilePanel, RelTopbarProfile, RelTopbarUtilities, RelUpload, RelUploadActions, type SegmentAlign, type SegmentOption, type SegmentSize, type SelectBorder, type SelectLabelStyle, type SelectOption, type SelectOptionObject, type SelectSize, type SelectState, type ShortcutHandler, type SkeletonAnimation, type SkeletonShape, type SliderType, type SnackbarLines, type SnackbarType, type Step, type StepStatus, type StepperSize, type StepperType, type TabItem, type TextAlign, type TextFieldSize, type TextFieldState, type TextFieldVariant, type ToastType, type TooltipPosition, type TooltipType, type TopbarForceLayout, type TopbarProfileType, type TopbarRewardTier, type TopbarVariant, type TrackStyle, type UploadFile, type UploadPhase, type UploadRejection, type UploadState, type UploadStatus, type Uploader, type UploaderContext, bindShortcut, formatShortcutParts, getDeepActiveElement, getFocusableElements, isApplePlatform, isEditableTarget, matchesShortcut, parseShortcut, trapTabKey };