UNPKG

react-docx

Version:

React Reconciler for DOCX - build Docx with JSX

436 lines (366 loc) 14.5 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var ReactReconciler = require('react-reconciler'); var Docx = require('docx'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) { return e; } else { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n['default'] = e; return Object.freeze(n); } } var ReactReconciler__default = /*#__PURE__*/_interopDefaultLegacy(ReactReconciler); var Docx__namespace = /*#__PURE__*/_interopNamespace(Docx); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } /// IS helper from /// https://github.com/react-spring/react-three-fiber var is = { obj: function obj(a) { return a === Object(a) && !is.arr(a); }, fun: function fun(a) { return typeof a === "function"; }, str: function str(a) { return typeof a === "string"; }, num: function num(a) { return typeof a === "number"; }, und: function und(a) { return a === void 0; }, arr: function arr(a) { return Array.isArray(a); }, equ: function equ(a, b) { // Wrong type or one of the two undefined, doesn't match if (_typeof(a) !== _typeof(b) || !!a !== !!b) return false; // Atomic, just compare a against b if (is.str(a) || is.num(a) || is.obj(a)) return a === b; // Array, shallow compare first to see if it's a match // eslint-disable-next-line eqeqeq if (is.arr(a) && a == b) return true; // Last resort, go through keys var i; for (i in a) { if (!(i in b)) return false; } for (i in b) { if (a[i] !== b[i]) return false; } return is.und(i) ? a === b : true; } }; var DocxTypes = {}; Object.keys(Docx__namespace).forEach(function (key) { return is.fun(Docx__namespace[key]) ? DocxTypes[key.toLowerCase()] = Docx__namespace[key] : null; }); DocxTypes["document"] = /*#__PURE__*/function () { function Document(props) { _classCallCheck(this, Document); this.type = "document"; this.props = props; this.children = []; } _createClass(Document, [{ key: "addChildElement", value: function addChildElement(child) { this.children.push(child); } }]); return Document; }(); // missing Docx Primitive placholder DocxTypes["section"] = /*#__PURE__*/function () { function Section(props) { _classCallCheck(this, Section); this.type = "section"; this.props = props; this.children = []; } _createClass(Section, [{ key: "addChildElement", value: function addChildElement(child) { this.children.push(child); } }]); return Section; }(); /// image wrapper DocxTypes["image"] = function (_ref) { var src = _ref.src, width = _ref.width, height = _ref.height, __document = _ref.__document, props = _objectWithoutProperties(_ref, ["src", "width", "height", "__document"]); if (!src) { throw new Error("No image src provided"); } return Docx.Media.addImage(__document, src, width, height, props); }; DocxTypes["href"] = function (_ref2) { var src = _ref2.src, anchor = _ref2.anchor, __document = _ref2.__document, label = _ref2.label; var hyperlink = new Docx.Hyperlink(label || src, "link" + (__document.docRelationships.RelationshipCount + 1), anchor); __document.docRelationships.createRelationship(hyperlink.linkId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", src, "External"); return hyperlink; }; // shortcuts DocxTypes["t"] = DocxTypes["textrun"]; DocxTypes["p"] = DocxTypes["paragraph"]; DocxTypes["img"] = DocxTypes["image"]; var hostConfig = { // _props contain raw react children too createInstance: function createInstance(type, _props, rootContainerInstance, hostContext // internalInstanceHandle - fiber root, we don't need any react magic for now ) { //locate instance constructor in DocxTypes var classConstructor = DocxTypes[type]; // sanitise children away from props // eslint-disable-next-line no-unused-vars var _props$children = _props.children, children = _props$children === void 0 ? [] : _props$children, props = _objectWithoutProperties(_props, ["children"]); if (classConstructor) { var params = _objectSpread2(_objectSpread2({ text: classConstructor.name === "TextRun" && (is.str(children) || is.num(children)) ? children : undefined }, props), {}, { rows: [], children: [], // some docx elements require children param __document: hostContext.document // pass document reference for fictive elements }); var docxInstance; // either call class constructor or just a function try { docxInstance = classConstructor.name ? new classConstructor(params) : classConstructor(params); } catch (error) { console.error(error); } Object.keys(props).filter(function (p) { return is.fun(docxInstance[p]); }).forEach(function (prop) { var propVal = props[prop]; var propFun = docxInstance[prop]; docxInstance = is.arr(propVal) ? propFun.apply(docxInstance, propVal) // array was passed as prop val so we treat as arguments : propFun.call(docxInstance, propVal); // whaterver else was passed is single argument }); return docxInstance; } throw new Error("".concat(type, " is not Docx Element")); }, // both parentInstance and child are types of host elements (DOCX objects) appendInitialChild: function appendInitialChild(parentInstance, child) { if ("addChildElement" in parentInstance) { parentInstance.addChildElement(child); } else { var _ref, _parentInstance$type, _parentInstance$proto; throw new Error("".concat((_ref = (_parentInstance$type = parentInstance === null || parentInstance === void 0 ? void 0 : parentInstance.type) !== null && _parentInstance$type !== void 0 ? _parentInstance$type : parentInstance === null || parentInstance === void 0 ? void 0 : (_parentInstance$proto = parentInstance.prototype) === null || _parentInstance$proto === void 0 ? void 0 : _parentInstance$proto.constructor.name) !== null && _ref !== void 0 ? _ref : parentInstance, " does not have any methods to append a child")); } }, // asks us if CreateTextInstance must be called for text content of that specific element // for explicit TextRun we return true, so no CreateTextInstance is called shouldSetTextContent: function shouldSetTextContent(type, props) { return type === "textrun" && (typeof props.children === "string" || typeof props.children === "number"); }, // create implicit TextRun createTextInstance: function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { return new Docx.TextRun({ text: text }); }, /// we use that to add sections to document we have in our context /// in this step all instances are created, and we add fictive section instance to document finalizeInitialChildren: function finalizeInitialChildren(domElement, type, _props, rootContainerInstance, hostContext) { var children = _props.children, props = _objectWithoutProperties(_props, ["children"]); if (domElement.type === "section" && hostContext.isRootContext) { hostContext.document.addSection({ children: domElement.children, properties: props }); } else if (domElement.type === "section" || hostContext.isRootContext) { throw new Error("Section is not a root element or part of root Fragment"); } }, /// provide document instance to all children getRootHostContext: function getRootHostContext(rootContainerInstance) { return { document: rootContainerInstance.document, isRootContext: true }; }, // this is how we let createInstance know that its a child element getChildHostContext: function getChildHostContext(parentHostContext, type, rootContainerInstance) { return _objectSpread2(_objectSpread2({}, parentHostContext), {}, { isRootContext: false, type: type }); }, // or even that getPublicInstance: function getPublicInstance(instance) { return instance; }, // pre/post commit callbacks prepareForCommit: function prepareForCommit() { return null; }, preparePortalMount: function preparePortalMount() { return null; }, clearContainer: function clearContainer() { return false; }, resetAfterCommit: function resetAfterCommit(containerInfo) {}, prepareUpdate: function prepareUpdate(domElement, type, oldProps, newProps, rootContainerInstance, hostContext) { console.log("prepareUpdate", domElement, type, oldProps, newProps, rootContainerInstance, hostContext); return [null]; }, shouldDeprioritizeSubtree: function shouldDeprioritizeSubtree(type, props) { //console.log("shouldDeprioritizeSubtree", type, props); return false; }, now: Date.now(), isPrimaryRenderer: true, scheduleDeferredCallback: "", cancelDeferredCallback: "", // ------------------- // Mutation // ------------------- supportsMutation: true, commitMount: function commitMount(domElement, type, newProps, internalInstanceHandle) {}, commitUpdate: function commitUpdate(domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) {}, resetTextContent: function resetTextContent(domElement) {}, commitTextUpdate: function commitTextUpdate(textInstance, oldText, newText) {}, appendChild: function appendChild(parentInstance, child) {}, appendChildToContainer: function appendChildToContainer(container, child) {}, insertBefore: function insertBefore(parentInstance, child, beforeChild) {}, insertInContainerBefore: function insertInContainerBefore(container, child, beforeChild) {}, removeChild: function removeChild(parentInstance, child) {}, removeChildFromContainer: function removeChildFromContainer(container, child) {} }; var DocxRenderer = ReactReconciler__default['default'](hostConfig); var render = function render(elements, containerNode, callback) { if (!containerNode || !is.obj(containerNode)) throw new Error("containerNode must be an empty object"); // We must do this only once if (!containerNode.__internalContainerStructure) { containerNode.__internalContainerStructure = DocxRenderer.createContainer(containerNode, false, false); } DocxRenderer.updateContainer(elements, containerNode.__internalContainerStructure, null, callback); }; var renderAsyncDocument = function renderAsyncDocument(elements, options, fileProperties) { var containerNode = {}; containerNode.document = new Docx.Document(options, fileProperties); return new Promise(function (resolve) { render(elements, containerNode, function () { return resolve(containerNode.document); }); }); }; exports.renderAsyncDocument = renderAsyncDocument;