@underlayerdev/ui 0.8.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@underlayerdev/ui",
3
- "version": "0.8.2",
3
+ "version": "0.9.1",
4
4
  "peerDependencies": {
5
5
  "@angular/cdk": "^22.0.0",
6
6
  "@angular/common": "^22.0.0",
@@ -1085,6 +1085,13 @@ declare class ModalComponent {
1085
1085
  cancelLabel: _angular_core.InputSignal<string>;
1086
1086
  /** Optional CSS class for the panel (e.g. for custom variant). */
1087
1087
  customClass: _angular_core.InputSignal<string | undefined>;
1088
+ /**
1089
+ * Below the phone breakpoint, fills the entire viewport edge-to-edge (no
1090
+ * margin, no rounded corners, no visible backdrop) instead of the default
1091
+ * bottom-pinned sheet every variant otherwise gets there. Has no effect
1092
+ * above that breakpoint — desktop/tablet layout is unchanged either way.
1093
+ */
1094
+ fullScreenInMobile: _angular_core.InputSignal<boolean>;
1088
1095
  /** Emitted when the modal is closed (button, backdrop, or escape). */
1089
1096
  closed: _angular_core.OutputEmitterRef<void>;
1090
1097
  /** Emitted when the user confirms in the confirmation variant. */
@@ -1104,7 +1111,7 @@ declare class ModalComponent {
1104
1111
  onBackdropClick(event: MouseEvent): void;
1105
1112
  onEscape(): void;
1106
1113
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ModalComponent, never>;
1107
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ModalComponent, "ul-modal", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "closeOnBackdropClick": { "alias": "closeOnBackdropClick"; "required": false; "isSignal": true; }; "showCloseButton": { "alias": "showCloseButton"; "required": false; "isSignal": true; }; "confirmLabel": { "alias": "confirmLabel"; "required": false; "isSignal": true; }; "cancelLabel": { "alias": "cancelLabel"; "required": false; "isSignal": true; }; "customClass": { "alias": "customClass"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "closed": "closed"; "confirmed": "confirmed"; "cancelled": "cancelled"; }, never, ["*", "[ul-modal-footer]"], true, never>;
1114
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ModalComponent, "ul-modal", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "closeOnBackdropClick": { "alias": "closeOnBackdropClick"; "required": false; "isSignal": true; }; "showCloseButton": { "alias": "showCloseButton"; "required": false; "isSignal": true; }; "confirmLabel": { "alias": "confirmLabel"; "required": false; "isSignal": true; }; "cancelLabel": { "alias": "cancelLabel"; "required": false; "isSignal": true; }; "customClass": { "alias": "customClass"; "required": false; "isSignal": true; }; "fullScreenInMobile": { "alias": "fullScreenInMobile"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "closed": "closed"; "confirmed": "confirmed"; "cancelled": "cancelled"; }, never, ["*", "[ul-modal-footer]"], true, never>;
1108
1115
  }
1109
1116
 
1110
1117
  /** Place on the element projected into [ul-navbar-logo] so the navbar can detect logo content. */
@@ -1455,6 +1462,134 @@ declare class TooltipComponent {
1455
1462
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<TooltipComponent, "ul-tooltip", never, { "text": { "alias": "text"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "showDelay": { "alias": "showDelay"; "required": false; "isSignal": true; }; "hideDelay": { "alias": "hideDelay"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
1456
1463
  }
1457
1464
 
1465
+ /**
1466
+ * Open/focus/highlight state and keyboard navigation shared by combobox-
1467
+ * style inputs (a text field paired with a listbox of options) —
1468
+ * `ul-search-select` (closed list, one selection) and `ul-search-input`
1469
+ * (free text plus suggestions/results) need identical open/close timing and
1470
+ * arrow-key/Escape mechanics despite having different value semantics. This
1471
+ * holds only that shared mechanics; each consumer still owns its own list,
1472
+ * selection, and what Enter does when nothing is highlighted.
1473
+ */
1474
+ declare class ComboboxState {
1475
+ readonly isOpen: _angular_core.WritableSignal<boolean>;
1476
+ readonly isFocused: _angular_core.WritableSignal<boolean>;
1477
+ readonly highlightedIndex: _angular_core.WritableSignal<number>;
1478
+ private closeTimeout;
1479
+ /** Cancels any pending blur-close and opens immediately — for focus/typing. */
1480
+ open(): void;
1481
+ /**
1482
+ * Closes after a short delay instead of immediately, so a mousedown on an
1483
+ * option (which fires before the field's blur) can still register before
1484
+ * the panel disappears. `onClosed` runs once the delay elapses, unless a
1485
+ * subsequent `open()`/`close()` cancels it first.
1486
+ */
1487
+ scheduleClose(onClosed?: () => void, delay?: number): void;
1488
+ /** Closes immediately — for selecting an option, submitting, or Escape. */
1489
+ close(): void;
1490
+ cancelScheduledClose(): void;
1491
+ resetHighlight(): void;
1492
+ /**
1493
+ * Handles ArrowDown/ArrowUp (cycling over `listLength`) and Escape
1494
+ * (closes). Returns whether it handled the key, so the caller's own
1495
+ * keydown handler knows whether to fall through to its own Enter logic —
1496
+ * Enter is deliberately not handled here, since selecting the highlighted
1497
+ * option vs. falling back to something else (e.g. `ul-search-input`'s
1498
+ * free-text submit) is caller-specific.
1499
+ */
1500
+ handleNavigationKey(event: KeyboardEvent, listLength: number): boolean;
1501
+ }
1502
+
1503
+ interface SearchSuggestion {
1504
+ value: string;
1505
+ label: string;
1506
+ icon?: IconName;
1507
+ }
1508
+ /**
1509
+ * Free-text search box with a results panel: `suggestions` (e.g. recent
1510
+ * searches) while the query is empty, swapped for `results` as soon as the
1511
+ * user types. On desktop the panel is an anchored dropdown below the field.
1512
+ * Below the phone breakpoint, tapping the field opens a full-screen `ul-modal`
1513
+ * (via `fullScreenInMobile`) instead — the same pattern as X/Twitter, Google,
1514
+ * etc.: a back button and the real field pinned to the top, results filling
1515
+ * the rest of the screen edge to edge, no card, no backdrop. `ul-modal`
1516
+ * supplies the focus trap, dialog role, and Escape-to-close; this component
1517
+ * just projects its own header/results as the modal's body content.
1518
+ * Consumers never branch on viewport or manage this themselves.
1519
+ *
1520
+ * Implements FormValueControl for Signal Forms. Use `[(value)]` for two-way
1521
+ * binding.
1522
+ */
1523
+ declare class SearchInputComponent implements FormValueControl<string> {
1524
+ readonly size: _angular_core.InputSignal<UiSize>;
1525
+ readonly label: _angular_core.InputSignal<string | null>;
1526
+ readonly helperText: _angular_core.InputSignal<string | null>;
1527
+ readonly errorText: _angular_core.InputSignal<string | null>;
1528
+ readonly error: _angular_core.InputSignal<boolean>;
1529
+ readonly disabled: _angular_core.InputSignal<boolean>;
1530
+ readonly placeholder: _angular_core.InputSignal<string>;
1531
+ /** Aria-label for the back button shown in the mobile takeover. */
1532
+ readonly backLabel: _angular_core.InputSignal<string>;
1533
+ /** Aria-label for the clear button shown in the mobile takeover when query is not empty. */
1534
+ readonly clearLabel: _angular_core.InputSignal<string>;
1535
+ /** Shown while the query is empty — e.g. recent searches. Replaced by `results` as soon as the user types. The consumer owns the data/persistence; this component only renders and reports selection. */
1536
+ readonly suggestions: _angular_core.InputSignal<SearchSuggestion[]>;
1537
+ /** Heading shown above `suggestions`, e.g. "Recent searches". Not shown once `results` takes over. */
1538
+ readonly suggestionsLabel: _angular_core.InputSignal<string | null>;
1539
+ /** Shown once the query is non-empty — e.g. live search results. The consumer computes/fetches these as `value` changes (via `[(value)]`/`valueChange`). */
1540
+ readonly results: _angular_core.InputSignal<SearchSuggestion[]>;
1541
+ /**
1542
+ * Overrides `results` once the query is non-empty, projecting arbitrary
1543
+ * content (e.g. rich cards with images/prices) instead of the built-in
1544
+ * plain-text rows. `suggestions` (shown while the query is empty) are
1545
+ * unaffected and keep rendering as plain `SearchSuggestion` rows regardless.
1546
+ * When set, arrow-key/Enter option-highlighting is skipped — Enter always
1547
+ * falls through to `searchSubmit` since the projected content owns its own
1548
+ * selection interaction.
1549
+ */
1550
+ readonly resultsTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
1551
+ readonly invalid: _angular_core.InputSignal<boolean>;
1552
+ readonly errors: _angular_core.InputSignal<readonly WithOptionalFieldTree<ValidationError>[]>;
1553
+ readonly value: _angular_core.ModelSignal<string>;
1554
+ /** Emitted when the user picks a suggestion, by click or keyboard. */
1555
+ readonly suggestionSelected: _angular_core.OutputEmitterRef<SearchSuggestion>;
1556
+ /** Emitted on Enter when no suggestion is highlighted — the free-typed query. */
1557
+ readonly searchSubmit: _angular_core.OutputEmitterRef<string>;
1558
+ protected readonly ids: {
1559
+ controlId: string;
1560
+ helperId: string;
1561
+ errorId: string;
1562
+ };
1563
+ /** Open/focus/highlight state and arrow-key/Escape mechanics shared with ul-search-select. */
1564
+ protected readonly combobox: ComboboxState;
1565
+ private readonly mobileInput;
1566
+ /** Phone-sized viewport — below this, tapping the field opens the full-screen takeover instead of the anchored dropdown. */
1567
+ protected readonly isMobile: _angular_core.Signal<boolean>;
1568
+ protected readonly listId: string;
1569
+ protected readonly hasError: _angular_core.Signal<boolean>;
1570
+ protected readonly describedBy: _angular_core.Signal<string | undefined>;
1571
+ /** Whether the query is non-empty — `results` replaces `suggestions` (and its heading) once true. */
1572
+ protected readonly hasQuery: _angular_core.Signal<boolean>;
1573
+ protected readonly activeList: _angular_core.Signal<SearchSuggestion[]>;
1574
+ protected readonly activeListLabel: _angular_core.Signal<string | null>;
1575
+ protected readonly hasCustomResults: _angular_core.Signal<boolean>;
1576
+ protected readonly shouldShowPanel: _angular_core.Signal<boolean>;
1577
+ protected readonly optionId: (index: number) => string;
1578
+ protected readonly activeDescendantId: _angular_core.Signal<string | undefined>;
1579
+ onValueChange(text: string): void;
1580
+ onInputFocus(): void;
1581
+ onInputBlur(): void;
1582
+ /** The visible field on mobile is a read-only trigger — typing happens in the takeover's own field, focused once it renders. */
1583
+ openMobileSearch(): void;
1584
+ closeMobileSearch(): void;
1585
+ clearInput(): void;
1586
+ onKeydown(event: KeyboardEvent): void;
1587
+ selectSuggestion(suggestion: SearchSuggestion): void;
1588
+ private submitSearch;
1589
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SearchInputComponent, never>;
1590
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SearchInputComponent, "ul-search-input", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "backLabel": { "alias": "backLabel"; "required": false; "isSignal": true; }; "clearLabel": { "alias": "clearLabel"; "required": false; "isSignal": true; }; "suggestions": { "alias": "suggestions"; "required": false; "isSignal": true; }; "suggestionsLabel": { "alias": "suggestionsLabel"; "required": false; "isSignal": true; }; "results": { "alias": "results"; "required": false; "isSignal": true; }; "resultsTemplate": { "alias": "resultsTemplate"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "suggestionSelected": "suggestionSelected"; "searchSubmit": "searchSubmit"; }, never, never, true, never>;
1591
+ }
1592
+
1458
1593
  interface SearchSelectOption {
1459
1594
  label: string;
1460
1595
  value: string;
@@ -1484,10 +1619,8 @@ declare class SearchSelectComponent implements FormValueControl<string | null> {
1484
1619
  errorId: string;
1485
1620
  };
1486
1621
  protected readonly query: _angular_core.WritableSignal<string>;
1487
- protected readonly isOpen: _angular_core.WritableSignal<boolean>;
1488
- protected readonly isFocused: _angular_core.WritableSignal<boolean>;
1489
- protected readonly highlightedIndex: _angular_core.WritableSignal<number>;
1490
- protected blurCloseTimeout: ReturnType<typeof setTimeout> | null;
1622
+ /** Open/focus/highlight state and arrow-key/Escape mechanics shared with ul-search-input. */
1623
+ protected readonly combobox: ComboboxState;
1491
1624
  protected readonly listId: string;
1492
1625
  protected readonly hasError: _angular_core.Signal<boolean>;
1493
1626
  protected readonly describedBy: _angular_core.Signal<string | undefined>;
@@ -1504,7 +1637,6 @@ declare class SearchSelectComponent implements FormValueControl<string | null> {
1504
1637
  onInputBlur(): void;
1505
1638
  onKeydown(event: KeyboardEvent): void;
1506
1639
  selectOption(opt: SearchSelectOption): void;
1507
- private cancelBlurClose;
1508
1640
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SearchSelectComponent, never>;
1509
1641
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SearchSelectComponent, "ul-search-select", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showRequiredIndicator": { "alias": "showRequiredIndicator"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "minCharsToOpen": { "alias": "minCharsToOpen"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
1510
1642
  }
@@ -1810,5 +1942,5 @@ declare class TextareaComponent implements FormValueControl<string> {
1810
1942
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<TextareaComponent, "ul-textarea", never, { "size": { "alias": "size"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readOnly": { "alias": "readOnly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "showRequiredIndicator": { "alias": "showRequiredIndicator"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "errorText": { "alias": "errorText"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "minLength": { "alias": "minLength"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "resize": { "alias": "resize"; "required": false; "isSignal": true; }; "groupFocused": { "alias": "groupFocused"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "touched": "touchedChange"; "touch": "touch"; "value": "valueChange"; "inputBlur": "inputBlur"; "inputFocus": "inputFocus"; }, ["customField"], ["[ul-textarea-left-elements]", "[ul-textarea-field]", "[ul-textarea-right-elements]"], true, never>;
1811
1943
  }
1812
1944
 
1813
- export { AccordionComponent, AccordionItemComponent, AreaCodeComponent, AvatarComponent, AvatarGroupComponent, BreadcrumbComponent, ButtonComponent, CalendarComponent, CardComponent, CarouselComponent, CarouselItemComponent, CheckboxComponent, CollapseComponent, CustomCurrencyPipe, DockComponent, DockItemComponent, DockItemContentSlotDirective, DropdownComponent, FileInputComponent, FooterComponent, FormFieldHelperComponent, FormFieldLabelComponent, HeroComponent, IconComponent, ImageNotFoundDirective, InputComponent, ListItemComponent, LongPressDirective, MenuComponent, MenuItemsComponent, MenuTriggerComponent, ModalComponent, NavbarAppNameSlotDirective, NavbarAvatarSlotDirective, NavbarComponent, NavbarLogoSlotDirective, NavbarSearchSlotDirective, PeHeroActionsSlotDirective, PeHeroBadgesSlotDirective, PeHeroContentSlotDirective, PeHeroSubtitleSlotDirective, PeHeroTitleSlotDirective, PillComponent, PriceButtonComponent, RadialComponent, RadioComponent, RadioGroupComponent, RichTextComponent, SearchSelectComponent, SelectComponent, SelectableRowComponent, SidebarComponent, SkeletonComponent, StatusComponent, TableComponent, TextareaComponent, TextareaFieldDirective, ToastContainerComponent, ToastService, TooltipComponent, createFormFieldIds, getFormFieldDescribedBy, toastIcon };
1814
- export type { ActionsDistribution, AvatarData, BreadcrumbItem, BreadcrumbSeparator, CalendarDay, CalendarMode, CardCaptionSize, CardDirection, CheckboxZoneType, CollapseVariant, Currency, DockItemVariant, DropdownItem, FileInputAppearance, HeroAction, HeroAlignment, HeroSize, IconName, IconSize, IconWeight, InputAppearance, InputType, ListItemTheme, MediaAspectRatio, MenuItem, ModalVariant, PillSize, PillTheme, PillVariant, RadioGroupOption, RichTextSize, RichTextTone, SalePosition, SearchSelectOption, SelectOption, SidebarItem, SkeletonBorderRadius, SkeletonVariant, SortDirection, Status, TableColumn, TextareaResize, TimeSelection, ToastConfig, ToastKind, ToastWithRole, TooltipPosition };
1945
+ export { AccordionComponent, AccordionItemComponent, AreaCodeComponent, AvatarComponent, AvatarGroupComponent, BreadcrumbComponent, ButtonComponent, CalendarComponent, CardComponent, CarouselComponent, CarouselItemComponent, CheckboxComponent, CollapseComponent, CustomCurrencyPipe, DockComponent, DockItemComponent, DockItemContentSlotDirective, DropdownComponent, FileInputComponent, FooterComponent, FormFieldHelperComponent, FormFieldLabelComponent, HeroComponent, IconComponent, ImageNotFoundDirective, InputComponent, ListItemComponent, LongPressDirective, MenuComponent, MenuItemsComponent, MenuTriggerComponent, ModalComponent, NavbarAppNameSlotDirective, NavbarAvatarSlotDirective, NavbarComponent, NavbarLogoSlotDirective, NavbarSearchSlotDirective, PeHeroActionsSlotDirective, PeHeroBadgesSlotDirective, PeHeroContentSlotDirective, PeHeroSubtitleSlotDirective, PeHeroTitleSlotDirective, PillComponent, PriceButtonComponent, RadialComponent, RadioComponent, RadioGroupComponent, RichTextComponent, SearchInputComponent, SearchSelectComponent, SelectComponent, SelectableRowComponent, SidebarComponent, SkeletonComponent, StatusComponent, TableComponent, TextareaComponent, TextareaFieldDirective, ToastContainerComponent, ToastService, TooltipComponent, createFormFieldIds, getFormFieldDescribedBy, toastIcon };
1946
+ export type { ActionsDistribution, AvatarData, BreadcrumbItem, BreadcrumbSeparator, CalendarDay, CalendarMode, CardCaptionSize, CardDirection, CheckboxZoneType, CollapseVariant, Currency, DockItemVariant, DropdownItem, FileInputAppearance, HeroAction, HeroAlignment, HeroSize, IconName, IconSize, IconWeight, InputAppearance, InputType, ListItemTheme, MediaAspectRatio, MenuItem, ModalVariant, PillSize, PillTheme, PillVariant, RadioGroupOption, RichTextSize, RichTextTone, SalePosition, SearchSelectOption, SearchSuggestion, SelectOption, SidebarItem, SkeletonBorderRadius, SkeletonVariant, SortDirection, Status, TableColumn, TextareaResize, TimeSelection, ToastConfig, ToastKind, ToastWithRole, TooltipPosition };