@revolist/react-datagrid
Version:
React DataGrid Spreadsheet component with native cell render support
261 lines (260 loc) • 8.64 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
import { defineCustomElements } from "@revolist/revogrid/loader";
export * from "@revolist/revogrid/loader";
export * from "@revolist/revogrid";
import { createRoot } from "react-dom/client";
import React, { createElement } from "react";
import { jsx } from "react/jsx-runtime";
const dashToPascalCase = (str) => str.toLowerCase().split("-").map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("");
const camelToDashCase = (str) => str.replace(/([A-Z])/g, (m) => `-${m[0].toLowerCase()}`);
const attachProps = (node, newProps, oldProps = {}) => {
if (node instanceof Element) {
const className = getClassName(node.classList, newProps, oldProps);
if (className !== "") {
node.className = className;
}
Object.keys(newProps).forEach((name) => {
if (name === "children" || name === "style" || name === "ref" || name === "class" || name === "className" || name === "forwardedRef") {
return;
}
if (name.indexOf("on") === 0 && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2);
const eventNameLc = eventName[0].toLowerCase() + eventName.substring(1);
if (!isCoveredByReact(eventNameLc)) {
syncEvent(node, eventNameLc, newProps[name]);
}
} else {
node[name] = newProps[name];
const propType = typeof newProps[name];
if (propType === "string") {
node.setAttribute(camelToDashCase(name), newProps[name]);
}
}
});
}
};
const getClassName = (classList, newProps, oldProps) => {
const newClassProp = newProps.className || newProps.class;
const oldClassProp = oldProps.className || oldProps.class;
const currentClasses = arrayToMap(classList);
const incomingPropClasses = arrayToMap(newClassProp ? newClassProp.split(" ") : []);
const oldPropClasses = arrayToMap(oldClassProp ? oldClassProp.split(" ") : []);
const finalClassNames = [];
currentClasses.forEach((currentClass) => {
if (incomingPropClasses.has(currentClass)) {
finalClassNames.push(currentClass);
incomingPropClasses.delete(currentClass);
} else if (!oldPropClasses.has(currentClass)) {
finalClassNames.push(currentClass);
}
});
incomingPropClasses.forEach((s) => finalClassNames.push(s));
return finalClassNames.join(" ");
};
const transformReactEventName = (eventNameSuffix) => {
switch (eventNameSuffix) {
case "doubleclick":
return "dblclick";
}
return eventNameSuffix;
};
/**
* Checks if an event is supported in the current execution environment.
* @license Modernizr 3.0.0pre (Custom Build) | MIT
*/
const isCoveredByReact = (eventNameSuffix) => {
if (typeof document === "undefined") {
return true;
} else {
const eventName = "on" + transformReactEventName(eventNameSuffix);
let isSupported = eventName in document;
if (!isSupported) {
const element = document.createElement("div");
element.setAttribute(eventName, "return;");
isSupported = typeof element[eventName] === "function";
}
return isSupported;
}
};
const syncEvent = (node, eventName, newEventHandler) => {
const eventStore = node.__events || (node.__events = {});
const oldEventHandler = eventStore[eventName];
if (oldEventHandler) {
node.removeEventListener(eventName, oldEventHandler);
}
node.addEventListener(
eventName,
eventStore[eventName] = function handler(e) {
if (newEventHandler) {
newEventHandler.call(this, e);
}
}
);
};
const arrayToMap = (arr) => {
const map = /* @__PURE__ */ new Map();
arr.forEach((s) => map.set(s, s));
return map;
};
const setRef = (ref, value) => {
if (typeof ref === "function") {
ref(value);
} else if (ref != null) {
ref.current = value;
}
};
const mergeRefs = (...refs) => {
return (value) => {
refs.forEach((ref) => {
setRef(ref, value);
});
};
};
const createForwardRef = (ReactComponent, displayName) => {
const forwardRef = (props, ref) => {
return /* @__PURE__ */ jsx(ReactComponent, { ...props, forwardedRef: ref });
};
forwardRef.displayName = displayName;
return React.forwardRef(forwardRef);
};
const createReactComponent = (tagName, ReactComponentContext, manipulatePropsFunction, defineCustomElement) => {
if (defineCustomElement !== void 0) {
defineCustomElement();
}
const displayName = dashToPascalCase(tagName);
const ReactComponent = class extends React.Component {
constructor(props) {
super(props);
__publicField(this, "componentEl");
__publicField(this, "setComponentElRef", (element) => {
this.componentEl = element;
});
}
componentDidMount() {
this.componentDidUpdate(this.props);
}
componentDidUpdate(prevProps) {
attachProps(this.componentEl, this.props, prevProps);
}
render() {
const { children, forwardedRef, style, className, ref, ...cProps } = this.props;
let propsToPass = Object.keys(cProps).reduce((acc, name) => {
const value = cProps[name];
if (name.indexOf("on") === 0 && name[2] === name[2].toUpperCase()) {
const eventName = name.substring(2).toLowerCase();
if (typeof document !== "undefined" && isCoveredByReact(eventName)) {
acc[name] = value;
}
} else {
const type = typeof value;
if (type === "string" || type === "boolean" || type === "number") {
acc[camelToDashCase(name)] = value;
}
}
return acc;
}, {});
const newProps = {
...propsToPass,
ref: mergeRefs(forwardedRef, this.setComponentElRef),
style
};
return createElement(tagName, newProps, children);
}
static get displayName() {
return displayName;
}
};
return createForwardRef(ReactComponent, displayName);
};
function TemplateConstructor(el, ReactComponent, initialProps, lastEl = null) {
var _a;
if (!el) {
(_a = lastEl == null ? void 0 : lastEl.destroy) == null ? void 0 : _a.call(lastEl);
return null;
}
if (!el._root) {
el._root = createRoot(el);
}
const renderComponent = (props) => {
var _a2;
const vNode = createElement(ReactComponent, props);
(_a2 = el._root) == null ? void 0 : _a2.render(vNode);
};
renderComponent(initialProps);
const update = (newProps) => {
renderComponent(newProps);
};
const destroy = () => {
var _a2;
(_a2 = el._root) == null ? void 0 : _a2.unmount();
el._root = void 0;
};
return { update, destroy };
}
const Template = (ReactComponent, customProps) => {
return (h, p, addition) => {
const props = customProps ? { ...customProps, ...p } : p;
props.addition = addition;
let lastEl = null;
return h("span", {
key: `${p.prop}-${p.rowIndex || 0}`,
ref: (el) => {
lastEl = TemplateConstructor(el, ReactComponent, props, lastEl);
}
});
};
};
class EditorAdapter {
constructor(EditorComponent, column, save, close) {
__publicField(this, "element", null);
__publicField(this, "editCell");
__publicField(this, "renderedComponent", null);
this.EditorComponent = EditorComponent;
this.column = column;
this.save = save;
this.close = close;
}
// optional, called after editor rendered
componentDidRender() {
}
// optional, called after editor destroyed
disconnectedCallback() {
var _a;
(_a = this.renderedComponent) == null ? void 0 : _a.destroy();
this.renderedComponent = null;
}
render(h) {
var _a;
return h("span", {
key: `${this.column.prop}-${((_a = this.editCell) == null ? void 0 : _a.rowIndex) || 0}`,
ref: (el) => this.renderedComponent = TemplateConstructor(
el,
this.EditorComponent,
{
...this.editCell,
column: this.column,
save: this.save,
close: this.close
},
this.renderedComponent
)
});
}
}
const Editor = (EditorComponent) => {
return function(column, save, close) {
return new EditorAdapter(EditorComponent, column, save, close);
};
};
const RevoGrid = /* @__PURE__ */ createReactComponent("revo-grid", void 0, void 0, defineCustomElements);
export {
Editor,
EditorAdapter,
RevoGrid,
Template
};