import { SelectionModel } from '@angular/cdk/collections'; import { CdkConnectedOverlay, ViewportRuler } from '@angular/cdk/overlay'; import { AfterContentInit, ChangeDetectorRef, ElementRef, EventEmitter, NgZone, OnChanges, OnDestroy, OnInit, QueryList, SimpleChanges } from '@angular/core'; import { NgControl } from '@angular/forms'; import { TsDocumentService } from '@terminus/ngx-tools/browser'; import { TsFormFieldControl } from '@terminus/ui/form-field'; import { TsOptgroupComponent, TsOptionComponent, TsOptionSelectionChange } from '@terminus/ui/option'; import { TsStyleThemeTypes } from '@terminus/ui/utilities'; import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { TsSelectTriggerComponent } from './select-trigger.component'; /** * The following style constants are necessary to save here in order to properly calculate the alignment of the selected option over the * trigger element. */ export declare const SELECT_PANEL_MAX_HEIGHT = 256; export declare const SELECT_PANEL_PADDING_X = 16; export declare const SELECT_PANEL_INDENT_PADDING_X: number; export declare const SELECT_ITEM_HEIGHT_EM = 3; /** * Distance between the panel edge and the option text in multi-selection mode. * * Calculated as: * (SELECT_PANEL_PADDING_X * 1.5) + 20 = 44 * The padding is multiplied by 1.5 because the checkbox's margin is half the padding. * The checkbox width is 16px. */ export declare const SELECT_MULTIPLE_PANEL_PADDING_X = 0; /** * The select panel will only "fit" inside the viewport if it is positioned at this value or more away from the viewport boundary */ export declare const SELECT_PANEL_VIEWPORT_PADDING = 8; /** * Expose the formatter function type */ export declare type TsSelectFormatFn = (v: unknown) => string; /** * Used to sort selected options. * * Function used to sort the values in a select in multiple mode. Follows the same logic as `Array.prototype.sort`. */ export declare type TsSelectSortComparatorFunction = (a: TsOptionComponent, b: TsOptionComponent, options: TsOptionComponent[]) => number; /** * Comparison function to specify which option is displayed */ export declare type TsSelectOptionCompareWith = (o1: unknown, o2: unknown) => boolean; /** * The default compare with function used when the consumer does not define one * * @param o1 * @param o2 */ export declare const DEFAULT_COMPARE_WITH: TsSelectOptionCompareWith; /** * The select panel will only "fit" inside the viewport if it is positioned at this value or more away from the viewport boundary */ export declare const TS_SELECT_PANEL_VIEWPORT_PADDING = 8; /** * The event object that is emitted when the select value has changed */ export declare class TsSelectChange { source: TsSelectComponent; value: T; constructor(source: TsSelectComponent, value: T); } /** * Interface requirements for a selected option */ export interface TsSelectOption { isDisabled?: boolean; children?: TsSelectOption[]; } /** * A component to create a select menu * * @deprecated Please use `TsSelectionListComponent` * * @example * * * https://getterminus.github.io/ui-demos-release/components/select */ export declare class TsSelectComponent implements OnInit, AfterContentInit, OnChanges, OnDestroy, TsFormFieldControl { private viewportRuler; private changeDetectorRef; private ngZone; private documentService; private elementRef; ngControl: NgControl; /** * Give the component an explicit name */ readonly componentName = "TsSelectComponent"; /** * Store a reference to the document object */ private document; /** * Define the flex layout gap */ flexGap: string; /** * Subject used to alert the parent {@link FormFieldComponent} when the label gap should be recalculated * * Implemented as part of TsFormFieldControl. */ readonly labelChanges: Subject; /** * Manages keyboard events for options in the panel. */ private keyManager; /** * The y-offset of the overlay panel in relation to the trigger's top start corner. * This must be adjusted to align the selected option text over the trigger text. * when the panel opens. This will be changed based on the y-position of the selected option. */ offsetY: number; /** * The IDs of child options to be passed to the aria-owns attribute. */ optionIds: string; /** * Combined stream of all of the child options' change events */ readonly optionSelectionChanges: Observable; /** * Emits when the panel element is finished transforming in. */ panelDoneAnimatingStream: Subject; /** * Whether or not the overlay panel is open */ panelOpen: boolean; /** * This position config ensures that the top "start" corner of the overlay * is aligned with with the top "start" of the origin by default (overlapping * the trigger completely). */ positions: { originX: string; originY: string; overlayX: string; overlayY: string; }[]; /** * The scroll position of the overlay panel, calculated to center the selected option. */ private scrollTop; /** * Store the search query */ searchQuery: string; /** * Manage selections * */ selectionModel: SelectionModel; selfReference: this; readonly stateChanges: Subject; /** * The value of the select panel's transform-origin property */ transformOrigin: string; /** * The cached font-size of the trigger element */ triggerFontSize: number; /** * The last measured value for the trigger's client bounding rect */ triggerRect: ClientRect | undefined; /** * Define the default component ID */ readonly uid: string; /** * Management of the query string */ querySubject: BehaviorSubject; /** * Margin between select panel edge and viewport edge */ viewportMarginSpacing: number; /** * Whether all options are selected */ get allOptionsSelected(): boolean; /** * Whether the select has a value */ get empty(): boolean; /** * Whether the input has focus */ get focused(): boolean; /** * Calculates the amount of items in the select. This includes options and group labels. */ private get itemCount(); /** * Calculates the height of the options * * Only called if at least one option exists */ private get itemHeight(); /** * Whether at least 1 option is selected, but not all options */ get someOptionsSelected(): boolean; /** * Determine if the label should float */ get shouldLabelFloat(): boolean; /** * The value displayed in the select trigger */ get selectTriggerValue(): string; /** * The currently selected option or options */ get selected(): TsOptionComponent | TsOptionComponent[]; /** * Access the user-supplied override of the trigger element */ customTrigger: TsSelectTriggerComponent | undefined; /** * Access to the actual HTML element */ inputElement: ElementRef; /** * Access the label element */ labelElement: ElementRef; /** * Access the trigger that opens the select */ trigger: ElementRef; /** * Access the overlay pane containing the options */ overlayDir: CdkConnectedOverlay; /** * Access the panel containing the select options */ panel: ElementRef; /** * Access a list of all the defined select options */ options: QueryList; /** * Access all of the defined groups of options */ optionGroups: QueryList; /** * Define if multiple selections are allowed */ allowMultiple: boolean; /** * Function to compare the option values with the selected values. The first argument * is a value from an option. The second is a value from the selection. A boolean * should be returned. * * Learn more about `compareWith` in the Angular docs: * https://angular.io/api/forms/SelectControlValueAccessor#customizing-option-selection * * @param fn */ set compareWith(fn: TsSelectOptionCompareWith); get compareWith(): TsSelectOptionCompareWith; private _compareWith; /** * Define the delimiter used in the list of selected options * * @param value */ set delimiter(value: string); get delimiter(): string; private _delimiter; /** * Define if the required marker should be hidden */ hideRequiredMarker: boolean; /** * Define a hint for the input * * @param value */ set hint(value: string | undefined); get hint(): string | undefined; private _hint; /** * Define an ID for the component * * @param value */ set id(value: string); get id(): string; protected _id: string; /** * Define if the control should be disabled */ isDisabled: boolean; /** * Define if the select is filterable */ isFilterable: boolean; /** * Define if the control is required * * @param value */ set isRequired(value: boolean); get isRequired(): boolean; private _isRequired; /** * Define the label text * * @param value */ set label(value: string | undefined); get label(): string | undefined; private _label; /** * Define whether a validation or a hint needed. */ noValidationOrHint: boolean; /** * Placeholder to be shown if no value has been selected * * @param value */ set placeholder(value: string | undefined); get placeholder(): string | undefined; private _placeholder; /** * Define if the component should currently be showing a progress spinner */ showProgress: boolean; /** * Define if the component should expose a message telling the user to refine their search */ showRefineSearchMessage: boolean; /** * Define if the select should show an option to trigger a refresh (by emitting an event) */ showRefresh: boolean; /** * Function used to sort the values in a select in multiple mode * * Follows the same logic as `Array.prototype.sort`. * * See {@link TsSelectSortComparatorFunction} */ sortComparator: TsSelectSortComparatorFunction | undefined; /** * Define the tab index for the component * * @param value */ set tabIndex(value: string | number); get tabIndex(): string | number; private _tabIndex; /** * Define the component theme */ theme: TsStyleThemeTypes; /** * Define the total number of records */ totalHiddenResults: undefined | number; /** * Define if validation messages should be shown immediately or on blur */ validateOnChange: boolean; /** * Value of the select control * * @param newValue */ set value(newValue: unknown); get value(): unknown; private _value; /** * Event for when the panel is closed */ readonly closed: EventEmitter; /** * Event for when a duplicate selection is made */ readonly duplicateSelection: EventEmitter; /** * Event for when the panel is opened */ readonly opened: EventEmitter; /** * Event for when an option is removed */ readonly optionDeselected: EventEmitter; /** * Event for when an option is selected */ readonly optionSelected: EventEmitter; /** * Event for when the user requests a refresh of the available options */ readonly optionsRefreshRequested: EventEmitter; /** * Event for when the query has changed, used by filterable select */ readonly queryChange: EventEmitter; /** * Event for when the selections change */ readonly selectionChange: EventEmitter; /** * Event that emits whenever the raw value of the select changes. This is here primarily * to facilitate the two-way binding for the `value` input. * * Needed for {@link TsFormFieldComponent}. */ readonly valueChange: EventEmitter; constructor(viewportRuler: ViewportRuler, changeDetectorRef: ChangeDetectorRef, ngZone: NgZone, documentService: TsDocumentService, elementRef: ElementRef, ngControl: NgControl); /** * Trigger change detection when the underlying form changes */ ngOnInit(): void; /** * Initialize the key manager and set up change listeners */ ngAfterContentInit(): void; /** * Trigger updates when the label is dynamically changed * * @param changes */ ngOnChanges(changes: SimpleChanges): void; /** * Cleanup */ ngOnDestroy(): void; /** * Stub in onChange * * Needed for ControlValueAccessor (View -> model callback called when value changes) */ onChange: (value: unknown) => void; /** * Stub in onTouched * * Needed for ControlValueAccessor (View -> model callback called when select has been touched) */ onTouched: () => void; /** * Toggles the overlay panel open or closed. */ toggle(): void; /** * Open the overlay panel */ open(): void; /** * Close the overlay panel */ close(): void; /** * Callback that is invoked when the overlay panel has been attached */ onAttached(): void; /** * Handles all keydown events on the select * * @param event - The KeyboardEvent */ handleKeydown(event: KeyboardEvent): void; /** * Handle keyboard events when the select panel is closed * * @param event - The KeyboardEvent */ private handleClosedKeydown; /** * Handle keyboard events when the select panel is open * * @param event - The KeyboardEvent */ private handleOpenKeydown; /** * Drops current option subscriptions and IDs and resets from scratch */ private resetOptions; /** * Handle the selection when an option is clicked * * @param option - The selected option * @param isUserInput - Whether this selection happened from a user's click */ private onSelect; /** * Records option IDs to pass to the aria-owns property */ private setOptionIds; /** * Set up a key manager to listen to keyboard events on the overlay panel */ private initKeyManager; /** * Focus the correct element * * When in standard select mode we should focus the select itself. */ focus(): void; /** * Sort the selected values in the selectedModel based on their order in the panel */ private sortValues; /** * Emit a change event to set the model value * * @param fallbackValue - A fallback value to use when no selection exists */ private propagateChanges; /** * Call FormControl updateValueAndValidity function to ensure value and valid status get updated. */ private updateValueAndValidity; /** * Sets the select's value. Part of the ControlValueAccessor interface required to integrate with Angular's core forms API. * * NOTE: Currently we are not using this, but it still must be present since this component is acting as a CVA. * * @param value - New value to be written to the model */ writeValue(value: unknown): void; /** * Save a callback function to be invoked when the select's value changes from user input. * Part of the ControlValueAccessor interface required to integrate with Angular's core forms API. * * @param fn - Callback to be triggered when the value changes */ registerOnChange(fn: (value: unknown) => void): void; /** * Save a callback function to be invoked when the select is blurred by the user. * Part of the ControlValueAccessor interface required to integrate with Angular's core forms API. * * @param fn - Callback to be triggered when the component has been touched */ registerOnTouched(fn: () => {}): void; /** * Disables the select. * Part of the ControlValueAccessor interface required to integrate with Angular's core forms API. * * @param isDisabled - If the component is disabled */ setDisabledState(isDisabled: boolean): void; /** * Initialize any existing selections into the selectionModel */ private initializeSelection; /** * Sets the selected option based on a value. * If no option can be found with the designated value, the select trigger is cleared. * * @param value - The value to use to look up options */ private setSelectionByValue; /** * Find and select an option based on its value * * @param value - The value to use when searching for a matching option * @returns Option that has the corresponding value */ private selectOptionByValue; /** * Scroll the active option into view */ private scrollActiveOptionIntoView; /** * Calculate the scroll position and x- and y- offsets of the overlay panel */ private calculateOverlayPosition; /** * Calculate the scroll position of the select's overlay panel * * This attempts to center the selected option in the panel. If the option is too high or too low in the panel to be scrolled to the * center, it clamps the scroll position to the min or max scroll positions respectively. * * @param selectedIndex - The index of the item to scroll to * @param scrollBuffer - The amount to buffer the scroll * @param maxScroll - The maximum amount the panel can scroll */ private calculateOverlayScroll; /** * Calculates the y-offset of the select's overlay panel in relation to the top start corner of the trigger. * It has to be adjusted in order for the selected option to be aligned over the trigger when the panel opens. * * @param selectedIndex - The index of the selected item * @param scrollBuffer - The number of pixels to buffer the scroll by * @param maxScroll - The farthest the panel can scroll * @returns The overlay's Y offset */ private calculateOverlayOffsetY; /** * Check that the attempted overlay position will fit within the viewport. * * If it will not fit, tries to adjust the scroll position and the associated y-offset so the panel can open fully on-screen. * If it still won't fit, sets the offset back to 0 to allow the fallback position to take over. * * @param maxScroll - The maximum amount to allow the panel to scroll */ private checkOverlayWithinViewport; /** * Adjust the overlay panel up to fit in the viewport * * @param panelHeightBottom - The height of the panel bottom * @param bottomSpaceAvailable - The amount of available space at the bottom */ private adjustPanelUp; /** * Adjusts the overlay panel down to fit in the viewport * * @param panelHeightTop - The height of the panel top * @param topSpaceAvailable - The amount of available space at the top * @param maxScroll - The maximum amount the panel can be scrolled */ private adjustPanelDown; /** * Set the transform origin point based on the selected option * * @returns The transform origin CSS string */ private getOriginBasedOnOption; /** * Get the index of the provided option in the option list * * @param option - The option whose index should be found * @returns The index of the option */ private getOptionIndex; /** * Highlight the selected item. * * If no option is selected, it will highlight the first item instead. */ private highlightCorrectOption; /** * Toggle the selection all options * * If any are selected, it will unselect all & vice-versa. */ toggleAllOptions(): void; /** * Ensure the correct element gets focus when the primary container is clicked. * * Implemented as part of TsFormFieldControl. */ onContainerClick(): void; /** * Get the panel's scrollTop * * @returns The scrollTop number */ private getPanelScrollTop; /** * Set the panel's scrollTop * * This allows us to manually scroll to display options above or below the fold, as they are not actually being focused when active. * * * @param scrollTop - The number to set scrollTop to */ private setPanelScrollTop; }