@knoopx/react-pdf
Version:
<p align="center"> <img src="https://user-images.githubusercontent.com/5600341/27505816-c8bc37aa-587f-11e7-9a86-08a2d081a8b9.png" height="280px"> <p align="center">React renderer for creating PDF files on the browser and server<p> <p align="center">
1,792 lines (1,470 loc) • 114 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var fs = _interopDefault(require('fs'));
var BlobStream = _interopDefault(require('blob-stream'));
var ReactFiberReconciler = _interopDefault(require('react-reconciler'));
var PDFDocument = require('@react-pdf/pdfkit');
var PDFDocument__default = _interopDefault(PDFDocument);
var react = require('react');
var Yoga = _interopDefault(require('yoga-layout-prebuilt'));
var ramda = require('ramda');
var matchMedia = _interopDefault(require('media-engine'));
var PDFRenderer$1 = _interopDefault(require('@react-pdf/textkit/renderers/pdf'));
var AttributedString = _interopDefault(require('@react-pdf/textkit/attributedString'));
var isUrl = _interopDefault(require('is-url'));
var fontkit = _interopDefault(require('@react-pdf/fontkit'));
var fetch = _interopDefault(require('cross-fetch'));
var layoutEngine = _interopDefault(require('@react-pdf/textkit/layout'));
var linebreaker = _interopDefault(require('@react-pdf/textkit/engines/linebreaker'));
var justification = _interopDefault(require('@react-pdf/textkit/engines/justification'));
var textDecoration = _interopDefault(require('@react-pdf/textkit/engines/textDecoration'));
var scriptItemizer = _interopDefault(require('@react-pdf/textkit/engines/scriptItemizer'));
var wordHyphenation = _interopDefault(require('@react-pdf/textkit/engines/wordHyphenation'));
var emojiRegex = _interopDefault(require('emoji-regex'));
var url = _interopDefault(require('url'));
var path = _interopDefault(require('path'));
var PNG = _interopDefault(require('@react-pdf/png-js'));
var wrapPages = _interopDefault(require('page-wrapping'));
class Root {
constructor() {
this.isDirty = false;
this.document = null;
this.instance = null;
}
get name() {
return 'Root';
}
appendChild(child) {
this.document = child;
}
removeChild() {
this.document.cleanup();
this.document = null;
}
markDirty() {
this.isDirty = true;
}
cleanup() {
this.document.cleanup();
}
finish() {
this.document.finish();
}
async render() {
this.instance = new PDFDocument__default({
autoFirstPage: false
});
await this.document.render();
this.cleanup();
this.isDirty = false;
}
}
const upperFirst = value => value.charAt(0).toUpperCase() + value.slice(1);
const isPercent = value => /((-)?\d+\.?\d*)%/g.exec(value);
const matchPercent = value => {
const match = isPercent(value);
if (match) {
const value = parseFloat(match[1], 10);
const percent = value / 100;
return {
value,
percent,
absValue: Math.abs(value),
absPercent: Math.abs(percent)
};
}
return null;
};
class Node {
constructor() {
this.parent = null;
this.children = [];
this.computed = false;
this.layout = Yoga.Node.createDefault();
}
appendChild(child) {
if (child) {
child.parent = this;
this.children.push(child);
this.layout.insertChild(child.layout, this.layout.getChildCount());
}
}
appendChildBefore(child, beforeChild) {
const index = this.children.indexOf(beforeChild);
if (index !== -1 && child) {
child.parent = this;
this.children.splice(index, 0, child);
this.layout.insertChild(child.layout, index);
}
}
removeChild(child) {
const index = this.children.indexOf(child);
if (index !== -1) {
child.parent = null;
this.children.splice(index, 1);
this.layout.removeChild(child.layout);
}
child.cleanup();
}
removeAllChilds() {
const children = [...this.children];
for (let i = 0; i < children.length; i++) {
children[i].remove();
}
}
remove() {
this.parent.removeChild(this);
}
setDimension(attr, value) {
const fixedMethod = `set${upperFirst(attr)}`;
const percentMethod = `${fixedMethod}Percent`;
const percent = matchPercent(value);
if (percent) {
this.layout[percentMethod](percent.value);
} else {
this.layout[fixedMethod](value);
}
}
setPosition(edge, value) {
const percent = matchPercent(value);
if (percent) {
this.layout.setPositionPercent(edge, percent.value);
} else {
this.layout.setPosition(edge, value);
}
}
setPadding(edge, value) {
const percent = matchPercent(value);
if (percent) {
this.layout.setPaddingPercent(edge, percent.value);
} else {
this.layout.setPadding(edge, value);
}
}
setMargin(edge, value) {
const percent = matchPercent(value);
if (percent) {
this.layout.setMarginPercent(edge, percent.value);
} else {
this.layout.setMargin(edge, value);
}
}
setBorder(edge, value) {
if (matchPercent(value)) {
throw new Error('Node: You cannot set percentage border widths');
}
this.layout.setBorder(edge, value);
}
getAbsoluteLayout() {
const parent = this.parent;
const parentLayout = parent && parent.getAbsoluteLayout ? parent.getAbsoluteLayout() : {
left: 0,
top: 0
};
return {
left: this.left + parentLayout.left,
top: this.top + parentLayout.top,
height: this.height,
width: this.width
};
}
copyStyle(node) {
this.layout.copyStyle(node.layout);
}
calculateLayout() {
this.layout.calculateLayout();
this.computed = true;
}
isEmpty() {
return this.children.length === 0;
}
markDirty() {
return this.layout.markDirty();
}
onAppendDynamically() {}
cleanup() {
this.children.forEach(c => c.cleanup());
this.layout.unsetMeasureFunc();
Yoga.Node.destroy(this.layout);
}
get position() {
return this.layout.getPositionType() === Yoga.POSITION_TYPE_ABSOLUTE ? 'absolute' : 'relative';
}
get top() {
return this.layout.getComputedTop() || 0;
}
get left() {
return this.layout.getComputedLeft() || 0;
}
get right() {
return this.layout.getComputedRight() || 0;
}
get bottom() {
return this.layout.getComputedBottom() || 0;
}
get width() {
return this.layout.getComputedWidth();
}
get minWidth() {
return this.layout.getMinWidth().value;
}
get maxWidth() {
return this.layout.getMaxWidth().value;
}
get height() {
return this.layout.getComputedHeight();
}
get minHeight() {
return this.layout.getMinHeight().value;
}
get maxHeight() {
return this.layout.getMaxHeight().value;
}
get paddingTop() {
return this.layout.getComputedPadding(Yoga.EDGE_TOP) || 0;
}
get paddingRight() {
return this.layout.getComputedPadding(Yoga.EDGE_RIGHT) || 0;
}
get paddingBottom() {
return this.layout.getComputedPadding(Yoga.EDGE_BOTTOM) || 0;
}
get paddingLeft() {
return this.layout.getComputedPadding(Yoga.EDGE_LEFT) || 0;
}
get marginTop() {
return this.layout.getComputedMargin(Yoga.EDGE_TOP) || 0;
}
get marginRight() {
return this.layout.getComputedMargin(Yoga.EDGE_RIGHT) || 0;
}
get marginBottom() {
return this.layout.getComputedMargin(Yoga.EDGE_BOTTOM) || 0;
}
get marginLeft() {
return this.layout.getComputedMargin(Yoga.EDGE_LEFT) || 0;
}
get borderTopWidth() {
return this.layout.getComputedBorder(Yoga.EDGE_TOP) || 0;
}
get borderRightWidth() {
return this.layout.getComputedBorder(Yoga.EDGE_RIGHT) || 0;
}
get borderBottomWidth() {
return this.layout.getComputedBorder(Yoga.EDGE_BOTTOM) || 0;
}
get borderLeftWidth() {
return this.layout.getComputedBorder(Yoga.EDGE_LEFT) || 0;
}
get padding() {
return {
top: this.paddingTop,
right: this.paddingRight,
bottom: this.paddingBottom,
left: this.paddingLeft
};
}
get margin() {
return {
top: this.marginTop,
right: this.marginRight,
bottom: this.marginBottom,
left: this.marginLeft
};
}
set position(value) {
this.layout.setPositionType(value === 'absolute' ? Yoga.POSITION_TYPE_ABSOLUTE : Yoga.POSITION_TYPE_RELATIVE);
}
set top(value) {
this.setPosition(Yoga.EDGE_TOP, value);
}
set left(value) {
this.setPosition(Yoga.EDGE_LEFT, value);
}
set right(value) {
this.setPosition(Yoga.EDGE_RIGHT, value);
}
set bottom(value) {
this.setPosition(Yoga.EDGE_BOTTOM, value);
}
set width(value) {
this.setDimension('width', value);
}
set minWidth(value) {
this.setDimension('minWidth', value);
}
set maxWidth(value) {
this.setDimension('maxWidth', value);
}
set height(value) {
this.setDimension('height', value);
}
set minHeight(value) {
this.setDimension('minHeight', value);
}
set maxHeight(value) {
this.setDimension('maxHeight', value);
}
set paddingTop(value) {
this.setPadding(Yoga.EDGE_TOP, value);
}
set paddingRight(value) {
this.setPadding(Yoga.EDGE_RIGHT, value);
}
set paddingBottom(value) {
this.setPadding(Yoga.EDGE_BOTTOM, value);
}
set paddingLeft(value) {
this.setPadding(Yoga.EDGE_LEFT, value);
}
set marginTop(value) {
this.setMargin(Yoga.EDGE_TOP, value);
}
set marginRight(value) {
this.setMargin(Yoga.EDGE_RIGHT, value);
}
set marginBottom(value) {
this.setMargin(Yoga.EDGE_BOTTOM, value);
}
set marginLeft(value) {
this.setMargin(Yoga.EDGE_LEFT, value);
}
set padding(value) {
this.paddingTop = value;
this.paddingRight = value;
this.paddingBottom = value;
this.paddingLeft = value;
}
set margin(value) {
this.marginTop = value;
this.marginRight = value;
this.marginBottom = value;
this.marginLeft = value;
}
set borderTopWidth(value) {
this.setBorder(Yoga.EDGE_TOP, value);
}
set borderRightWidth(value) {
this.setBorder(Yoga.EDGE_RIGHT, value);
}
set borderBottomWidth(value) {
this.setBorder(Yoga.EDGE_BOTTOM, value);
}
set borderLeftWidth(value) {
this.setBorder(Yoga.EDGE_LEFT, value);
}
}
const yogaValue = (prop, value) => {
const isAlignType = prop => prop === 'alignItems' || prop === 'alignContent' || prop === 'alignSelf';
switch (value) {
case 'auto':
if (prop === 'alignSelf') {
return Yoga.ALIGN_AUTO;
}
break;
case 'flex':
return Yoga.DISPLAY_FLEX;
case 'none':
return Yoga.DISPLAY_NONE;
case 'row':
return Yoga.FLEX_DIRECTION_ROW;
case 'row-reverse':
return Yoga.FLEX_DIRECTION_ROW_REVERSE;
case 'column':
return Yoga.FLEX_DIRECTION_COLUMN;
case 'column-reverse':
return Yoga.FLEX_DIRECTION_COLUMN_REVERSE;
case 'stretch':
return Yoga.ALIGN_STRETCH;
case 'baseline':
return Yoga.ALIGN_BASELINE;
case 'space-around':
if (prop === 'justifyContent') {
return Yoga.JUSTIFY_SPACE_AROUND;
} else if (isAlignType(prop)) {
return Yoga.ALIGN_SPACE_AROUND;
}
break;
case 'space-between':
if (prop === 'justifyContent') {
return Yoga.JUSTIFY_SPACE_BETWEEN;
} else if (isAlignType(prop)) {
return Yoga.ALIGN_SPACE_BETWEEN;
}
break;
case 'around':
return Yoga.JUSTIFY_SPACE_AROUND;
case 'between':
return Yoga.JUSTIFY_SPACE_BETWEEN;
case 'wrap':
return Yoga.WRAP_WRAP;
case 'wrap-reverse':
return Yoga.WRAP_WRAP_REVERSE;
case 'nowrap':
return Yoga.WRAP_NO_WRAP;
case 'flex-start':
if (prop === 'justifyContent') {
return Yoga.JUSTIFY_FLEX_START;
} else if (isAlignType(prop)) {
return Yoga.ALIGN_FLEX_START;
}
break;
case 'flex-end':
if (prop === 'justifyContent') {
return Yoga.JUSTIFY_FLEX_END;
} else if (isAlignType(prop)) {
return Yoga.ALIGN_FLEX_END;
}
break;
case 'center':
if (prop === 'justifyContent') {
return Yoga.JUSTIFY_CENTER;
} else if (isAlignType(prop)) {
return Yoga.ALIGN_CENTER;
}
break;
default:
return value;
}
}; // These are not supported yet
const DPI = 72; // 72pt per inch.
const parseValue = value => {
const match = /^(-?\d*\.?\d+)(in|mm|cm|pt|vh|vw)?$/g.exec(value);
if (match) {
return {
value: parseFloat(match[1], 10),
unit: match[2] || 'pt'
};
}
return {
value,
unit: undefined
};
};
const parseScalar = (value, container) => {
const scalar = parseValue(value);
switch (scalar.unit) {
case 'in':
return scalar.value * DPI;
case 'mm':
return scalar.value * (1 / 25.4) * DPI;
case 'cm':
return scalar.value * (1 / 2.54) * DPI;
case 'vh':
if (container.isAutoHeight) {
throw new Error('vh unit not supported in auto-height pages. Please specify page height if you want to use vh.');
}
return scalar.value * (container.height / 100);
case 'vw':
return scalar.value * (container.width / 100);
default:
return scalar.value;
}
};
const isBorderStyle = (key, value) => key.match(/^border/) && typeof value === 'string';
const matchBorderShorthand = value => value.match(/(\d+(px|in|mm|cm|pt|vw|vh)?)\s(\S+)\s(\S+)/); // Transforms shorthand border values
const processBorders = (key, value) => {
const match = matchBorderShorthand(value);
if (match) {
if (key.match(/.Color/)) {
return match[4];
} else if (key.match(/.Style/)) {
return match[3];
} else if (key.match(/.Width/)) {
return match[1];
} else {
throw new Error(`StyleSheet: Invalid '${value}' for '${key}'`);
}
}
return value;
};
const isBoxModelStyle = (key, value) => key.match(/^(margin)|(padding)/) && typeof value === 'string';
const matchBoxModel = value => value.match(/\d+(px|in|mm|cm|pt|%|vw|vh)?/g); // Transforms shorthand margin and padding values
const processBoxModel = (key, value) => {
const match = matchBoxModel(value);
if (match) {
if (key.match(/.Top/)) {
return match[0];
} else if (key.match(/.Right/)) {
return match[1] || match[0];
} else if (key.match(/.Bottom/)) {
return match[2] || match[0];
} else if (key.match(/.Left/)) {
return match[3] || match[1] || match[0];
} else {
throw new Error(`StyleSheet: Invalid '${value}' for '${key}'`);
}
}
return value;
};
// https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#Common_weight_name_mapping
const FONT_WEIGHTS = {
thin: 100,
hairline: 100,
ultralight: 200,
extralight: 200,
light: 300,
normal: 400,
medium: 500,
semibold: 600,
demibold: 600,
bold: 700,
ultrabold: 800,
extrabold: 800,
heavy: 900,
black: 900
};
const isFontWeightStyle = key => key.match(/^fontWeight/);
const processFontWeight = value => {
if (!value) return FONT_WEIGHTS.normal;
if (typeof value === 'number') return value;
return FONT_WEIGHTS[value.toLowerCase()];
};
const isObjectPositionStyle = (key, value) => key.match(/^objectPosition/) && typeof value === 'string';
const matchObjectPosition = value => value.match(/\d+(px|in|mm|cm|pt|%|vw|vh)?/g); // Transforms shorthand objectPosition values
const processObjectPosition = (key, value) => {
const match = matchObjectPosition(value);
if (match) {
if (key.match(/.X/)) {
return match[0];
} else if (key.match(/.Y/)) {
return match[1];
} else {
throw new Error(`StyleSheet: Invalid '${value}' for '${key}'`);
}
}
return value;
};
const isTransformOriginStyle = (key, value) => key.match(/^transformOrigin/) && typeof value === 'string';
const matchTransformOrigin = value => value.match(/(-?\d+(px|in|mm|cm|pt|%|vw|vh)?)|top|right|bottom|left|center/g);
const transformOffsetKeywords = value => {
switch (value) {
case 'top':
case 'left':
return '0%';
case 'right':
case 'bottom':
return '100%';
case 'center':
return '50%';
default:
return value;
}
}; // Transforms shorthand transformOrigin values
const processTransformOrigin = (key, value) => {
const match = matchTransformOrigin(value);
if (match) {
let result;
if (key.match(/.X/)) {
result = match[0];
} else if (key.match(/.Y/)) {
result = match[1] || match[0];
} else {
throw new Error(`StyleSheet: Invalid '${value}' for '${key}'`);
}
return transformOffsetKeywords(result);
}
return value;
};
const hasOwnProperty = Object.prototype.hasOwnProperty;
const styleShorthands = {
margin: {
marginTop: true,
marginRight: true,
marginBottom: true,
marginLeft: true
},
marginHorizontal: {
marginLeft: true,
marginRight: true
},
marginVertical: {
marginTop: true,
marginBottom: true
},
padding: {
paddingTop: true,
paddingRight: true,
paddingBottom: true,
paddingLeft: true
},
paddingHorizontal: {
paddingLeft: true,
paddingRight: true
},
paddingVertical: {
paddingTop: true,
paddingBottom: true
},
border: {
borderTopColor: true,
borderTopStyle: true,
borderTopWidth: true,
borderRightColor: true,
borderRightStyle: true,
borderRightWidth: true,
borderBottomColor: true,
borderBottomStyle: true,
borderBottomWidth: true,
borderLeftColor: true,
borderLeftStyle: true,
borderLeftWidth: true
},
borderTop: {
borderTopColor: true,
borderTopStyle: true,
borderTopWidth: true
},
borderRight: {
borderRightColor: true,
borderRightStyle: true,
borderRightWidth: true
},
borderBottom: {
borderBottomColor: true,
borderBottomStyle: true,
borderBottomWidth: true
},
borderLeft: {
borderLeftColor: true,
borderLeftStyle: true,
borderLeftWidth: true
},
borderColor: {
borderTopColor: true,
borderRightColor: true,
borderBottomColor: true,
borderLeftColor: true
},
borderRadius: {
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderBottomRightRadius: true,
borderBottomLeftRadius: true
},
borderStyle: {
borderTopStyle: true,
borderRightStyle: true,
borderBottomStyle: true,
borderLeftStyle: true
},
borderWidth: {
borderTopWidth: true,
borderRightWidth: true,
borderBottomWidth: true,
borderLeftWidth: true
},
objectPosition: {
objectPositionX: true,
objectPositionY: true
},
transformOrigin: {
transformOriginX: true,
transformOriginY: true
}
}; // Expand the shorthand properties to isolate every declaration from the others.
const expandStyles = style => {
if (!style) return style;
const propsArray = Object.keys(style);
const resolvedStyle = {};
for (let i = 0; i < propsArray.length; i++) {
const key = propsArray[i];
const value = style[key];
switch (key) {
case 'display':
case 'flex':
case 'flexDirection':
case 'flexWrap':
case 'flexFlow':
case 'flexGrow':
case 'flexShrink':
case 'flexBasis':
case 'justifyContent':
case 'alignSelf':
case 'alignItems':
case 'alignContent':
case 'order':
resolvedStyle[key] = yogaValue(key, value);
break;
case 'textAlignVertical':
resolvedStyle.verticalAlign = value === 'center' ? 'middle' : value;
break;
case 'margin':
case 'marginHorizontal':
case 'marginVertical':
case 'padding':
case 'paddingHorizontal':
case 'paddingVertical':
case 'border':
case 'borderTop':
case 'borderRight':
case 'borderBottom':
case 'borderLeft':
case 'borderColor':
case 'borderRadius':
case 'borderStyle':
case 'borderWidth':
case 'objectPosition':
case 'transformOrigin':
{
const expandedProps = styleShorthands[key];
for (const propName in expandedProps) {
if (hasOwnProperty.call(expandedProps, propName)) {
resolvedStyle[propName] = value;
}
}
}
break;
default:
resolvedStyle[key] = value;
break;
}
}
return resolvedStyle;
};
const transformStyles = (style, container) => {
const expandedStyles = expandStyles(style);
const propsArray = Object.keys(expandedStyles);
const resolvedStyle = {};
for (let i = 0; i < propsArray.length; i++) {
const key = propsArray[i];
const value = expandedStyles[key];
let resolved;
if (isBorderStyle(key, value)) {
resolved = processBorders(key, value);
} else if (isBoxModelStyle(key, value)) {
resolved = processBoxModel(key, value);
} else if (isObjectPositionStyle(key, value)) {
resolved = processObjectPosition(key, value);
} else if (isTransformOriginStyle(key, value)) {
resolved = processTransformOrigin(key, value);
} else if (isFontWeightStyle(key)) {
resolved = processFontWeight(value);
} else {
resolved = value;
}
resolvedStyle[key] = parseScalar(resolved, container);
}
return resolvedStyle;
};
const create = styles => styles;
const flatten = input => {
if (!Array.isArray(input)) {
input = [input];
}
const result = input.reduce((acc, style) => {
if (style) {
const s = Array.isArray(style) ? flatten(style) : style;
Object.keys(s).forEach(key => {
if (s[key] !== null && s[key] !== undefined) {
acc[key] = s[key];
}
});
}
return acc;
}, {});
return result;
};
const resolveMediaQueries = (input, container) => {
const result = Object.keys(input).reduce((acc, key) => {
if (/@media/.test(key)) {
return { ...acc,
...matchMedia({
[key]: input[key]
}, container)
};
}
return { ...acc,
[key]: input[key]
};
}, {});
return result;
};
const resolve = (styles, container) => {
if (!styles) return null;
styles = flatten(styles);
styles = resolveMediaQueries(styles, container);
styles = transformStyles(styles, container);
return styles;
};
const absoluteFillObject = {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0
};
var StyleSheet = {
hairlineWidth: 1,
create,
resolve,
flatten,
absoluteFillObject
};
const Debug = {
debug() {
const layout = this.getAbsoluteLayout();
const padding = this.padding;
const margin = this.margin;
this.root.instance.save();
this.debugContent(layout, margin, padding);
this.debugPadding(layout, margin, padding);
this.debugMargin(layout, margin);
this.debugText(layout, margin);
this.debugOrigin();
this.root.instance.restore();
},
debugOrigin() {
if (this.style.transform) {
const origin = this.origin;
this.root.instance.circle(origin[0], origin[1], 3).fill('red').circle(origin[0], origin[1], 5).stroke('red');
}
},
debugText(layout, margin) {
const roundedWidth = Math.round(this.width + margin.left + margin.right);
const roundedHeight = Math.round(this.height + margin.top + margin.bottom);
this.root.instance.fontSize(4).opacity(1).fillColor('black').text(`${roundedWidth} x ${roundedHeight}`, layout.left - margin.left, Math.max(layout.top - margin.top - 4, 1));
},
debugContent(layout, margin, padding) {
this.root.instance.fillColor('#a1c6e7').opacity(0.5).rect(layout.left + padding.left, layout.top + padding.top, layout.width - padding.left - padding.right, layout.height - padding.top - padding.bottom).fill();
},
debugPadding(layout, margin, padding) {
this.root.instance.fillColor('#c4deb9').opacity(0.5); // Padding top
this.root.instance.rect(layout.left + padding.left, layout.top, layout.width - padding.right - padding.left, padding.top).fill(); // Padding left
this.root.instance.rect(layout.left, layout.top, padding.left, layout.height).fill(); // Padding right
this.root.instance.rect(layout.left + layout.width - padding.right, layout.top, padding.right, layout.height).fill(); // Padding bottom
this.root.instance.rect(layout.left + padding.left, layout.top + layout.height - padding.bottom, layout.width - padding.right - padding.left, padding.bottom).fill();
},
debugMargin(layout, margin) {
this.root.instance.fillColor('#f8cca1').opacity(0.5); // Margin top
this.root.instance.rect(layout.left, layout.top - margin.top, layout.width, margin.top).fill(); // Margin left
this.root.instance.rect(layout.left - margin.left, layout.top - margin.top, margin.left, layout.height + margin.top + margin.bottom).fill(); // Margin right
this.root.instance.rect(layout.left + layout.width, layout.top - margin.top, margin.right, layout.height + margin.top + margin.bottom).fill(); // Margin bottom
this.root.instance.rect(layout.left, layout.top + layout.height, layout.width, margin.bottom).fill();
}
};
// Ref: https://www.w3.org/TR/css-backgrounds-3/#borders
// This constant is used to approximate a symmetrical arc using a cubic Bezier curve.
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
function drawBorders() {
const {
instance
} = this.root;
const layout = this.getAbsoluteLayout();
const {
borderTopWidth,
borderLeftWidth,
borderRightWidth,
borderBottomWidth
} = this;
const {
opacity,
borderTopLeftRadius = 0,
borderTopRightRadius = 0,
borderBottomLeftRadius = 0,
borderBottomRightRadius = 0,
borderTopColor = 'black',
borderTopStyle = 'solid',
borderLeftColor = 'black',
borderLeftStyle = 'solid',
borderRightColor = 'black',
borderRightStyle = 'solid',
borderBottomColor = 'black',
borderBottomStyle = 'solid'
} = this.style;
const style = {
borderTopColor,
borderTopWidth,
borderTopStyle,
borderLeftColor,
borderLeftWidth,
borderLeftStyle,
borderRightColor,
borderRightWidth,
borderRightStyle,
borderBottomColor,
borderBottomWidth,
borderBottomStyle,
borderTopLeftRadius,
borderTopRightRadius,
borderBottomLeftRadius,
borderBottomRightRadius
};
const {
width,
height
} = layout;
const rtr = Math.min(borderTopRightRadius, 0.5 * width, 0.5 * height);
const rtl = Math.min(borderTopLeftRadius, 0.5 * width, 0.5 * height);
const rbr = Math.min(borderBottomRightRadius, 0.5 * width, 0.5 * height);
const rbl = Math.min(borderBottomLeftRadius, 0.5 * width, 0.5 * height);
instance.save();
instance.strokeOpacity(opacity);
if (borderTopWidth) {
instance.save();
clipBorderTop(instance, layout, style, rtr, rtl);
fillBorderTop(instance, layout, style, rtr, rtl);
instance.restore();
}
if (borderRightWidth) {
instance.save();
clipBorderRight(instance, layout, style, rtr, rbr);
fillBorderRight(instance, layout, style, rtr, rbr);
instance.restore();
}
if (borderBottomWidth) {
instance.save();
clipBorderBottom(instance, layout, style, rbl, rbr);
fillBorderBottom(instance, layout, style, rbl, rbr);
instance.restore();
}
if (borderLeftWidth) {
instance.save();
clipBorderLeft(instance, layout, style, rbl, rtl);
fillBorderLeft(instance, layout, style, rbl, rtl);
instance.restore();
}
instance.restore();
}
const clipBorderTop = (ctx, layout, style, rtr, rtl) => {
const {
top,
left,
width,
height
} = layout;
const {
borderTopWidth,
borderRightWidth,
borderLeftWidth
} = style; // Clip outer top border edge
ctx.moveTo(left + rtl, top);
ctx.lineTo(left + width - rtr, top); // Ellipse coefficients outer top right cap
const c0 = rtr * (1.0 - KAPPA); // Clip outer top right cap
ctx.bezierCurveTo(left + width - c0, top, left + width, top + c0, left + width, top + rtr); // Move down in case the margin exceedes the radius
const topRightYCoord = top + Math.max(borderTopWidth, rtr);
ctx.lineTo(left + width, topRightYCoord); // Clip inner top right cap
ctx.lineTo(left + width - borderRightWidth, topRightYCoord); // Ellipse coefficients inner top right cap
const innerTopRightRadiusX = Math.max(rtr - borderRightWidth, 0);
const innerTopRightRadiusY = Math.max(rtr - borderTopWidth, 0);
const c1 = innerTopRightRadiusX * (1.0 - KAPPA);
const c2 = innerTopRightRadiusY * (1.0 - KAPPA); // Clip inner top right cap
ctx.bezierCurveTo(left + width - borderRightWidth, top + borderTopWidth + c2, left + width - borderRightWidth - c1, top + borderTopWidth, left + width - borderRightWidth - innerTopRightRadiusX, top + borderTopWidth); // Clip inner top border edge
ctx.lineTo(left + Math.max(rtl, borderLeftWidth), top + borderTopWidth); // Ellipse coefficients inner top left cap
const innerTopLeftRadiusX = Math.max(rtl - borderLeftWidth, 0);
const innerTopLeftRadiusY = Math.max(rtl - borderTopWidth, 0);
const c3 = innerTopLeftRadiusX * (1.0 - KAPPA);
const c4 = innerTopLeftRadiusY * (1.0 - KAPPA);
const topLeftYCoord = top + Math.max(borderTopWidth, rtl); // Clip inner top left cap
ctx.bezierCurveTo(left + borderLeftWidth + c3, top + borderTopWidth, left + borderLeftWidth, top + borderTopWidth + c4, left + borderLeftWidth, topLeftYCoord);
ctx.lineTo(left, topLeftYCoord); // Move down in case the margin exceedes the radius
ctx.lineTo(left, top + rtl); // Ellipse coefficients outer top left cap
const c5 = rtl * (1.0 - KAPPA); // Clip outer top left cap
ctx.bezierCurveTo(left, top + c5, left + c5, top, left + rtl, top);
ctx.closePath();
ctx.clip(); // Clip border top cap joins
if (borderRightWidth) {
const trSlope = -borderTopWidth / borderRightWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left + width, top);
ctx.lineTo(left, top);
ctx.lineTo(left, top + height);
ctx.closePath();
ctx.clip();
}
if (borderLeftWidth) {
const trSlope = -borderTopWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left, top);
ctx.lineTo(left + width, top);
ctx.lineTo(left + width, top + height);
ctx.closePath();
ctx.clip();
}
};
const fillBorderTop = (ctx, layout, style, rtr, rtl) => {
const {
top,
left,
width
} = layout;
const {
borderTopColor,
borderTopWidth,
borderTopStyle,
borderRightWidth,
borderLeftWidth
} = style;
const c0 = rtl * (1.0 - KAPPA);
const c1 = rtr * (1.0 - KAPPA);
ctx.moveTo(left, top + Math.max(rtl, borderTopWidth));
ctx.bezierCurveTo(left, top + c0, left + c0, top, left + rtl, top);
ctx.lineTo(left + width - rtr, top);
ctx.bezierCurveTo(left + width - c1, top, left + width, top + c1, left + width, top + rtr);
ctx.strokeColor(borderTopColor);
ctx.lineWidth(Math.max(borderRightWidth, borderTopWidth, borderLeftWidth) * 2);
if (borderTopStyle === 'dashed') {
ctx.dash(borderTopWidth * 2, {
space: borderTopWidth * 1.2
});
} else if (borderTopStyle === 'dotted') {
ctx.dash(borderTopWidth, {
space: borderTopWidth * 1.2
});
}
ctx.stroke();
ctx.undash();
};
const clipBorderRight = (ctx, layout, style, rtr, rbr) => {
const {
top,
left,
width,
height
} = layout;
const {
borderTopWidth,
borderRightWidth,
borderBottomWidth
} = style; // Clip outer right border edge
ctx.moveTo(left + width, top + rtr);
ctx.lineTo(left + width, top + height - rbr); // Ellipse coefficients outer bottom right cap
const c0 = rbr * (1.0 - KAPPA); // Clip outer top right cap
ctx.bezierCurveTo(left + width, top + height - c0, left + width - c0, top + height, left + width - rbr, top + height); // Move left in case the margin exceedes the radius
const topBottomXCoord = left + width - Math.max(borderRightWidth, rbr);
ctx.lineTo(topBottomXCoord, top + height); // Clip inner bottom right cap
ctx.lineTo(topBottomXCoord, top + height - borderBottomWidth); // Ellipse coefficients inner bottom right cap
const innerBottomRightRadiusX = Math.max(rbr - borderRightWidth, 0);
const innerBottomRightRadiusY = Math.max(rbr - borderBottomWidth, 0);
const c1 = innerBottomRightRadiusX * (1.0 - KAPPA);
const c2 = innerBottomRightRadiusY * (1.0 - KAPPA); // Clip inner top right cap
ctx.bezierCurveTo(left + width - borderRightWidth - c1, top + height - borderBottomWidth, left + width - borderRightWidth, top + height - borderBottomWidth - c2, left + width - borderRightWidth, top + height - Math.max(rbr, borderBottomWidth)); // Clip inner right border edge
ctx.lineTo(left + width - borderRightWidth, top + Math.max(rtr, borderTopWidth)); // Ellipse coefficients inner top right cap
const innerTopRightRadiusX = Math.max(rtr - borderRightWidth, 0);
const innerTopRightRadiusY = Math.max(rtr - borderTopWidth, 0);
const c3 = innerTopRightRadiusX * (1.0 - KAPPA);
const c4 = innerTopRightRadiusY * (1.0 - KAPPA);
const topRightXCoord = left + width - Math.max(rtr, borderRightWidth); // Clip inner top left cap
ctx.bezierCurveTo(left + width - borderRightWidth, top + borderTopWidth + c4, left + width - borderRightWidth - c3, top + borderTopWidth, topRightXCoord, top + borderTopWidth);
ctx.lineTo(topRightXCoord, top); // Move right in case the margin exceedes the radius
ctx.lineTo(left + width - rtr, top); // Ellipse coefficients outer top right cap
const c5 = rtr * (1.0 - KAPPA); // Clip outer top right cap
ctx.bezierCurveTo(left + width - c5, top, left + width, top + c5, left + width, top + rtr);
ctx.closePath();
ctx.clip(); // Clip border right cap joins
if (borderTopWidth) {
const trSlope = -borderTopWidth / borderRightWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left + width, top);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left, top + height);
ctx.closePath();
ctx.clip();
}
if (borderBottomWidth) {
const brSlope = borderBottomWidth / borderRightWidth;
ctx.moveTo(left + width / 2, brSlope * (-width / 2) + top + height);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left + width, top);
ctx.lineTo(left, top);
ctx.closePath();
ctx.clip();
}
};
const fillBorderRight = (ctx, layout, style, rtr, rbr) => {
const {
top,
left,
width,
height
} = layout;
const {
borderRightColor,
borderRightStyle,
borderRightWidth,
borderTopWidth,
borderBottomWidth
} = style;
const c0 = rbr * (1.0 - KAPPA);
const c1 = rtr * (1.0 - KAPPA);
ctx.moveTo(left + width - rtr, top);
ctx.bezierCurveTo(left + width - c1, top, left + width, top + c1, left + width, top + rtr);
ctx.lineTo(left + width, top + height - rbr);
ctx.bezierCurveTo(left + width, top + height - c0, left + width - c0, top + height, left + width - rbr, top + height);
ctx.strokeColor(borderRightColor);
ctx.lineWidth(Math.max(borderRightWidth, borderTopWidth, borderBottomWidth) * 2);
if (borderRightStyle === 'dashed') {
ctx.dash(borderRightWidth * 2, {
space: borderRightWidth * 1.2
});
} else if (borderRightStyle === 'dotted') {
ctx.dash(borderRightWidth, {
space: borderRightWidth * 1.2
});
}
ctx.stroke();
ctx.undash();
};
const clipBorderBottom = (ctx, layout, style, rbl, rbr) => {
const {
top,
left,
width,
height
} = layout;
const {
borderBottomWidth,
borderRightWidth,
borderLeftWidth
} = style; // Clip outer top border edge
ctx.moveTo(left + width - rbr, top + height);
ctx.lineTo(left + rbl, top + height); // Ellipse coefficients outer top right cap
const c0 = rbl * (1.0 - KAPPA); // Clip outer top right cap
ctx.bezierCurveTo(left + c0, top + height, left, top + height - c0, left, top + height - rbl); // Move up in case the margin exceedes the radius
const bottomLeftYCoord = top + height - Math.max(borderBottomWidth, rbl);
ctx.lineTo(left, bottomLeftYCoord); // Clip inner bottom left cap
ctx.lineTo(left + borderLeftWidth, bottomLeftYCoord); // Ellipse coefficients inner top right cap
const innerBottomLeftRadiusX = Math.max(rbl - borderLeftWidth, 0);
const innerBottomLeftRadiusY = Math.max(rbl - borderBottomWidth, 0);
const c1 = innerBottomLeftRadiusX * (1.0 - KAPPA);
const c2 = innerBottomLeftRadiusY * (1.0 - KAPPA); // Clip inner bottom left cap
ctx.bezierCurveTo(left + borderLeftWidth, top + height - borderBottomWidth - c2, left + borderLeftWidth + c1, top + height - borderBottomWidth, left + borderLeftWidth + innerBottomLeftRadiusX, top + height - borderBottomWidth); // Clip inner bottom border edge
ctx.lineTo(left + width - Math.max(rbr, borderRightWidth), top + height - borderBottomWidth); // Ellipse coefficients inner top left cap
const innerBottomRightRadiusX = Math.max(rbr - borderRightWidth, 0);
const innerBottomRightRadiusY = Math.max(rbr - borderBottomWidth, 0);
const c3 = innerBottomRightRadiusX * (1.0 - KAPPA);
const c4 = innerBottomRightRadiusY * (1.0 - KAPPA);
const bottomRightYCoord = top + height - Math.max(borderBottomWidth, rbr); // Clip inner top left cap
ctx.bezierCurveTo(left + width - borderRightWidth - c3, top + height - borderBottomWidth, left + width - borderRightWidth, top + height - borderBottomWidth - c4, left + width - borderRightWidth, bottomRightYCoord);
ctx.lineTo(left + width, bottomRightYCoord); // Move down in case the margin exceedes the radius
ctx.lineTo(left + width, top + height - rbr); // Ellipse coefficients outer top left cap
const c5 = rbr * (1.0 - KAPPA); // Clip outer top left cap
ctx.bezierCurveTo(left + width, top + height - c5, left + width - c5, top + height, left + width - rbr, top + height);
ctx.closePath();
ctx.clip(); // Clip border bottom cap joins
if (borderRightWidth) {
const brSlope = borderBottomWidth / borderRightWidth;
ctx.moveTo(left + width / 2, brSlope * (-width / 2) + top + height);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left, top + height);
ctx.lineTo(left, top);
ctx.closePath();
ctx.clip();
}
if (borderLeftWidth) {
const trSlope = -borderBottomWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (width / 2) + top + height);
ctx.lineTo(left, top + height);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left + width, top);
ctx.closePath();
ctx.clip();
}
};
const fillBorderBottom = (ctx, layout, style, rbl, rbr) => {
const {
top,
left,
width,
height
} = layout;
const {
borderBottomColor,
borderBottomStyle,
borderBottomWidth,
borderRightWidth,
borderLeftWidth
} = style;
const c0 = rbl * (1.0 - KAPPA);
const c1 = rbr * (1.0 - KAPPA);
ctx.moveTo(left + width, top + height - rbr);
ctx.bezierCurveTo(left + width, top + height - c1, left + width - c1, top + height, left + width - rbr, top + height);
ctx.lineTo(left + rbl, top + height);
ctx.bezierCurveTo(left + c0, top + height, left, top + height - c0, left, top + height - rbl);
ctx.strokeColor(borderBottomColor);
ctx.lineWidth(Math.max(borderBottomWidth, borderRightWidth, borderLeftWidth) * 2);
if (borderBottomStyle === 'dashed') {
ctx.dash(borderBottomWidth * 2, {
space: borderBottomWidth * 1.2
});
} else if (borderBottomStyle === 'dotted') {
ctx.dash(borderBottomWidth, {
space: borderBottomWidth * 1.2
});
}
ctx.stroke();
ctx.undash();
};
const clipBorderLeft = (ctx, layout, style, rbl, rtl) => {
const {
top,
left,
width,
height
} = layout;
const {
borderTopWidth,
borderLeftWidth,
borderBottomWidth
} = style; // Clip outer left border edge
ctx.moveTo(left, top + height - rbl);
ctx.lineTo(left, top + rtl); // Ellipse coefficients outer top left cap
const c0 = rtl * (1.0 - KAPPA); // Clip outer top left cap
ctx.bezierCurveTo(left, top + c0, left + c0, top, left + rtl, top); // Move right in case the margin exceedes the radius
const topLeftCoordX = left + Math.max(borderLeftWidth, rtl);
ctx.lineTo(topLeftCoordX, top); // Clip inner top left cap
ctx.lineTo(topLeftCoordX, top + borderTopWidth); // Ellipse coefficients inner top left cap
const innerTopLeftRadiusX = Math.max(rtl - borderLeftWidth, 0);
const innerTopLeftRadiusY = Math.max(rtl - borderTopWidth, 0);
const c1 = innerTopLeftRadiusX * (1.0 - KAPPA);
const c2 = innerTopLeftRadiusY * (1.0 - KAPPA); // Clip inner top right cap
ctx.bezierCurveTo(left + borderLeftWidth + c1, top + borderTopWidth, left + borderLeftWidth, top + borderTopWidth + c2, left + borderLeftWidth, top + Math.max(rtl, borderTopWidth)); // Clip inner left border edge
ctx.lineTo(left + borderLeftWidth, top + height - Math.max(rbl, borderBottomWidth)); // Ellipse coefficients inner bottom left cap
const innerBottomLeftRadiusX = Math.max(rbl - borderLeftWidth, 0);
const innerBottomLeftRadiusY = Math.max(rbl - borderBottomWidth, 0);
const c3 = innerBottomLeftRadiusX * (1.0 - KAPPA);
const c4 = innerBottomLeftRadiusY * (1.0 - KAPPA);
const bottomLeftXCoord = left + Math.max(rbl, borderLeftWidth); // Clip inner top left cap
ctx.bezierCurveTo(left + borderLeftWidth, top + height - borderBottomWidth - c4, left + borderLeftWidth + c3, top + height - borderBottomWidth, bottomLeftXCoord, top + height - borderBottomWidth);
ctx.lineTo(bottomLeftXCoord, top + height); // Move left in case the margin exceedes the radius
ctx.lineTo(left + rbl, top + height); // Ellipse coefficients outer top right cap
const c5 = rbl * (1.0 - KAPPA); // Clip outer top right cap
ctx.bezierCurveTo(left + c5, top + height, left, top + height - c5, left, top + height - rbl);
ctx.closePath();
ctx.clip(); // Clip border right cap joins
if (borderBottomWidth) {
const trSlope = -borderBottomWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (width / 2) + top + height);
ctx.lineTo(left, top + height);
ctx.lineTo(left, top);
ctx.lineTo(left + width, top);
ctx.closePath();
ctx.clip();
}
if (borderBottomWidth) {
const trSlope = -borderTopWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left, top);
ctx.lineTo(left, top + height);
ctx.lineTo(left + width, top + height);
ctx.closePath();
ctx.clip();
}
};
const fillBorderLeft = (ctx, layout, style, rbl, rtl) => {
const {
top,
left,
height
} = layout;
const {
borderLeftColor,
borderLeftStyle,
borderLeftWidth,
borderTopWidth,
borderBottomWidth
} = style;
const c0 = rbl * (1.0 - KAPPA);
const c1 = rtl * (1.0 - KAPPA);
ctx.moveTo(left + rbl, top + height);
ctx.bezierCurveTo(left + c0, top + height, left, top + height - c0, left, top + height - rbl);
ctx.lineTo(left, top + rtl);
ctx.bezierCurveTo(left, top + c1, left + c1, top, left + rtl, top);
ctx.strokeColor(borderLeftColor);
ctx.lineWidth(Math.max(borderLeftWidth, borderTopWidth, borderBottomWidth) * 2);
if (borderLeftStyle === 'dashed') {
ctx.dash(borderLeftWidth * 2, {
space: borderLeftWidth * 1.2
});
} else if (borderLeftStyle === 'dotted') {
ctx.dash(borderLeftWidth, {
space: borderLeftWidth * 1.2
});
}
ctx.stroke();
ctx.undash();
};
var Borders = {
drawBorders
};
// This constant is used to approximate a symmetrical arc using a cubic
// Bezier curve.
const KAPPA$1 = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
const Clipping = {
clip() {
const {
top,
left,
width,
height
} = this.getAbsoluteLayout();
const {
borderTopLeftRadius = 0,
borderTopRightRadius = 0,
borderBottomRightRadius = 0,
borderBottomLeftRadius = 0
} = this.style; // Border top
const rtr = Math.min(borderTopRightRadius, 0.5 * width, 0.5 * height);
const ctr = rtr * (1.0 - KAPPA$1);
this.root.instance.moveTo(left + rtr, top);
this.root.instance.lineTo(left + width - rtr, top);
this.root.instance.bezierCurveTo(left + width - ctr, top, left + width, top + ctr, left + width, top + rtr); // Border right
const rbr = Math.min(borderBottomRightRadius, 0.5 * width, 0.5 * height);
const cbr = rbr * (1.0 - KAPPA$1);
this.root.instance.lineTo(left + width, top + height - rbr);
this.root.instance.bezierCurveTo(left + width, top + height - cbr, left + width - cbr, top + height, left + width - rbr, top + height); // Border bottom
const rbl = Math.min(borderBottomLeftRadius, 0.5 * width, 0.5 * height);
const cbl = rbl * (1.0 - KAPPA$1);
this.root.instance.lineTo(left + rbl, top + height);
this.root.instance.bezierCurveTo(left + cbl, top + height, left, top + height - cbl, left, top + height - rbl); // Border left
const rtl = Math.min(borderTopLeftRadius, 0.5 * width, 0.5 * height);
const ctl = rtl * (1.0 - KAPPA$1);
this.root.instance.lineTo(left, top + rtl);
this.root.instance.bezierCurveTo(left, top + ctl, left + ctl, top, left + rtl, top);
this.root.instance.closePath();
this.root.instance.clip();
}
};
const getRotation = transform => {
const match = /rotate\((-?\d+.?\d+)(.+)\)/g.exec(transform);
if (match && match[1] && match[2]) {
const value = match[1];
return match[2] === 'rad' ? value * 180 / Math.PI : value;
}
return 0;
};
const getTranslateX = transform => {
const matchX = /translateX\((-?\d+\.?d*)\)/g.exec(transform);
const matchGeneric = /translate\((-?\d+\.?d*).*,\s*(-?\d+\.?d*).*\)/g.exec(transform);
if (matchX && matchX[1]) return matchX[1];
if (matchGeneric && matchGeneric[1]) return matchGeneric[1];
return 0;
};
const getTranslateY = transform => {
const matchY = /translateY\((-?\d+\.?\d*)\)/g.exec(transform);
const matchGeneric = /translate\((-?\d+\.?\d*).*,\s*(-?\d+\.?\d*).*\)/g.exec(transform);
if (matchY && matchY[1]) return matchY[1];
if (matchGeneric && matchGeneric[2]) return matchGeneric[2];
return 0;
};
const getScaleX = transform => {
const matchX = /scaleX\((-?\d+\.?\d*)\)/g.exec(transform);
const matchGeneric = /scale\((-?\d+\.?\d*).*,\s*(-?\d+\.?\d*).*\)/g.exec(transform);
if (matchX && matchX[1]) return matchX[1];
if (matchGeneric && matchGeneric[1]) return matchGeneric[1];
return 1;
};
const getScaleY = transform => {
const matchY = /scaleY\((-?\d+\.?\d*)\)/g.exec(transform);
const matchGeneric = /scale\((-?\d+\.?\d*).*,\s*(-?\d+\.?\d*).*\)/g.exec(transform);
if (matchY && matchY[1]) return matchY[1];
if (matchGeneric && matchGeneric[2]) return matchGeneric[2];
return 1;
};
const getMatrix = transform => {
const match = /matrix\(([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)\)/g.exec(transform);
if (match) return match.slice(1, 7);
return null;
};
const applySingleTransformation = (element, transform, origin) => {
if (/rotate/g.test(transform)) {
element.root.instance.rotate(getRotation(transform), {
origin
});
} else if (/scaleX/g.test(transform)) {
element.root.instance.scale(getScaleX(transform), 1, {
origin
});
} else if (/scaleY/g.test(transform)) {
element.root.instance.scale(1, getScaleY(transform), {
origin
});
} else if (/scale/g.test(transform)) {
element.root.instance.scale(getScaleX(transform), getScaleY(transform), {
origin
});
} else if (/translateX/g.test(transform)) {
element.root.instance.translate(getTranslateX(transform), 1, {
origin
});
} else if (/translateY/g.test(transform)) {
element.root.instance.translate(1, getTranslateY(transform), {
origin
});
} else if (/translate/g.test(transform)) {
element.root.instance.translate(getTranslateX(transform), getTranslateY(transform), {
origin
});
} else if (/matrix/g.test(transform)) {
element.root.instance.transform(...getMatrix(transform));
}
};
const Transformations = {
applyTransformations() {
let match;
const re = /[a-zA-Z]+\([^)]+\)/g;
const origin = this.origin;
const transform = this.style && this.style.transform || '';
while ((match = re.exec(transform)) != null) {
applySingleTransformation(this, match[0], origin);
}
}
};
function printWarning(format, ...args) {
let argIndex = 0;
const message = 'Warning: ' + format.replace(/%s/g, () => args[argIndex++]);
if (typeof console !== 'undefined') {
console.error(message);
}
try {
throw new Error(message);
} catch (x) {}
}
const __DEV__ = process.env.NODE_ENV !== 'production';
const warning = __DEV__ ? (condition, format, ...args) => {
if (format === undefined) {
throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
}
if (!condition) {
printWarning(format, ...args);
}
} : () => {};
const merge = (a, b) => {
return ramda.isNil(b) ? a : b;
};
const deepMerge = objs => objs.reduce((acc, obj) => {
return ramda.mergeDeepWith(merge, acc, obj);
}, {});
const isFunction = ramda.compose(ramda.equals('Function'), ramda.type);
const inheritedProperties = ['color', 'fontFamily', 'fontSize', 'fontStyle', 'fontWeight', 'letterSpacing', 'opacity', 'textDecoration', 'lineHeight', 'textAlign', 'visibility', 'wordSpacing'];
class Base extends Node {
constructor(root, props) {
super();
this.root = root;
this.style = {};
this.props = deepMerge([this.constructor.defaultProps, Base.defaultProps, props]);
warning(!this.props.styles, '"styles" prop passed instead of "style" prop');
}
get page() {
return this.parent.page;
}
get wrap() {
return this.props.wrap;
}
get break() {
return this.props.break;
}
get fixed() {
return this.props.fixed;
}
get minPresenceAhead() {
return this.props.minPresenceAhead;
}
get absolute() {
return this.props.style.position === 'absolute';
}
get origin() {
const {
transformOriginX,
transf