@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
147 lines (146 loc) • 5.61 kB
JavaScript
import * as React from 'react';
import { renderWithAdaptableContext } from '../../../View/renderWithAdaptableContext';
import { InternalAdaptableNumberEditor, } from './InternalAdaptableNumberEditor';
import { KeyCode } from 'ag-grid-enterprise';
import { forwardRef, useImperativeHandle, useRef, useState } from 'react';
function shouldClearExistingValue(params) {
return params.eventKey === KeyCode.BACKSPACE || params.eventKey === KeyCode.DELETE;
}
function isValidChar(char) {
// allow only digits
return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(char);
// we do NOT allow key shortcuts for starting non-digits (minus sign, decimal separators) as the input[number] handling is very buggy and we would open a can of worms
}
export function getStartValue(params) {
if (shouldClearExistingValue(params)) {
return '';
}
if (params.eventKey && isValidChar(params.eventKey)) {
return Number(params.eventKey);
}
return params.value;
}
const defaultValueParser = ({ newValue, oldValue: _ }) => {
return newValue;
};
const style = {
position: 'absolute',
top: '0px',
left: '0px',
right: '0px',
bottom: '0px',
};
export const AdaptableReactNumberEditor = forwardRef((props, ref) => {
const [initialValue] = useState(() => getStartValue(props));
const valueRef = useRef(initialValue);
const columnId = props.column.getColId();
const adaptable = props.context.__adaptable;
const colValueParser = props.column.getColDef().valueParser;
const valueParser = typeof colValueParser === 'function' ? colValueParser : defaultValueParser;
function onValueChange(value) {
value = valueParser
? valueParser({
...props,
oldValue: props.value,
newValue: value,
})
: value;
valueRef.current = value;
props.onValueChange?.(value);
}
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(InternalAdaptableNumberEditor, { defaultValue: initialValue, showClearButton: props.showClearButton ?? true, emptyValue: props.emptyValue ?? '', onValueChange: onValueChange, ref: (editor) => {
editorRef.current = editor;
editor?.focus();
} }));
function onKeyDown(keyDownEvent) {
adaptable._emit('CellEditorKeyDown', {
keyDownEvent,
cellValue: valueRef.current,
columnId,
updateValueCallback: (updatedValue) => {
editorRef.current.setValue(updatedValue);
},
});
}
return (React.createElement("div", { style: style, onKeyDown: onKeyDown }, renderWithAdaptableContext(editorElement, adaptable)));
});
AdaptableReactNumberEditor.displayName = 'AdaptableReactNumberEditor';
/**
* Number Editor provided by AdapTable and used by default for all `number` columns
*/
export class AdaptableNumberEditor {
constructor() {
this.valueParser = defaultValueParser;
this.onValueChange = (value) => {
this.value = this.valueParser
? this.valueParser({
...this.params,
oldValue: this.params.value,
newValue: value,
})
: value;
};
}
init(params) {
this.value = getStartValue(params);
this.params = params;
this.columnId = params.column.getColId();
const { valueParser } = params.column.getColDef();
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() { }
// after this component has been created and inserted into the grid
afterGuiAttached() {
const adaptable = this.params.context.__adaptable;
const defaultValue = this.value;
const editorElement = (React.createElement(InternalAdaptableNumberEditor, { defaultValue: defaultValue, showClearButton: this.params.showClearButton ?? true, emptyValue: this.params.emptyValue ?? '', onValueChange: this.onValueChange, ref: (editor) => {
this.editor = editor;
editor?.focus();
} }));
this.unmountReactRoot = adaptable.renderReactRoot(renderWithAdaptableContext(editorElement, adaptable), this.el);
this.getGui().addEventListener('keydown', (keyDownEvent) => {
adaptable._emit('CellEditorKeyDown', {
keyDownEvent,
cellValue: this.value,
columnId: this.columnId,
updateValueCallback: (updatedValue) => {
this.editor.setValue(updatedValue);
},
});
});
}
destroy() {
this.unmountReactRoot?.();
}
}