@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
JavaScript
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?.();
}
}