@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
|
@@ -59,6 +59,38 @@ var IMAGE_SIZES = [
|
|
|
59
59
|
"l",
|
|
60
60
|
"full"
|
|
61
61
|
];
|
|
62
|
+
/**
|
|
63
|
+
* RT9: an image's framing as production writes it on the `<img>` (richtext richTextImageFrame): `data-src` the stored
|
|
64
|
+
* url when the drawn one carries the crop, `data-crop` "top,right,bottom,left" and `data-focal` "x,y", each 0–1.
|
|
65
|
+
*/
|
|
66
|
+
function readImageFrame(img) {
|
|
67
|
+
const src = img?.getAttribute("data-src") ?? img?.getAttribute("src") ?? "";
|
|
68
|
+
const nums = (raw, n) => {
|
|
69
|
+
const v = (raw ?? "").split(",").map((x) => Number(x));
|
|
70
|
+
return raw && v.length === n && v.every((x) => Number.isFinite(x) && x >= 0 && x <= 1) ? v : null;
|
|
71
|
+
};
|
|
72
|
+
const c = nums(img?.getAttribute("data-crop"), 4);
|
|
73
|
+
const f = nums(img?.getAttribute("data-focal"), 2);
|
|
74
|
+
return {
|
|
75
|
+
src,
|
|
76
|
+
...c && c[0] + c[2] < 1 && c[1] + c[3] < 1 ? { crop: {
|
|
77
|
+
top: c[0],
|
|
78
|
+
right: c[1],
|
|
79
|
+
bottom: c[2],
|
|
80
|
+
left: c[3]
|
|
81
|
+
} } : {},
|
|
82
|
+
...f ? { focal: {
|
|
83
|
+
x: f[0],
|
|
84
|
+
y: f[1]
|
|
85
|
+
} } : {}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
var frameAttrs = (crop, focal) => `${crop ? ` data-crop="${[
|
|
89
|
+
crop.top,
|
|
90
|
+
crop.right,
|
|
91
|
+
crop.bottom,
|
|
92
|
+
crop.left
|
|
93
|
+
].join(",")}"` : ""}${focal ? ` data-focal="${focal.x},${focal.y}"` : ""}`;
|
|
62
94
|
var CALLOUT_TONES = [
|
|
63
95
|
"info",
|
|
64
96
|
"tip",
|
|
@@ -152,7 +184,12 @@ var ISLAND_KINDS = [
|
|
|
152
184
|
"video",
|
|
153
185
|
"embed",
|
|
154
186
|
"file",
|
|
155
|
-
"component"
|
|
187
|
+
"component",
|
|
188
|
+
"gallery",
|
|
189
|
+
"toc",
|
|
190
|
+
"columns",
|
|
191
|
+
"author",
|
|
192
|
+
"related"
|
|
156
193
|
];
|
|
157
194
|
function defaultModel(kind, extra) {
|
|
158
195
|
const base = {
|
|
@@ -183,7 +220,8 @@ function defaultModel(kind, extra) {
|
|
|
183
220
|
video: () => ({ url: "" }),
|
|
184
221
|
embed: () => ({
|
|
185
222
|
url: "",
|
|
186
|
-
title: ""
|
|
223
|
+
title: "",
|
|
224
|
+
labelled: true
|
|
187
225
|
}),
|
|
188
226
|
file: () => ({
|
|
189
227
|
url: "",
|
|
@@ -192,6 +230,31 @@ function defaultModel(kind, extra) {
|
|
|
192
230
|
component: () => ({
|
|
193
231
|
id: rid("ci"),
|
|
194
232
|
overrides: "{}"
|
|
233
|
+
}),
|
|
234
|
+
gallery: () => ({
|
|
235
|
+
layout: "grid",
|
|
236
|
+
images: []
|
|
237
|
+
}),
|
|
238
|
+
toc: () => ({
|
|
239
|
+
title: "In this article",
|
|
240
|
+
depth: "3"
|
|
241
|
+
}),
|
|
242
|
+
columns: () => ({
|
|
243
|
+
gap: "m",
|
|
244
|
+
cols: [{
|
|
245
|
+
id: rid("col"),
|
|
246
|
+
html: ""
|
|
247
|
+
}, {
|
|
248
|
+
id: rid("col"),
|
|
249
|
+
html: ""
|
|
250
|
+
}]
|
|
251
|
+
}),
|
|
252
|
+
author: () => ({ author: "" }),
|
|
253
|
+
related: () => ({
|
|
254
|
+
title: "Related stories",
|
|
255
|
+
mode: "topic",
|
|
256
|
+
count: 3,
|
|
257
|
+
posts: []
|
|
195
258
|
})
|
|
196
259
|
};
|
|
197
260
|
if (kind === "table") return {
|
|
@@ -230,7 +293,7 @@ function renderStatic(kind, model) {
|
|
|
230
293
|
switch (kind) {
|
|
231
294
|
case "image": {
|
|
232
295
|
const m = model;
|
|
233
|
-
const img = m.src ? `<img src="${escAttr(m.src)}"${attr("alt", m.alt)}>` : "";
|
|
296
|
+
const img = m.src ? `<img src="${escAttr(m.src)}"${attr("alt", m.alt)}${frameAttrs(m.crop, m.focal)}>` : "";
|
|
234
297
|
const linked = img && m.href !== void 0 ? `<a href="${escAttr(m.href)}">${img}</a>` : img;
|
|
235
298
|
const cap = m.caption !== void 0 ? `<figcaption>${esc(m.caption)}</figcaption>` : "";
|
|
236
299
|
return `<figure data-rt="image"${attr("data-align", m.align)}${attr("data-size", m.size)}${xAttr(m.extra)}>${linked}${cap}</figure>`;
|
|
@@ -266,7 +329,29 @@ function renderStatic(kind, model) {
|
|
|
266
329
|
}
|
|
267
330
|
case "embed": {
|
|
268
331
|
const m = model;
|
|
269
|
-
return `<figure data-rt="embed"${attr("data-url", m.url)}${attr("data-title", m.title)}${attr("data-aspect", m.aspect)}${xAttr(m.extra)}>${m.url ? `<a href="${escAttr(m.url)}">${esc(m.title || m.url)}</a>` : ""}</figure>`;
|
|
332
|
+
return `<figure data-rt="embed"${attr("data-url", m.url)}${attr("data-title", m.title)}${m.labelled ? attr("aria-label", m.title ?? "") : ""}${attr("data-aspect", m.aspect)}${xAttr(m.extra)}>${m.url ? `<a href="${escAttr(m.url)}">${esc(m.title || m.url)}</a>` : ""}</figure>`;
|
|
333
|
+
}
|
|
334
|
+
case "gallery": {
|
|
335
|
+
const m = model;
|
|
336
|
+
const items = m.images.map((x) => `<li><figure>${x.src ? `<img src="${escAttr(x.src)}" alt="${escAttr(x.alt ?? "")}"${frameAttrs(x.crop, x.focal)}>` : ""}${x.caption ? `<figcaption>${esc(x.caption)}</figcaption>` : ""}</figure></li>`).join("");
|
|
337
|
+
return `<figure data-rt="gallery"${attr("data-layout", m.layout)}${xAttr(m.extra)}><ul>${items}</ul></figure>`;
|
|
338
|
+
}
|
|
339
|
+
case "toc": {
|
|
340
|
+
const m = model;
|
|
341
|
+
const title = (m.title ?? "").trim();
|
|
342
|
+
return `<nav data-rt="toc"${attr("data-depth", m.depth)} aria-label="${escAttr(title || "Table of contents")}"${xAttr(m.extra)}>${title ? `<p data-title>${esc(title)}</p>` : ""}<ol></ol></nav>`;
|
|
343
|
+
}
|
|
344
|
+
case "columns": {
|
|
345
|
+
const m = model;
|
|
346
|
+
return `<div data-rt="columns"${attr("data-gap", m.gap)} data-cols="${m.cols.length}"${xAttr(m.extra)}>${m.cols.map((c) => `<div data-col="true">${c.html}</div>`).join("")}</div>`;
|
|
347
|
+
}
|
|
348
|
+
case "author": {
|
|
349
|
+
const m = model;
|
|
350
|
+
return `<aside data-rt="author"${attr("data-author", m.author)}${xAttr(m.extra)}></aside>`;
|
|
351
|
+
}
|
|
352
|
+
case "related": {
|
|
353
|
+
const m = model;
|
|
354
|
+
return `<aside data-rt="related"${attr("data-mode", m.mode)}${attr("data-count", m.count)} data-posts="${escAttr(m.posts.join(","))}"${xAttr(m.extra)}>${m.title ? `<p data-title>${esc(m.title)}</p>` : ""}</aside>`;
|
|
270
355
|
}
|
|
271
356
|
case "file": {
|
|
272
357
|
const m = model;
|
|
@@ -740,8 +825,11 @@ function parseIsland(kind, el) {
|
|
|
740
825
|
const img = el.querySelector("img");
|
|
741
826
|
const a = img?.parentElement?.tagName === "A" ? img.parentElement : null;
|
|
742
827
|
const cap = el.querySelector(":scope > figcaption");
|
|
743
|
-
const
|
|
828
|
+
const frame = readImageFrame(img);
|
|
829
|
+
const m = { src: frame.src };
|
|
744
830
|
if (img?.hasAttribute("alt")) m.alt = img.getAttribute("alt");
|
|
831
|
+
if (frame.crop) m.crop = frame.crop;
|
|
832
|
+
if (frame.focal) m.focal = frame.focal;
|
|
745
833
|
if (cap) m.caption = (cap.textContent ?? "").replace(/\u200b/g, "");
|
|
746
834
|
const align = oneOf(IMAGE_ALIGNS, attrOf(el, "data-align"));
|
|
747
835
|
const size = oneOf(IMAGE_SIZES, attrOf(el, "data-size"));
|
|
@@ -815,11 +903,75 @@ function parseIsland(kind, el) {
|
|
|
815
903
|
case "embed": {
|
|
816
904
|
const m = {};
|
|
817
905
|
const url = attrOf(el, "data-url");
|
|
818
|
-
const title = attrOf(el, "data-title");
|
|
906
|
+
const title = attrOf(el, "data-title") ?? attrOf(el, "aria-label");
|
|
819
907
|
const aspect = attrOf(el, "data-aspect");
|
|
820
908
|
if (url !== void 0) m.url = url;
|
|
821
909
|
if (title !== void 0) m.title = title;
|
|
822
910
|
if (aspect !== void 0 && EMBED_ASPECT_VALUES.includes(aspect)) m.aspect = aspect;
|
|
911
|
+
if (el.hasAttribute("aria-label")) m.labelled = true;
|
|
912
|
+
const extra = attrOf(el, "data-extra");
|
|
913
|
+
if (extra) m.extra = extra;
|
|
914
|
+
return m;
|
|
915
|
+
}
|
|
916
|
+
case "gallery": {
|
|
917
|
+
const m = { images: [] };
|
|
918
|
+
const layout = attrOf(el, "data-layout");
|
|
919
|
+
if (layout === "grid" || layout === "carousel") m.layout = layout;
|
|
920
|
+
m.images = Array.from(el.querySelectorAll("li")).map((li) => {
|
|
921
|
+
const img = li.querySelector("img");
|
|
922
|
+
const caption = li.querySelector("figcaption")?.textContent ?? void 0;
|
|
923
|
+
const frame = readImageFrame(img);
|
|
924
|
+
return {
|
|
925
|
+
_key: rid("g"),
|
|
926
|
+
src: frame.src,
|
|
927
|
+
...img ? { alt: img.getAttribute("alt") ?? "" } : {},
|
|
928
|
+
...caption ? { caption } : {},
|
|
929
|
+
...frame.crop ? { crop: frame.crop } : {},
|
|
930
|
+
...frame.focal ? { focal: frame.focal } : {}
|
|
931
|
+
};
|
|
932
|
+
});
|
|
933
|
+
const extra = attrOf(el, "data-extra");
|
|
934
|
+
if (extra) m.extra = extra;
|
|
935
|
+
return m;
|
|
936
|
+
}
|
|
937
|
+
case "toc": {
|
|
938
|
+
const m = {};
|
|
939
|
+
const title = el.querySelector("[data-title]")?.textContent?.trim();
|
|
940
|
+
if (title) m.title = title;
|
|
941
|
+
const depth = attrOf(el, "data-depth");
|
|
942
|
+
if (depth === "2" || depth === "3") m.depth = depth;
|
|
943
|
+
const extra = attrOf(el, "data-extra");
|
|
944
|
+
if (extra) m.extra = extra;
|
|
945
|
+
return m;
|
|
946
|
+
}
|
|
947
|
+
case "columns": {
|
|
948
|
+
const m = { cols: Array.from(el.children).filter((c) => c.hasAttribute("data-col")).map((c) => ({
|
|
949
|
+
id: rid("col"),
|
|
950
|
+
html: c.innerHTML
|
|
951
|
+
})) };
|
|
952
|
+
const gap = attrOf(el, "data-gap");
|
|
953
|
+
if (gap === "s" || gap === "m" || gap === "l") m.gap = gap;
|
|
954
|
+
const extra = attrOf(el, "data-extra");
|
|
955
|
+
if (extra) m.extra = extra;
|
|
956
|
+
return m;
|
|
957
|
+
}
|
|
958
|
+
case "author": {
|
|
959
|
+
const m = {};
|
|
960
|
+
const author = attrOf(el, "data-author");
|
|
961
|
+
if (author !== void 0) m.author = author;
|
|
962
|
+
const extra = attrOf(el, "data-extra");
|
|
963
|
+
if (extra) m.extra = extra;
|
|
964
|
+
return m;
|
|
965
|
+
}
|
|
966
|
+
case "related": {
|
|
967
|
+
const m = { posts: (attrOf(el, "data-posts") ?? "").split(",").map((x) => x.trim()).filter(Boolean) };
|
|
968
|
+
const title = (attrOf(el, "data-title") ?? el.querySelector("[data-title]")?.textContent ?? "").trim();
|
|
969
|
+
if (title) m.title = title;
|
|
970
|
+
const mode = attrOf(el, "data-mode");
|
|
971
|
+
if (mode === "topic" || mode === "newest" || mode === "manual") m.mode = mode;
|
|
972
|
+
else if (mode === "auto") m.mode = "topic";
|
|
973
|
+
const count = Number(attrOf(el, "data-count"));
|
|
974
|
+
if (Number.isInteger(count) && count > 0) m.count = count;
|
|
823
975
|
const extra = attrOf(el, "data-extra");
|
|
824
976
|
if (extra) m.extra = extra;
|
|
825
977
|
return m;
|
|
@@ -1023,6 +1175,6 @@ function rangeRect(r, fallback) {
|
|
|
1023
1175
|
}
|
|
1024
1176
|
var isEmptyHtml = (html) => !html.replace(/<(?!img|hr|figure|table|details|div data-rt)[^>]*>/g, "").replace(/ /g, "").trim();
|
|
1025
1177
|
//#endregion
|
|
1026
|
-
export { CALLOUT_TONES, IMAGE_ALIGNS, IMAGE_SIZES, ISLAND_KINDS, STORED_COLUMN_TYPES, TEXT_BLOCKS, cloneModel, closestBlock, colAttrs, colSettingsOf, columnSettings, createIsland, defaultModel, detectEmbed, detectKind, editingHost, editorRoundTrip, esc, escAttr, hydrate, isEmptyHtml, isValueType, parasToText, parseIsland, parseStoredTable, placeCaret, rangeRect, renderStatic, renderStoredTable, rid, sanitize, serialize, textBeforeCaret, textToParas, topBlock, typeAttrOf, typedCellView, typedValueOf, typedWords };
|
|
1178
|
+
export { CALLOUT_TONES, IMAGE_ALIGNS, IMAGE_SIZES, ISLAND_KINDS, STORED_COLUMN_TYPES, TEXT_BLOCKS, cloneModel, closestBlock, colAttrs, colSettingsOf, columnSettings, createIsland, defaultModel, detectEmbed, detectKind, editingHost, editorRoundTrip, esc, escAttr, hydrate, isEmptyHtml, isValueType, parasToText, parseIsland, parseStoredTable, placeCaret, rangeRect, readImageFrame, renderStatic, renderStoredTable, rid, sanitize, serialize, textBeforeCaret, textToParas, topBlock, typeAttrOf, typedCellView, typedValueOf, typedWords };
|
|
1027
1179
|
|
|
1028
1180
|
//# sourceMappingURL=dom.js.map
|