@bettercms-ai/types 1.37.0 → 1.39.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/dist/index.d.ts +270 -10
- package/dist/index.js +166 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,67 @@
|
|
|
1
1
|
// src/block.ts
|
|
2
|
+
var WINDOW_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/;
|
|
3
|
+
function normalizeWindow(value) {
|
|
4
|
+
if (value == null) return { window: null };
|
|
5
|
+
if (typeof value !== "object" || Array.isArray(value)) return { error: "invalid_window" };
|
|
6
|
+
const out = {};
|
|
7
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
8
|
+
if (key !== "from" && key !== "until") return { error: "invalid_window" };
|
|
9
|
+
if (raw == null) continue;
|
|
10
|
+
const at = typeof raw === "string" && WINDOW_INSTANT.test(raw) ? Date.parse(raw) : NaN;
|
|
11
|
+
const day = Number(String(raw).slice(8, 10));
|
|
12
|
+
if (Number.isNaN(at) || new Date(Date.UTC(Number(String(raw).slice(0, 4)), Number(String(raw).slice(5, 7)) - 1, day)).getUTCDate() !== day) {
|
|
13
|
+
return { error: "invalid_window" };
|
|
14
|
+
}
|
|
15
|
+
out[key] = `${new Date(at).toISOString().slice(0, 19)}Z`;
|
|
16
|
+
}
|
|
17
|
+
if (out.from && out.until && out.from >= out.until) return { error: "window_inverted" };
|
|
18
|
+
return { window: out.from || out.until ? out : null };
|
|
19
|
+
}
|
|
20
|
+
function windowState(item, now) {
|
|
21
|
+
const w = item && typeof item === "object" ? item.window : void 0;
|
|
22
|
+
if (!w || typeof w !== "object") return "live";
|
|
23
|
+
const at = typeof now === "number" ? now : now.getTime();
|
|
24
|
+
const { from, until } = w;
|
|
25
|
+
const start = typeof from === "string" ? Date.parse(from) : NaN;
|
|
26
|
+
const end = typeof until === "string" ? Date.parse(until) : NaN;
|
|
27
|
+
if (!Number.isNaN(end) && at >= end) return "expired";
|
|
28
|
+
if (!Number.isNaN(start) && at < start) return "pending";
|
|
29
|
+
return "live";
|
|
30
|
+
}
|
|
31
|
+
var inWindow = (item, now) => windowState(item, now) === "live";
|
|
32
|
+
function mapSame(list, fn) {
|
|
33
|
+
let changed = false;
|
|
34
|
+
const out = list.map((item) => {
|
|
35
|
+
const next = fn(item);
|
|
36
|
+
if (next !== item) changed = true;
|
|
37
|
+
return next;
|
|
38
|
+
});
|
|
39
|
+
return changed ? out : list;
|
|
40
|
+
}
|
|
41
|
+
function withVisibleChildren(block, now) {
|
|
42
|
+
const p = block.props ?? {};
|
|
43
|
+
const key = block.type === "section" ? "children" : block.type === "columns" ? "columns" : block.type === "slider" ? "slides" : block.type === "tabs" ? "tabs" : null;
|
|
44
|
+
if (!key || !Array.isArray(p[key])) return block;
|
|
45
|
+
const held = p[key];
|
|
46
|
+
const next = key === "children" ? visibleBlocks(held, now) : key === "columns" ? mapSame(held, (column) => visibleBlocks(column, now)) : (
|
|
47
|
+
// A slide or a tab panel: `{ id, children }`.
|
|
48
|
+
mapSame(held, (row) => {
|
|
49
|
+
const children = row?.children;
|
|
50
|
+
const shown = visibleBlocks(children, now);
|
|
51
|
+
return shown === children ? row : { ...row, children: shown };
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
return next === held ? block : { ...block, props: { ...p, [key]: next } };
|
|
55
|
+
}
|
|
56
|
+
function visibleBlocks(blocks, now) {
|
|
57
|
+
if (!Array.isArray(blocks)) return blocks;
|
|
58
|
+
const shown = blocks.filter((block) => inWindow(block, now));
|
|
59
|
+
const pruned = mapSame(
|
|
60
|
+
shown,
|
|
61
|
+
(block) => block && typeof block === "object" ? withVisibleChildren(block, now) : block
|
|
62
|
+
);
|
|
63
|
+
return shown.length === blocks.length && pruned === shown ? blocks : pruned;
|
|
64
|
+
}
|
|
2
65
|
function isBlock(value) {
|
|
3
66
|
return typeof value === "object" && value !== null && "type" in value && typeof value["type"] === "string";
|
|
4
67
|
}
|
|
@@ -164,6 +227,22 @@ var SHADOW_CSS = {
|
|
|
164
227
|
};
|
|
165
228
|
var HAIRLINE = "1px solid rgba(0,0,0,.10)";
|
|
166
229
|
var CONTENT_WIDTH_PX = { narrow: "640px", default: "1024px", wide: "1280px" };
|
|
230
|
+
var BREAKPOINTS = { mobile: 767, tablet: 1023 };
|
|
231
|
+
var RESPONSIVE_CSS = `@media(max-width:${BREAKPOINTS.mobile}px){[data-bcms-hide~="mobile"]{display:none!important}}@media(min-width:${BREAKPOINTS.mobile + 1}px) and (max-width:${BREAKPOINTS.tablet}px){[data-bcms-hide~="tablet"]{display:none!important}}@media(min-width:${BREAKPOINTS.tablet + 1}px){[data-bcms-hide~="desktop"]{display:none!important}}`;
|
|
232
|
+
function hideOnAttr(style) {
|
|
233
|
+
const raw = style && typeof style === "object" ? style.hideOn : void 0;
|
|
234
|
+
if (!Array.isArray(raw)) return "";
|
|
235
|
+
const on = ["mobile", "tablet", "desktop"].filter((b) => raw.includes(b));
|
|
236
|
+
return on.length === 3 ? "" : on.join(" ");
|
|
237
|
+
}
|
|
238
|
+
function usesHideOn(blocks) {
|
|
239
|
+
let found = false;
|
|
240
|
+
JSON.stringify(blocks ?? null, (k, v) => {
|
|
241
|
+
if (k === "hideOn" && hideOnAttr({ hideOn: v })) found = true;
|
|
242
|
+
return v;
|
|
243
|
+
});
|
|
244
|
+
return found;
|
|
245
|
+
}
|
|
167
246
|
var HEX = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
168
247
|
var clamp = (n, lo, hi) => Math.min(hi, Math.max(lo, n));
|
|
169
248
|
var own = (map, key) => typeof key === "string" && Object.prototype.hasOwnProperty.call(map, key) ? map[key] : void 0;
|
|
@@ -276,7 +355,8 @@ var BUTTON_PLACEMENT_KEYS = [
|
|
|
276
355
|
"marginBottom",
|
|
277
356
|
"fullHeight",
|
|
278
357
|
"spaceTop",
|
|
279
|
-
"spaceBottom"
|
|
358
|
+
"spaceBottom",
|
|
359
|
+
"hideOn"
|
|
280
360
|
];
|
|
281
361
|
var PLACEMENT = new Set(BUTTON_PLACEMENT_KEYS);
|
|
282
362
|
function splitButtonStyle(style) {
|
|
@@ -335,8 +415,25 @@ var COMPONENT_PROP_TYPES = [
|
|
|
335
415
|
"group",
|
|
336
416
|
"table",
|
|
337
417
|
"slot",
|
|
338
|
-
"form"
|
|
418
|
+
"form",
|
|
419
|
+
// The seven below each store what the same-named content-model FIELD stores (`icon` and
|
|
420
|
+
// `multiselect` have no field twin; see the value notes on ComponentPropDef.type).
|
|
421
|
+
"link",
|
|
422
|
+
"button",
|
|
423
|
+
"date",
|
|
424
|
+
"color",
|
|
425
|
+
"file",
|
|
426
|
+
"icon",
|
|
427
|
+
"multiselect"
|
|
339
428
|
];
|
|
429
|
+
var SLOT_MAX_ITEMS = 12;
|
|
430
|
+
var SLOT_ITEMS_CAP = 50;
|
|
431
|
+
function slotItems(value) {
|
|
432
|
+
const list = Array.isArray(value) ? value : [value];
|
|
433
|
+
return list.filter(
|
|
434
|
+
(item) => !!item && typeof item === "object" && !Array.isArray(item) && typeof item.componentId === "string" && item.componentId !== ""
|
|
435
|
+
);
|
|
436
|
+
}
|
|
340
437
|
|
|
341
438
|
// src/layout-lucide-icons.ts
|
|
342
439
|
var LAYOUT_SECTION_ICONS = Object.freeze([
|
|
@@ -2304,6 +2401,36 @@ var LAYOUT_SECTION_ICON_SET = new Set(LAYOUT_SECTION_ICONS);
|
|
|
2304
2401
|
var PAGE_CONTENT_ANCHOR_ID = "page-content";
|
|
2305
2402
|
var NAVIGATION_SECTION_ID = "navigation";
|
|
2306
2403
|
var FOOTER_SECTION_ID = "footer";
|
|
2404
|
+
function visibleLayoutStructure(structure, now) {
|
|
2405
|
+
const sections = structure?.sections;
|
|
2406
|
+
if (!Array.isArray(sections)) return structure;
|
|
2407
|
+
const hidden = new Set(
|
|
2408
|
+
sections.filter((section) => section && !section.variantOf && !inWindow(section, now)).map((section) => section.id)
|
|
2409
|
+
);
|
|
2410
|
+
if (hidden.size === 0) return structure;
|
|
2411
|
+
return {
|
|
2412
|
+
...structure,
|
|
2413
|
+
sections: sections.filter((section) => !hidden.has(section?.variantOf ?? section?.id))
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
function visibleDeliveredLayout(layout2, now) {
|
|
2417
|
+
if (!layout2) return layout2;
|
|
2418
|
+
const hiddenIds = /* @__PURE__ */ new Set();
|
|
2419
|
+
const hiddenSlugs = /* @__PURE__ */ new Set();
|
|
2420
|
+
for (const node of layout2.nodes) {
|
|
2421
|
+
if (node.kind !== "section" || inWindow(layout2.sections[node.slug], now)) continue;
|
|
2422
|
+
hiddenIds.add(node.id);
|
|
2423
|
+
hiddenSlugs.add(node.slug);
|
|
2424
|
+
}
|
|
2425
|
+
if (hiddenIds.size === 0) return layout2;
|
|
2426
|
+
return {
|
|
2427
|
+
...layout2,
|
|
2428
|
+
nodes: layout2.nodes.filter((node) => node.kind !== "section" || !hiddenIds.has(node.id)),
|
|
2429
|
+
sections: Object.fromEntries(
|
|
2430
|
+
Object.entries(layout2.sections).filter(([slug, section]) => !hiddenSlugs.has(slug) && !(section.variantOf && hiddenIds.has(section.variantOf)))
|
|
2431
|
+
)
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2307
2434
|
|
|
2308
2435
|
// src/dock-icon-names.ts
|
|
2309
2436
|
var DOCK_ICON_NAMES = [
|
|
@@ -2810,6 +2937,11 @@ function buttonIconSvg(name, cls) {
|
|
|
2810
2937
|
return iconSvg(name, cls);
|
|
2811
2938
|
}
|
|
2812
2939
|
var BUTTON_SIZES = ["sm", "md", "lg"];
|
|
2940
|
+
var LINK_RELS = ["nofollow", "sponsored", "ugc"];
|
|
2941
|
+
function anchorTargetRel(newTab, rel) {
|
|
2942
|
+
const tokens = [...newTab ? ["noopener", "noreferrer"] : [], ...LINK_RELS.includes(rel) ? [rel] : []];
|
|
2943
|
+
return `${newTab ? ' target="_blank"' : ""}${tokens.length ? ` rel="${tokens.join(" ")}"` : ""}`;
|
|
2944
|
+
}
|
|
2813
2945
|
var hrefOf = (href) => typeof href === "string" ? href : href && typeof href === "object" && typeof href.href === "string" ? href.href : null;
|
|
2814
2946
|
function readButtonValue(value) {
|
|
2815
2947
|
const v = value && typeof value === "object" ? value : {};
|
|
@@ -2820,7 +2952,8 @@ function readButtonValue(value) {
|
|
|
2820
2952
|
size: BUTTON_SIZES.includes(v.size) ? v.size : "md",
|
|
2821
2953
|
arrow: v.arrow === true,
|
|
2822
2954
|
icon: buttonIconOf(v.icon),
|
|
2823
|
-
newTab: v.newTab === true
|
|
2955
|
+
newTab: v.newTab === true,
|
|
2956
|
+
...LINK_RELS.includes(v.rel) ? { rel: v.rel } : {}
|
|
2824
2957
|
};
|
|
2825
2958
|
}
|
|
2826
2959
|
function buttonValueProblem(value) {
|
|
@@ -2832,10 +2965,21 @@ function buttonValueProblem(value) {
|
|
|
2832
2965
|
if (v.size !== void 0 && !BUTTON_SIZES.includes(v.size)) return `has an unknown size "${String(v.size)}"`;
|
|
2833
2966
|
if (v.arrow !== void 0 && typeof v.arrow !== "boolean") return "arrow must be true or false";
|
|
2834
2967
|
if (v.newTab !== void 0 && typeof v.newTab !== "boolean") return "newTab must be true or false";
|
|
2968
|
+
if (v.rel !== void 0 && !LINK_RELS.includes(v.rel)) return `has an unknown rel "${String(v.rel)}" (nofollow, sponsored or ugc)`;
|
|
2835
2969
|
if (v.icon !== void 0 && v.icon !== null && buttonIconOf(v.icon) === null) return `has an unknown icon "${String(v.icon)}"`;
|
|
2836
2970
|
return null;
|
|
2837
2971
|
}
|
|
2838
2972
|
var BUTTON_LOOK_KEYS = ["variant", "size", "arrow", "icon", "newTab"];
|
|
2973
|
+
function buttonBlockProps(value) {
|
|
2974
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2975
|
+
const v = value;
|
|
2976
|
+
const out = {};
|
|
2977
|
+
if (typeof v.label === "string") out.text = v.label;
|
|
2978
|
+
const href = hrefOf(v.href);
|
|
2979
|
+
if (href !== null) out.href = href;
|
|
2980
|
+
for (const key of BUTTON_LOOK_KEYS) if (key in v) out[key] = v[key];
|
|
2981
|
+
return out;
|
|
2982
|
+
}
|
|
2839
2983
|
function soleButtonId(blockJson) {
|
|
2840
2984
|
const ids = [];
|
|
2841
2985
|
const walk = (list) => {
|
|
@@ -2878,8 +3022,9 @@ function buttonValueOfInstance(def, overrides) {
|
|
|
2878
3022
|
walk(def.blockJson);
|
|
2879
3023
|
const props = { ...found[0]?.props ?? {} };
|
|
2880
3024
|
for (const p of withButtonLookProps(def)) {
|
|
2881
|
-
if (p.target.blockId !== blockId || !
|
|
2882
|
-
|
|
3025
|
+
if (p.target.blockId !== blockId || !overrides || !(p.key in overrides)) continue;
|
|
3026
|
+
if (p.type === "button") Object.assign(props, buttonBlockProps(overrides[p.key]));
|
|
3027
|
+
else if (p.target.path.startsWith("props.")) props[p.target.path.slice("props.".length)] = overrides[p.key];
|
|
2883
3028
|
}
|
|
2884
3029
|
return readButtonValue({ ...props, label: props.text });
|
|
2885
3030
|
}
|
|
@@ -2946,6 +3091,7 @@ function regionOf(regions, el) {
|
|
|
2946
3091
|
}
|
|
2947
3092
|
export {
|
|
2948
3093
|
BLOCK_BINDINGS,
|
|
3094
|
+
BREAKPOINTS,
|
|
2949
3095
|
BUTTON_ICONS,
|
|
2950
3096
|
BUTTON_ICON_NAMES,
|
|
2951
3097
|
BUTTON_LOOK_KEYS,
|
|
@@ -2962,16 +3108,22 @@ export {
|
|
|
2962
3108
|
LANDMARK_SELECTOR,
|
|
2963
3109
|
LAYOUT_SECTION_ICONS,
|
|
2964
3110
|
LAYOUT_SECTION_ICON_SET,
|
|
3111
|
+
LINK_RELS,
|
|
2965
3112
|
MAIN_SELECTOR,
|
|
2966
3113
|
NAVIGATION_SECTION_ID,
|
|
2967
3114
|
PAGE_CONTENT_ANCHOR_ID,
|
|
3115
|
+
RESPONSIVE_CSS,
|
|
2968
3116
|
SECTION_DOCTRINE,
|
|
2969
3117
|
SECTION_SPACE_TOKENS,
|
|
3118
|
+
SLOT_ITEMS_CAP,
|
|
3119
|
+
SLOT_MAX_ITEMS,
|
|
2970
3120
|
SPACE_BOTTOM_TOKENS,
|
|
2971
3121
|
SPACE_STEP_TOKENS,
|
|
3122
|
+
anchorTargetRel,
|
|
2972
3123
|
blockStyleToColumnCss,
|
|
2973
3124
|
blockStyleToCss,
|
|
2974
3125
|
blockStyleToInnerCss,
|
|
3126
|
+
buttonBlockProps,
|
|
2975
3127
|
buttonIconOf,
|
|
2976
3128
|
buttonIconSvg,
|
|
2977
3129
|
buttonLinkPairs,
|
|
@@ -2990,19 +3142,28 @@ export {
|
|
|
2990
3142
|
formatPropsAttribute,
|
|
2991
3143
|
getBlockType,
|
|
2992
3144
|
headingPaintCss,
|
|
3145
|
+
hideOnAttr,
|
|
3146
|
+
inWindow,
|
|
2993
3147
|
isBlock,
|
|
2994
3148
|
isChromeLandmark,
|
|
2995
3149
|
keyWords,
|
|
2996
3150
|
landmarkRegions,
|
|
2997
3151
|
locatorFor,
|
|
3152
|
+
normalizeWindow,
|
|
2998
3153
|
parsePropsAttribute,
|
|
2999
3154
|
pickFieldStyle,
|
|
3000
3155
|
readButtonValue,
|
|
3001
3156
|
readPath,
|
|
3002
3157
|
regionOf,
|
|
3003
3158
|
safeCssUrl,
|
|
3159
|
+
slotItems,
|
|
3004
3160
|
spaceTokenCss,
|
|
3005
3161
|
splitButtonStyle,
|
|
3162
|
+
usesHideOn,
|
|
3163
|
+
visibleBlocks,
|
|
3164
|
+
visibleDeliveredLayout,
|
|
3165
|
+
visibleLayoutStructure,
|
|
3166
|
+
windowState,
|
|
3006
3167
|
withButtonLookProps
|
|
3007
3168
|
};
|
|
3008
3169
|
//# sourceMappingURL=index.js.map
|