@kontakto/email-template-editor 2.1.0 → 2.2.1
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/index.cjs +333 -111
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +336 -114
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -166,6 +166,20 @@ function renderMarkdownString(str) {
|
|
|
166
166
|
}
|
|
167
167
|
return sanitizer(html2);
|
|
168
168
|
}
|
|
169
|
+
function renderInlineMarkdownString(str) {
|
|
170
|
+
const html2 = marked.marked.parseInline(str, {
|
|
171
|
+
async: false,
|
|
172
|
+
breaks: true,
|
|
173
|
+
gfm: true,
|
|
174
|
+
pedantic: false,
|
|
175
|
+
silent: false,
|
|
176
|
+
renderer: new CustomRenderer()
|
|
177
|
+
});
|
|
178
|
+
if (typeof html2 !== "string") {
|
|
179
|
+
throw new Error("marked.parseInline did not return a string");
|
|
180
|
+
}
|
|
181
|
+
return sanitizer(html2);
|
|
182
|
+
}
|
|
169
183
|
function EmailMarkdown(_a) {
|
|
170
184
|
var _b = _a, { markdown } = _b, props = __objRest(_b, ["markdown"]);
|
|
171
185
|
const data = React58.useMemo(() => renderMarkdownString(markdown), [markdown]);
|
|
@@ -691,7 +705,8 @@ function getFontFamily3(fontFamily) {
|
|
|
691
705
|
var HeadingPropsSchema = zod.z.object({
|
|
692
706
|
props: zod.z.object({
|
|
693
707
|
text: zod.z.string().optional().nullable(),
|
|
694
|
-
level: zod.z.enum(["h1", "h2", "h3"]).optional().nullable()
|
|
708
|
+
level: zod.z.enum(["h1", "h2", "h3"]).optional().nullable(),
|
|
709
|
+
markdown: zod.z.boolean().optional().nullable()
|
|
695
710
|
}).optional().nullable(),
|
|
696
711
|
style: zod.z.object({
|
|
697
712
|
color: COLOR_SCHEMA6,
|
|
@@ -710,28 +725,31 @@ var HeadingPropsDefaults = {
|
|
|
710
725
|
text: ""
|
|
711
726
|
};
|
|
712
727
|
function Heading({ props, style }) {
|
|
713
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
728
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
714
729
|
const level = (_a = props == null ? void 0 : props.level) != null ? _a : HeadingPropsDefaults.level;
|
|
715
730
|
const text = (_b = props == null ? void 0 : props.text) != null ? _b : HeadingPropsDefaults.text;
|
|
731
|
+
const isMarkdown = (_c = props == null ? void 0 : props.markdown) != null ? _c : false;
|
|
716
732
|
const hStyle = {
|
|
717
|
-
color: (
|
|
718
|
-
backgroundColor: (
|
|
719
|
-
fontWeight: (
|
|
720
|
-
lineHeight: (
|
|
733
|
+
color: (_d = style == null ? void 0 : style.color) != null ? _d : void 0,
|
|
734
|
+
backgroundColor: (_e = style == null ? void 0 : style.backgroundColor) != null ? _e : void 0,
|
|
735
|
+
fontWeight: (_f = style == null ? void 0 : style.fontWeight) != null ? _f : "bold",
|
|
736
|
+
lineHeight: (_g = style == null ? void 0 : style.lineHeight) != null ? _g : void 0,
|
|
721
737
|
letterSpacing: (style == null ? void 0 : style.letterSpacing) != null ? `${style.letterSpacing}px` : void 0,
|
|
722
|
-
textAlign: (
|
|
738
|
+
textAlign: (_h = style == null ? void 0 : style.textAlign) != null ? _h : void 0,
|
|
723
739
|
margin: 0,
|
|
724
740
|
fontFamily: getFontFamily3(style == null ? void 0 : style.fontFamily),
|
|
725
741
|
fontSize: getFontSize(level),
|
|
726
742
|
padding: getPadding7(style == null ? void 0 : style.padding)
|
|
727
743
|
};
|
|
744
|
+
const html2 = React58.useMemo(() => isMarkdown ? renderInlineMarkdownString(text) : null, [isMarkdown, text]);
|
|
745
|
+
const renderProps = isMarkdown ? { style: hStyle, dangerouslySetInnerHTML: { __html: html2 != null ? html2 : "" } } : { style: hStyle, children: text };
|
|
728
746
|
switch (level) {
|
|
729
747
|
case "h1":
|
|
730
|
-
return /* @__PURE__ */ React58__default.default.createElement("h1", {
|
|
748
|
+
return /* @__PURE__ */ React58__default.default.createElement("h1", __spreadValues({}, renderProps));
|
|
731
749
|
case "h2":
|
|
732
|
-
return /* @__PURE__ */ React58__default.default.createElement("h2", {
|
|
750
|
+
return /* @__PURE__ */ React58__default.default.createElement("h2", __spreadValues({}, renderProps));
|
|
733
751
|
case "h3":
|
|
734
|
-
return /* @__PURE__ */ React58__default.default.createElement("h3", {
|
|
752
|
+
return /* @__PURE__ */ React58__default.default.createElement("h3", __spreadValues({}, renderProps));
|
|
735
753
|
}
|
|
736
754
|
}
|
|
737
755
|
function getFontSize(level) {
|
|
@@ -2504,59 +2522,46 @@ function FontWeightInput({ label, defaultValue, onChange }) {
|
|
|
2504
2522
|
);
|
|
2505
2523
|
}
|
|
2506
2524
|
function LetterSpacingInput({ label, defaultValue, onChange }) {
|
|
2507
|
-
const
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
onChange(isNaN(value) ? null : value);
|
|
2525
|
+
const [value, setValue] = React58.useState(defaultValue != null ? defaultValue : 0);
|
|
2526
|
+
React58.useEffect(() => {
|
|
2527
|
+
setValue(defaultValue != null ? defaultValue : 0);
|
|
2528
|
+
}, [defaultValue]);
|
|
2529
|
+
const handleChange = (v) => {
|
|
2530
|
+
setValue(v);
|
|
2531
|
+
onChange(v === 0 ? null : v);
|
|
2515
2532
|
};
|
|
2516
|
-
return /* @__PURE__ */ React58__default.default.createElement(material.Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58__default.default.createElement(
|
|
2517
|
-
|
|
2533
|
+
return /* @__PURE__ */ React58__default.default.createElement(material.Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58__default.default.createElement(material.InputLabel, { shrink: true }, label), /* @__PURE__ */ React58__default.default.createElement(
|
|
2534
|
+
RawSliderInput,
|
|
2518
2535
|
{
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
type: "number",
|
|
2527
|
-
inputProps: { step: 0.5 },
|
|
2528
|
-
InputProps: {
|
|
2529
|
-
startAdornment: /* @__PURE__ */ React58__default.default.createElement(material.InputAdornment, { position: "start" }, /* @__PURE__ */ React58__default.default.createElement(iconsMaterial.SpaceBarOutlined, { sx: { fontSize: 16 } })),
|
|
2530
|
-
endAdornment: /* @__PURE__ */ React58__default.default.createElement(material.Typography, { variant: "body2", color: "text.secondary" }, "px")
|
|
2531
|
-
}
|
|
2536
|
+
iconLabel: /* @__PURE__ */ React58__default.default.createElement(iconsMaterial.SpaceBarOutlined, { sx: { fontSize: 16 } }),
|
|
2537
|
+
value,
|
|
2538
|
+
setValue: handleChange,
|
|
2539
|
+
units: "px",
|
|
2540
|
+
step: 0.1,
|
|
2541
|
+
min: 0,
|
|
2542
|
+
max: 2
|
|
2532
2543
|
}
|
|
2533
2544
|
));
|
|
2534
2545
|
}
|
|
2535
2546
|
function LineHeightInput({ label, defaultValue, onChange }) {
|
|
2536
|
-
const
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
onChange(isNaN(value) ? null : value);
|
|
2547
|
+
const [value, setValue] = React58.useState(defaultValue != null ? defaultValue : 0);
|
|
2548
|
+
React58.useEffect(() => {
|
|
2549
|
+
setValue(defaultValue != null ? defaultValue : 0);
|
|
2550
|
+
}, [defaultValue]);
|
|
2551
|
+
const handleChange = (v) => {
|
|
2552
|
+
setValue(v);
|
|
2553
|
+
onChange(v === 0 ? null : v);
|
|
2544
2554
|
};
|
|
2545
|
-
return /* @__PURE__ */ React58__default.default.createElement(material.Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58__default.default.createElement(
|
|
2546
|
-
|
|
2555
|
+
return /* @__PURE__ */ React58__default.default.createElement(material.Stack, { spacing: 1, alignItems: "flex-start" }, /* @__PURE__ */ React58__default.default.createElement(material.InputLabel, { shrink: true }, label), /* @__PURE__ */ React58__default.default.createElement(
|
|
2556
|
+
RawSliderInput,
|
|
2547
2557
|
{
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
type: "number",
|
|
2556
|
-
inputProps: { step: 0.1 },
|
|
2557
|
-
InputProps: {
|
|
2558
|
-
startAdornment: /* @__PURE__ */ React58__default.default.createElement(material.InputAdornment, { position: "start" }, /* @__PURE__ */ React58__default.default.createElement(iconsMaterial.FormatLineSpacingOutlined, { sx: { fontSize: 16 } }))
|
|
2559
|
-
}
|
|
2558
|
+
iconLabel: /* @__PURE__ */ React58__default.default.createElement(iconsMaterial.FormatLineSpacingOutlined, { sx: { fontSize: 16 } }),
|
|
2559
|
+
value,
|
|
2560
|
+
setValue: handleChange,
|
|
2561
|
+
units: "",
|
|
2562
|
+
step: 0.1,
|
|
2563
|
+
min: 0,
|
|
2564
|
+
max: 2
|
|
2560
2565
|
}
|
|
2561
2566
|
));
|
|
2562
2567
|
}
|
|
@@ -6229,6 +6234,174 @@ function ButtonEditor({ style, props }) {
|
|
|
6229
6234
|
}
|
|
6230
6235
|
return /* @__PURE__ */ React58__default.default.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React58__default.default.createElement("span", { style: linkStyle }, /* @__PURE__ */ React58__default.default.createElement("span", null, text)));
|
|
6231
6236
|
}
|
|
6237
|
+
function useMarkdownToolbar({ text, isSelected, commitText, trackSelection }) {
|
|
6238
|
+
const textareaRef = React58.useRef(null);
|
|
6239
|
+
const [selection, setSelection] = React58.useState({ start: 0, end: 0 });
|
|
6240
|
+
const [linkPrompt, setLinkPrompt] = React58.useState(false);
|
|
6241
|
+
const pendingSelectionRef = React58.useRef(null);
|
|
6242
|
+
const textRef = React58.useRef(text);
|
|
6243
|
+
React58.useEffect(() => {
|
|
6244
|
+
textRef.current = text;
|
|
6245
|
+
}, [text]);
|
|
6246
|
+
const syncSelection = React58.useCallback(
|
|
6247
|
+
(start, end) => {
|
|
6248
|
+
const next = { start, end };
|
|
6249
|
+
setSelection(next);
|
|
6250
|
+
trackSelection == null ? void 0 : trackSelection(next);
|
|
6251
|
+
},
|
|
6252
|
+
[trackSelection]
|
|
6253
|
+
);
|
|
6254
|
+
const trackFocus = React58.useCallback(
|
|
6255
|
+
(e) => {
|
|
6256
|
+
var _a, _b;
|
|
6257
|
+
const el = e.currentTarget;
|
|
6258
|
+
const start = (_a = el.selectionStart) != null ? _a : el.value.length;
|
|
6259
|
+
const end = (_b = el.selectionEnd) != null ? _b : el.value.length;
|
|
6260
|
+
syncSelection(start, end);
|
|
6261
|
+
},
|
|
6262
|
+
[syncSelection]
|
|
6263
|
+
);
|
|
6264
|
+
React58.useEffect(() => {
|
|
6265
|
+
const target = pendingSelectionRef.current;
|
|
6266
|
+
if (!target) return;
|
|
6267
|
+
const ta = textareaRef.current;
|
|
6268
|
+
if (!ta) return;
|
|
6269
|
+
ta.focus();
|
|
6270
|
+
ta.setSelectionRange(target.start, target.end);
|
|
6271
|
+
syncSelection(target.start, target.end);
|
|
6272
|
+
pendingSelectionRef.current = null;
|
|
6273
|
+
}, [text, syncSelection]);
|
|
6274
|
+
React58.useEffect(() => {
|
|
6275
|
+
if (!isSelected || selection.start === selection.end) {
|
|
6276
|
+
setLinkPrompt(false);
|
|
6277
|
+
}
|
|
6278
|
+
}, [isSelected, selection.start, selection.end]);
|
|
6279
|
+
const wrapSelection = (prefix, suffix) => {
|
|
6280
|
+
var _a, _b;
|
|
6281
|
+
const ta = textareaRef.current;
|
|
6282
|
+
if (!ta) return;
|
|
6283
|
+
const start = (_a = ta.selectionStart) != null ? _a : selection.start;
|
|
6284
|
+
const end = (_b = ta.selectionEnd) != null ? _b : selection.end;
|
|
6285
|
+
if (start === end) return;
|
|
6286
|
+
const current = textRef.current;
|
|
6287
|
+
const selected = current.slice(start, end);
|
|
6288
|
+
const before = current.slice(0, start);
|
|
6289
|
+
const after = current.slice(end);
|
|
6290
|
+
const wrapped = `${prefix}${selected}${suffix}`;
|
|
6291
|
+
const newText = `${before}${wrapped}${after}`;
|
|
6292
|
+
const newStart = start + prefix.length;
|
|
6293
|
+
const newEnd = newStart + selected.length;
|
|
6294
|
+
pendingSelectionRef.current = { start: newStart, end: newEnd };
|
|
6295
|
+
commitText(newText);
|
|
6296
|
+
};
|
|
6297
|
+
const handleBold = () => wrapSelection("**", "**");
|
|
6298
|
+
const handleItalic = () => wrapSelection("*", "*");
|
|
6299
|
+
const handleLinkRequest = () => {
|
|
6300
|
+
if (selection.start === selection.end) return;
|
|
6301
|
+
setLinkPrompt(true);
|
|
6302
|
+
};
|
|
6303
|
+
const handleLinkSubmit = (url) => {
|
|
6304
|
+
const start = selection.start;
|
|
6305
|
+
const end = selection.end;
|
|
6306
|
+
if (start === end) {
|
|
6307
|
+
setLinkPrompt(false);
|
|
6308
|
+
return;
|
|
6309
|
+
}
|
|
6310
|
+
const current = textRef.current;
|
|
6311
|
+
const selected = current.slice(start, end);
|
|
6312
|
+
const before = current.slice(0, start);
|
|
6313
|
+
const after = current.slice(end);
|
|
6314
|
+
const wrapped = `[${selected}](${url})`;
|
|
6315
|
+
const newText = `${before}${wrapped}${after}`;
|
|
6316
|
+
const newStart = start + wrapped.length;
|
|
6317
|
+
pendingSelectionRef.current = { start: newStart, end: newStart };
|
|
6318
|
+
commitText(newText);
|
|
6319
|
+
setLinkPrompt(false);
|
|
6320
|
+
};
|
|
6321
|
+
const handleLinkCancel = () => {
|
|
6322
|
+
var _a;
|
|
6323
|
+
setLinkPrompt(false);
|
|
6324
|
+
(_a = textareaRef.current) == null ? void 0 : _a.focus();
|
|
6325
|
+
};
|
|
6326
|
+
const handleKeyDown = (e) => {
|
|
6327
|
+
if (!(e.metaKey || e.ctrlKey)) return;
|
|
6328
|
+
const key = e.key.toLowerCase();
|
|
6329
|
+
if (key === "b") {
|
|
6330
|
+
e.preventDefault();
|
|
6331
|
+
handleBold();
|
|
6332
|
+
} else if (key === "i") {
|
|
6333
|
+
e.preventDefault();
|
|
6334
|
+
handleItalic();
|
|
6335
|
+
} else if (key === "k") {
|
|
6336
|
+
e.preventDefault();
|
|
6337
|
+
handleLinkRequest();
|
|
6338
|
+
}
|
|
6339
|
+
};
|
|
6340
|
+
const toolbarVisible = isSelected && (selection.start !== selection.end || linkPrompt);
|
|
6341
|
+
return {
|
|
6342
|
+
textareaRef,
|
|
6343
|
+
selection,
|
|
6344
|
+
trackFocus,
|
|
6345
|
+
handleKeyDown,
|
|
6346
|
+
toolbarProps: {
|
|
6347
|
+
visible: toolbarVisible,
|
|
6348
|
+
linkPrompt,
|
|
6349
|
+
onBold: handleBold,
|
|
6350
|
+
onItalic: handleItalic,
|
|
6351
|
+
onLinkRequest: handleLinkRequest,
|
|
6352
|
+
onLinkSubmit: handleLinkSubmit,
|
|
6353
|
+
onLinkCancel: handleLinkCancel
|
|
6354
|
+
}
|
|
6355
|
+
};
|
|
6356
|
+
}
|
|
6357
|
+
function InlineFormattingToolbar({
|
|
6358
|
+
anchorEl,
|
|
6359
|
+
visible,
|
|
6360
|
+
linkPrompt,
|
|
6361
|
+
onBold,
|
|
6362
|
+
onItalic,
|
|
6363
|
+
onLinkRequest,
|
|
6364
|
+
onLinkSubmit,
|
|
6365
|
+
onLinkCancel
|
|
6366
|
+
}) {
|
|
6367
|
+
const [url, setUrl] = React58.useState("");
|
|
6368
|
+
const inputRef = React58.useRef(null);
|
|
6369
|
+
React58.useEffect(() => {
|
|
6370
|
+
if (linkPrompt) {
|
|
6371
|
+
setUrl("");
|
|
6372
|
+
setTimeout(() => {
|
|
6373
|
+
var _a;
|
|
6374
|
+
return (_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
6375
|
+
}, 0);
|
|
6376
|
+
}
|
|
6377
|
+
}, [linkPrompt]);
|
|
6378
|
+
const preventBlur = (e) => e.preventDefault();
|
|
6379
|
+
return /* @__PURE__ */ React58__default.default.createElement(material.Popper, { open: visible, anchorEl, placement: "top-start", style: { zIndex: 1300 } }, /* @__PURE__ */ React58__default.default.createElement(material.Paper, { elevation: 4, sx: { px: 0.5, py: 0.25, mb: 0.5 }, onMouseDown: preventBlur }, linkPrompt ? /* @__PURE__ */ React58__default.default.createElement(material.Stack, { direction: "row", alignItems: "center", spacing: 0.5, sx: { px: 0.5 } }, /* @__PURE__ */ React58__default.default.createElement(
|
|
6380
|
+
material.TextField,
|
|
6381
|
+
{
|
|
6382
|
+
inputRef,
|
|
6383
|
+
value: url,
|
|
6384
|
+
onChange: (e) => setUrl(e.target.value),
|
|
6385
|
+
placeholder: "https://example.com",
|
|
6386
|
+
variant: "standard",
|
|
6387
|
+
size: "small",
|
|
6388
|
+
onKeyDown: (e) => {
|
|
6389
|
+
if (e.key === "Enter") {
|
|
6390
|
+
e.preventDefault();
|
|
6391
|
+
const trimmed = url.trim();
|
|
6392
|
+
if (trimmed) onLinkSubmit(trimmed);
|
|
6393
|
+
else onLinkCancel();
|
|
6394
|
+
} else if (e.key === "Escape") {
|
|
6395
|
+
e.preventDefault();
|
|
6396
|
+
onLinkCancel();
|
|
6397
|
+
}
|
|
6398
|
+
},
|
|
6399
|
+
sx: { width: 220 }
|
|
6400
|
+
}
|
|
6401
|
+
)) : /* @__PURE__ */ React58__default.default.createElement(material.Stack, { direction: "row", spacing: 0.25 }, /* @__PURE__ */ React58__default.default.createElement(material.IconButton, { size: "small", onClick: onBold, title: "Bold (Cmd+B)", "aria-label": "Bold" }, /* @__PURE__ */ React58__default.default.createElement(iconsMaterial.FormatBoldOutlined, { fontSize: "small" })), /* @__PURE__ */ React58__default.default.createElement(material.IconButton, { size: "small", onClick: onItalic, title: "Italic (Cmd+I)", "aria-label": "Italic" }, /* @__PURE__ */ React58__default.default.createElement(iconsMaterial.FormatItalicOutlined, { fontSize: "small" })), /* @__PURE__ */ React58__default.default.createElement(material.IconButton, { size: "small", onClick: onLinkRequest, title: "Link (Cmd+K)", "aria-label": "Link" }, /* @__PURE__ */ React58__default.default.createElement(iconsMaterial.LinkOutlined, { fontSize: "small" })))));
|
|
6402
|
+
}
|
|
6403
|
+
|
|
6404
|
+
// src/editor/blocks/heading/heading-editor.tsx
|
|
6232
6405
|
function getFontFamily9(fontFamily) {
|
|
6233
6406
|
switch (fontFamily) {
|
|
6234
6407
|
case "MODERN_SANS":
|
|
@@ -6291,7 +6464,7 @@ function getFontSize2(level) {
|
|
|
6291
6464
|
}
|
|
6292
6465
|
}
|
|
6293
6466
|
function HeadingEditor({ style, props }) {
|
|
6294
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
6467
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
6295
6468
|
const blockId = useCurrentBlockId();
|
|
6296
6469
|
const selectedBlockId = useSelectedBlockId();
|
|
6297
6470
|
const document2 = useDocument();
|
|
@@ -6299,6 +6472,7 @@ function HeadingEditor({ style, props }) {
|
|
|
6299
6472
|
const level = (_a = props == null ? void 0 : props.level) != null ? _a : HeadingPropsDefaults.level;
|
|
6300
6473
|
const textContent = (_b = props == null ? void 0 : props.text) != null ? _b : HeadingPropsDefaults.text;
|
|
6301
6474
|
const [localText, setLocalText] = React58.useState(textContent);
|
|
6475
|
+
const isMarkdown = (_c = props == null ? void 0 : props.markdown) != null ? _c : false;
|
|
6302
6476
|
const rootBlock = document2.root;
|
|
6303
6477
|
const rootFontFamily = rootBlock && rootBlock.type === "EmailLayout" ? getFontFamily9(rootBlock.data.fontFamily) : '"Helvetica Neue", Arial, sans-serif';
|
|
6304
6478
|
React58.useEffect(() => {
|
|
@@ -6306,12 +6480,12 @@ function HeadingEditor({ style, props }) {
|
|
|
6306
6480
|
}, [textContent]);
|
|
6307
6481
|
const fontFamily = getFontFamily9(style == null ? void 0 : style.fontFamily) || rootFontFamily;
|
|
6308
6482
|
const hStyle = {
|
|
6309
|
-
color: (
|
|
6310
|
-
backgroundColor: (
|
|
6311
|
-
fontWeight: (
|
|
6312
|
-
lineHeight: (
|
|
6483
|
+
color: (_d = style == null ? void 0 : style.color) != null ? _d : void 0,
|
|
6484
|
+
backgroundColor: (_e = style == null ? void 0 : style.backgroundColor) != null ? _e : void 0,
|
|
6485
|
+
fontWeight: (_f = style == null ? void 0 : style.fontWeight) != null ? _f : "bold",
|
|
6486
|
+
lineHeight: (_g = style == null ? void 0 : style.lineHeight) != null ? _g : void 0,
|
|
6313
6487
|
letterSpacing: (style == null ? void 0 : style.letterSpacing) != null ? `${style.letterSpacing}px` : void 0,
|
|
6314
|
-
textAlign: (
|
|
6488
|
+
textAlign: (_h = style == null ? void 0 : style.textAlign) != null ? _h : void 0,
|
|
6315
6489
|
margin: 0,
|
|
6316
6490
|
fontFamily,
|
|
6317
6491
|
fontSize: getFontSize2(level),
|
|
@@ -6325,69 +6499,92 @@ function HeadingEditor({ style, props }) {
|
|
|
6325
6499
|
resize: "none",
|
|
6326
6500
|
backgroundColor: "transparent",
|
|
6327
6501
|
overflow: "hidden",
|
|
6328
|
-
lineHeight: (
|
|
6502
|
+
lineHeight: (_i = hStyle.lineHeight) != null ? _i : "inherit",
|
|
6329
6503
|
margin: 0,
|
|
6330
6504
|
display: "block",
|
|
6331
6505
|
width: "100%"
|
|
6332
6506
|
});
|
|
6333
|
-
const
|
|
6334
|
-
const newText = e.target.value;
|
|
6507
|
+
const commitText = (newText, opts) => {
|
|
6335
6508
|
setLocalText(newText);
|
|
6336
6509
|
setDocument({
|
|
6337
6510
|
[blockId]: {
|
|
6338
6511
|
type: "Heading",
|
|
6339
6512
|
data: {
|
|
6340
6513
|
style,
|
|
6341
|
-
props: __spreadProps(__spreadValues({}, props), {
|
|
6514
|
+
props: __spreadValues(__spreadProps(__spreadValues({}, props), {
|
|
6342
6515
|
text: newText
|
|
6343
|
-
})
|
|
6516
|
+
}), (opts == null ? void 0 : opts.enableMarkdown) ? { markdown: true } : {})
|
|
6344
6517
|
}
|
|
6345
6518
|
}
|
|
6346
6519
|
});
|
|
6347
6520
|
};
|
|
6348
|
-
const
|
|
6349
|
-
|
|
6350
|
-
element.style.height = "auto";
|
|
6351
|
-
element.style.height = `${element.scrollHeight}px`;
|
|
6352
|
-
}
|
|
6521
|
+
const handleTextChange = (e) => {
|
|
6522
|
+
commitText(e.target.value);
|
|
6353
6523
|
};
|
|
6354
|
-
const
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6524
|
+
const displayRef = React58.useRef(null);
|
|
6525
|
+
const lastDisplayHeightRef = React58.useRef(0);
|
|
6526
|
+
React58.useLayoutEffect(() => {
|
|
6527
|
+
if (!isSelected && displayRef.current) {
|
|
6528
|
+
const h = displayRef.current.offsetHeight;
|
|
6529
|
+
if (h > 0) lastDisplayHeightRef.current = h;
|
|
6530
|
+
}
|
|
6531
|
+
}, [isSelected, textContent, isMarkdown, level]);
|
|
6532
|
+
const adjustTextareaHeight = (element) => {
|
|
6533
|
+
if (!element) return;
|
|
6534
|
+
element.style.height = "auto";
|
|
6535
|
+
const scrollH = element.scrollHeight;
|
|
6536
|
+
const floor = lastDisplayHeightRef.current;
|
|
6537
|
+
element.style.height = `${Math.max(scrollH, floor)}px`;
|
|
6363
6538
|
};
|
|
6539
|
+
const { textareaRef, trackFocus, handleKeyDown, toolbarProps } = useMarkdownToolbar({
|
|
6540
|
+
text: localText,
|
|
6541
|
+
isSelected,
|
|
6542
|
+
commitText: (newText) => commitText(newText, { enableMarkdown: true }),
|
|
6543
|
+
trackSelection: (sel) => {
|
|
6544
|
+
setLastFocusedEditable({
|
|
6545
|
+
blockId,
|
|
6546
|
+
field: "text",
|
|
6547
|
+
selectionStart: sel.start,
|
|
6548
|
+
selectionEnd: sel.end
|
|
6549
|
+
});
|
|
6550
|
+
}
|
|
6551
|
+
});
|
|
6552
|
+
React58.useLayoutEffect(() => {
|
|
6553
|
+
if (textareaRef.current) adjustTextareaHeight(textareaRef.current);
|
|
6554
|
+
}, [localText, isSelected]);
|
|
6364
6555
|
if (isSelected) {
|
|
6365
|
-
return /* @__PURE__ */ React58__default.default.createElement(
|
|
6556
|
+
return /* @__PURE__ */ React58__default.default.createElement(React58__default.default.Fragment, null, /* @__PURE__ */ React58__default.default.createElement(
|
|
6366
6557
|
"textarea",
|
|
6367
6558
|
{
|
|
6559
|
+
ref: textareaRef,
|
|
6368
6560
|
value: localText,
|
|
6369
6561
|
onChange: handleTextChange,
|
|
6370
6562
|
onFocus: trackFocus,
|
|
6371
6563
|
onSelect: trackFocus,
|
|
6372
6564
|
onKeyUp: trackFocus,
|
|
6565
|
+
onKeyDown: handleKeyDown,
|
|
6373
6566
|
onClick: (e) => {
|
|
6374
6567
|
e.stopPropagation();
|
|
6375
6568
|
trackFocus(e);
|
|
6376
6569
|
},
|
|
6377
6570
|
style: textareaStyle,
|
|
6378
6571
|
rows: 1,
|
|
6379
|
-
onInput: (e) => adjustTextareaHeight(e.target)
|
|
6380
|
-
ref: (el) => el && adjustTextareaHeight(el)
|
|
6572
|
+
onInput: (e) => adjustTextareaHeight(e.target)
|
|
6381
6573
|
}
|
|
6382
|
-
);
|
|
6574
|
+
), /* @__PURE__ */ React58__default.default.createElement(InlineFormattingToolbar, __spreadValues({ anchorEl: textareaRef.current }, toolbarProps)));
|
|
6383
6575
|
}
|
|
6576
|
+
const headingProps = isMarkdown ? {
|
|
6577
|
+
ref: displayRef,
|
|
6578
|
+
style: hStyle,
|
|
6579
|
+
dangerouslySetInnerHTML: { __html: renderInlineMarkdownString(textContent) }
|
|
6580
|
+
} : { ref: displayRef, style: hStyle, children: textContent };
|
|
6384
6581
|
switch (level) {
|
|
6385
6582
|
case "h1":
|
|
6386
|
-
return /* @__PURE__ */ React58__default.default.createElement("h1", {
|
|
6583
|
+
return /* @__PURE__ */ React58__default.default.createElement("h1", __spreadValues({}, headingProps));
|
|
6387
6584
|
case "h2":
|
|
6388
|
-
return /* @__PURE__ */ React58__default.default.createElement("h2", {
|
|
6585
|
+
return /* @__PURE__ */ React58__default.default.createElement("h2", __spreadValues({}, headingProps));
|
|
6389
6586
|
case "h3":
|
|
6390
|
-
return /* @__PURE__ */ React58__default.default.createElement("h3", {
|
|
6587
|
+
return /* @__PURE__ */ React58__default.default.createElement("h3", __spreadValues({}, headingProps));
|
|
6391
6588
|
}
|
|
6392
6589
|
}
|
|
6393
6590
|
function HtmlEditor({ style, props }) {
|
|
@@ -6795,61 +6992,86 @@ function TextEditor({ style, props }) {
|
|
|
6795
6992
|
fontWeight: wStyle.fontWeight,
|
|
6796
6993
|
textAlign: wStyle.textAlign
|
|
6797
6994
|
});
|
|
6798
|
-
const
|
|
6799
|
-
const newText = e.target.value;
|
|
6995
|
+
const commitText = (newText, opts) => {
|
|
6800
6996
|
setLocalText(newText);
|
|
6801
6997
|
setDocument({
|
|
6802
6998
|
[blockId]: {
|
|
6803
6999
|
type: "Text",
|
|
6804
7000
|
data: {
|
|
6805
7001
|
style,
|
|
6806
|
-
props: __spreadProps(__spreadValues({}, props), {
|
|
7002
|
+
props: __spreadValues(__spreadProps(__spreadValues({}, props), {
|
|
6807
7003
|
text: newText
|
|
6808
|
-
})
|
|
7004
|
+
}), (opts == null ? void 0 : opts.enableMarkdown) ? { markdown: true } : {})
|
|
6809
7005
|
}
|
|
6810
7006
|
}
|
|
6811
7007
|
});
|
|
6812
7008
|
};
|
|
6813
|
-
const
|
|
6814
|
-
|
|
6815
|
-
element.style.height = "auto";
|
|
6816
|
-
element.style.height = `${element.scrollHeight}px`;
|
|
6817
|
-
}
|
|
7009
|
+
const handleTextChange = (e) => {
|
|
7010
|
+
commitText(e.target.value);
|
|
6818
7011
|
};
|
|
6819
|
-
const
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
7012
|
+
const displayRef = React58.useRef(null);
|
|
7013
|
+
const lastDisplayHeightRef = React58.useRef(0);
|
|
7014
|
+
React58.useLayoutEffect(() => {
|
|
7015
|
+
if (!isSelected && displayRef.current) {
|
|
7016
|
+
const h = displayRef.current.offsetHeight;
|
|
7017
|
+
if (h > 0) lastDisplayHeightRef.current = h;
|
|
7018
|
+
}
|
|
7019
|
+
}, [isSelected, textContent, isMarkdown]);
|
|
7020
|
+
const adjustTextareaHeight = (element) => {
|
|
7021
|
+
if (!element) return;
|
|
7022
|
+
element.style.height = "auto";
|
|
7023
|
+
const scrollH = element.scrollHeight;
|
|
7024
|
+
const floor = lastDisplayHeightRef.current;
|
|
7025
|
+
element.style.height = `${Math.max(scrollH, floor)}px`;
|
|
6828
7026
|
};
|
|
7027
|
+
const { textareaRef, trackFocus, handleKeyDown, toolbarProps } = useMarkdownToolbar({
|
|
7028
|
+
text: localText,
|
|
7029
|
+
isSelected,
|
|
7030
|
+
commitText: (newText) => commitText(newText, { enableMarkdown: true }),
|
|
7031
|
+
trackSelection: (sel) => {
|
|
7032
|
+
setLastFocusedEditable({
|
|
7033
|
+
blockId,
|
|
7034
|
+
field: "text",
|
|
7035
|
+
selectionStart: sel.start,
|
|
7036
|
+
selectionEnd: sel.end
|
|
7037
|
+
});
|
|
7038
|
+
}
|
|
7039
|
+
});
|
|
7040
|
+
React58.useLayoutEffect(() => {
|
|
7041
|
+
if (textareaRef.current) adjustTextareaHeight(textareaRef.current);
|
|
7042
|
+
}, [localText, isSelected]);
|
|
6829
7043
|
if (isSelected) {
|
|
6830
|
-
return /* @__PURE__ */ React58__default.default.createElement(
|
|
7044
|
+
return /* @__PURE__ */ React58__default.default.createElement(React58__default.default.Fragment, null, /* @__PURE__ */ React58__default.default.createElement(
|
|
6831
7045
|
"textarea",
|
|
6832
7046
|
{
|
|
7047
|
+
ref: textareaRef,
|
|
6833
7048
|
value: localText,
|
|
6834
7049
|
onChange: handleTextChange,
|
|
6835
7050
|
onFocus: trackFocus,
|
|
6836
7051
|
onSelect: trackFocus,
|
|
6837
7052
|
onKeyUp: trackFocus,
|
|
7053
|
+
onKeyDown: handleKeyDown,
|
|
6838
7054
|
onClick: (e) => {
|
|
6839
7055
|
e.stopPropagation();
|
|
6840
7056
|
trackFocus(e);
|
|
6841
7057
|
},
|
|
6842
7058
|
style: textareaStyle,
|
|
6843
7059
|
rows: 1,
|
|
6844
|
-
onInput: (e) => adjustTextareaHeight(e.target)
|
|
6845
|
-
ref: (el) => el && adjustTextareaHeight(el)
|
|
7060
|
+
onInput: (e) => adjustTextareaHeight(e.target)
|
|
6846
7061
|
}
|
|
6847
|
-
);
|
|
7062
|
+
), /* @__PURE__ */ React58__default.default.createElement(InlineFormattingToolbar, __spreadValues({ anchorEl: textareaRef.current }, toolbarProps)));
|
|
6848
7063
|
}
|
|
6849
7064
|
if (isMarkdown) {
|
|
6850
|
-
return /* @__PURE__ */ React58__default.default.createElement(
|
|
7065
|
+
return /* @__PURE__ */ React58__default.default.createElement(
|
|
7066
|
+
"div",
|
|
7067
|
+
{
|
|
7068
|
+
ref: displayRef,
|
|
7069
|
+
style: wStyle,
|
|
7070
|
+
dangerouslySetInnerHTML: { __html: renderMarkdownString(textContent) }
|
|
7071
|
+
}
|
|
7072
|
+
);
|
|
6851
7073
|
}
|
|
6852
|
-
return /* @__PURE__ */ React58__default.default.createElement("div", { style: wStyle }, textContent);
|
|
7074
|
+
return /* @__PURE__ */ React58__default.default.createElement("div", { ref: displayRef, style: wStyle }, textContent);
|
|
6853
7075
|
}
|
|
6854
7076
|
|
|
6855
7077
|
// src/editor/core.tsx
|