gadgets
Version:
Reusable React UI widgets - This is my widget library. There are many like it, but this one is mine...
241 lines (240 loc) • 9.27 kB
TypeScript
/**
* The `DynamicList` control is a specialized List control that can be
* manipulated by the user. They can add/remove/select items from it. The
* control takes an initial list to seed the control, but then items can be
* dynamically added/removed.
*
* Some of the features include:
*
* - Add new items with the "+" button
* - Sort the list in ascending/descending order
* - Incrementally search for items
* - List is divided into pages for performance
* - A right or left widget can be added to each list item
*
* ## Screen:
* <img src="https://github.com/jmquigley/gadgets/blob/master/images/dynamicList.png" width="60%" />
*
* ## Examples:
*
* #### Simple
* ```javascript
* import {DynamicList} from 'gadgets';
*
* <DynamicList
* errorMessage="Error message"
* items={{
* title1: {left: widget1, right: widget1}
* title2: {left: widget2, right: widget2}
* title1: {left: widget3, right: widget3}
* }}
* onDelete={(title: string) => {
* console.log(`Deleting item from list: ${title}`);
* }}
* onError({message: string} => {
* console.log(message);
* })
* onNew={(title: string) => {
* console.log(`Adding new item to list: ${title}`);
* }}
* onSelection={(title: string) => {
* console.log(`Selected item: ${title}`);
* }}
* onUpdate={(previous: string, title: string) =>
* console.log(`previous: ${previous}, title: ${title}`);
* }}
* pageSizes={[10, 20, 30]}
* title="Dynamic List Test"
* />
* ```
*
* #### With Error Handling
* This will display an error message at the top of the list and then automatically
* fade away after 5 seconds.
*
* ```javascript
* import {DynamicList} from 'gadgets';
*
* <DynamicList
* errorMessage="Show this error message"
* errorMessageDuration={3}
* items={{
* title1: {right: widget1}
* title2: {right: widget2}
* title1: {right: widget3}
* }}
* onError={(message: string) => console.log(message)}
* pageSizes={[10, 20, 30]}
* title="Dynamic List Test"
* />
* ```
*
* ## API
* #### Events
* - `onBlur` - Invoked when a list item control loses focus.
* - `onClick` - Invoked when a list item is clicked.
* - `onDelete(title: string)` - This event is executed when an item is removed
* from the list.
* - `onError(message: string)` - when an error message is written to the
* component this callback is invoked.
* - `onFocus` - Invoked when a list item is clicked.
* - `onNew(title: string)` - This event is executed when an item is added to
* the list. The title of the new item is a parameter to the callback
* - `onSelection(title: string)` - Invoked when a list item is selected. The title
* of the selected item is a parameter to the callback.
* - `onSort(sortOrder: SortOrder)` - Invoked whne the list is sorted. It will
* give the selected order to the callback.
* - `onUpdate(previous: string, title: string)` - When an item is renamed this
* callback is invoked. The previous value and the new title are passed to the
* callback
*
* #### Styles
* - `ui-dynamiclist` - applied to the `div` accordion control that holds the
* list.
* - `ui-dynamiclist-container` - applied to the top level container `div` that
* surrounds the list and the *toast* for error message handling.
*
* #### Properties
* - `errorMessage="" {string}` - A message the will be temporarily displayed
* within the control. When this message is first set it will be shown and
* then decay. It will then invoke the onError callback.
* - `errorMessageDuration=5 {number}` - the time in seconds that the
* error message string will be shown within the control before fading away.
* Set to five seconds by default.
* - `items={} {DynamicListItem}` - An object that holds unique title and
* widgets in the format `{[title]: {left: widget, right: widget}`. Each item in
* the object represents a list item. A widget, like a button or Option, can
* be used as supporting widgets in the list.
* - `layout=TitleLayout.dominant {TitleLayout}` - How the title/widget
* will be displayed in the list item (seee the Title control).
* - `nocollapse=false {boolean}` - Determines if the list can be
* "rolled up" when the header is clicked. The default behavior is to
* allow. IF this is set to false, then the list can't be collapsed.
* - `noselect=false {boolean}` - when true the selection highlight is
* disabled and removed.
* - `pageSizes=[25, 50, 100] number[]` - A list of page number sizes that
* can be used by the pager. It is used against the total items to
* determine the total number of pages in the control display.
* - `sortOrder=SortOrder.ascending {SortOrder}` - The list sort order. Can
* be either ascending or descending.
* - `title="" {string}` - This string value is in the header of the control.
*
* @module DynamicList
*/
import * as React from "react";
import { BaseComponent, BaseProps, BaseState, SortOrder } from "../shared";
import { TitleLayout } from "../title/Title";
export interface DynamicListItem {
[key: string]: any;
}
export interface DynamicListProps extends BaseProps {
collapsable?: boolean;
errorMessageDuration?: number;
items?: DynamicListItem;
layout?: TitleLayout;
nocollapse?: boolean;
noselect?: boolean;
onBlur?: (e: React.FocusEvent<HTMLLIElement>) => void;
onClick?: (e: React.MouseEvent<HTMLLIElement>) => void;
onDelete?: (title: string) => void;
onError?: (message: string) => void;
onFocus?: (e: React.FocusEvent<HTMLLIElement>) => void;
onNew?: (title: string, widget: any) => void;
onSelection?: (title: string) => void;
onSort?: (sortOrder: SortOrder) => void;
onUpdate?: (previousTitle: string, title: string) => void;
pageSizes?: number[];
sortOrder?: SortOrder;
title?: any;
}
export interface DynamicListState extends BaseState {
errorMessage?: string;
initialToggle?: boolean;
page?: number;
pageSize?: number;
search?: string;
showConfirm?: boolean;
showError?: boolean;
showNew?: boolean;
sortOrder?: SortOrder;
totalItems?: number;
}
export declare class DynamicList extends BaseComponent<DynamicListProps, DynamicListState> {
static readonly defaultProps: DynamicListProps;
private readonly _baseMessage;
private _emptyListItem;
private _fillerKeys;
private _fillerIdx;
private _footer;
private _footerID;
private _keyList;
private _listItems;
private _pager;
private _pagerID;
private _previousPage;
private _qDelete;
private _selection;
private _startSearch;
constructor(props: DynamicListProps);
private buildListItems;
private buildTitle;
/**
* Takes the given title and computes the page where this title would
* be found. It takes the current position within the list items and
* divides it by the page size to find its current page.
* @param title {string} the title to find within the list items
* @returns the page number where this item resides. If it is not
* found it will return 1.
*/
private computePageByItem;
private createListItem;
/**
* Sets the control into a new item mode. This will show the input control
* and wait for user input.
*/
private createNewItem;
private handleBlur;
/**
* Receives the name of an element to remove from the List. This will
* remove it from the state and remove its ListItem control that was
* generated for it.
* @param title {string} the title to remove from the list
* @param cb {Function} a callback function that is executed when the
* delete state event update completes.
*/
private handleDelete;
private handleDeleteConfirm;
private handleErrorClose;
private handleKeyDown;
/**
* When the data in the input control is changed/added, this event handler
* is called to process it. This happens when the label within the
* ListItem for new items is changed.
* @param title {string} the title that will be added to the list
* @param cb {Function} a callback function that is executed when the update
* is complete
*/
private handleNewItem;
private handleNewPageSize;
private handlePageChange;
private handleSearch;
private handleSelect;
private handleSort;
private handleTitleClick;
private handleUpdate;
private hideEdit;
private listItemDeletor;
static getDerivedStateFromProps(props: DynamicListProps, state: DynamicListState): any;
/**
* An internal convenience method that updates internal components of the
* the component. This could all be pasted into render, but I hate making
* large single functions even if react wants to force me to do it. This
* is a consequence of the updates to the react lifecycle.
*
* @param nextProps {DynamicListProps} the next set of props used to draw the component
* @param nextState {DynamicListState} the current state of the component befoer render
*/
private _updateWidgets;
render(): JSX.Element;
}
export default DynamicList;