UNPKG

mobx-restful-table

Version:

A Pagination Table & Scroll List component suite for CRUD operation, which is based on MobX RESTful & React.

240 lines (238 loc) 11.6 kB
import { FC, Component, HTMLAttributes, InputHTMLAttributes, DragEvent, TextareaHTMLAttributes, ReactNode, KeyboardEvent, ChangeEvent, FormEvent, FocusEvent } from "react"; import { BadgeProps, ImageProps, FloatingLabelProps, FormControlProps, FormSelectProps, FormGroupProps, FormProps, TableProps } from "react-bootstrap"; import { Variant } from "react-bootstrap/esm/types"; import { JSX } from "react/jsx-runtime"; import { FormComponent, FormComponentProps, ObservedComponent } from "mobx-react-helper"; import { BaseModel, DataObject, Filter, IDType, ListModel } from "mobx-restful"; import { TranslationModel } from "mobx-i18n"; import { EditorProps } from "react-bootstrap-editor"; import { DebouncedFunc } from "lodash"; export const VariantColors: Variant[]; export const text2color: (raw: string) => Variant; export interface BadgeItem { text: string; link?: string; } export interface BadgeBarProps extends BadgeProps { list: BadgeItem[]; bgResolver?: (text: string) => Variant | string; onDelete?: (item: BadgeItem, index: number) => any; } export const BadgeBar: FC<BadgeBarProps>; export class ImagePreview extends Component<ImageProps> { static readonly displayName = "ImagePreview"; accessor downloading: boolean; accessor loadedPath: string; accessor viewing: boolean; componentDidMount(): void; componentDidUpdate({ src }: Readonly<ImageProps>): void; load(path: string): Promise<void>; render(): JSX.Element; } export type FilePreviewProps = ImageProps & HTMLAttributes<HTMLAudioElement> & HTMLAttributes<HTMLVideoElement> & HTMLAttributes<HTMLAnchorElement> & { type?: InputHTMLAttributes<HTMLInputElement>['accept']; path: string; }; export const FileTypeMap: { stream: string; compressed: string; msword: string; document: string; powerpoint: string; presentation: string; excel: string; sheet: string; }; export const FilePreview: FC<FilePreviewProps>; export type FilePickerProps = FormComponentProps<string | File>; export class FilePicker extends FormComponent<FilePickerProps> { #private; static readonly displayName = "FilePicker"; accessor file: File | undefined; get fileType(): string; get filePath(): string; componentDidMount(): void; componentWillUnmount(): void; renderInput(): JSX.Element; render(): JSX.Element; } export abstract class FileModel extends BaseModel { accessor files: string[]; clear(): void; /** * Override this method for Network calling, * then call `super.upload(fileURL)` to update `this.files` array. */ upload(file: string | Blob): Promise<string>; /** * Override this method for Network calling, * then call `super.delete(fileURL)` to update `this.files` array. */ delete(file: string): Promise<void>; move(sourceIndex: number, targetIndex: number): void; } export interface FileUploaderProps extends FormComponentProps<string[]> { store: FileModel; } export class FileUploader extends FormComponent<FileUploaderProps> { #private; static readonly displayName = "FileUploader"; accessor pickIndex: number | undefined; componentDidMount(): void; componentWillUnmount(): void; handleDrop: (index: number) => (event: DragEvent<HTMLElement>) => void; handleChange: (oldURI?: string) => (file: File) => Promise<void>; render(): JSX.Element; } export interface SelectOption extends Partial<Pick<HTMLOptionElement, 'text' | 'label' | 'disabled'>> { value: string; } export type FormFieldProps = FormControlProps & FormSelectProps & Pick<TextareaHTMLAttributes<HTMLTextAreaElement>, 'rows'> & Pick<FloatingLabelProps, 'label'> & { options?: SelectOption[]; }; export const FormField: FC<FormFieldProps>; export interface RangeInputProps extends Omit<FormComponentProps, 'type'> { icon?: ReactNode | ((itemValue: number) => ReactNode); } export class RangeInput extends FormComponent<RangeInputProps> { static readonly displayName = "RangeInput"; renderItem(index: number): JSX.Element; render(): JSX.Element; } export const TextInputTypes: readonly ["text", "number", "tel", "email", "url"]; export interface BadgeInputProps extends FormComponentProps<string[]> { type?: (typeof TextInputTypes)[number]; } export class BadgeInput extends FormComponent<BadgeInputProps> { static readonly displayName = "BadgeInput"; static match(type: string): type is BadgeInputProps['type']; handleInput: (event: KeyboardEvent<HTMLInputElement>) => void; delete(index: number): void; render(): JSX.Element; } export type ArrayFieldProps<T extends DataObject = DataObject> = Pick<HTMLAttributes<HTMLFieldSetElement>, 'className' | 'style'> & FormComponentProps<T[]> & { renderItem: (item: T, index: number) => ReactNode; }; export class ArrayField<T extends DataObject = DataObject> extends FormComponent<ArrayFieldProps<T>> { static displayName: string; componentDidMount(): void; add: () => T[]; remove: (index: number) => T[]; handleChange: (index: number) => ({ currentTarget }: ChangeEvent<EventTarget>) => void; handleUpdate: (index: number) => ({ currentTarget }: ChangeEvent<EventTarget>) => T; render(): JSX.Element; } export interface Field<T extends DataObject> extends Pick<InputHTMLAttributes<HTMLInputElement>, 'type' | 'readOnly' | 'disabled' | 'required' | 'min' | 'minLength' | 'max' | 'maxLength' | 'step' | 'pattern' | 'multiple' | 'accept' | 'placeholder'>, Pick<FormFieldProps, 'options' | 'rows' | 'contentEditable'>, Pick<EditorProps, 'tools'>, Partial<Record<`${'' | 'in'}validMessage`, ReactNode>> { key?: keyof T; renderLabel?: ReactNode | ((key: keyof T) => ReactNode); renderInput?: (data: T, meta: Field<T>) => ReactNode; uploader?: FileModel; } export interface FieldBoxProps<D extends DataObject> extends FormGroupProps, Pick<Field<D>, 'renderLabel' | `${'' | 'in'}validMessage`> { name: Field<D>['key']; } export interface RestFormProps<D extends DataObject, F extends Filter<D> = Filter<D>> extends Pick<FormProps, 'className' | 'style'> { id?: IDType; fields: Field<D>[]; store: ListModel<D, F>; translator: TranslationModel<string, 'submit' | 'cancel'>; onSubmit?: (data: D) => any; } export class RestForm<D extends DataObject, F extends Filter<D> = Filter<D>> extends ObservedComponent<RestFormProps<D, F>> { static readonly displayName = "RestForm"; static dateValueOf: <D_1 extends DataObject>({ type, step }: Field<D_1>, raw: D_1[keyof D_1]) => string | D_1[keyof D_1]; static FieldBox: <D_1 extends DataObject>({ name, renderLabel, validMessage, invalidMessage, children, ...props }: FieldBoxProps<D_1>) => JSX.Element; accessor validated: boolean; componentDidMount(): void; handleSubmit: (event: FormEvent<HTMLFormElement>) => Promise<void>; get fields(): Field<D>[]; get readOnly(): boolean; get customValidation(): boolean; get fieldReady(): boolean; renderFile: ({ key, type, required, multiple, accept, uploader, ...meta }: Field<D>) => ({ [key]: paths }: D) => JSX.Element; renderCheckGroup: ({ key, type, options, ...meta }: Field<D>) => (data: D) => JSX.Element; renderMultipleInput: ({ key, type, ...meta }: Field<D>) => ({ [key]: value }: D) => JSX.Element; renderHTMLEditor: ({ key, contentEditable, tools, ...meta }: Field<D>) => ({ [key]: value }: D) => JSX.Element; renderField: ({ key, type, step, renderLabel, renderInput, validMessage, invalidMessage, ...meta }: Field<D>, props?: Partial<FormFieldProps>) => ({ [key]: value }: D) => JSX.Element; render(): JSX.Element; } export type PageMeta = Pick<ListModel<{}>, 'pageSize' | 'pageIndex'>; export interface PagerProps extends PageMeta { pageCount: number; onChange?: (meta: PageMeta) => any; } export const Pager: FC<PagerProps>; export interface Column<T extends DataObject> extends Omit<Field<T>, 'renderLabel'> { renderHead?: Field<T>['renderLabel']; renderBody?: (data: T) => ReactNode; renderFoot?: ReactNode | ((data: keyof T) => ReactNode); } type Translator<T extends DataObject> = RestFormProps<T>['translator'] & TranslationModel<string, 'create' | 'view' | 'edit' | 'delete' | 'total_x_rows' | 'sure_to_delete_x'>; export interface RestTableProps<T extends DataObject> extends Omit<TableProps, 'onSubmit'>, Omit<RestFormProps<T>, 'id' | 'fields' | 'translator'> { editable?: boolean; deletable?: boolean; columns: Column<T>[]; translator: Translator<T>; onCheck?: (keys: IDType[]) => any; } export class RestTable<T extends DataObject> extends ObservedComponent<RestTableProps<T>> { static readonly displayName = "RestTable"; componentDidMount(): void; accessor checkedKeys: IDType[]; toggleCheck(key: IDType): void; toggleCheckAll: () => void; get checkColumn(): Column<T>; get operateColumn(): Column<T>; get columns(): Column<T>[]; get hasHeader(): boolean; get hasFooter(): boolean; get editing(): boolean; renderCustomBody: ({ key, type, multiple, options, accept, rows, }: Column<T>) => Column<T>["renderBody"]; renderTable(): JSX.Element; getList: DebouncedFunc<({ pageIndex, pageSize }: any) => void>; deleteList(keys: IDType[]): Promise<void>; render(): JSX.Element; } export type EdgePosition = 'top' | 'bottom' | 'left' | 'right'; export type TouchHandler = (edge: EdgePosition) => any; export interface ScrollBoundaryProps extends HTMLAttributes<HTMLDivElement>, Partial<Record<EdgePosition, ReactNode>> { onTouch: TouchHandler; } export const ScrollBoundary: FC<ScrollBoundaryProps>; export interface ScrollListProps<D extends DataObject, F extends Filter<D> = Filter<D>> extends Omit<ScrollBoundaryProps, 'onTouch'> { translator: TranslationModel<string, 'load_more' | 'no_more'>; store: ListModel<D, F>; filter?: F; defaultData?: D[]; renderList(allItems: D[]): ReactNode; } export class ScrollList<D extends DataObject = DataObject, F extends Filter<D> = Filter<D>> extends Component<ScrollListProps<D, F>> { static readonly displayName = "ScrollList"; componentDidMount(): Promise<void>; componentWillUnmount(): void; loadMore: DebouncedFunc<(edge: EdgePosition) => void>; render(): JSX.Element; } export type OptionData = Record<'label' | 'value', string>; export type SearchableInputProps<D extends DataObject, F extends Filter<D> = Filter<D>> = Omit<ScrollListProps<D, F>, 'id' | 'defaultValue' | 'onChange' | 'defaultData' | 'renderList'> & FormComponentProps<OptionData[]> & Omit<RestFormProps<D, F>, 'fields'> & { translator: RestFormProps<D, F>['translator'] & ScrollListProps<D, F>['translator']; fields?: RestFormProps<D, F>['fields']; labelKey: keyof D; valueKey: keyof D; renderList?: ScrollListProps<D, F>['renderList']; type?: (typeof TextInputTypes)[number]; multiple?: boolean; }; export class SearchableInput<D extends DataObject, F extends Filter<D> = Filter<D>> extends FormComponent<SearchableInputProps<D, F>> { static readonly displayName = "SearchableInput"; accessor filter: F; accessor listShown: boolean; search: DebouncedFunc<(value: string) => Promise<void>>; add: (label: string, value: string) => void; delete: (index: number) => OptionData[]; handleBlur: ({ target, relatedTarget }: FocusEvent<HTMLElement>) => void; renderList: ScrollListProps<D, F>['renderList']; renderOverlay(): JSX.Element; render(): JSX.Element; } //# sourceMappingURL=index.d.ts.map