@bettercms-ai/types 1.38.0 → 1.40.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.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) {
@@ -297,7 +377,8 @@ function splitButtonStyle(style) {
297
377
  paint: Object.keys(paint).length ? paint : void 0
298
378
  };
299
379
  }
300
- var FIELD_STYLE_KEYS = ["contentWidth", "contentAlign", "marginTop", "marginBottom", "align", "fontSize", "weight"];
380
+ var FIELD_STYLE_KEYS = ["contentWidth", "contentAlign", "marginTop", "marginBottom", "align", "fontSize", "weight", "size"];
381
+ var FIELD_SIZE_ZOOM = { sm: "0.875", lg: "1.125" };
301
382
  var FIELD_KEY_SET = new Set(FIELD_STYLE_KEYS);
302
383
  function pickFieldStyle(style) {
303
384
  const out = {};
@@ -309,6 +390,8 @@ function fieldStyleToCss(style) {
309
390
  const picked = pickFieldStyle(style);
310
391
  const css = { ...blockStyleToCss(picked) };
311
392
  Object.assign(css, blockStyleToColumnCss(picked));
393
+ const zoom = own(FIELD_SIZE_ZOOM, picked.size);
394
+ if (zoom) css.zoom = zoom;
312
395
  return Object.keys(css).length ? css : void 0;
313
396
  }
314
397
  function blockStyleToColumnCss(style) {
@@ -346,6 +429,14 @@ var COMPONENT_PROP_TYPES = [
346
429
  "icon",
347
430
  "multiselect"
348
431
  ];
432
+ var SLOT_MAX_ITEMS = 12;
433
+ var SLOT_ITEMS_CAP = 50;
434
+ function slotItems(value) {
435
+ const list = Array.isArray(value) ? value : [value];
436
+ return list.filter(
437
+ (item) => !!item && typeof item === "object" && !Array.isArray(item) && typeof item.componentId === "string" && item.componentId !== ""
438
+ );
439
+ }
349
440
 
350
441
  // src/layout-lucide-icons.ts
351
442
  var LAYOUT_SECTION_ICONS = Object.freeze([
@@ -2313,6 +2404,36 @@ var LAYOUT_SECTION_ICON_SET = new Set(LAYOUT_SECTION_ICONS);
2313
2404
  var PAGE_CONTENT_ANCHOR_ID = "page-content";
2314
2405
  var NAVIGATION_SECTION_ID = "navigation";
2315
2406
  var FOOTER_SECTION_ID = "footer";
2407
+ function visibleLayoutStructure(structure, now) {
2408
+ const sections = structure?.sections;
2409
+ if (!Array.isArray(sections)) return structure;
2410
+ const hidden = new Set(
2411
+ sections.filter((section) => section && !section.variantOf && !inWindow(section, now)).map((section) => section.id)
2412
+ );
2413
+ if (hidden.size === 0) return structure;
2414
+ return {
2415
+ ...structure,
2416
+ sections: sections.filter((section) => !hidden.has(section?.variantOf ?? section?.id))
2417
+ };
2418
+ }
2419
+ function visibleDeliveredLayout(layout2, now) {
2420
+ if (!layout2) return layout2;
2421
+ const hiddenIds = /* @__PURE__ */ new Set();
2422
+ const hiddenSlugs = /* @__PURE__ */ new Set();
2423
+ for (const node of layout2.nodes) {
2424
+ if (node.kind !== "section" || inWindow(layout2.sections[node.slug], now)) continue;
2425
+ hiddenIds.add(node.id);
2426
+ hiddenSlugs.add(node.slug);
2427
+ }
2428
+ if (hiddenIds.size === 0) return layout2;
2429
+ return {
2430
+ ...layout2,
2431
+ nodes: layout2.nodes.filter((node) => node.kind !== "section" || !hiddenIds.has(node.id)),
2432
+ sections: Object.fromEntries(
2433
+ Object.entries(layout2.sections).filter(([slug, section]) => !hiddenSlugs.has(slug) && !(section.variantOf && hiddenIds.has(section.variantOf)))
2434
+ )
2435
+ };
2436
+ }
2316
2437
 
2317
2438
  // src/dock-icon-names.ts
2318
2439
  var DOCK_ICON_NAMES = [
@@ -2973,6 +3094,7 @@ function regionOf(regions, el) {
2973
3094
  }
2974
3095
  export {
2975
3096
  BLOCK_BINDINGS,
3097
+ BREAKPOINTS,
2976
3098
  BUTTON_ICONS,
2977
3099
  BUTTON_ICON_NAMES,
2978
3100
  BUTTON_LOOK_KEYS,
@@ -2984,6 +3106,7 @@ export {
2984
3106
  DOCK_BUDGET,
2985
3107
  DOCK_ICON_NAMES,
2986
3108
  DOCK_ICON_NAME_SET,
3109
+ FIELD_SIZE_ZOOM,
2987
3110
  FIELD_STYLE_KEYS,
2988
3111
  FOOTER_SECTION_ID,
2989
3112
  LANDMARK_SELECTOR,
@@ -2993,8 +3116,11 @@ export {
2993
3116
  MAIN_SELECTOR,
2994
3117
  NAVIGATION_SECTION_ID,
2995
3118
  PAGE_CONTENT_ANCHOR_ID,
3119
+ RESPONSIVE_CSS,
2996
3120
  SECTION_DOCTRINE,
2997
3121
  SECTION_SPACE_TOKENS,
3122
+ SLOT_ITEMS_CAP,
3123
+ SLOT_MAX_ITEMS,
2998
3124
  SPACE_BOTTOM_TOKENS,
2999
3125
  SPACE_STEP_TOKENS,
3000
3126
  anchorTargetRel,
@@ -3020,19 +3146,28 @@ export {
3020
3146
  formatPropsAttribute,
3021
3147
  getBlockType,
3022
3148
  headingPaintCss,
3149
+ hideOnAttr,
3150
+ inWindow,
3023
3151
  isBlock,
3024
3152
  isChromeLandmark,
3025
3153
  keyWords,
3026
3154
  landmarkRegions,
3027
3155
  locatorFor,
3156
+ normalizeWindow,
3028
3157
  parsePropsAttribute,
3029
3158
  pickFieldStyle,
3030
3159
  readButtonValue,
3031
3160
  readPath,
3032
3161
  regionOf,
3033
3162
  safeCssUrl,
3163
+ slotItems,
3034
3164
  spaceTokenCss,
3035
3165
  splitButtonStyle,
3166
+ usesHideOn,
3167
+ visibleBlocks,
3168
+ visibleDeliveredLayout,
3169
+ visibleLayoutStructure,
3170
+ windowState,
3036
3171
  withButtonLookProps
3037
3172
  };
3038
3173
  //# sourceMappingURL=index.js.map