UNPKG

@platform/ui.datagrid

Version:

Isolated tabular DataGrid.

138 lines (137 loc) 5 kB
import '../../styles'; import * as React from 'react'; import { Subject } from 'rxjs'; import { debounceTime, filter, takeUntil } from 'rxjs/operators'; import { FactoryManager } from '../../factory'; import * as render from '../../render'; import { constants, containsFocus, css, defaultValue, events, Handsontable as TableLib, } from '../common'; import { getSettings } from '../settings'; import { DataGridOverlay } from './DataGrid.Overlay'; const { CSS } = constants; export class DataGrid extends React.PureComponent { constructor() { super(...arguments); this.state = {}; this.unmounted$ = new Subject(); this.state$ = new Subject(); this.elRef = (ref) => (this.el = ref); } componentDidMount() { const grid = (this.grid = this.props.grid); this.unmounted$.subscribe(() => grid.dispose()); this.state$.pipe(takeUntil(this.unmounted$)).subscribe((e) => this.setState(e)); const settings = getSettings({ grid }); const Table = this.props.Handsontable || TableLib; const table = (this.table = new Table(this.el, settings)); grid.initialize({ table }); const factory = (this.factory = new FactoryManager({ grid, factory: this.props.factory })); render.registerAll(Table, grid, factory); const refs = { grid, editorEvents$: new Subject(), factory: this.factory, }; table.__gridRefs = refs; const { events$, keyboard$ } = grid; const editor$ = refs.editorEvents$.pipe(takeUntil(this.unmounted$)); const bubble$ = this.props.events$; if (bubble$) { events$.subscribe((e) => bubble$.next(e)); } editor$.subscribe((e) => this.grid.fire(e)); events$ .pipe(filter((e) => e.type === 'GRID/redraw'), debounceTime(0)) .subscribe(() => this.redraw()); keyboard$ .pipe(filter((e) => e.metaKey && e.key === 'a'), filter((e) => this.props.canSelectAll !== true), filter((e) => !grid.isEditing)) .subscribe((e) => e.cancel()); this.updateSize(); events.resize$.pipe(takeUntil(this.unmounted$)).subscribe(() => this.redraw()); const hot = module.hot; if (hot) { hot.dispose(() => this.dispose()); } events.focus$ .pipe(takeUntil(this.unmounted$), debounceTime(0), filter((e) => e.to !== document.body), filter((e) => !containsFocus(this))) .subscribe((e) => this.grid.deselect()); this.init(); } async init() { if (this.isDisposed) { return; } const { initial = {} } = this.props; const grid = this.grid; if (initial.selection) { const selection = typeof initial.selection === 'string' ? { cell: initial.selection } : initial.selection; const { cell, ranges } = selection; grid.select({ cell, ranges }); } await grid.calc.update(); const cells = grid.data.cells; grid.changeCells(cells, { init: true, silent: true }); grid.mergeCells({ cells, init: true }); grid.fire({ type: 'GRID/ready', payload: { grid } }); this.forceUpdate(); } componentWillUnmount() { this.dispose(); } dispose() { this.unmounted$.next(); this.unmounted$.complete(); } get isDisposed() { return this.unmounted$.isStopped || this.grid.isDisposed; } get isReady() { return this.grid ? this.grid.isReady : false; } get events$() { return this.grid.events$; } focus(isFocused) { if (defaultValue(isFocused, true)) { this.grid.focus(); } else { this.grid.blur(); } return this; } redraw() { this.updateSize(); if (this.table) { this.table.render(); } return this; } updateSize() { const el = this.el; if (!el || this.isDisposed) { return; } const { offsetWidth: width, offsetHeight: height } = el; const size = { width, height }; this.state$.next({ size }); return this; } render() { const { factory } = this.props; const grid = this.grid; const styles = { base: css({ position: 'relative', overflow: 'hidden', }), grid: css({ Absolute: 0, userSelect: 'none', visibility: this.isReady ? 'visible' : 'hidden', }), }; return (React.createElement("div", Object.assign({}, css(styles.base, this.props.style)), React.createElement("div", Object.assign({ ref: this.elRef, className: CSS.CLASS.GRID.BASE }, styles.grid)), grid && React.createElement(DataGridOverlay, { grid: grid, factory: factory }))); } }