@bettercms-ai/ui 0.6.1 → 0.7.0
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/README.md +0 -0
- package/dist/blocks.js +109 -1
- package/dist/blocks.js.map +1 -1
- package/dist/index.js +109 -1
- package/dist/index.js.map +1 -1
- package/dist/registry.js +109 -1
- package/dist/registry.js.map +1 -1
- package/dist/renderer.js +109 -1
- package/dist/renderer.js.map +1 -1
- package/package.json +2 -2
package/dist/renderer.js
CHANGED
|
@@ -47,7 +47,13 @@ var PT_TYPES = {
|
|
|
47
47
|
*/
|
|
48
48
|
table: "table",
|
|
49
49
|
/** The annotation carrying a hyperlink's `href`. Spelled `link` because that is the spec's convention. */
|
|
50
|
-
link: "link"
|
|
50
|
+
link: "link",
|
|
51
|
+
/**
|
|
52
|
+
* The annotation carrying a site's OWN inline markup — `<span class>`, `<small>`, `<time
|
|
53
|
+
* datetime>`. Unprefixed, like `table`, because it describes HTML rather than a BetterCMS
|
|
54
|
+
* concept. See `styled.ts` for what it may hold and why the list is that short.
|
|
55
|
+
*/
|
|
56
|
+
styled: "styled"
|
|
51
57
|
};
|
|
52
58
|
var BUILTIN_TABLE_KEY = "builtin:table";
|
|
53
59
|
var STORABLE_BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -59,6 +65,66 @@ var STORABLE_BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
|
59
65
|
PT_TYPES.mention
|
|
60
66
|
]);
|
|
61
67
|
|
|
68
|
+
// ../richtext/src/styled.ts
|
|
69
|
+
var STYLED_TAGS = ["span", "small", "sup", "sub", "kbd", "abbr", "time"];
|
|
70
|
+
var TAG_SET = new Set(STYLED_TAGS);
|
|
71
|
+
var isStyledTag = (tag) => typeof tag === "string" && TAG_SET.has(tag);
|
|
72
|
+
var ATTR_NAMES = /* @__PURE__ */ new Set(["title", "datetime", "style", "aria-label"]);
|
|
73
|
+
var DATA_ATTR = /^data-[a-z][a-z0-9-]*$/;
|
|
74
|
+
var isStyledAttr = (name) => ATTR_NAMES.has(name) || DATA_ATTR.test(name) && !name.startsWith("data-bcms-");
|
|
75
|
+
var STYLE_PROPS = /* @__PURE__ */ new Set([
|
|
76
|
+
"color",
|
|
77
|
+
"background-color",
|
|
78
|
+
"opacity",
|
|
79
|
+
"font",
|
|
80
|
+
"font-family",
|
|
81
|
+
"font-size",
|
|
82
|
+
"font-style",
|
|
83
|
+
"font-weight",
|
|
84
|
+
"font-variant",
|
|
85
|
+
"font-feature-settings",
|
|
86
|
+
"font-variation-settings",
|
|
87
|
+
"letter-spacing",
|
|
88
|
+
"line-height",
|
|
89
|
+
"word-spacing",
|
|
90
|
+
"white-space",
|
|
91
|
+
"word-break",
|
|
92
|
+
"text-align",
|
|
93
|
+
"text-decoration",
|
|
94
|
+
"text-decoration-color",
|
|
95
|
+
"text-decoration-line",
|
|
96
|
+
"text-decoration-style",
|
|
97
|
+
"text-transform",
|
|
98
|
+
"text-underline-offset",
|
|
99
|
+
"vertical-align"
|
|
100
|
+
]);
|
|
101
|
+
var STYLE_VALUE_BAN = /url\(|expression\(|@import|\\|\/\*|[<>]/i;
|
|
102
|
+
function safeStyle(css) {
|
|
103
|
+
const kept = [];
|
|
104
|
+
for (const declaration of css.split(";")) {
|
|
105
|
+
const at = declaration.indexOf(":");
|
|
106
|
+
if (at < 0) continue;
|
|
107
|
+
const name = declaration.slice(0, at).trim().toLowerCase();
|
|
108
|
+
const value = declaration.slice(at + 1).trim();
|
|
109
|
+
if (!name || !value) continue;
|
|
110
|
+
if (!name.startsWith("--") && !STYLE_PROPS.has(name)) continue;
|
|
111
|
+
if (STYLE_VALUE_BAN.test(value)) continue;
|
|
112
|
+
kept.push(`${name}:${value}`);
|
|
113
|
+
}
|
|
114
|
+
return kept.length ? kept.join(";") : void 0;
|
|
115
|
+
}
|
|
116
|
+
function styledAttrEntries(attrs) {
|
|
117
|
+
if (!attrs || typeof attrs !== "object" || Array.isArray(attrs)) return [];
|
|
118
|
+
const out = [];
|
|
119
|
+
for (const [name, raw] of Object.entries(attrs)) {
|
|
120
|
+
if (!isStyledAttr(name) || typeof raw !== "string") continue;
|
|
121
|
+
const value = name === "style" ? safeStyle(raw) : raw;
|
|
122
|
+
if (value === void 0) continue;
|
|
123
|
+
out.push([name, value]);
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
|
|
62
128
|
// ../richtext/src/href.ts
|
|
63
129
|
var SAFE_HREF_SCHEMES = ["http:", "https:", "mailto:", "tel:"];
|
|
64
130
|
function safeHref(raw) {
|
|
@@ -233,6 +299,18 @@ function readStructuredContent(props) {
|
|
|
233
299
|
// src/blocks/portableText.tsx
|
|
234
300
|
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
235
301
|
var TOKEN = /^[a-z0-9-]+$/i;
|
|
302
|
+
function styleObject(css) {
|
|
303
|
+
const out = {};
|
|
304
|
+
for (const declaration of css.split(";")) {
|
|
305
|
+
const at = declaration.indexOf(":");
|
|
306
|
+
if (at < 0) continue;
|
|
307
|
+
const name = declaration.slice(0, at).trim();
|
|
308
|
+
const value = declaration.slice(at + 1).trim();
|
|
309
|
+
if (!name || !value) continue;
|
|
310
|
+
out[name.startsWith("--") ? name : name.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = value;
|
|
311
|
+
}
|
|
312
|
+
return out;
|
|
313
|
+
}
|
|
236
314
|
function Bound({
|
|
237
315
|
base,
|
|
238
316
|
nodeKey,
|
|
@@ -303,6 +381,36 @@ function buildComponents() {
|
|
|
303
381
|
const blank = v.target === "_blank";
|
|
304
382
|
return /* @__PURE__ */ jsx2("a", { href, ...blank ? { target: "_blank", rel: "noopener noreferrer" } : {}, children });
|
|
305
383
|
},
|
|
384
|
+
/**
|
|
385
|
+
* The site's own inline markup, rendered as itself — the React half of
|
|
386
|
+
* `portableTextToHtml`'s `styled` mark, and it has to stay the same shape: Astro and the
|
|
387
|
+
* editor canvas render through that serialiser while a Next site renders through this
|
|
388
|
+
* one, and two renderers of one value that disagree is the whole bug class.
|
|
389
|
+
*
|
|
390
|
+
* The tag is re-checked against `STYLED_TAGS` and the attribute bag re-filtered, because
|
|
391
|
+
* a markDef is DATA and arrives from imports, the Management API and AI writes. React
|
|
392
|
+
* escapes the values it writes; the allowlist is what keeps a `href` or an `onClick` out
|
|
393
|
+
* of the props entirely. An unrecognised tag renders its CHILDREN — the words are the
|
|
394
|
+
* author's, the wrapper is only the design.
|
|
395
|
+
*/
|
|
396
|
+
[PT_TYPES.styled]: ({ value, children }) => {
|
|
397
|
+
const v = value ?? {};
|
|
398
|
+
const tag = typeof v.tag === "string" ? v.tag.toLowerCase() : "";
|
|
399
|
+
if (!isStyledTag(tag)) return /* @__PURE__ */ jsx2(Fragment, { children });
|
|
400
|
+
const Tag = tag;
|
|
401
|
+
const className = typeof v.className === "string" && v.className ? v.className : void 0;
|
|
402
|
+
const attrs = styledAttrEntries(v.attrs);
|
|
403
|
+
const style = attrs.find(([name]) => name === "style")?.[1];
|
|
404
|
+
return /* @__PURE__ */ jsx2(
|
|
405
|
+
Tag,
|
|
406
|
+
{
|
|
407
|
+
className,
|
|
408
|
+
...Object.fromEntries(attrs.filter(([name]) => name !== "style")),
|
|
409
|
+
...style ? { style: styleObject(style) } : {},
|
|
410
|
+
children
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
},
|
|
306
414
|
highlight: ({ children }) => /* @__PURE__ */ jsx2("mark", { children }),
|
|
307
415
|
"strike-through": ({ children }) => /* @__PURE__ */ jsx2("s", { children }),
|
|
308
416
|
/**
|