@bettercms-ai/kit 2.0.0-next.1 → 2.0.0-next.2
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/adapters/lossy.d.ts +4 -0
- package/dist/adapters/lossy.js +8 -2
- package/dist/adapters/lossy.js.map +1 -1
- package/dist/adapters/schema.js +28 -0
- package/dist/adapters/schema.js.map +1 -1
- package/dist/controls/rich-text/blocks.d.ts +6 -0
- package/dist/controls/rich-text/blocks.js +187 -0
- package/dist/controls/rich-text/blocks.js.map +1 -1
- package/dist/controls/rich-text/catalog.d.ts +2 -5
- package/dist/controls/rich-text/catalog.js +104 -6
- package/dist/controls/rich-text/catalog.js.map +1 -1
- package/dist/controls/rich-text/codec.d.ts +10 -1
- package/dist/controls/rich-text/codec.js +7 -0
- package/dist/controls/rich-text/codec.js.map +1 -1
- package/dist/controls/rich-text/control.js +1 -0
- package/dist/controls/rich-text/control.js.map +1 -1
- package/dist/controls/rich-text/dom.d.ts +79 -0
- package/dist/controls/rich-text/dom.js +159 -7
- package/dist/controls/rich-text/dom.js.map +1 -1
- package/dist/controls/rich-text/editor.d.ts +4 -2
- package/dist/controls/rich-text/editor.js +93 -3
- package/dist/controls/rich-text/editor.js.map +1 -1
- package/dist/controls/rich-text/ops.js +6 -0
- package/dist/controls/rich-text/ops.js.map +1 -1
- package/dist/controls/rich-text/toc.d.ts +3 -2
- package/dist/controls/rich-text/toc.js +1 -2
- package/dist/controls/rich-text/toc.js.map +1 -1
- package/dist/core/core.d.ts +1 -0
- package/dist/core/core.js +2 -0
- package/dist/core/core.js.map +1 -1
- package/dist/core/facets.d.ts +8 -0
- package/dist/core/facets.js +8 -0
- package/dist/core/facets.js.map +1 -1
- package/dist/library/kit-catalog.json +4 -2
- package/dist/schema/types.d.ts +8 -0
- package/dist/schema/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -9,6 +9,7 @@ import { COMPONENT_INSERT_TOAST } from "../component-services.js";
|
|
|
9
9
|
import { eventKey } from "../../lib/key-event.js";
|
|
10
10
|
import { closestBlock, createIsland, defaultModel, editingHost, esc, hydrate, isEmptyHtml, placeCaret, rangeRect, rid, sanitize, serialize, textBeforeCaret, topBlock } from "./dom.js";
|
|
11
11
|
import { LinkForm } from "./link-form.js";
|
|
12
|
+
import { createOutlineStore, outlineOf } from "./toc.js";
|
|
12
13
|
import { CatalogComponentsProvider, InsertMenuContent, SlashMenuPanel, blockAllowed, catalogKey, noteRecent, useCatalog } from "./catalog.js";
|
|
13
14
|
import { openComponentPanel } from "./component-panel.js";
|
|
14
15
|
import { Island } from "./blocks.js";
|
|
@@ -19,6 +20,7 @@ import { ALL_FEATURES } from "./codec.js";
|
|
|
19
20
|
import { htmlToMarkdown, looksLikeMarkdown, markdownToHtml } from "./markdown.js";
|
|
20
21
|
import { EMPTY_FMT, FormatToolbar, MARK_FEATURE, stylesFor } from "./toolbar.js";
|
|
21
22
|
import { SelectionBubble } from "./floating.js";
|
|
23
|
+
import { FN_MARK, FOOTNOTE_POPOVER_CLASS, FOOTNOTE_REFUSED, FootnoteEditor, FootnotesList, backToMarker, caretAfterMarker, insertFootnote, renumberFootnotes } from "./footnote.js";
|
|
22
24
|
import * as React from "react";
|
|
23
25
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
24
26
|
import { IconArrowBarToDown, IconArrowBarToUp, IconCopy, IconGripVertical, IconPlus, IconTransform, IconTrash } from "@tabler/icons-react";
|
|
@@ -175,7 +177,7 @@ function slashPlacement(caret, viewportH) {
|
|
|
175
177
|
maxHeight: Math.max(SLASH_MIN_H, Math.min(SLASH_MENU_H, flipUp ? above : below))
|
|
176
178
|
};
|
|
177
179
|
}
|
|
178
|
-
function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, features = ALL_FEATURES, single, allowNewTab = true, id, invalid, variant = "document", expandCrumbs, expandedOpen, onExpandedOpenChange, inModal, hideFullscreen, maxHeight, autoFocus, onComment, components }) {
|
|
180
|
+
function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, features = ALL_FEATURES, references, single, allowNewTab = true, id, invalid, variant = "document", expandCrumbs, expandedOpen, onExpandedOpenChange, inModal, hideFullscreen, maxHeight, autoFocus, onComment, components }) {
|
|
179
181
|
const hints = shortcutHintsOn();
|
|
180
182
|
const ph = placeholder ?? (hints ? "Type '/' for commands" : "Write something…");
|
|
181
183
|
const dense = variant === "panel";
|
|
@@ -263,6 +265,11 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
263
265
|
const t = window.setTimeout(() => setNotice(null), 8e3);
|
|
264
266
|
return () => window.clearTimeout(t);
|
|
265
267
|
}, [notice]);
|
|
268
|
+
/** V2 article-blocks.tsx:45-66: one live outline per editor, so every table of contents follows the headings */
|
|
269
|
+
const outline = React.useRef(createOutlineStore());
|
|
270
|
+
/** V2 rich-text-editor.tsx:271-276: the body's markers in text order, and the one whose note is open */
|
|
271
|
+
const [footnotes, setFootnotes] = React.useState([]);
|
|
272
|
+
const [fnEdit, setFnEdit] = React.useState(null);
|
|
266
273
|
const syncIslands = React.useCallback(() => {
|
|
267
274
|
const el = ref.current;
|
|
268
275
|
if (!el) return setIslands((p) => p.length ? [] : p);
|
|
@@ -286,8 +293,12 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
286
293
|
const el = ref.current;
|
|
287
294
|
if (!el) return;
|
|
288
295
|
el.innerHTML = sanitize(html || "") || "<p><br></p>";
|
|
296
|
+
el.querySelectorAll(":scope > ol[data-rt=\"footnotes\"]").forEach((n) => n.remove());
|
|
297
|
+
el.querySelectorAll(FN_MARK).forEach((m) => m.setAttribute("contenteditable", "false"));
|
|
289
298
|
hydrate(el);
|
|
290
299
|
syncTaskA11y(el);
|
|
300
|
+
setFootnotes(renumberFootnotes(el));
|
|
301
|
+
outline.current.set(outlineOf(el));
|
|
291
302
|
known.current = html;
|
|
292
303
|
setEmpty(isEmptyHtml(html));
|
|
293
304
|
setWords(countWords(html));
|
|
@@ -299,6 +310,8 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
299
310
|
if (!el) return;
|
|
300
311
|
syncIslands();
|
|
301
312
|
syncTaskA11y(el);
|
|
313
|
+
outline.current.set(outlineOf(el));
|
|
314
|
+
setFootnotes(renumberFootnotes(el));
|
|
302
315
|
const html = serialize(el);
|
|
303
316
|
setEmpty(isEmptyHtml(html) && !el.querySelector(":scope > [data-rt-island], :scope > hr"));
|
|
304
317
|
setWords(countWords(html));
|
|
@@ -584,6 +597,13 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
584
597
|
}
|
|
585
598
|
if (!it.id || !blockAllowed(it.id, allows)) return;
|
|
586
599
|
noteRecent(it);
|
|
600
|
+
if (it.id === "footnote") {
|
|
601
|
+
const m = insertFootnote(el);
|
|
602
|
+
if (!m) return void notify(FOOTNOTE_REFUSED.title, { description: FOOTNOTE_REFUSED.description });
|
|
603
|
+
emit();
|
|
604
|
+
openFootnote(m, true);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
587
607
|
if (it.id === "task") insertChecklist(el);
|
|
588
608
|
else if (it.id === "button") {
|
|
589
609
|
const a = insertButton(el);
|
|
@@ -838,6 +858,28 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
838
858
|
} : { href: "" }
|
|
839
859
|
});
|
|
840
860
|
};
|
|
861
|
+
const openFootnote = (m, fresh = false) => {
|
|
862
|
+
if (readOnly) return;
|
|
863
|
+
setBubble(null);
|
|
864
|
+
setFnEdit({
|
|
865
|
+
el: m,
|
|
866
|
+
rect: m.getBoundingClientRect(),
|
|
867
|
+
fresh
|
|
868
|
+
});
|
|
869
|
+
};
|
|
870
|
+
const removeFootnote = (m) => {
|
|
871
|
+
setFnEdit(null);
|
|
872
|
+
m.remove();
|
|
873
|
+
emit();
|
|
874
|
+
};
|
|
875
|
+
/** closed: a new footnote with no note is taken back out (V2), else the caret goes back after its marker */
|
|
876
|
+
const closeFootnote = () => {
|
|
877
|
+
const f = fnEdit;
|
|
878
|
+
setFnEdit(null);
|
|
879
|
+
if (!f || !ref.current) return;
|
|
880
|
+
if (f.fresh && !(f.el.getAttribute("data-note") ?? "").trim()) return removeFootnote(f.el);
|
|
881
|
+
caretAfterMarker(ref.current, f.el);
|
|
882
|
+
};
|
|
841
883
|
/** V2 rich-text-editor.tsx:865-873: a button's popover, its label above the link form */
|
|
842
884
|
const openButton = (a) => {
|
|
843
885
|
if (readOnly) return;
|
|
@@ -1159,8 +1201,14 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
1159
1201
|
undo: () => api.current.islandUndo(),
|
|
1160
1202
|
redo: () => api.current.islandRedo(),
|
|
1161
1203
|
drag: (x, e) => api.current.startDrag(x, e),
|
|
1162
|
-
allows: (f) => api.current.allows(f)
|
|
1163
|
-
|
|
1204
|
+
allows: (f) => api.current.allows(f),
|
|
1205
|
+
outline: outline.current,
|
|
1206
|
+
references
|
|
1207
|
+
}), [
|
|
1208
|
+
readOnly,
|
|
1209
|
+
dense,
|
|
1210
|
+
references
|
|
1211
|
+
]);
|
|
1164
1212
|
const commentSel = onComment ? () => {
|
|
1165
1213
|
restoreSel();
|
|
1166
1214
|
const q = window.getSelection()?.toString().trim();
|
|
@@ -1370,6 +1418,11 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
1370
1418
|
emit();
|
|
1371
1419
|
},
|
|
1372
1420
|
onClick: (e) => {
|
|
1421
|
+
const fn = e.target.closest?.(FN_MARK);
|
|
1422
|
+
if (fn && ref.current?.contains(fn) && !fn.closest("[data-rt-island]") && !readOnly) {
|
|
1423
|
+
e.preventDefault();
|
|
1424
|
+
return openFootnote(fn);
|
|
1425
|
+
}
|
|
1373
1426
|
const a = ref.current ? buttonAt(ref.current, e.target) : null;
|
|
1374
1427
|
if (!a || readOnly) return;
|
|
1375
1428
|
e.preventDefault();
|
|
@@ -1551,6 +1604,13 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
1551
1604
|
}), el, key))
|
|
1552
1605
|
]
|
|
1553
1606
|
}),
|
|
1607
|
+
/* @__PURE__ */ jsx(FootnotesList, {
|
|
1608
|
+
notes: footnotes,
|
|
1609
|
+
readOnly,
|
|
1610
|
+
density: dense ? "dense" : "default",
|
|
1611
|
+
onEdit: (m) => openFootnote(m),
|
|
1612
|
+
onBack: (m) => ref.current && backToMarker(ref.current, m)
|
|
1613
|
+
}),
|
|
1554
1614
|
/* @__PURE__ */ jsxs("div", {
|
|
1555
1615
|
className: "flex h-7 items-center justify-end gap-3 rounded-b-kit-lg border-t border-kit-line-subtle px-3 text-kit-2xs text-kit-fg-3",
|
|
1556
1616
|
children: [notice ? /* @__PURE__ */ jsxs("span", {
|
|
@@ -1632,6 +1692,35 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
1632
1692
|
maxHeight: slashMaxH
|
|
1633
1693
|
})
|
|
1634
1694
|
})] }), document.body) : null,
|
|
1695
|
+
/* @__PURE__ */ jsxs(Popover, {
|
|
1696
|
+
open: !!fnEdit,
|
|
1697
|
+
onOpenChange: (o) => !o && closeFootnote(),
|
|
1698
|
+
children: [/* @__PURE__ */ jsx(PopoverAnchor, { render: /* @__PURE__ */ jsx("span", {
|
|
1699
|
+
className: "pointer-events-none fixed",
|
|
1700
|
+
style: fnEdit ? {
|
|
1701
|
+
top: fnEdit.rect.bottom,
|
|
1702
|
+
left: fnEdit.rect.left,
|
|
1703
|
+
width: Math.max(1, fnEdit.rect.width),
|
|
1704
|
+
height: 1
|
|
1705
|
+
} : {
|
|
1706
|
+
top: 0,
|
|
1707
|
+
left: 0
|
|
1708
|
+
}
|
|
1709
|
+
}) }), /* @__PURE__ */ jsx(PopoverContent, {
|
|
1710
|
+
className: FOOTNOTE_POPOVER_CLASS,
|
|
1711
|
+
finalFocus: false,
|
|
1712
|
+
children: fnEdit ? /* @__PURE__ */ jsx(FootnoteEditor, {
|
|
1713
|
+
n: footnotes.findIndex((f) => f.el === fnEdit.el) + 1,
|
|
1714
|
+
note: fnEdit.el.getAttribute("data-note") ?? "",
|
|
1715
|
+
onChange: (v) => {
|
|
1716
|
+
fnEdit.el.setAttribute("data-note", v);
|
|
1717
|
+
emit();
|
|
1718
|
+
},
|
|
1719
|
+
onRemove: () => removeFootnote(fnEdit.el),
|
|
1720
|
+
onDone: closeFootnote
|
|
1721
|
+
}, footnotes.findIndex((f) => f.el === fnEdit.el)) : null
|
|
1722
|
+
})]
|
|
1723
|
+
}),
|
|
1635
1724
|
/* @__PURE__ */ jsxs(Popover, {
|
|
1636
1725
|
open: !!link,
|
|
1637
1726
|
onOpenChange: (o) => !o && setLink(null),
|
|
@@ -1691,6 +1780,7 @@ function RichTextEditor({ value, onChange, readOnly, placeholder, docKey, featur
|
|
|
1691
1780
|
placeholder,
|
|
1692
1781
|
docKey: `${docKey}:expanded`,
|
|
1693
1782
|
features,
|
|
1783
|
+
references,
|
|
1694
1784
|
single,
|
|
1695
1785
|
allowNewTab,
|
|
1696
1786
|
expandCrumbs,
|