UNPKG

@adaptabletools/adaptable

Version:

Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

179 lines (178 loc) 7.29 kB
import * as React from 'react'; import { renderWithAdaptableContext } from '../../../View/renderWithAdaptableContext'; import { InternalAdaptableDateEditor, } from './InternalAdaptableDateEditor'; import { KeyCode } from 'ag-grid-enterprise'; import { forwardRef, useImperativeHandle, useRef, useState } from 'react'; import { DateFormatter } from '../../../Utilities/Helpers/FormatHelper'; function shouldClearExistingValue(params) { return params.eventKey === KeyCode.BACKSPACE || params.eventKey === KeyCode.DELETE; } function getStartValue(params) { return shouldClearExistingValue(params) ? '' : params.value; } const style = { position: 'absolute', top: '0px', left: '0px', right: '0px', bottom: '0px', }; const defaultDateValueParser = ({ newValue, oldValue, defaultParser }) => { if ((typeof oldValue === 'string' || oldValue == null) && defaultParser) { return defaultParser(newValue); } return newValue; }; export const AdaptableReactDateEditor = forwardRef((props, ref) => { const [initialValue] = useState(() => getStartValue(props)); const valueRef = useRef(initialValue); const colValueParser = props.column.getColDef().valueParser; const valueParser = typeof colValueParser === 'function' ? colValueParser : defaultDateValueParser; const adaptable = props.context.__adaptable; const editorRef = useRef(null); useImperativeHandle(ref, () => { return { focusIn() { editorRef.current?.focus(); }, // the final value to send to the grid, on completion of editing getValue() { return valueRef.current; }, }; }); const editorElement = (React.createElement(InternalAdaptableDateEditor, { defaultValue: initialValue, dateFormat: adaptable.adaptableOptions.userInterfaceOptions.dateInputOptions.dateFormat, onValueChange: (value) => { const invalid = isNaN(+value); if (valueParser) { const params = { ...props, oldValue: props.value, newValue: value, defaultParser: (value) => { const Pattern = adaptable.adaptableOptions.userInterfaceOptions?.dateInputOptions?.dateFormat; if (!Pattern) { return value; } return DateFormatter(value, { Pattern, }); }, }; // @ts-ignore it will be fixed with https://github.com/AdaptableTools/adaptable/issues/2230 valueRef.current = valueParser(params); props.onValueChange?.(valueRef.current); } else { valueRef.current = invalid ? null : value; } if (!invalid) { requestAnimationFrame(() => { props.stopEditing(); }); } }, onStopEdit: (keyboardEventKey) => { if (keyboardEventKey === 'Escape') { props.api.stopEditing(true); } else { props.stopEditing(); } }, ref: (editor) => { editorRef.current = editor; editor?.focus(); } })); return React.createElement("div", { style: style }, renderWithAdaptableContext(editorElement, adaptable)); }); /** * Used by default for all `date` columns. * * * When the colDef has a `valueParser` provided as a function, it will be used before setting the value for the cell. * This is useful because dates can be stored as strings, numbers or Date instances - the value parser will be called with a `Date` instance, * and it's your responsibility to transform that to whatever format you want to use for persisting it to the grid. * * We strongly recommend you specify a `colDef.valueParser` function */ export class AdaptableDateEditor { constructor() { this.valueParser = defaultDateValueParser; } init(params) { this.value = getStartValue(params); const { valueParser } = params.column.getColDef(); this.params = params; if (typeof valueParser === 'function') { this.valueParser = valueParser; } this.el = document.createElement('div'); Object.keys(style).forEach((key) => { //@ts-ignore this.el.style[key] = style[key]; }); } /* Component Editor Lifecycle methods */ // gets called once when grid ready to insert the element getGui() { return this.el; } // the final value to send to the grid, on completion of editing getValue() { return this.value; } focusIn() { this.editor?.focus(); } focusOut() { } getAdaptableInstance(params) { const adaptable = params.context.__adaptable; return adaptable; } // after this component has been created and inserted into the grid afterGuiAttached() { const adaptable = this.getAdaptableInstance(this.params); const defaultValue = shouldClearExistingValue(this.params) ? '' : this.params.value; const editorElement = (React.createElement(InternalAdaptableDateEditor, { defaultValue: defaultValue, dateFormat: adaptable.adaptableOptions.userInterfaceOptions.dateInputOptions.dateFormat, onValueChange: (value) => { const invalid = isNaN(+value); if (this.valueParser) { const params = { ...this.params, oldValue: this.params.value, newValue: value, defaultParser: (value) => { const Pattern = adaptable.adaptableOptions.userInterfaceOptions?.dateInputOptions?.dateFormat; if (!Pattern) { return value; } return DateFormatter(value, { Pattern, }); }, }; // @ts-ignore it will be fixed with https://github.com/AdaptableTools/adaptable/issues/2230 this.value = this.valueParser(params); } else { this.value = invalid ? null : value; } if (!invalid) { requestAnimationFrame(() => { this.params.stopEditing(); }); } }, onStopEdit: (keyboardEventKey) => { if (keyboardEventKey === 'Escape') { this.params.api.stopEditing(true); } else { this.params.stopEditing(); } }, ref: (editor) => { this.editor = editor; editor?.focus(); } })); this.unmountReactRoot = adaptable.renderReactRoot(renderWithAdaptableContext(editorElement, adaptable), this.el); } destroy() { this.unmountReactRoot?.(); } }