@pagenflow/email 1.4.4 → 1.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Button.d.ts +4 -0
- package/dist/components/Column.d.ts +1 -1
- package/dist/components/Container.d.ts +1 -1
- package/dist/components/Image.d.ts +8 -0
- package/dist/components/Row.d.ts +1 -1
- package/dist/components/Section.d.ts +1 -1
- package/dist/components/Text.d.ts +2 -1
- package/dist/components/utils/MiniDomParser.d.ts +23 -0
- package/dist/components/utils/injectLinkStyles.d.ts +1 -0
- package/dist/index.cjs.js +177 -132
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +177 -132
- package/dist/index.esm.js.map +1 -1
- package/dist/types/IInnerLink.d.ts +17 -0
- package/package.json +1 -1
- package/dist/components/Body.js +0 -57
- package/dist/components/BodyDev.js +0 -57
- package/dist/components/Button.js +0 -327
- package/dist/components/Column.js +0 -127
- package/dist/components/Container.js +0 -179
- package/dist/components/Divider.js +0 -41
- package/dist/components/Font.js +0 -44
- package/dist/components/Head.js +0 -134
- package/dist/components/HeadDev.js +0 -311
- package/dist/components/Heading.js +0 -46
- package/dist/components/Html.js +0 -20
- package/dist/components/Icon.js +0 -276
- package/dist/components/Image.js +0 -119
- package/dist/components/MsoConditional.js +0 -19
- package/dist/components/Row.js +0 -157
- package/dist/components/Section.js +0 -65
- package/dist/components/Spacer.js +0 -40
- package/dist/components/Text.js +0 -42
- package/dist/index.js +0 -17
- package/dist/types/IInnerLink.js +0 -1
- package/dist/types/ResolvedFont.js +0 -1
- package/dist/types/index.js +0 -1
- package/dist/utils/isEqual.js +0 -1439
- package/dist/utils/memoUtils.js +0 -55
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
export type CalendarProvider = "google" | "outlook" | "office365" | "yahoo" | "ics";
|
|
2
|
+
export interface ICalendarLink {
|
|
3
|
+
calendarProvider?: CalendarProvider;
|
|
4
|
+
calendarTitle?: string;
|
|
5
|
+
calendarStart?: string;
|
|
6
|
+
calendarEnd?: string;
|
|
7
|
+
calendarAllDay?: boolean;
|
|
8
|
+
calendarDescription?: string;
|
|
9
|
+
calendarLocation?: string;
|
|
10
|
+
}
|
|
1
11
|
export type InnerLinkType = "none" | "anchor" | "url" | "email" | "phone" | "page_top" | "page_bottom";
|
|
2
12
|
export default interface IInnerLink {
|
|
3
13
|
type: InnerLinkType;
|
|
@@ -6,4 +16,11 @@ export default interface IInnerLink {
|
|
|
6
16
|
url?: string;
|
|
7
17
|
anchor?: string;
|
|
8
18
|
target?: "_blank" | "_self" | "_parent" | "_top";
|
|
19
|
+
calendarProvider?: CalendarProvider;
|
|
20
|
+
calendarTitle?: string;
|
|
21
|
+
calendarStart?: string;
|
|
22
|
+
calendarEnd?: string;
|
|
23
|
+
calendarAllDay?: boolean;
|
|
24
|
+
calendarDescription?: string;
|
|
25
|
+
calendarLocation?: string;
|
|
9
26
|
}
|
package/package.json
CHANGED
package/dist/components/Body.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export default function Body({ children, config = {} }) {
|
|
3
|
-
var _a, _b, _c, _d;
|
|
4
|
-
// Extract config values with fallbacks
|
|
5
|
-
const globalColor = config.color || "#000000";
|
|
6
|
-
const globalFontSize = config.fontSize || "16px";
|
|
7
|
-
const globalBackgroundColor = config.backgroundColor || "#ffffff";
|
|
8
|
-
const globalLineHeight = config.lineHeight || "1.4";
|
|
9
|
-
const globalFontFamily = config.fontFamily || "Arial, Helvetica, sans-serif";
|
|
10
|
-
// Background image properties
|
|
11
|
-
const bgImage = ((_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.src) || "";
|
|
12
|
-
const bgRepeat = ((_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.repeat) || "no-repeat";
|
|
13
|
-
const bgSize = ((_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.size) || "cover";
|
|
14
|
-
const bgPosition = ((_d = config.backgroundImage) === null || _d === void 0 ? void 0 : _d.position) || "center";
|
|
15
|
-
// 1. Style for the <body> tag inline
|
|
16
|
-
const bodyStyle = {
|
|
17
|
-
backgroundColor: globalBackgroundColor,
|
|
18
|
-
color: globalColor,
|
|
19
|
-
fontSize: globalFontSize,
|
|
20
|
-
lineHeight: globalLineHeight,
|
|
21
|
-
padding: "0",
|
|
22
|
-
margin: "0",
|
|
23
|
-
WebkitTextSizeAdjust: "100%",
|
|
24
|
-
overflowX: "hidden",
|
|
25
|
-
["msTextSizeAdjust"]: "100%",
|
|
26
|
-
["msoLineHeightRule"]: "exactly",
|
|
27
|
-
fontFamily: globalFontFamily,
|
|
28
|
-
// Background image support (if provided)
|
|
29
|
-
...(bgImage && {
|
|
30
|
-
backgroundImage: `url(${bgImage})`,
|
|
31
|
-
backgroundRepeat: bgRepeat,
|
|
32
|
-
backgroundSize: bgSize,
|
|
33
|
-
backgroundPosition: bgPosition,
|
|
34
|
-
}),
|
|
35
|
-
};
|
|
36
|
-
// 2. Style for the top-level <table> wrapper
|
|
37
|
-
const outerTableStyle = {
|
|
38
|
-
width: "100%",
|
|
39
|
-
["msoLineHeightRule"]: "exactly",
|
|
40
|
-
borderCollapse: "collapse",
|
|
41
|
-
};
|
|
42
|
-
return (_jsxs("body", { style: bodyStyle, children: [_jsx("center", { style: {
|
|
43
|
-
width: "100%",
|
|
44
|
-
background: globalBackgroundColor,
|
|
45
|
-
...(bgImage && {
|
|
46
|
-
backgroundImage: `url(${bgImage})`,
|
|
47
|
-
backgroundRepeat: bgRepeat,
|
|
48
|
-
backgroundSize: bgSize,
|
|
49
|
-
backgroundPosition: bgPosition,
|
|
50
|
-
}),
|
|
51
|
-
}, children: _jsx("table", { role: "presentation", border: 0, cellPadding: 0, cellSpacing: 0, align: "center", width: "100%", style: outerTableStyle, children: _jsx("tbody", { children: _jsx("tr", { children: _jsx("td", { align: "center", style: { padding: "0", margin: "0" }, children: children }) }) }) }) }), _jsx("div", { style: {
|
|
52
|
-
display: "none",
|
|
53
|
-
whiteSpace: "nowrap",
|
|
54
|
-
font: "15px courier",
|
|
55
|
-
lineHeight: "0",
|
|
56
|
-
}, children: "\u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0 \u00A0" })] }));
|
|
57
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
export default function BodyDev({ children, config = {} }) {
|
|
3
|
-
var _a, _b, _c, _d;
|
|
4
|
-
// Extract config values with fallbacks
|
|
5
|
-
const globalColor = config.color || "#000000";
|
|
6
|
-
const globalFontSize = config.fontSize || "16px";
|
|
7
|
-
const globalBackgroundColor = config.backgroundColor || "#ffffff";
|
|
8
|
-
const globalLineHeight = config.lineHeight || "1.4";
|
|
9
|
-
// Background image properties
|
|
10
|
-
const bgImage = ((_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.src) || "";
|
|
11
|
-
const bgRepeat = ((_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.repeat) || "no-repeat";
|
|
12
|
-
const bgSize = ((_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.size) || "cover";
|
|
13
|
-
const bgPosition = ((_d = config.backgroundImage) === null || _d === void 0 ? void 0 : _d.position) || "center";
|
|
14
|
-
// Main container style (simulates body behavior in dev mode)
|
|
15
|
-
const bodyDevStyle = {
|
|
16
|
-
backgroundColor: globalBackgroundColor,
|
|
17
|
-
color: globalColor,
|
|
18
|
-
fontSize: globalFontSize,
|
|
19
|
-
lineHeight: globalLineHeight,
|
|
20
|
-
padding: "0",
|
|
21
|
-
margin: "0",
|
|
22
|
-
fontFamily: "Arial, Helvetica, sans-serif",
|
|
23
|
-
overflowX: "hidden",
|
|
24
|
-
// Background image support (if provided)
|
|
25
|
-
...(bgImage && {
|
|
26
|
-
backgroundImage: `url(${bgImage})`,
|
|
27
|
-
backgroundRepeat: bgRepeat,
|
|
28
|
-
backgroundSize: bgSize,
|
|
29
|
-
backgroundPosition: bgPosition,
|
|
30
|
-
}),
|
|
31
|
-
};
|
|
32
|
-
// // Center wrapper style
|
|
33
|
-
// const centerStyle: CSSProperties = {
|
|
34
|
-
// width: '100%',
|
|
35
|
-
// minHeight: '100vh',
|
|
36
|
-
// display: 'flex',
|
|
37
|
-
// justifyContent: 'center',
|
|
38
|
-
// alignItems: 'flex-start',
|
|
39
|
-
// background: globalBackgroundColor,
|
|
40
|
-
// ...(bgImage && {
|
|
41
|
-
// backgroundImage: `url(${bgImage})`,
|
|
42
|
-
// backgroundRepeat: bgRepeat,
|
|
43
|
-
// backgroundSize: bgSize,
|
|
44
|
-
// backgroundPosition: bgPosition,
|
|
45
|
-
// }),
|
|
46
|
-
// };
|
|
47
|
-
// // Table wrapper style
|
|
48
|
-
// const tableWrapperStyle: CSSProperties = {
|
|
49
|
-
// width: '100%',
|
|
50
|
-
// maxWidth: '100%',
|
|
51
|
-
// };
|
|
52
|
-
return (_jsx("div", { className: "builder-canvas body-dev", style: {
|
|
53
|
-
...bodyDevStyle,
|
|
54
|
-
containerName: "builder-canvas",
|
|
55
|
-
containerType: "inline-size",
|
|
56
|
-
}, children: children }));
|
|
57
|
-
}
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo } from "react";
|
|
3
|
-
import { arePropsEqual } from "../utils/memoUtils";
|
|
4
|
-
// Map alignment to HTML 'align' attribute
|
|
5
|
-
const justifyMap = {
|
|
6
|
-
start: "left",
|
|
7
|
-
center: "center",
|
|
8
|
-
end: "right",
|
|
9
|
-
};
|
|
10
|
-
function getBorderStyle(border) {
|
|
11
|
-
if (!border)
|
|
12
|
-
return {};
|
|
13
|
-
const style = {};
|
|
14
|
-
// If a full border is specified, apply it
|
|
15
|
-
if (border.width && border.style && border.color) {
|
|
16
|
-
style.border = `${border.width} ${border.style} ${border.color}`;
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
// If only individual borders are specified, explicitly set others to 'none'
|
|
20
|
-
// to prevent Outlook Classic from showing black borders
|
|
21
|
-
const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
|
|
22
|
-
if (hasIndividualBorders) {
|
|
23
|
-
// Default all borders to none
|
|
24
|
-
style.borderTop = "none";
|
|
25
|
-
style.borderRight = "none";
|
|
26
|
-
style.borderBottom = "none";
|
|
27
|
-
style.borderLeft = "none";
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// Override with specific borders if provided
|
|
31
|
-
if (border.top) {
|
|
32
|
-
style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
|
|
33
|
-
}
|
|
34
|
-
if (border.right) {
|
|
35
|
-
style.borderRight = `${border.right.width} ${border.right.style} ${border.right.color}`;
|
|
36
|
-
}
|
|
37
|
-
if (border.bottom) {
|
|
38
|
-
style.borderBottom = `${border.bottom.width} ${border.bottom.style} ${border.bottom.color}`;
|
|
39
|
-
}
|
|
40
|
-
if (border.left) {
|
|
41
|
-
style.borderLeft = `${border.left.width} ${border.left.style} ${border.left.color}`;
|
|
42
|
-
}
|
|
43
|
-
return style;
|
|
44
|
-
}
|
|
45
|
-
function getBorderStyleString(border) {
|
|
46
|
-
if (!border)
|
|
47
|
-
return "";
|
|
48
|
-
const styles = [];
|
|
49
|
-
// If a full border is specified, apply it
|
|
50
|
-
if (border.width && border.style && border.color) {
|
|
51
|
-
styles.push(`border: ${border.width} ${border.style} ${border.color};`);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
// If only individual borders are specified
|
|
55
|
-
const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
|
|
56
|
-
if (hasIndividualBorders) {
|
|
57
|
-
// Default all borders to none
|
|
58
|
-
styles.push("border-top: none;");
|
|
59
|
-
styles.push("border-right: none;");
|
|
60
|
-
styles.push("border-bottom: none;");
|
|
61
|
-
styles.push("border-left: none;");
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// Override with specific borders if provided
|
|
65
|
-
if (border.top) {
|
|
66
|
-
styles.push(`border-top: ${border.top.width} ${border.top.style} ${border.top.color};`);
|
|
67
|
-
}
|
|
68
|
-
if (border.right) {
|
|
69
|
-
styles.push(`border-right: ${border.right.width} ${border.right.style} ${border.right.color};`);
|
|
70
|
-
}
|
|
71
|
-
if (border.bottom) {
|
|
72
|
-
styles.push(`border-bottom: ${border.bottom.width} ${border.bottom.style} ${border.bottom.color};`);
|
|
73
|
-
}
|
|
74
|
-
if (border.left) {
|
|
75
|
-
styles.push(`border-left: ${border.left.width} ${border.left.style} ${border.left.color};`);
|
|
76
|
-
}
|
|
77
|
-
return styles.join(" ");
|
|
78
|
-
}
|
|
79
|
-
function Button({ config, devMode }) {
|
|
80
|
-
const { href, children, backgroundColor = "#007bff", // Default blue
|
|
81
|
-
color = "#ffffff", padding = "12px 24px", borderRadius = "3px", border, width, maxWidth, justifyContent = "center", textAlign = "center", fontSize = "16px", fontWeight = "500", fontStyle, fontFamily = "Arial, sans-serif", lineHeight = "1.2", letterSpacing, textTransform, textDecoration = "none", direction, verticalAlign, opacity, whiteSpace = "normal", wordBreak = "break-word", } = config;
|
|
82
|
-
// Sanitize fontFamily early so safeFontFamily is available for all paths below.
|
|
83
|
-
const safeFontFamily = fontFamily
|
|
84
|
-
? fontFamily.replace(/['"]/g, "")
|
|
85
|
-
: fontFamily;
|
|
86
|
-
// 1. Link (A) Tag Styles (Fallback for Webmail/Mobile)
|
|
87
|
-
const linkStyle = {
|
|
88
|
-
color: color,
|
|
89
|
-
textDecoration: textDecoration,
|
|
90
|
-
display: "block",
|
|
91
|
-
padding: padding,
|
|
92
|
-
wordBreak: wordBreak,
|
|
93
|
-
fontFamily: fontFamily,
|
|
94
|
-
fontSize: fontSize,
|
|
95
|
-
fontWeight: fontWeight,
|
|
96
|
-
fontStyle: fontStyle,
|
|
97
|
-
lineHeight: lineHeight,
|
|
98
|
-
letterSpacing: letterSpacing,
|
|
99
|
-
textTransform: textTransform,
|
|
100
|
-
textAlign: textAlign,
|
|
101
|
-
direction: direction,
|
|
102
|
-
verticalAlign: verticalAlign,
|
|
103
|
-
opacity: opacity,
|
|
104
|
-
whiteSpace: whiteSpace,
|
|
105
|
-
};
|
|
106
|
-
// 2. Outer TD Style for Background and Border Radius (no border)
|
|
107
|
-
const backgroundTdStyle = {
|
|
108
|
-
backgroundColor: backgroundColor,
|
|
109
|
-
borderRadius: borderRadius,
|
|
110
|
-
width: width || "auto",
|
|
111
|
-
...(maxWidth && { maxWidth: maxWidth }),
|
|
112
|
-
// Overflow hidden to clip background to border-radius
|
|
113
|
-
...(borderRadius && { overflow: "hidden" }),
|
|
114
|
-
};
|
|
115
|
-
// 3. Border styles
|
|
116
|
-
const borderStyle = getBorderStyle(border);
|
|
117
|
-
const borderStyleString = getBorderStyleString(border);
|
|
118
|
-
// --- Determine Button Approach Based on Width ---
|
|
119
|
-
// Check if width is percentage-based or not defined
|
|
120
|
-
const isPercentageWidth = !width || width.includes("%");
|
|
121
|
-
const useSimpleOutlookApproach = isPercentageWidth;
|
|
122
|
-
const align = justifyMap[justifyContent];
|
|
123
|
-
// --- VML Calculation and Code for Outlook Compatibility (Fixed Width Only) ---
|
|
124
|
-
let vmlButton = "";
|
|
125
|
-
if (!useSimpleOutlookApproach) {
|
|
126
|
-
// Parse maxWidth if provided (always in px)
|
|
127
|
-
const maxWidthPx = maxWidth ? parseInt(maxWidth, 10) : null;
|
|
128
|
-
// VML needs fixed pixel height. We estimate it based on padding and potential wrapping.
|
|
129
|
-
const numericPadding = parseInt(padding.split(" ")[0] || "12", 10);
|
|
130
|
-
const numericFontSize = parseInt(fontSize, 10);
|
|
131
|
-
const numericLineHeight = lineHeight.includes("px")
|
|
132
|
-
? parseInt(lineHeight, 10)
|
|
133
|
-
: numericFontSize * parseFloat(lineHeight);
|
|
134
|
-
// Trust user's explicit pixel width - no calculation needed
|
|
135
|
-
const vmlWidth = parseInt(width, 10);
|
|
136
|
-
// Calculate VML height - trust user's padding and let text wrap naturally
|
|
137
|
-
// VML v:textbox will handle text wrapping automatically
|
|
138
|
-
const textContent = typeof children === "string" ? children : "";
|
|
139
|
-
// Estimate number of lines based on text length and button width
|
|
140
|
-
const horizontalPadding = padding.split(" ")[1]
|
|
141
|
-
? parseInt(padding.split(" ")[1], 10) * 2
|
|
142
|
-
: numericPadding * 2;
|
|
143
|
-
const availableTextWidth = vmlWidth - horizontalPadding;
|
|
144
|
-
const charWidthMultiplier = fontWeight && parseInt(fontWeight) >= 500 ? 0.7 : 0.6;
|
|
145
|
-
const avgCharWidth = numericFontSize * charWidthMultiplier;
|
|
146
|
-
const charsPerLine = Math.max(Math.floor(availableTextWidth / avgCharWidth), 1);
|
|
147
|
-
const numberOfLines = Math.max(Math.ceil(textContent.length / charsPerLine), 1);
|
|
148
|
-
// Calculate height: vertical padding + (lines * line height) + extra buffer for VML
|
|
149
|
-
const textHeight = numberOfLines * numericLineHeight;
|
|
150
|
-
// Add extra 4px buffer to prevent bottom cropping in VML
|
|
151
|
-
const vmlHeight = Math.max(numericPadding * 2 + textHeight + 4, 40);
|
|
152
|
-
// VML colors must use the full hex format (e.g., #000000)
|
|
153
|
-
const vmlFillColor = backgroundColor.startsWith("#")
|
|
154
|
-
? backgroundColor
|
|
155
|
-
: `#${backgroundColor}`;
|
|
156
|
-
// VML stroke color for border
|
|
157
|
-
const vmlStrokeColor = (border === null || border === void 0 ? void 0 : border.color) || vmlFillColor;
|
|
158
|
-
const vmlStrokeWeight = (border === null || border === void 0 ? void 0 : border.width) ? parseInt(border.width, 10) : 0;
|
|
159
|
-
const hasVmlStroke = vmlStrokeWeight > 0;
|
|
160
|
-
// Build VML font styles - consistent with other rendering paths
|
|
161
|
-
const vmlFontWeight = fontWeight || "500";
|
|
162
|
-
const vmlFontStyle = fontStyle === "italic" ? "font-style:italic;" : "";
|
|
163
|
-
const vmlLetterSpacing = letterSpacing
|
|
164
|
-
? `letter-spacing:${letterSpacing};`
|
|
165
|
-
: "";
|
|
166
|
-
const vmlTextTransform = textTransform
|
|
167
|
-
? `text-transform:${textTransform};`
|
|
168
|
-
: "";
|
|
169
|
-
const vmlTextDecoration = textDecoration && textDecoration !== "none"
|
|
170
|
-
? `text-decoration:${textDecoration};`
|
|
171
|
-
: "";
|
|
172
|
-
const vmlWhiteSpace = whiteSpace !== "normal" ? `white-space:${whiteSpace};` : "";
|
|
173
|
-
const vmlDirection = direction ? `direction:${direction};` : "";
|
|
174
|
-
const vmlOpacity = opacity !== undefined ? `opacity:${opacity};` : "";
|
|
175
|
-
// VML code uses MSO conditional comments to render only in Outlook
|
|
176
|
-
// Use table with explicit MSO height for vertical centering
|
|
177
|
-
const horizontalPaddingValue = padding.split(" ")[1]
|
|
178
|
-
? parseInt(padding.split(" ")[1], 10)
|
|
179
|
-
: numericPadding;
|
|
180
|
-
// For VML, we need to use a table inside to properly apply padding and centering
|
|
181
|
-
let vmlAlignAttr = "";
|
|
182
|
-
let vmlAlignStyle = "";
|
|
183
|
-
if (textAlign === "center") {
|
|
184
|
-
vmlAlignAttr = 'align="center"';
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
vmlAlignStyle = `text-align:${textAlign};`;
|
|
188
|
-
}
|
|
189
|
-
// Border radius is intentionally omitted (arcsize="0%") for Outlook Classic.
|
|
190
|
-
// Outlook Classic does not reliably support rounded corners and the result
|
|
191
|
-
// is inconsistent, so we render sharp corners there instead.
|
|
192
|
-
vmlButton = `
|
|
193
|
-
<!--[if mso]>
|
|
194
|
-
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${href}" style="height:${vmlHeight}px;width:${vmlWidth}px;" arcsize="0%" strokecolor="${vmlStrokeColor}" ${hasVmlStroke ? `strokeweight="${vmlStrokeWeight}px"` : 'stroke="f"'} fillcolor="${vmlFillColor}">
|
|
195
|
-
<w:anchorlock/>
|
|
196
|
-
<v:textbox inset="${horizontalPaddingValue}px,${numericPadding}px,${horizontalPaddingValue}px,${numericPadding}px">
|
|
197
|
-
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse;">
|
|
198
|
-
<tr>
|
|
199
|
-
<td ${vmlAlignAttr} valign="middle" style="${vmlAlignStyle}color:${color};font-family:${safeFontFamily};font-size:${fontSize};font-weight:${vmlFontWeight};${vmlFontStyle}${vmlLetterSpacing}${vmlTextTransform}${vmlTextDecoration}${vmlWhiteSpace}${vmlDirection}${vmlOpacity}line-height:${lineHeight};mso-line-height-rule:exactly;">
|
|
200
|
-
${typeof children === "string" ? children : ""}
|
|
201
|
-
</td>
|
|
202
|
-
</tr>
|
|
203
|
-
</table>
|
|
204
|
-
</v:textbox>
|
|
205
|
-
</v:roundrect>
|
|
206
|
-
<![endif]-->
|
|
207
|
-
`;
|
|
208
|
-
}
|
|
209
|
-
// --- Simple Outlook Approach for Percentage Widths ---
|
|
210
|
-
let simpleOutlookButton = "";
|
|
211
|
-
if (useSimpleOutlookApproach) {
|
|
212
|
-
// Build consistent inline styles for text properties
|
|
213
|
-
const textDecorationStyle = textDecoration && textDecoration !== "none"
|
|
214
|
-
? `text-decoration: ${textDecoration};`
|
|
215
|
-
: "";
|
|
216
|
-
const fontStyleProp = fontStyle ? `font-style: ${fontStyle};` : "";
|
|
217
|
-
const letterSpacingProp = letterSpacing
|
|
218
|
-
? `letter-spacing: ${letterSpacing};`
|
|
219
|
-
: "";
|
|
220
|
-
const textTransformProp = textTransform
|
|
221
|
-
? `text-transform: ${textTransform};`
|
|
222
|
-
: "";
|
|
223
|
-
const whiteSpaceProp = whiteSpace !== "normal" ? `white-space: ${whiteSpace};` : "";
|
|
224
|
-
const directionProp = direction ? `direction: ${direction};` : "";
|
|
225
|
-
const opacityProp = opacity !== undefined ? `opacity: ${opacity};` : "";
|
|
226
|
-
const wordBreakProp = wordBreak !== "break-word" ? `word-break: ${wordBreak};` : "";
|
|
227
|
-
// Border radius is intentionally omitted from the Outlook Classic table cell.
|
|
228
|
-
// Outlook Classic ignores border-radius on table cells anyway, and including it
|
|
229
|
-
// can cause unexpected rendering artifacts, so we explicitly leave it out.
|
|
230
|
-
simpleOutlookButton = `
|
|
231
|
-
<!--[if mso]>
|
|
232
|
-
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse: collapse;">
|
|
233
|
-
<tr>
|
|
234
|
-
<td align="${align}" style="padding: 0;">
|
|
235
|
-
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="${width || "auto"}" style="border-collapse: collapse;">
|
|
236
|
-
<tr>
|
|
237
|
-
<td bgcolor="${backgroundColor}" align="${textAlign}" style="padding: ${padding}; text-align: ${textAlign}; ${borderStyleString}">
|
|
238
|
-
<a href="${href}" target="_blank" rel="noopener noreferrer" style="color: ${color}; ${textDecorationStyle} display: block; font-family: ${safeFontFamily}; font-size: ${fontSize}; font-weight: ${fontWeight}; ${fontStyleProp} line-height: ${lineHeight}; ${letterSpacingProp} ${textTransformProp} text-align: ${textAlign}; ${whiteSpaceProp} ${directionProp} ${opacityProp} ${wordBreakProp} mso-line-height-rule: exactly;">
|
|
239
|
-
${typeof children === "string" ? children : ""}
|
|
240
|
-
</a>
|
|
241
|
-
</td>
|
|
242
|
-
</tr>
|
|
243
|
-
</table>
|
|
244
|
-
</td>
|
|
245
|
-
</tr>
|
|
246
|
-
</table>
|
|
247
|
-
<![endif]-->
|
|
248
|
-
`;
|
|
249
|
-
}
|
|
250
|
-
// Build shared inline style fragments for the non-MSO path.
|
|
251
|
-
// fontFamily uses the sanitized value so embedded quotes never break the
|
|
252
|
-
// style attribute string (which is always wrapped in double quotes).
|
|
253
|
-
const sharedTextStyles = [
|
|
254
|
-
`color: ${color};`,
|
|
255
|
-
safeFontFamily ? `font-family: ${safeFontFamily};` : "",
|
|
256
|
-
fontSize ? `font-size: ${fontSize};` : "",
|
|
257
|
-
fontWeight ? `font-weight: ${fontWeight};` : "",
|
|
258
|
-
fontStyle ? `font-style: ${fontStyle};` : "",
|
|
259
|
-
lineHeight ? `line-height: ${lineHeight};` : "",
|
|
260
|
-
letterSpacing ? `letter-spacing: ${letterSpacing};` : "",
|
|
261
|
-
textTransform ? `text-transform: ${textTransform};` : "",
|
|
262
|
-
textDecoration && textDecoration !== "none"
|
|
263
|
-
? `text-decoration: ${textDecoration};`
|
|
264
|
-
: "",
|
|
265
|
-
direction ? `direction: ${direction};` : "",
|
|
266
|
-
opacity !== undefined ? `opacity: ${opacity};` : "",
|
|
267
|
-
whiteSpace !== "normal" ? `white-space: ${whiteSpace};` : "",
|
|
268
|
-
]
|
|
269
|
-
.filter(Boolean)
|
|
270
|
-
.join(" ");
|
|
271
|
-
return (
|
|
272
|
-
// Wrapper table for alignment - maintains proper positioning for hover indicators
|
|
273
|
-
_jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
274
|
-
width: "100%",
|
|
275
|
-
borderCollapse: "collapse",
|
|
276
|
-
boxSizing: "border-box",
|
|
277
|
-
border: 0,
|
|
278
|
-
margin: 0,
|
|
279
|
-
padding: 0,
|
|
280
|
-
}, children: _jsx("tbody", { children: _jsx("tr", { children: _jsx("td", { align: align, style: {
|
|
281
|
-
padding: 0,
|
|
282
|
-
}, children: _jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
283
|
-
// --- Start dev
|
|
284
|
-
position: "relative",
|
|
285
|
-
// --- End dev
|
|
286
|
-
width: width || "auto",
|
|
287
|
-
...(maxWidth && { maxWidth: maxWidth }),
|
|
288
|
-
borderCollapse: "collapse",
|
|
289
|
-
// base
|
|
290
|
-
boxSizing: "border-box",
|
|
291
|
-
border: 0,
|
|
292
|
-
margin: 0,
|
|
293
|
-
padding: 0,
|
|
294
|
-
}, onClick: devMode ? (e) => e.preventDefault() : undefined, children: _jsx("tbody", { children: _jsx("tr", { children: _jsx("td", { dangerouslySetInnerHTML: {
|
|
295
|
-
__html: `
|
|
296
|
-
${devMode ? "" : useSimpleOutlookApproach ? simpleOutlookButton : vmlButton}
|
|
297
|
-
<!--[if !mso]><!-->
|
|
298
|
-
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse; width: 100%;">
|
|
299
|
-
<tbody>
|
|
300
|
-
<tr>
|
|
301
|
-
<td style="background-color: ${backgroundTdStyle.backgroundColor}; border-radius: ${backgroundTdStyle.borderRadius}; width: ${backgroundTdStyle.width}; ${maxWidth ? `max-width: ${maxWidth};` : ""} ${borderRadius ? "overflow: hidden;" : ""}">
|
|
302
|
-
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="border-collapse: separate; border-spacing: 0; border-radius: ${borderRadius}; width: 100%; ${borderStyleString}">
|
|
303
|
-
<tbody>
|
|
304
|
-
<tr>
|
|
305
|
-
<td style="padding: 0;">
|
|
306
|
-
${devMode
|
|
307
|
-
? `<span style="${sharedTextStyles} display: block; text-align: ${textAlign}; word-break: ${wordBreak}; padding: ${padding};">
|
|
308
|
-
${typeof children === "string" ? children : ""}
|
|
309
|
-
</span>`
|
|
310
|
-
: `<a href="${href}" target="_blank" rel="noopener noreferrer" style="${sharedTextStyles} ${textDecoration && textDecoration !== "none" ? "" : "text-decoration: none;"} display: block; word-break: ${wordBreak}; text-align: ${textAlign}; padding: ${padding};">
|
|
311
|
-
<span style="${sharedTextStyles}">
|
|
312
|
-
${typeof children === "string" ? children : ""}
|
|
313
|
-
</span>
|
|
314
|
-
</a>`}
|
|
315
|
-
</td>
|
|
316
|
-
</tr>
|
|
317
|
-
</tbody>
|
|
318
|
-
</table>
|
|
319
|
-
</td>
|
|
320
|
-
</tr>
|
|
321
|
-
</tbody>
|
|
322
|
-
</table>
|
|
323
|
-
<!--<![endif]-->
|
|
324
|
-
`,
|
|
325
|
-
} }) }) }) }) }) }) }) }));
|
|
326
|
-
}
|
|
327
|
-
export default memo(Button, arePropsEqual);
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Fragment, memo } from "react";
|
|
3
|
-
import { arePropsEqual } from "../utils/memoUtils";
|
|
4
|
-
// Helper for vertical alignment
|
|
5
|
-
const vAlignMap = {
|
|
6
|
-
start: "top",
|
|
7
|
-
center: "middle",
|
|
8
|
-
end: "bottom",
|
|
9
|
-
};
|
|
10
|
-
// Helper for horizontal alignment
|
|
11
|
-
const alignMap = {
|
|
12
|
-
start: "left",
|
|
13
|
-
center: "center",
|
|
14
|
-
end: "right",
|
|
15
|
-
};
|
|
16
|
-
// Helper to convert border config to CSS border shorthand
|
|
17
|
-
function getBorderStyle(border) {
|
|
18
|
-
if (!border)
|
|
19
|
-
return {};
|
|
20
|
-
const style = {};
|
|
21
|
-
// If a full border is specified, apply it
|
|
22
|
-
if (border.width && border.style && border.color) {
|
|
23
|
-
style.border = `${border.width} ${border.style} ${border.color}`;
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
// If only individual borders are specified, explicitly set others to 'none'
|
|
27
|
-
// to prevent Outlook Classic from showing black borders
|
|
28
|
-
const hasIndividualBorders = border.top || border.right || border.bottom || border.left;
|
|
29
|
-
if (hasIndividualBorders) {
|
|
30
|
-
// Default all borders to none
|
|
31
|
-
style.borderTop = "none";
|
|
32
|
-
style.borderRight = "none";
|
|
33
|
-
style.borderBottom = "none";
|
|
34
|
-
style.borderLeft = "none";
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// Override with specific borders if provided
|
|
38
|
-
if (border.top) {
|
|
39
|
-
style.borderTop = `${border.top.width} ${border.top.style} ${border.top.color}`;
|
|
40
|
-
}
|
|
41
|
-
if (border.right) {
|
|
42
|
-
style.borderRight = `${border.right.width} ${border.right.style} ${border.right.color}`;
|
|
43
|
-
}
|
|
44
|
-
if (border.bottom) {
|
|
45
|
-
style.borderBottom = `${border.bottom.width} ${border.bottom.style} ${border.bottom.color}`;
|
|
46
|
-
}
|
|
47
|
-
if (border.left) {
|
|
48
|
-
style.borderLeft = `${border.left.width} ${border.left.style} ${border.left.color}`;
|
|
49
|
-
}
|
|
50
|
-
return style;
|
|
51
|
-
}
|
|
52
|
-
function Column({ children, config, devNode }) {
|
|
53
|
-
var _a, _b, _c;
|
|
54
|
-
// Process children array for gap support
|
|
55
|
-
const childrenArray = (Array.isArray(children) ? children : [children]).filter((child) => child != null);
|
|
56
|
-
const numChildren = childrenArray.length;
|
|
57
|
-
// 1. Outer table style: Takes up the full width/height of its parent TD.
|
|
58
|
-
// height here drives the *total* outer height of the column.
|
|
59
|
-
const outerTableStyle = {
|
|
60
|
-
width: "100%",
|
|
61
|
-
height: config.height,
|
|
62
|
-
borderCollapse: "collapse",
|
|
63
|
-
};
|
|
64
|
-
// 2. Outer TD style: Background and Border Radius (no border here).
|
|
65
|
-
// height is set so the TD occupies the full declared height.
|
|
66
|
-
const outerTdStyle = {
|
|
67
|
-
width: config.width,
|
|
68
|
-
height: config.height,
|
|
69
|
-
backgroundColor: config.backgroundColor,
|
|
70
|
-
borderRadius: config.borderRadius,
|
|
71
|
-
// Background Image styles
|
|
72
|
-
backgroundImage: config.backgroundImage
|
|
73
|
-
? `url(${config.backgroundImage.src})`
|
|
74
|
-
: undefined,
|
|
75
|
-
backgroundRepeat: (_a = config.backgroundImage) === null || _a === void 0 ? void 0 : _a.repeat,
|
|
76
|
-
backgroundSize: (_b = config.backgroundImage) === null || _b === void 0 ? void 0 : _b.size,
|
|
77
|
-
backgroundPosition: (_c = config.backgroundImage) === null || _c === void 0 ? void 0 : _c.position,
|
|
78
|
-
// Overflow hidden to clip background to border-radius
|
|
79
|
-
...(config.borderRadius && { overflow: "hidden" }),
|
|
80
|
-
};
|
|
81
|
-
// 2b. Inner table style: Border and Border Radius.
|
|
82
|
-
// height: 100% so it stretches to fill the outer TD's declared height.
|
|
83
|
-
const innerTableStyle = {
|
|
84
|
-
width: "100%",
|
|
85
|
-
height: "100%", // fill the outer TD rather than re-declaring the pixel value
|
|
86
|
-
borderCollapse: "separate",
|
|
87
|
-
borderSpacing: 0,
|
|
88
|
-
borderRadius: config.borderRadius,
|
|
89
|
-
...getBorderStyle(config.border),
|
|
90
|
-
};
|
|
91
|
-
// 3. Inner TD style: Padding and Vertical Alignment only.
|
|
92
|
-
// *** No height here. ***
|
|
93
|
-
// The outer TD/table owns the height; padding is purely inner spacing,
|
|
94
|
-
// so the total rendered height = declared height (padding is inside).
|
|
95
|
-
const innerTdStyle = {
|
|
96
|
-
padding: config.padding,
|
|
97
|
-
// height intentionally omitted — setting it here would make browsers
|
|
98
|
-
// treat it as content-box height and add padding on top, causing the
|
|
99
|
-
// total to exceed the declared height in preview mode.
|
|
100
|
-
verticalAlign: config.alignItems ? alignMap[config.alignItems] : "top",
|
|
101
|
-
};
|
|
102
|
-
// 4. Gap spacer style (used between children)
|
|
103
|
-
const gapSpacerStyle = {
|
|
104
|
-
height: config.gap || "0",
|
|
105
|
-
lineHeight: "1px",
|
|
106
|
-
fontSize: "1px",
|
|
107
|
-
width: "100%",
|
|
108
|
-
};
|
|
109
|
-
// Main content rendering
|
|
110
|
-
const renderContent = () => (_jsx("table", { "aria-label": "Column Padding", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: innerTableStyle, children: _jsx("tbody", { children: _jsx("tr", { children: _jsx("td", { style: innerTdStyle, valign: config.justifyContent ? vAlignMap[config.justifyContent] : "top", align: config.alignItems ? alignMap[config.alignItems] : "left", children: config.gap && numChildren > 1 ? (_jsx("table", { "aria-label": "Column Gap Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
111
|
-
width: "100%",
|
|
112
|
-
borderCollapse: "collapse",
|
|
113
|
-
}, children: _jsx("tbody", { children: childrenArray.map((child, index) => (_jsxs(Fragment, { children: [_jsx("tr", { children: _jsx("td", { style: {
|
|
114
|
-
verticalAlign: config.alignItems
|
|
115
|
-
? alignMap[config.alignItems]
|
|
116
|
-
: "top",
|
|
117
|
-
}, valign: config.justifyContent
|
|
118
|
-
? vAlignMap[config.justifyContent]
|
|
119
|
-
: "top", align: config.alignItems
|
|
120
|
-
? alignMap[config.alignItems]
|
|
121
|
-
: "left", children: child }) }), index < numChildren - 1 && (_jsx("tr", { children: _jsx("td", { style: gapSpacerStyle, children: "\u00A0" }) }))] }, `col-child-${index}`))) }) })) : (children) }) }) }) }));
|
|
122
|
-
return (_jsxs("table", { "aria-label": "Column Wrapper", role: "presentation", cellPadding: 0, cellSpacing: 0, border: 0, style: {
|
|
123
|
-
position: "relative",
|
|
124
|
-
...outerTableStyle,
|
|
125
|
-
}, ...(config.height && { height: config.height }), children: [_jsx("tbody", { children: _jsx("tr", { children: _jsx("td", { style: outerTdStyle, ...(config.width && { width: config.width }), ...(config.height && { height: config.height }), children: renderContent() }) }) }), devNode && (_jsx("tfoot", { children: _jsx("tr", { children: _jsx("td", { children: devNode }) }) }))] }));
|
|
126
|
-
}
|
|
127
|
-
export default memo(Column, arePropsEqual);
|