UNPKG

mobx-restful-table

Version:

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

252 lines (250 loc) 12.4 kB
import { FC, JSX, HTMLAttributes, InputHTMLAttributes, DragEvent, TextareaHTMLAttributes, ReactNode, KeyboardEvent, ChangeEvent, FormEvent, Component, FocusEvent } from "react"; import { BadgeProps, ImageProps, FloatingLabelProps, FormControlProps, FormSelectProps, ButtonProps, FormGroupProps, FormProps, TableProps } from "react-bootstrap"; import { Variant } from "react-bootstrap/esm/types"; import { ObservedComponent, FormComponent, FormComponentProps } 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; onCheck?: (item: BadgeItem, index: number) => any; onDelete?: (item: BadgeItem, index: number) => any; } export const BadgeBar: FC<BadgeBarProps>; export type ImagePreviewProps = ImageProps & Partial<Pick<HTMLMediaElement, 'srcObject'>>; export class ImagePreview extends ObservedComponent<ImagePreviewProps> { static readonly displayName = "ImagePreview"; accessor downloading: boolean; accessor loadedPath: string; accessor viewing: boolean; objectURL: string; componentDidMount(): void; componentWillUnmount(): 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; file?: HTMLMediaElement['srcObject']; }; 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 interface FilePickerProps extends FormComponentProps<string | File> { onView?: (data: Pick<FilePreviewProps, 'path' | 'file'>) => void; } export class FilePicker extends FormComponent<FilePickerProps> { #private; static readonly displayName = "FilePicker"; accessor file: File | undefined; get fileType(): string; get filePath(): string; protected restoreFile(data: FilePickerProps['value']): Promise<File>; componentDidMount(): 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[]>, Pick<FilePickerProps, 'onView'> { store: FileModel; } export class FileUploader extends FormComponent<FileUploaderProps> { static readonly displayName = "FileUploader"; accessor pickIndex: number | undefined; componentDidMount(): void; protected restoreFile(value: FileUploaderProps['value']): 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 type TextInputType = (typeof TextInputTypes)[number]; export interface BadgeInputProps extends FormComponentProps<string[]> { type?: TextInputType; } export class BadgeInput extends FormComponent<BadgeInputProps> { static readonly displayName = "BadgeInput"; static match(type: string): type is TextInputType; 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; protected readonly rowIds: string[]; protected getRowId(index: number): string; componentDidMount(): void; insert: (index?: number) => void; remove: (index: number) => void; handleChange: (index: number) => ({ currentTarget }: ChangeEvent<EventTarget>) => void; handleUpdate: (index: number) => ({ currentTarget }: ChangeEvent<EventTarget>) => void; 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'>, Pick<ButtonProps, 'size'> { id?: IDType; fields: Field<D>[]; store?: ListModel<D, F>; translator: TranslationModel<string, 'submit' | 'cancel'>; onSubmit?: (data: D) => any; onReset?: (data: Partial<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>; handleReset: ({ currentTarget }: FormEvent<HTMLFormElement>) => 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<D extends DataObject, F extends Filter<D> = Filter<D>> extends Omit<TableProps, 'onSubmit' | 'onReset'>, Omit<RestFormProps<D>, 'id' | 'size' | 'fields' | 'translator'> { filter?: F; filterFields?: Field<F>[]; editable?: boolean; deletable?: boolean; columns: Column<D>[]; translator: Translator<D>; onCheck?: (keys: IDType[]) => any; } export class RestTable<D extends DataObject, F extends Filter<D> = Filter<D>> extends ObservedComponent<RestTableProps<D, F>> { static readonly displayName = "RestTable"; componentDidMount(): void; get fieldSize(): "sm" | "lg"; accessor checkedKeys: IDType[]; toggleCheck(key: IDType): void; toggleCheckAll: () => void; get checkColumn(): Column<D>; get operateColumn(): Column<D>; get columns(): Column<D>[]; get hasHeader(): boolean; get hasFooter(): boolean; get editing(): boolean; renderCustomBody: ({ key, type, multiple, options, accept, rows, }: Column<D>) => Column<D>["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>, 'defaultValue' | 'onChange' | '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?: TextInputType; 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