@bettercms-ai/kit 2.0.0 → 2.0.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.
Files changed (120) hide show
  1. package/dist/adapters/lossy.d.ts +14 -6
  2. package/dist/adapters/lossy.js +23 -11
  3. package/dist/adapters/lossy.js.map +1 -1
  4. package/dist/adapters/prod-types.d.ts +46 -14
  5. package/dist/adapters/prod-types.js +37 -35
  6. package/dist/adapters/prod-types.js.map +1 -1
  7. package/dist/adapters/schema.d.ts +39 -0
  8. package/dist/adapters/schema.js +281 -82
  9. package/dist/adapters/schema.js.map +1 -1
  10. package/dist/context.d.ts +39 -0
  11. package/dist/context.js +40 -1
  12. package/dist/context.js.map +1 -1
  13. package/dist/controls/form-picker-register.d.ts +7 -1
  14. package/dist/controls/form-picker-register.js +1 -5
  15. package/dist/controls/form-picker-register.js.map +1 -1
  16. package/dist/controls/icon.d.ts +1 -1
  17. package/dist/controls/icon.js +1 -1
  18. package/dist/controls/icon.js.map +1 -1
  19. package/dist/controls/link.d.ts +11 -4
  20. package/dist/controls/link.js +120 -202
  21. package/dist/controls/link.js.map +1 -1
  22. package/dist/controls/location.js +3 -8
  23. package/dist/controls/location.js.map +1 -1
  24. package/dist/controls/media.d.ts +0 -14
  25. package/dist/controls/media.js +52 -95
  26. package/dist/controls/media.js.map +1 -1
  27. package/dist/controls/reference-services.d.ts +23 -2
  28. package/dist/controls/reference.d.ts +2 -2
  29. package/dist/controls/reference.js +79 -28
  30. package/dist/controls/reference.js.map +1 -1
  31. package/dist/controls/rich-text/article-shell.d.ts +145 -0
  32. package/dist/controls/rich-text/article-shell.js +514 -0
  33. package/dist/controls/rich-text/article-shell.js.map +1 -0
  34. package/dist/controls/rich-text/author.d.ts +25 -0
  35. package/dist/controls/rich-text/author.js +107 -0
  36. package/dist/controls/rich-text/author.js.map +1 -0
  37. package/dist/controls/rich-text/blocks.d.ts +19 -2
  38. package/dist/controls/rich-text/blocks.js +275 -638
  39. package/dist/controls/rich-text/blocks.js.map +1 -1
  40. package/dist/controls/rich-text/button.d.ts +23 -0
  41. package/dist/controls/rich-text/button.js +81 -0
  42. package/dist/controls/rich-text/button.js.map +1 -0
  43. package/dist/controls/rich-text/catalog.d.ts +2 -5
  44. package/dist/controls/rich-text/catalog.js +121 -7
  45. package/dist/controls/rich-text/catalog.js.map +1 -1
  46. package/dist/controls/rich-text/checklist.d.ts +24 -0
  47. package/dist/controls/rich-text/checklist.js +115 -0
  48. package/dist/controls/rich-text/checklist.js.map +1 -0
  49. package/dist/controls/rich-text/codec.d.ts +15 -1
  50. package/dist/controls/rich-text/codec.js +11 -1
  51. package/dist/controls/rich-text/codec.js.map +1 -1
  52. package/dist/controls/rich-text/columns.d.ts +41 -0
  53. package/dist/controls/rich-text/columns.js +181 -0
  54. package/dist/controls/rich-text/columns.js.map +1 -0
  55. package/dist/controls/rich-text/control.js +1 -0
  56. package/dist/controls/rich-text/control.js.map +1 -1
  57. package/dist/controls/rich-text/dom.d.ts +84 -4
  58. package/dist/controls/rich-text/dom.js +171 -10
  59. package/dist/controls/rich-text/dom.js.map +1 -1
  60. package/dist/controls/rich-text/editor.d.ts +4 -2
  61. package/dist/controls/rich-text/editor.js +199 -26
  62. package/dist/controls/rich-text/editor.js.map +1 -1
  63. package/dist/controls/rich-text/embed.d.ts +28 -0
  64. package/dist/controls/rich-text/embed.js +210 -0
  65. package/dist/controls/rich-text/embed.js.map +1 -0
  66. package/dist/controls/rich-text/footnote.d.ts +41 -0
  67. package/dist/controls/rich-text/footnote.js +185 -0
  68. package/dist/controls/rich-text/footnote.js.map +1 -0
  69. package/dist/controls/rich-text/gallery.d.ts +28 -0
  70. package/dist/controls/rich-text/gallery.js +167 -0
  71. package/dist/controls/rich-text/gallery.js.map +1 -0
  72. package/dist/controls/rich-text/link-form.d.ts +13 -1
  73. package/dist/controls/rich-text/link-form.js +41 -7
  74. package/dist/controls/rich-text/link-form.js.map +1 -1
  75. package/dist/controls/rich-text/ops.js +6 -0
  76. package/dist/controls/rich-text/ops.js.map +1 -1
  77. package/dist/controls/rich-text/related.d.ts +49 -0
  78. package/dist/controls/rich-text/related.js +233 -0
  79. package/dist/controls/rich-text/related.js.map +1 -0
  80. package/dist/controls/rich-text/toc.d.ts +47 -0
  81. package/dist/controls/rich-text/toc.js +160 -0
  82. package/dist/controls/rich-text/toc.js.map +1 -0
  83. package/dist/controls/slot-register.d.ts +6 -1
  84. package/dist/controls/slot-register.js +1 -4
  85. package/dist/controls/slot-register.js.map +1 -1
  86. package/dist/core/core.d.ts +11 -3
  87. package/dist/core/core.js +24 -6
  88. package/dist/core/core.js.map +1 -1
  89. package/dist/core/facets.d.ts +16 -0
  90. package/dist/core/facets.js +17 -1
  91. package/dist/core/facets.js.map +1 -1
  92. package/dist/core/index.js +2 -2
  93. package/dist/index.js +16 -5
  94. package/dist/index.js.map +1 -1
  95. package/dist/ledgers/exclusions.v1.js +141 -0
  96. package/dist/ledgers/exclusions.v1.js.map +1 -0
  97. package/dist/library/coverage.d.ts +13 -1
  98. package/dist/library/coverage.js +12 -1
  99. package/dist/library/coverage.js.map +1 -1
  100. package/dist/library/kit-catalog.json +158 -154
  101. package/dist/schema/types.d.ts +17 -0
  102. package/dist/schema/types.js.map +1 -1
  103. package/dist/styles.css +1 -1
  104. package/dist/testing/coverage-extras.d.ts +8 -0
  105. package/dist/testing/coverage-extras.js +44 -0
  106. package/dist/testing/coverage-extras.js.map +1 -0
  107. package/dist/testing/exclusions.d.ts +30 -0
  108. package/dist/testing/exclusions.js +13 -0
  109. package/dist/testing/exclusions.js.map +1 -0
  110. package/dist/ui/autocomplete.d.ts +29 -1
  111. package/dist/ui/autocomplete.js +102 -47
  112. package/dist/ui/autocomplete.js.map +1 -1
  113. package/dist/ui/button.js +3 -5
  114. package/dist/ui/button.js.map +1 -1
  115. package/dist/ui/index.js +2 -2
  116. package/dist/ui/overlay.d.ts +4 -1
  117. package/dist/ui/overlay.js +2 -1
  118. package/dist/ui/overlay.js.map +1 -1
  119. package/dist/ui/toast.js +1 -1
  120. package/package.json +8 -2
@@ -30,9 +30,9 @@ import { boolLabels, cellText, cellValue, emptyTable, formatNumber, isCellObject
30
30
  * <div data-body><p>…` (the message is plain text: paragraphs and line breaks)
31
31
  * toggle `bcmsBlock` builtin:toggle {title, body}: `<details data-rt="toggle"><summary>…<div data-body><p>…`
32
32
  * video the `video` block {src, title}: `<div data-rt="video" data-url data-title>`
33
- * embed `bcmsBlock` builtin:video {url, title} (the package's embed: `<iframe src title>` on the page), V2's
34
- * article Embed: `<figure data-rt="embed" data-url data-title><a href>…`. V2's Shape (`aspect`) has no
35
- * stored key, so it is not offered: every embed draws 16:9.
33
+ * embed V2's article Embed {url, title, aspect}: `<figure data-rt="embed" data-url data-title data-aspect><a href>…`
34
+ * (embed.tsx). Stored today as `bcmsBlock` builtin:video {url, title}, which keeps no aspect; the PT
35
+ * `embed` block (plan RT3) does.
36
36
  * file the `file` block {src, name, size}: `<div data-rt="file" data-url data-name data-size>`
37
37
  * component `bcmsBlock` "component" {componentId, overrides, variant} (CPO D28): `<div data-rt="component" data-ref
38
38
  * data-id data-name data-overrides data-variant>` — a linked instance of a project component, shown as a card.
@@ -59,11 +59,49 @@ 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",
65
97
  "warning"
66
98
  ];
99
+ var EMBED_ASPECT_VALUES = [
100
+ "16:9",
101
+ "4:3",
102
+ "1:1",
103
+ "9:16"
104
+ ];
67
105
  var hostOf = (url) => {
68
106
  try {
69
107
  return new URL(url).hostname.replace(/^www\./, "");
@@ -146,7 +184,12 @@ var ISLAND_KINDS = [
146
184
  "video",
147
185
  "embed",
148
186
  "file",
149
- "component"
187
+ "component",
188
+ "gallery",
189
+ "toc",
190
+ "columns",
191
+ "author",
192
+ "related"
150
193
  ];
151
194
  function defaultModel(kind, extra) {
152
195
  const base = {
@@ -177,7 +220,8 @@ function defaultModel(kind, extra) {
177
220
  video: () => ({ url: "" }),
178
221
  embed: () => ({
179
222
  url: "",
180
- title: ""
223
+ title: "",
224
+ labelled: true
181
225
  }),
182
226
  file: () => ({
183
227
  url: "",
@@ -186,6 +230,31 @@ function defaultModel(kind, extra) {
186
230
  component: () => ({
187
231
  id: rid("ci"),
188
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: []
189
258
  })
190
259
  };
191
260
  if (kind === "table") return {
@@ -224,7 +293,7 @@ function renderStatic(kind, model) {
224
293
  switch (kind) {
225
294
  case "image": {
226
295
  const m = model;
227
- 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)}>` : "";
228
297
  const linked = img && m.href !== void 0 ? `<a href="${escAttr(m.href)}">${img}</a>` : img;
229
298
  const cap = m.caption !== void 0 ? `<figcaption>${esc(m.caption)}</figcaption>` : "";
230
299
  return `<figure data-rt="image"${attr("data-align", m.align)}${attr("data-size", m.size)}${xAttr(m.extra)}>${linked}${cap}</figure>`;
@@ -260,7 +329,29 @@ function renderStatic(kind, model) {
260
329
  }
261
330
  case "embed": {
262
331
  const m = model;
263
- return `<figure data-rt="embed"${attr("data-url", m.url)}${attr("data-title", m.title)}${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>`;
264
355
  }
265
356
  case "file": {
266
357
  const m = model;
@@ -734,8 +825,11 @@ function parseIsland(kind, el) {
734
825
  const img = el.querySelector("img");
735
826
  const a = img?.parentElement?.tagName === "A" ? img.parentElement : null;
736
827
  const cap = el.querySelector(":scope > figcaption");
737
- const m = { src: img?.getAttribute("src") ?? "" };
828
+ const frame = readImageFrame(img);
829
+ const m = { src: frame.src };
738
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;
739
833
  if (cap) m.caption = (cap.textContent ?? "").replace(/\u200b/g, "");
740
834
  const align = oneOf(IMAGE_ALIGNS, attrOf(el, "data-align"));
741
835
  const size = oneOf(IMAGE_SIZES, attrOf(el, "data-size"));
@@ -809,9 +903,75 @@ function parseIsland(kind, el) {
809
903
  case "embed": {
810
904
  const m = {};
811
905
  const url = attrOf(el, "data-url");
812
- const title = attrOf(el, "data-title");
906
+ const title = attrOf(el, "data-title") ?? attrOf(el, "aria-label");
907
+ const aspect = attrOf(el, "data-aspect");
813
908
  if (url !== void 0) m.url = url;
814
909
  if (title !== void 0) m.title = title;
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;
815
975
  const extra = attrOf(el, "data-extra");
816
976
  if (extra) m.extra = extra;
817
977
  return m;
@@ -925,6 +1085,7 @@ function serialize(root) {
925
1085
  c.replaceWith(tpl.content);
926
1086
  });
927
1087
  clone.querySelectorAll("[data-hint]").forEach((n) => n.removeAttribute("data-hint"));
1088
+ clone.querySelectorAll("ul[data-task] > li").forEach((li) => (li.removeAttribute("role"), li.removeAttribute("aria-checked")));
928
1089
  while (clone.children.length > 1 && clone.lastElementChild && isEmptyP(clone.lastElementChild)) clone.lastElementChild.remove();
929
1090
  const html = clone.innerHTML.replace(/​/g, "");
930
1091
  return html === "<p><br></p>" || html === "<p></p>" ? "" : html;
@@ -1014,6 +1175,6 @@ function rangeRect(r, fallback) {
1014
1175
  }
1015
1176
  var isEmptyHtml = (html) => !html.replace(/<(?!img|hr|figure|table|details|div data-rt)[^>]*>/g, "").replace(/&nbsp;/g, "").trim();
1016
1177
  //#endregion
1017
- 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 };
1018
1179
 
1019
1180
  //# sourceMappingURL=dom.js.map