@react-email/editor 0.0.0-experimental.4 → 0.0.0-experimental.40
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/core/index.cjs +9 -0
- package/dist/core/index.d.cts +2 -0
- package/dist/core/index.d.mts +3 -0
- package/dist/core/index.mjs +4 -0
- package/dist/create-paste-handler-B8BtjBk3.d.cts +14 -0
- package/dist/create-paste-handler-B8BtjBk3.d.cts.map +1 -0
- package/dist/create-paste-handler-CGR738bC.d.mts +14 -0
- package/dist/create-paste-handler-CGR738bC.d.mts.map +1 -0
- package/dist/event-bus-CHEzOS_O.mjs +329 -0
- package/dist/event-bus-CHEzOS_O.mjs.map +1 -0
- package/dist/event-bus-fb8U7hrl.cjs +450 -0
- package/dist/extension-DyY8_bh4.mjs +1110 -0
- package/dist/extension-DyY8_bh4.mjs.map +1 -0
- package/dist/extension-w5VaUeSw.cjs +1235 -0
- package/dist/extensions/index.cjs +51 -0
- package/dist/extensions/index.d.cts +399 -0
- package/dist/extensions/index.d.cts.map +1 -0
- package/dist/extensions/index.d.mts +400 -0
- package/dist/extensions/index.d.mts.map +1 -0
- package/dist/extensions/index.mjs +5 -0
- package/dist/extensions-BvfmaKCn.mjs +2088 -0
- package/dist/extensions-BvfmaKCn.mjs.map +1 -0
- package/dist/extensions-CkjPj2JO.cjs +2369 -0
- package/dist/global-content-D_WYaFgX.mjs +78 -0
- package/dist/global-content-D_WYaFgX.mjs.map +1 -0
- package/dist/global-content-bJgotqmA.cjs +89 -0
- package/dist/index-C4KcMQ0R.d.cts +161 -0
- package/dist/index-C4KcMQ0R.d.cts.map +1 -0
- package/dist/index-CxX7W63O.d.mts +161 -0
- package/dist/index-CxX7W63O.d.mts.map +1 -0
- package/dist/index.cjs +74 -0
- package/dist/index.css +832 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +33 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +31 -277
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +64 -1377
- package/dist/index.mjs.map +1 -1
- package/dist/plugins/index.cjs +23 -0
- package/dist/plugins/index.d.cts +191 -0
- package/dist/plugins/index.d.cts.map +1 -0
- package/dist/plugins/index.d.mts +191 -0
- package/dist/plugins/index.d.mts.map +1 -0
- package/dist/plugins/index.mjs +3 -0
- package/dist/root-CkYaJZpj.mjs +2316 -0
- package/dist/root-CkYaJZpj.mjs.map +1 -0
- package/dist/root-Gu08xybW.cjs +2832 -0
- package/dist/set-text-alignment-Cv72txmv.cjs +24 -0
- package/dist/set-text-alignment-OA8IMWmO.mjs +19 -0
- package/dist/set-text-alignment-OA8IMWmO.mjs.map +1 -0
- package/dist/styles-C-cCyJCn.cjs +211 -0
- package/dist/styles-_TMw3YxC.mjs +194 -0
- package/dist/styles-_TMw3YxC.mjs.map +1 -0
- package/dist/ui/bubble-menu/bubble-menu.css +285 -0
- package/dist/ui/index.cjs +147 -0
- package/dist/ui/index.d.cts +939 -0
- package/dist/ui/index.d.cts.map +1 -0
- package/dist/ui/index.d.mts +939 -0
- package/dist/ui/index.d.mts.map +1 -0
- package/dist/ui/index.mjs +60 -0
- package/dist/ui/index.mjs.map +1 -0
- package/dist/ui/slash-command/slash-command.css +44 -0
- package/dist/ui/themes/default.css +830 -0
- package/dist/utils/index.cjs +3 -0
- package/dist/utils/index.d.cts +7 -0
- package/dist/utils/index.d.cts.map +1 -0
- package/dist/utils/index.d.mts +7 -0
- package/dist/utils/index.d.mts.map +1 -0
- package/dist/utils/index.mjs +3 -0
- package/package.json +109 -21
- package/dist/index.d.ts +0 -279
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1436
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/set-text-alignment.ts
|
|
3
|
+
function setTextAlignment(editor, alignment) {
|
|
4
|
+
const { from, to } = editor.state.selection;
|
|
5
|
+
const tr = editor.state.tr;
|
|
6
|
+
editor.state.doc.nodesBetween(from, to, (node, pos) => {
|
|
7
|
+
if (node.isTextblock) {
|
|
8
|
+
const prop = "align" in node.attrs ? "align" : "alignment";
|
|
9
|
+
tr.setNodeMarkup(pos, null, {
|
|
10
|
+
...node.attrs,
|
|
11
|
+
[prop]: alignment
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
editor.view.dispatch(tr);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
Object.defineProperty(exports, 'setTextAlignment', {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () {
|
|
22
|
+
return setTextAlignment;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/utils/set-text-alignment.ts
|
|
2
|
+
function setTextAlignment(editor, alignment) {
|
|
3
|
+
const { from, to } = editor.state.selection;
|
|
4
|
+
const tr = editor.state.tr;
|
|
5
|
+
editor.state.doc.nodesBetween(from, to, (node, pos) => {
|
|
6
|
+
if (node.isTextblock) {
|
|
7
|
+
const prop = "align" in node.attrs ? "align" : "alignment";
|
|
8
|
+
tr.setNodeMarkup(pos, null, {
|
|
9
|
+
...node.attrs,
|
|
10
|
+
[prop]: alignment
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
editor.view.dispatch(tr);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { setTextAlignment as t };
|
|
19
|
+
//# sourceMappingURL=set-text-alignment-OA8IMWmO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-text-alignment-OA8IMWmO.mjs","names":[],"sources":["../src/utils/set-text-alignment.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core';\n\nexport function setTextAlignment(editor: Editor, alignment: string) {\n const { from, to } = editor.state.selection;\n const tr = editor.state.tr;\n editor.state.doc.nodesBetween(from, to, (node, pos) => {\n if (node.isTextblock) {\n const prop = 'align' in node.attrs ? 'align' : 'alignment';\n tr.setNodeMarkup(pos, null, { ...node.attrs, [prop]: alignment });\n }\n });\n editor.view.dispatch(tr);\n}\n"],"mappings":";AAEA,SAAgB,iBAAiB,QAAgB,WAAmB;CAClE,MAAM,EAAE,MAAM,OAAO,OAAO,MAAM;CAClC,MAAM,KAAK,OAAO,MAAM;AACxB,QAAO,MAAM,IAAI,aAAa,MAAM,KAAK,MAAM,QAAQ;AACrD,MAAI,KAAK,aAAa;GACpB,MAAM,OAAO,WAAW,KAAK,QAAQ,UAAU;AAC/C,MAAG,cAAc,KAAK,MAAM;IAAE,GAAG,KAAK;KAAQ,OAAO;IAAW,CAAC;;GAEnE;AACF,QAAO,KAAK,SAAS,GAAG"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/styles.ts
|
|
3
|
+
const WHITE_SPACE_REGEX = /\s+/;
|
|
4
|
+
const BORDER_WIDTH_TO_STYLE = {
|
|
5
|
+
borderWidth: "borderStyle",
|
|
6
|
+
borderTopWidth: "borderTopStyle",
|
|
7
|
+
borderRightWidth: "borderRightStyle",
|
|
8
|
+
borderBottomWidth: "borderBottomStyle",
|
|
9
|
+
borderLeftWidth: "borderLeftStyle"
|
|
10
|
+
};
|
|
11
|
+
const inlineCssToJs = (inlineStyle, options = {}) => {
|
|
12
|
+
const styleObject = {};
|
|
13
|
+
if (!inlineStyle || inlineStyle === "" || typeof inlineStyle === "object") return styleObject;
|
|
14
|
+
inlineStyle.split(";").forEach((style) => {
|
|
15
|
+
if (style.trim()) {
|
|
16
|
+
const [key, value] = style.split(":");
|
|
17
|
+
const valueTrimmed = value?.trim();
|
|
18
|
+
if (!valueTrimmed) return;
|
|
19
|
+
const formattedKey = key.trim().replace(/-\w/g, (match) => match[1].toUpperCase());
|
|
20
|
+
styleObject[formattedKey] = options?.removeUnit ? valueTrimmed.replace(/px|%/g, "") : valueTrimmed;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return styleObject;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Expands CSS shorthand properties (margin, padding) into their longhand equivalents.
|
|
27
|
+
* This prevents shorthand properties from overriding specific longhand properties in email clients.
|
|
28
|
+
*
|
|
29
|
+
* @param styles - Style object that may contain shorthand properties
|
|
30
|
+
* @returns New style object with shorthand properties expanded to longhand
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* expandShorthandProperties({ margin: '0', paddingTop: '10px' })
|
|
34
|
+
* // Returns: { marginTop: '0', marginRight: '0', marginBottom: '0', marginLeft: '0', paddingTop: '10px' }
|
|
35
|
+
*/
|
|
36
|
+
function expandShorthandProperties(styles) {
|
|
37
|
+
if (!styles || typeof styles !== "object") return {};
|
|
38
|
+
const expanded = {};
|
|
39
|
+
for (const key in styles) {
|
|
40
|
+
const value = styles[key];
|
|
41
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
42
|
+
switch (key) {
|
|
43
|
+
case "margin": {
|
|
44
|
+
const values = parseShorthandValue(value);
|
|
45
|
+
expanded.marginTop = values.top;
|
|
46
|
+
expanded.marginRight = values.right;
|
|
47
|
+
expanded.marginBottom = values.bottom;
|
|
48
|
+
expanded.marginLeft = values.left;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
case "padding": {
|
|
52
|
+
const values = parseShorthandValue(value);
|
|
53
|
+
expanded.paddingTop = values.top;
|
|
54
|
+
expanded.paddingRight = values.right;
|
|
55
|
+
expanded.paddingBottom = values.bottom;
|
|
56
|
+
expanded.paddingLeft = values.left;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case "border": {
|
|
60
|
+
const values = convertBorderValue(value);
|
|
61
|
+
expanded.borderStyle = values.style;
|
|
62
|
+
expanded.borderWidth = values.width;
|
|
63
|
+
expanded.borderColor = values.color;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case "borderTopLeftRadius":
|
|
67
|
+
case "borderTopRightRadius":
|
|
68
|
+
case "borderBottomLeftRadius":
|
|
69
|
+
case "borderBottomRightRadius":
|
|
70
|
+
expanded[key] = value;
|
|
71
|
+
if (styles.borderTopLeftRadius && styles.borderTopRightRadius && styles.borderBottomLeftRadius && styles.borderBottomRightRadius) {
|
|
72
|
+
const values = [
|
|
73
|
+
styles.borderTopLeftRadius,
|
|
74
|
+
styles.borderTopRightRadius,
|
|
75
|
+
styles.borderBottomLeftRadius,
|
|
76
|
+
styles.borderBottomRightRadius
|
|
77
|
+
];
|
|
78
|
+
if (new Set(values).size === 1) expanded.borderRadius = values[0];
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
default: expanded[key] = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return expanded;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Parses CSS shorthand value (1-4 values) into individual side values.
|
|
88
|
+
* Follows CSS specification for shorthand property value parsing.
|
|
89
|
+
*
|
|
90
|
+
* @param value - Shorthand value string (e.g., '0', '10px 20px', '5px 10px 15px 20px')
|
|
91
|
+
* @returns Object with top, right, bottom, left values
|
|
92
|
+
*/
|
|
93
|
+
function parseShorthandValue(value) {
|
|
94
|
+
const stringValue = String(value).trim();
|
|
95
|
+
const parts = stringValue.split(WHITE_SPACE_REGEX);
|
|
96
|
+
const len = parts.length;
|
|
97
|
+
if (len === 1) return {
|
|
98
|
+
top: parts[0],
|
|
99
|
+
right: parts[0],
|
|
100
|
+
bottom: parts[0],
|
|
101
|
+
left: parts[0]
|
|
102
|
+
};
|
|
103
|
+
if (len === 2) return {
|
|
104
|
+
top: parts[0],
|
|
105
|
+
right: parts[1],
|
|
106
|
+
bottom: parts[0],
|
|
107
|
+
left: parts[1]
|
|
108
|
+
};
|
|
109
|
+
if (len === 3) return {
|
|
110
|
+
top: parts[0],
|
|
111
|
+
right: parts[1],
|
|
112
|
+
bottom: parts[2],
|
|
113
|
+
left: parts[1]
|
|
114
|
+
};
|
|
115
|
+
if (len === 4) return {
|
|
116
|
+
top: parts[0],
|
|
117
|
+
right: parts[1],
|
|
118
|
+
bottom: parts[2],
|
|
119
|
+
left: parts[3]
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
top: stringValue,
|
|
123
|
+
right: stringValue,
|
|
124
|
+
bottom: stringValue,
|
|
125
|
+
left: stringValue
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function convertBorderValue(value) {
|
|
129
|
+
const stringValue = String(value).trim();
|
|
130
|
+
const parts = stringValue.split(WHITE_SPACE_REGEX);
|
|
131
|
+
switch (parts.length) {
|
|
132
|
+
case 1: return {
|
|
133
|
+
style: "solid",
|
|
134
|
+
width: parts[0],
|
|
135
|
+
color: "black"
|
|
136
|
+
};
|
|
137
|
+
case 2: return {
|
|
138
|
+
style: parts[1],
|
|
139
|
+
width: parts[0],
|
|
140
|
+
color: "black"
|
|
141
|
+
};
|
|
142
|
+
case 3: return {
|
|
143
|
+
style: parts[1],
|
|
144
|
+
width: parts[0],
|
|
145
|
+
color: parts[2]
|
|
146
|
+
};
|
|
147
|
+
case 4: return {
|
|
148
|
+
style: parts[1],
|
|
149
|
+
width: parts[0],
|
|
150
|
+
color: parts[2]
|
|
151
|
+
};
|
|
152
|
+
default: return {
|
|
153
|
+
style: "solid",
|
|
154
|
+
width: stringValue,
|
|
155
|
+
color: "black"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* When a border-width is present but border-style is missing, browsers default
|
|
161
|
+
* to `none` and the border is invisible. This adds `solid` as a sensible
|
|
162
|
+
* fallback so borders show up immediately after setting a width.
|
|
163
|
+
*/
|
|
164
|
+
function ensureBorderStyleFallback(styles) {
|
|
165
|
+
for (const [widthKey, styleKey] of Object.entries(BORDER_WIDTH_TO_STYLE)) {
|
|
166
|
+
const widthValue = styles[widthKey];
|
|
167
|
+
if (!widthValue || widthValue === "0" || widthValue === "0px") continue;
|
|
168
|
+
if (!styles[styleKey]) {
|
|
169
|
+
if (styleKey !== "borderStyle" && styles.borderStyle) continue;
|
|
170
|
+
styles[styleKey] = "solid";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return styles;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Resolves conflicts between reset styles and inline styles by expanding
|
|
177
|
+
* shorthand properties (margin, padding) to longhand before merging.
|
|
178
|
+
* This prevents shorthand properties from overriding specific longhand properties.
|
|
179
|
+
*
|
|
180
|
+
* @param resetStyles - Base reset styles that may contain shorthand properties
|
|
181
|
+
* @param inlineStyles - Inline styles that should override reset styles
|
|
182
|
+
* @returns Merged styles with inline styles taking precedence
|
|
183
|
+
*/
|
|
184
|
+
function resolveConflictingStyles(resetStyles, inlineStyles) {
|
|
185
|
+
const expandedResetStyles = expandShorthandProperties(resetStyles);
|
|
186
|
+
const expandedInlineStyles = expandShorthandProperties(inlineStyles);
|
|
187
|
+
return {
|
|
188
|
+
...expandedResetStyles,
|
|
189
|
+
...expandedInlineStyles
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
Object.defineProperty(exports, 'ensureBorderStyleFallback', {
|
|
195
|
+
enumerable: true,
|
|
196
|
+
get: function () {
|
|
197
|
+
return ensureBorderStyleFallback;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
Object.defineProperty(exports, 'inlineCssToJs', {
|
|
201
|
+
enumerable: true,
|
|
202
|
+
get: function () {
|
|
203
|
+
return inlineCssToJs;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
Object.defineProperty(exports, 'resolveConflictingStyles', {
|
|
207
|
+
enumerable: true,
|
|
208
|
+
get: function () {
|
|
209
|
+
return resolveConflictingStyles;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
//#region src/utils/styles.ts
|
|
2
|
+
const WHITE_SPACE_REGEX = /\s+/;
|
|
3
|
+
const BORDER_WIDTH_TO_STYLE = {
|
|
4
|
+
borderWidth: "borderStyle",
|
|
5
|
+
borderTopWidth: "borderTopStyle",
|
|
6
|
+
borderRightWidth: "borderRightStyle",
|
|
7
|
+
borderBottomWidth: "borderBottomStyle",
|
|
8
|
+
borderLeftWidth: "borderLeftStyle"
|
|
9
|
+
};
|
|
10
|
+
const inlineCssToJs = (inlineStyle, options = {}) => {
|
|
11
|
+
const styleObject = {};
|
|
12
|
+
if (!inlineStyle || inlineStyle === "" || typeof inlineStyle === "object") return styleObject;
|
|
13
|
+
inlineStyle.split(";").forEach((style) => {
|
|
14
|
+
if (style.trim()) {
|
|
15
|
+
const [key, value] = style.split(":");
|
|
16
|
+
const valueTrimmed = value?.trim();
|
|
17
|
+
if (!valueTrimmed) return;
|
|
18
|
+
const formattedKey = key.trim().replace(/-\w/g, (match) => match[1].toUpperCase());
|
|
19
|
+
styleObject[formattedKey] = options?.removeUnit ? valueTrimmed.replace(/px|%/g, "") : valueTrimmed;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return styleObject;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Expands CSS shorthand properties (margin, padding) into their longhand equivalents.
|
|
26
|
+
* This prevents shorthand properties from overriding specific longhand properties in email clients.
|
|
27
|
+
*
|
|
28
|
+
* @param styles - Style object that may contain shorthand properties
|
|
29
|
+
* @returns New style object with shorthand properties expanded to longhand
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* expandShorthandProperties({ margin: '0', paddingTop: '10px' })
|
|
33
|
+
* // Returns: { marginTop: '0', marginRight: '0', marginBottom: '0', marginLeft: '0', paddingTop: '10px' }
|
|
34
|
+
*/
|
|
35
|
+
function expandShorthandProperties(styles) {
|
|
36
|
+
if (!styles || typeof styles !== "object") return {};
|
|
37
|
+
const expanded = {};
|
|
38
|
+
for (const key in styles) {
|
|
39
|
+
const value = styles[key];
|
|
40
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
41
|
+
switch (key) {
|
|
42
|
+
case "margin": {
|
|
43
|
+
const values = parseShorthandValue(value);
|
|
44
|
+
expanded.marginTop = values.top;
|
|
45
|
+
expanded.marginRight = values.right;
|
|
46
|
+
expanded.marginBottom = values.bottom;
|
|
47
|
+
expanded.marginLeft = values.left;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "padding": {
|
|
51
|
+
const values = parseShorthandValue(value);
|
|
52
|
+
expanded.paddingTop = values.top;
|
|
53
|
+
expanded.paddingRight = values.right;
|
|
54
|
+
expanded.paddingBottom = values.bottom;
|
|
55
|
+
expanded.paddingLeft = values.left;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case "border": {
|
|
59
|
+
const values = convertBorderValue(value);
|
|
60
|
+
expanded.borderStyle = values.style;
|
|
61
|
+
expanded.borderWidth = values.width;
|
|
62
|
+
expanded.borderColor = values.color;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case "borderTopLeftRadius":
|
|
66
|
+
case "borderTopRightRadius":
|
|
67
|
+
case "borderBottomLeftRadius":
|
|
68
|
+
case "borderBottomRightRadius":
|
|
69
|
+
expanded[key] = value;
|
|
70
|
+
if (styles.borderTopLeftRadius && styles.borderTopRightRadius && styles.borderBottomLeftRadius && styles.borderBottomRightRadius) {
|
|
71
|
+
const values = [
|
|
72
|
+
styles.borderTopLeftRadius,
|
|
73
|
+
styles.borderTopRightRadius,
|
|
74
|
+
styles.borderBottomLeftRadius,
|
|
75
|
+
styles.borderBottomRightRadius
|
|
76
|
+
];
|
|
77
|
+
if (new Set(values).size === 1) expanded.borderRadius = values[0];
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
default: expanded[key] = value;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return expanded;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Parses CSS shorthand value (1-4 values) into individual side values.
|
|
87
|
+
* Follows CSS specification for shorthand property value parsing.
|
|
88
|
+
*
|
|
89
|
+
* @param value - Shorthand value string (e.g., '0', '10px 20px', '5px 10px 15px 20px')
|
|
90
|
+
* @returns Object with top, right, bottom, left values
|
|
91
|
+
*/
|
|
92
|
+
function parseShorthandValue(value) {
|
|
93
|
+
const stringValue = String(value).trim();
|
|
94
|
+
const parts = stringValue.split(WHITE_SPACE_REGEX);
|
|
95
|
+
const len = parts.length;
|
|
96
|
+
if (len === 1) return {
|
|
97
|
+
top: parts[0],
|
|
98
|
+
right: parts[0],
|
|
99
|
+
bottom: parts[0],
|
|
100
|
+
left: parts[0]
|
|
101
|
+
};
|
|
102
|
+
if (len === 2) return {
|
|
103
|
+
top: parts[0],
|
|
104
|
+
right: parts[1],
|
|
105
|
+
bottom: parts[0],
|
|
106
|
+
left: parts[1]
|
|
107
|
+
};
|
|
108
|
+
if (len === 3) return {
|
|
109
|
+
top: parts[0],
|
|
110
|
+
right: parts[1],
|
|
111
|
+
bottom: parts[2],
|
|
112
|
+
left: parts[1]
|
|
113
|
+
};
|
|
114
|
+
if (len === 4) return {
|
|
115
|
+
top: parts[0],
|
|
116
|
+
right: parts[1],
|
|
117
|
+
bottom: parts[2],
|
|
118
|
+
left: parts[3]
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
top: stringValue,
|
|
122
|
+
right: stringValue,
|
|
123
|
+
bottom: stringValue,
|
|
124
|
+
left: stringValue
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function convertBorderValue(value) {
|
|
128
|
+
const stringValue = String(value).trim();
|
|
129
|
+
const parts = stringValue.split(WHITE_SPACE_REGEX);
|
|
130
|
+
switch (parts.length) {
|
|
131
|
+
case 1: return {
|
|
132
|
+
style: "solid",
|
|
133
|
+
width: parts[0],
|
|
134
|
+
color: "black"
|
|
135
|
+
};
|
|
136
|
+
case 2: return {
|
|
137
|
+
style: parts[1],
|
|
138
|
+
width: parts[0],
|
|
139
|
+
color: "black"
|
|
140
|
+
};
|
|
141
|
+
case 3: return {
|
|
142
|
+
style: parts[1],
|
|
143
|
+
width: parts[0],
|
|
144
|
+
color: parts[2]
|
|
145
|
+
};
|
|
146
|
+
case 4: return {
|
|
147
|
+
style: parts[1],
|
|
148
|
+
width: parts[0],
|
|
149
|
+
color: parts[2]
|
|
150
|
+
};
|
|
151
|
+
default: return {
|
|
152
|
+
style: "solid",
|
|
153
|
+
width: stringValue,
|
|
154
|
+
color: "black"
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* When a border-width is present but border-style is missing, browsers default
|
|
160
|
+
* to `none` and the border is invisible. This adds `solid` as a sensible
|
|
161
|
+
* fallback so borders show up immediately after setting a width.
|
|
162
|
+
*/
|
|
163
|
+
function ensureBorderStyleFallback(styles) {
|
|
164
|
+
for (const [widthKey, styleKey] of Object.entries(BORDER_WIDTH_TO_STYLE)) {
|
|
165
|
+
const widthValue = styles[widthKey];
|
|
166
|
+
if (!widthValue || widthValue === "0" || widthValue === "0px") continue;
|
|
167
|
+
if (!styles[styleKey]) {
|
|
168
|
+
if (styleKey !== "borderStyle" && styles.borderStyle) continue;
|
|
169
|
+
styles[styleKey] = "solid";
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return styles;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Resolves conflicts between reset styles and inline styles by expanding
|
|
176
|
+
* shorthand properties (margin, padding) to longhand before merging.
|
|
177
|
+
* This prevents shorthand properties from overriding specific longhand properties.
|
|
178
|
+
*
|
|
179
|
+
* @param resetStyles - Base reset styles that may contain shorthand properties
|
|
180
|
+
* @param inlineStyles - Inline styles that should override reset styles
|
|
181
|
+
* @returns Merged styles with inline styles taking precedence
|
|
182
|
+
*/
|
|
183
|
+
function resolveConflictingStyles(resetStyles, inlineStyles) {
|
|
184
|
+
const expandedResetStyles = expandShorthandProperties(resetStyles);
|
|
185
|
+
const expandedInlineStyles = expandShorthandProperties(inlineStyles);
|
|
186
|
+
return {
|
|
187
|
+
...expandedResetStyles,
|
|
188
|
+
...expandedInlineStyles
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
export { inlineCssToJs as n, resolveConflictingStyles as r, ensureBorderStyleFallback as t };
|
|
194
|
+
//# sourceMappingURL=styles-_TMw3YxC.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles-_TMw3YxC.mjs","names":[],"sources":["../src/utils/styles.ts"],"sourcesContent":["import type { CssJs } from './types';\n\nconst WHITE_SPACE_REGEX = /\\s+/;\n\nconst BORDER_WIDTH_TO_STYLE: Record<string, string> = {\n borderWidth: 'borderStyle',\n borderTopWidth: 'borderTopStyle',\n borderRightWidth: 'borderRightStyle',\n borderBottomWidth: 'borderBottomStyle',\n borderLeftWidth: 'borderLeftStyle',\n};\n\nexport const jsToInlineCss = (styleObject: { [key: string]: any }) => {\n const parts: string[] = [];\n\n for (const key in styleObject) {\n const value = styleObject[key];\n if (value !== 0 && value !== undefined && value !== null && value !== '') {\n const KEBAB_CASE_REGEX = /[A-Z]/g;\n const formattedKey = key.replace(\n KEBAB_CASE_REGEX,\n (match) => `-${match.toLowerCase()}`,\n );\n parts.push(`${formattedKey}:${value}`);\n }\n }\n\n return parts.join(';') + (parts.length ? ';' : '');\n};\n\nexport const inlineCssToJs = (\n inlineStyle: string,\n options: { removeUnit?: boolean } = {},\n) => {\n const styleObject: { [key: string]: string } = {};\n\n if (!inlineStyle || inlineStyle === '' || typeof inlineStyle === 'object') {\n return styleObject;\n }\n\n inlineStyle.split(';').forEach((style: string) => {\n if (style.trim()) {\n const [key, value] = style.split(':');\n const valueTrimmed = value?.trim();\n\n if (!valueTrimmed) {\n return;\n }\n\n const formattedKey = key\n .trim()\n .replace(/-\\w/g, (match) => match[1].toUpperCase());\n\n const UNIT_REGEX = /px|%/g;\n const sanitizedValue = options?.removeUnit\n ? valueTrimmed.replace(UNIT_REGEX, '')\n : valueTrimmed;\n\n styleObject[formattedKey] = sanitizedValue;\n }\n });\n\n return styleObject;\n};\n\n/**\n * Expands CSS shorthand properties (margin, padding) into their longhand equivalents.\n * This prevents shorthand properties from overriding specific longhand properties in email clients.\n *\n * @param styles - Style object that may contain shorthand properties\n * @returns New style object with shorthand properties expanded to longhand\n *\n * @example\n * expandShorthandProperties({ margin: '0', paddingTop: '10px' })\n * // Returns: { marginTop: '0', marginRight: '0', marginBottom: '0', marginLeft: '0', paddingTop: '10px' }\n */\nexport function expandShorthandProperties(\n styles: Record<string, string>,\n): Record<string, string> {\n if (!styles || typeof styles !== 'object') {\n return {};\n }\n\n const expanded: Record<string, any> = {};\n\n for (const key in styles) {\n const value = styles[key];\n if (value === undefined || value === null || value === '') {\n continue;\n }\n\n switch (key) {\n case 'margin': {\n const values = parseShorthandValue(value);\n expanded.marginTop = values.top;\n expanded.marginRight = values.right;\n expanded.marginBottom = values.bottom;\n expanded.marginLeft = values.left;\n break;\n }\n case 'padding': {\n const values = parseShorthandValue(value);\n expanded.paddingTop = values.top;\n expanded.paddingRight = values.right;\n expanded.paddingBottom = values.bottom;\n expanded.paddingLeft = values.left;\n break;\n }\n case 'border': {\n const values = convertBorderValue(value);\n expanded.borderStyle = values.style;\n expanded.borderWidth = values.width;\n expanded.borderColor = values.color;\n break;\n }\n case 'borderTopLeftRadius':\n case 'borderTopRightRadius':\n case 'borderBottomLeftRadius':\n case 'borderBottomRightRadius': {\n // Always preserve the longhand property\n expanded[key] = value;\n\n // When all four corners are present and identical, also add the shorthand\n if (\n styles.borderTopLeftRadius &&\n styles.borderTopRightRadius &&\n styles.borderBottomLeftRadius &&\n styles.borderBottomRightRadius\n ) {\n const values = [\n styles.borderTopLeftRadius,\n styles.borderTopRightRadius,\n styles.borderBottomLeftRadius,\n styles.borderBottomRightRadius,\n ];\n\n if (new Set(values).size === 1) {\n expanded.borderRadius = values[0];\n }\n }\n\n break;\n }\n\n default: {\n // Keep all other properties as-is\n expanded[key] = value;\n }\n }\n }\n\n return expanded;\n}\n\n/**\n * Parses CSS shorthand value (1-4 values) into individual side values.\n * Follows CSS specification for shorthand property value parsing.\n *\n * @param value - Shorthand value string (e.g., '0', '10px 20px', '5px 10px 15px 20px')\n * @returns Object with top, right, bottom, left values\n */\nfunction parseShorthandValue(value: string | number): {\n top: string;\n right: string;\n bottom: string;\n left: string;\n} {\n const stringValue = String(value).trim();\n const parts = stringValue.split(WHITE_SPACE_REGEX);\n const len = parts.length;\n\n if (len === 1) {\n return { top: parts[0], right: parts[0], bottom: parts[0], left: parts[0] };\n }\n if (len === 2) {\n return { top: parts[0], right: parts[1], bottom: parts[0], left: parts[1] };\n }\n if (len === 3) {\n return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[1] };\n }\n if (len === 4) {\n return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };\n }\n\n return {\n top: stringValue,\n right: stringValue,\n bottom: stringValue,\n left: stringValue,\n };\n}\n\nfunction convertBorderValue(value: string | number): {\n style: string;\n width: string;\n color: string;\n} {\n const stringValue = String(value).trim();\n const parts = stringValue.split(WHITE_SPACE_REGEX);\n\n switch (parts.length) {\n case 1:\n // border: 1px → all sides\n return {\n style: 'solid',\n width: parts[0],\n color: 'black',\n };\n case 2:\n // border: 1px solid → top/bottom, left/right\n return {\n style: parts[1],\n width: parts[0],\n color: 'black',\n };\n case 3:\n // border: 1px solid #000 → top, left/right, bottom\n return {\n style: parts[1],\n width: parts[0],\n color: parts[2],\n };\n case 4:\n // border: 1px solid #000 #fff → top, right, bottom, left\n return {\n style: parts[1],\n width: parts[0],\n color: parts[2],\n };\n default:\n // Invalid format, return the original value for all sides\n return {\n style: 'solid',\n width: stringValue,\n color: 'black',\n };\n }\n}\n\n/**\n * When a border-width is present but border-style is missing, browsers default\n * to `none` and the border is invisible. This adds `solid` as a sensible\n * fallback so borders show up immediately after setting a width.\n */\nexport function ensureBorderStyleFallback(\n styles: Record<string, string | number>,\n): Record<string, string | number> {\n for (const [widthKey, styleKey] of Object.entries(BORDER_WIDTH_TO_STYLE)) {\n const widthValue = styles[widthKey];\n if (!widthValue || widthValue === '0' || widthValue === '0px') {\n continue;\n }\n if (!styles[styleKey]) {\n // Keep shorthand borderStyle authoritative for each side when present.\n if (styleKey !== 'borderStyle' && styles.borderStyle) {\n continue;\n }\n styles[styleKey] = 'solid';\n }\n }\n return styles;\n}\n\n/**\n * Resolves conflicts between reset styles and inline styles by expanding\n * shorthand properties (margin, padding) to longhand before merging.\n * This prevents shorthand properties from overriding specific longhand properties.\n *\n * @param resetStyles - Base reset styles that may contain shorthand properties\n * @param inlineStyles - Inline styles that should override reset styles\n * @returns Merged styles with inline styles taking precedence\n */\nexport function resolveConflictingStyles(\n resetStyles: CssJs['reset'],\n inlineStyles: Record<string, string>,\n) {\n const expandedResetStyles = expandShorthandProperties(\n resetStyles as Record<string, string>,\n );\n const expandedInlineStyles = expandShorthandProperties(inlineStyles);\n\n return {\n ...expandedResetStyles,\n ...expandedInlineStyles,\n };\n}\n"],"mappings":"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"}
|