UNPKG

@legumeinfo/web-components

Version:

Web Components for the Legume Information System and other AgBio databases

395 lines 18.3 kB
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