@legumeinfo/web-components
Version:
Web Components for the Legume Information System and other AgBio databases
395 lines • 18.3 kB
TypeScript
import { LitElement } from 'lit';
import { Ref } from 'lit/directives/ref.js';
import { LisCancelPromiseController, LisDomContentLoadedController, LisQueryStringParametersController } from '../controllers';
import { LisInlineLoadingElement } from '../core';
import { StringObjectModel } from '../models';
/**
* The constructor used to type constrain the super class type of the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin.
*
* @typeParam T - The type of class to be instantiated.
* @typeParam Params - The type of the parameters argument for T.
*
* @param args - The arguments that will be passed to the super class
* constructor.
*/
export type Constructor<T = {}, Params extends any[] = any[]> = new (...args: Params) => T;
/**
* The type of object a component that uses the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin expects
* back when it performs a search.
*
* @typeParam SearchResult - The type to expect in the results array of a
* paginated search results object.
*/
export type PaginatedSearchResults<SearchResult> = {
pageSize?: number;
hasNext?: boolean;
numResults?: number;
numPages?: number;
errors?: string[];
results: SearchResult[];
};
/**
* Used to require pagination information in generic types.
*/
export type PaginatedSearchData = {
page: number;
};
/**
* Optional parameters that may be given to a search function of a component
* that uses the {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`}
* mixin. The {@link !AbortSignal | `AbortSignal`} instance will emit if a search is
* performed before the current search completes. This signal should be used to
* cancel in-flight requests if the search API supports it.
*/
export type PaginatedSearchOptions = {
abortSignal?: AbortSignal;
};
/**
* The signature of the search function required by components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin.
*
* @typeParam SearchData - The type of data that will be given to the search
* function.
* @typeParam SearchResult - The type that is expected to be in the results
* array of the {@link PaginatedSearchResults | `PaginatedSearchResults`}
* instance resolved by the {@link !Promise | `Promise`} returned by the search
* function.
*
* @param searchData - The data that should be used to perform a search.
* @param page - What page of the paginated results should be returned.
* @param options - Optional parameters that aren't required to perform a search
* but may be useful.
*/
export type SearchFunction<SearchData, SearchResult> = (searchData: SearchData & PaginatedSearchData, options: PaginatedSearchOptions) => Promise<PaginatedSearchResults<SearchResult>>;
/**
* The type of object a component that uses the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin expects
* back when it performs a download.
*/
export type DownloadResults = {
errors?: string[];
};
/**
* The signature of the optional download function available in components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin.
*
* @typeParam SearchData - The type of data that will be given to the search
* function.
*
* @param searchData - The data that should be used to perform a search.
* @param options - Optional parameters that aren't required to perform a search
* but may be useful.
*/
export type DownloadFunction<SearchData> = (searchData: SearchData, options: PaginatedSearchOptions) => Promise<DownloadResults>;
/**
* The interface of the class generated by the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin.
*
* @typeParam SearchData - The type of data that will be given to
* {@link LisPaginatedSearchElementInterface.searchFunction | `searchFunction`}.
* @typeParam SearchResult - The type that is expected to be in the results
* array of the {@link PaginatedSearchResults | `PaginatedSearchResults`}
* instance resolved by the {@link !Promise | `Promise`} returned by the
* {@link LisPaginatedSearchElementInterface.searchFunction | `searchFunction`}.
*/
export declare class LisPaginatedSearchElementInterface<SearchData, SearchResult> {
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin will
* inherit this property. It stores an external function that must be provided
* by users of the component that performs a search using the data from the
* component's submitted search form.
*/
searchFunction: SearchFunction<SearchData, SearchResult>;
/**
* Components that use the {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`}
* mixin will inherit this property. It stores an external function that can optionally
* be provided by users of the component that loads a file to download using the data
* from the component's submitted search form.
*/
downloadFunction?: DownloadFunction<SearchData>;
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin must
* define what attributes their search results will have so the mixin can
* correctly parse and display the results in a table. These attributes
* can be specified by setting this property in a component's constructor.
* Additionally, this property may be used by the end user at run-time to override the
* default result attributes defined by the component.
*/
resultAttributes: string[];
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin must
* define what attributes their search results will have so the mixin can
* correctly parse and display the results in a table. The header of the
* table is set from an object that has these attributes. The object can
* be specified by setting this property in a component's constructor. Additionally,
* this property may be used by the end used at run-time to override the default table
* headers defined by the component.
*/
tableHeader: StringObjectModel;
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin can optionally
* define CSS classes for the columns of the table results are displayed in a table.
* The classes are set from an object that has attributes matching the
* `resultAttributes`. The object can be specified by setting this property in a
* component's constructor. Additionally, this property may be used by the end used at
* run-time to override the default table column classes defined by the component.
*/
tableColumnClasses: StringObjectModel;
/**
* A helper method that returns that first value that's defined: the given value, the value of the
* specified querystring parameter, an empty string.
*
* @param value - The value to potentially return.
* @param parameter - The querystring parameter to potentially return the value of.
*
* @returns The first value that was defined.
*/
protected valueOrQuerystringParameter(value: string | undefined, parameter: string): string;
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin will
* inherit this method. It allows the component's search form to be submitted
* programmatically.
*/
submit(): void;
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin can use
* this controller to interact with URL query string parameters. For example,
* it can be used to set values of form elements reactively, i.e. if the
* query string parameter a form element gets its value changes, then the
* element's value will be updated in the component's template.
*/
protected queryStringController: LisQueryStringParametersController;
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin can use
* this controller to subscribe to the
* {@link !DOMContentLoaded | `DOMContentLoaded`} event. The advantage to
* using the controller instead of subscribing to the event directly is that
* the controller triggers a redraw of the component's template, meaning if a
* listener updates a property that should change the template, triggering a
* redraw of the template will be handled by the controller.
*/
protected domContentLoadedController: LisDomContentLoadedController;
/**
* Current Web standards do not allow {@link !Promise | `Promises`} to be
* cancelled. Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin can use
* this controller to make {@link !Promise | `Promises`} cancelable. Event
* listeners can also subscribe to the controller and will be called whenever
* it cancels. The underlying {@link !AbortSignal | `AbortSignal`} is also
* available for more low-level access. This is the value of the `abortSignal`
* attribute of the {@link PaginatedSearchOptions | `PaginatedSearchOptions`}
* object passed to the component's {@link SearchFunction | `SearchFunction`}
* and {@link DownloadFunction | `DownloadFunction`}..
*/
protected cancelPromiseController: LisCancelPromiseController;
/**
* The {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin will
* automatically perform a search when loaded if certain parameters are
* present in the URL query string. Components that use the mixin can specify
* what parameters are necessary by setting this property in their
* constructor. Specifically, this property represents groups of parameters that will
* trigger a search if all parameters within a group are present.
*/
protected requiredQueryStringParams: string[][];
/**
* The {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin will
* automatically reflect all form field values in the URL querystring parameters.
* Set this property to `false` to disable this behavior.
*/
protected queryStringReflection: boolean;
/**
* The results returned by the `searchFunction`.
*/
searchResults: SearchResult[];
/**
* When the form of a component that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin is
* submitted, the mixin parses the form contents into a
* {@link !FormData | `FormData`} instance. This instance is converted into
* a simple object mapping form element names to their values. This conversion
* is done with the `formToObject` method. If the object doesn't match the
* expected `SearchData` template type or if there are redundant names in the
* {@link !FormData | `FormData`} instance that need to be resolved, then the
* component should override the `formToObject` method.
*
* @param formData - The {@link !FormData | `FormData`} instance to convert
* into an object.
*
* @returns The object generated from the given {@link !FormData | `FormData`}
* instance.
*/
protected formToObject(formData: FormData): SearchData;
/**
* Components that use the
* {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} mixin need to
* provide the search form that the mixin will process. This is done by
* overriding the `renderForm` method.
*
* @throws {@link !Error | `Error`}
* This exception is thrown if the `renderForm` method is not overridden when
* called.
*
* @returns The form portion of the template.
*/
protected renderForm(): unknown;
/**
* By default, the {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`}
* displays search results info using the in paragraph tags. Components that use the
* mixin can override this portion of the template by implementing their own
* `renderResultsInfo` method.
*
* @returns The results info portion of the template.
*/
protected renderResultsInfo(): unknown;
/**
* By default, the {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`}
* displays search results using the
* {@link LisSimpleTableElement | `LisSimpleTableElement`}. Components that use the
* mixin can override this portion of the template by implementing their own
* `renderResults` method. The results data will be available via the inherited
* `searchResults` variable.
*
* @returns The results portion of the template.
*/
protected renderResults(): unknown;
/** @internal */
protected _downloadingRef: Ref<LisInlineLoadingElement>;
}
/**
* A mixin that encapsulates code that implements a paginated search. The mixin
* is a function that uses the factory pattern to generate a class to be
* extended by a component. To use the mixin, call the function with the
* appropriate template arguments and extend the class it returns when defining
* a component.
*
* @typeParam T - The class to use as the super class of the generated mixin
* class. Should be an instance of the `LitElement` class or a descendant of it.
* @typeParam SearchData - The type of data that will be given to
* {@link LisPaginatedSearchElementInterface.searchFunction | `searchFunction`}.
* @typeParam SearchResult - The type that is expected to be in the results
* array of the {@link PaginatedSearchResults | `PaginatedSearchResults`}
* instance resolved by the {@link !Promise | `Promise`} returned by the
* {@link LisPaginatedSearchElementInterface.searchFunction | `searchFunction`}.
*
* @param superClass - The class to use as the super class of the generated
* mixin class. Should be an instance of the `LitElement` class or a descendant
* of it.
*
* @returns The generated mixin class.
*
* @example
* When using the mixin, the
* {@link LisPaginatedSearchElementInterface.requiredQueryStringParams | `requiredQueryStringParams`},
y {@link LisPaginatedSearchElementInterface.resultAttributes | `resultAttributes`},
* and {@link LisPaginatedSearchElementInterface.tableHeader | `tableHeader`}
* properties of the extended class must be set in the component's constructor.
*
* The {@link LisPaginatedSearchElementInterface.renderForm | `renderForm`}
* method must be overridden to define the form part of the component's
* template. It is recommended that the form's elements' values are bound to the
* URL query string parameters using the inherited
* {@link LisPaginatedSearchElementInterface.queryStringController | `queryStringController`}
* since their values will automatically be reflected in the URL query string
* parameters.
*
* Lastly, note the due to TypeScript's lack of support for partial type
* argument inference the mixin function is curried. This means the function
* returns another function that must also be called to generate the mixin
* class:
* ```js
* @customElement('lis-gene-search-element')
* export class LisGeneSearchElement extends
* LisPaginatedSearchMixin(LitElement)<GeneSearchData, GeneSearchResult>() // <-- curried function call
* {
*
* // set properties in the constructor
* constructor() {
* super();
* // configure query string parameters
* this.requiredQueryStringParams = [['query']];
* // configure results table
* this.resultAttributes = ['name', 'description'];
* this.tableHeader = {name: 'Name', description: 'Description'};
* }
*
* // define the form part of the template
* override renderForm() {
* // NOTE:
* // 1) the input element has a name attribute, which all form elemnts are required to have
* // 2) the input value is set to a URL query string parameter value
* return html`
* <form>
* <fieldset class="uk-fieldset">
* <legend class="uk-legend">Gene search</legend>
* <div class="uk-margin">
* <input
* name="query" // <-- all form elements need a name
* class="uk-input"
* type="text"
* placeholder="Input"
* aria-label="Input"
* .value=${this.queryStringController.getParameter('query')}>
* </div>
* <div class="uk-margin">
* <button type="submit" class="uk-button uk-button-primary">Search</button>
* </div>
* </fieldset>
* </form>
* `;
* }
*
* }
* ```
*
* @example
* By default, the {@link LisPaginatedSearchMixin | `LisPaginatedSearchMixin`} renders
* search results using the {@link LisSimpleTableElement | `LisSimpleTableElement`}.
* If this is too restrictive, a class that uses the mixin may override its
* `renderResults` method to draw the results portion of the template itself.
* For example:
* ```js
* @customElement('lis-gene-search-element')
* export class LisGeneSearchElement extends
* LisPaginatedSearchMixin(LitElement)<GeneSearchData, GeneSearchResult>() // <-- curried function call
* {
*
* // set properties in the constructor
* constructor() {
* super();
* // configure query string parameters
* this.requiredQueryStringParams = [['query']];
* // no need to configure the results table since we're going to override it
* }
*
* // define the form part of the template
* override renderForm() {
* ...
* }
*
* // define the results part of the template
* override renderResults() {
* // this is actually the default implementation provided by the mixin
* return html`
* <lis-simple-table-element
* caption="Search Results"
* .dataAttributes=${this.resultAttributes}
* .header=${this.tableHeader}
* .data=${this.searchResults}>
* </lis-simple-table-element>
* `;
* }
*
* }
* ```
*/
export declare const LisPaginatedSearchMixin: <T extends Constructor<LitElement>>(superClass: T) => <SearchData, SearchResult>() => Constructor<LisPaginatedSearchElementInterface<SearchData, SearchResult>> & T;
//# sourceMappingURL=lis-paginated-search-mixin.d.ts.map