@ohhwells/bridge 0.1.158 → 0.1.159

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.cjs CHANGED
@@ -220,6 +220,56 @@ function isRenderableTree(value) {
220
220
  return AI_TREE_SCHEMA_VERSIONS.includes(tree.schemaVersion) && tree.type === "section" && Array.isArray(tree.rows);
221
221
  }
222
222
 
223
+ // src/lib/headline-size.ts
224
+ var HEADLINE_SIZE_MULTIPLIERS = {
225
+ xs: 0.7,
226
+ sm: 0.85,
227
+ base: 1,
228
+ lg: 1.2,
229
+ xl: 1.45,
230
+ "2xl": 1.75
231
+ };
232
+ var HEADLINE_SIZE_ATTR = "data-ohw-style-headlinesize";
233
+ var PREV_ATTR = "data-ohw-style-prev-fsmul";
234
+ var NODE_FONT_SIZE_ATTR = "data-ohw-style-prev-font-size";
235
+ function headingsIn(section) {
236
+ return Array.from(section.querySelectorAll("h1, h2, h3"));
237
+ }
238
+ function clearHeadlineSizes(root = document) {
239
+ for (const el of Array.from(root.querySelectorAll(`[${PREV_ATTR}]`))) {
240
+ const prev = el.getAttribute(PREV_ATTR) ?? "";
241
+ if (prev) el.style.setProperty("font-size", prev);
242
+ else el.style.removeProperty("font-size");
243
+ el.removeAttribute(PREV_ATTR);
244
+ }
245
+ }
246
+ function applyHeadlineSizes(root = document) {
247
+ clearHeadlineSizes(root);
248
+ for (const section of Array.from(
249
+ root.querySelectorAll(`[${HEADLINE_SIZE_ATTR}]`)
250
+ )) {
251
+ const multiplier = HEADLINE_SIZE_MULTIPLIERS[section.getAttribute(HEADLINE_SIZE_ATTR) ?? ""];
252
+ if (!multiplier || multiplier === 1) continue;
253
+ for (const heading of headingsIn(section)) {
254
+ if (heading.hasAttribute(NODE_FONT_SIZE_ATTR)) continue;
255
+ const base = Number.parseFloat(window.getComputedStyle(heading).fontSize);
256
+ if (!Number.isFinite(base) || base <= 0) continue;
257
+ heading.setAttribute(PREV_ATTR, heading.style.getPropertyValue("font-size"));
258
+ heading.style.setProperty("font-size", `${Math.round(base * multiplier * 100) / 100}px`, "important");
259
+ }
260
+ }
261
+ }
262
+ var resizeInstalled = false;
263
+ function installHeadlineSizeResize() {
264
+ if (resizeInstalled || typeof window === "undefined") return;
265
+ resizeInstalled = true;
266
+ let timer;
267
+ window.addEventListener("resize", () => {
268
+ if (timer) clearTimeout(timer);
269
+ timer = setTimeout(() => applyHeadlineSizes(), 120);
270
+ });
271
+ }
272
+
223
273
  // src/lib/sections.ts
224
274
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
225
275
  function isChromeSection(el) {
@@ -6011,6 +6061,7 @@ var SECTION_ATTRS = {
6011
6061
  sectionBackground: "data-ohw-style-bg",
6012
6062
  textDistribution: "data-ohw-style-distribution",
6013
6063
  headlineScale: "data-ohw-style-headline",
6064
+ headlineSize: HEADLINE_SIZE_ATTR,
6014
6065
  imageAspect: "data-ohw-style-aspect",
6015
6066
  spacing: "data-ohw-style-spacing",
6016
6067
  verticalPadding: "data-ohw-style-vpadding",
@@ -6079,6 +6130,15 @@ function clearSectionAttrs(root) {
6079
6130
  }
6080
6131
  }
6081
6132
  var ITEM_WROTE_ATTR = "data-ohw-style-item";
6133
+ function paintIcon(slot, color) {
6134
+ for (const el of [slot, ...Array.from(slot.querySelectorAll("svg, svg *"))]) {
6135
+ const styled = el;
6136
+ if (!styled.style) continue;
6137
+ saveInline(styled, "color");
6138
+ styled.style.setProperty("color", color, "important");
6139
+ styled.setAttribute(NODE_WROTE_ATTR, "");
6140
+ }
6141
+ }
6082
6142
  function clearNodeProps(root) {
6083
6143
  for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
6084
6144
  const h = el;
@@ -6116,6 +6176,7 @@ function applyStylesToDom(store) {
6116
6176
  ensureStyleSheet();
6117
6177
  clearSectionAttrs(document);
6118
6178
  clearNodeProps(document);
6179
+ clearHeadlineSizes(document);
6119
6180
  loadStyleFonts(
6120
6181
  store ? [
6121
6182
  ...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
@@ -6189,9 +6250,13 @@ function applyStylesToDom(store) {
6189
6250
  const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
6190
6251
  for (const el of Array.from(nodes)) {
6191
6252
  if (override.color !== void 0) {
6192
- saveInline(el, "color");
6193
- el.style.setProperty("color", override.color, "important");
6194
- el.setAttribute(NODE_WROTE_ATTR, "");
6253
+ if (el.dataset.ohwEditable === "icon") {
6254
+ paintIcon(el, override.color);
6255
+ } else {
6256
+ saveInline(el, "color");
6257
+ el.style.setProperty("color", override.color, "important");
6258
+ el.setAttribute(NODE_WROTE_ATTR, "");
6259
+ }
6195
6260
  }
6196
6261
  if (override.fontFamily !== void 0) {
6197
6262
  saveInline(el, "font-family");
@@ -6248,6 +6313,18 @@ function applyStylesToDom(store) {
6248
6313
  }
6249
6314
  }
6250
6315
  }
6316
+ for (const [sectionId, override] of Object.entries(store.sections)) {
6317
+ if (override.iconColor === void 0) continue;
6318
+ const escaped = CSS.escape(sectionId);
6319
+ const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
6320
+ const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
6321
+ for (const marker of Array.from(sections)) {
6322
+ const icons = marker.querySelectorAll('[data-ohw-editable="icon"]');
6323
+ for (const el of Array.from(icons)) paintIcon(el, override.iconColor);
6324
+ }
6325
+ }
6326
+ applyHeadlineSizes(document);
6327
+ installHeadlineSizeResize();
6251
6328
  }
6252
6329
 
6253
6330
  // src/lib/ai-sections-store.ts
@@ -6287,17 +6364,21 @@ function resolveSectionTree(sectionId, aiSectionsRaw) {
6287
6364
  return parseAiSectionsState(aiSectionsRaw).sections.find((entry) => entry.id === sectionId)?.tree;
6288
6365
  }
6289
6366
  function resolveSectionSettingsContext(sectionId, aiSectionsRaw, stylesRaw) {
6367
+ const styleOverride = parseStyleStore(stylesRaw)?.sections[sectionId];
6368
+ const headlineSize = styleOverride?.headlineSize;
6290
6369
  const genSettings = parseAiSectionsState(aiSectionsRaw).sections.find(
6291
6370
  (entry) => entry.id === sectionId
6292
6371
  )?.tree.settings;
6293
- if (genSettings) return genSettings;
6294
- const styleOverride = parseStyleStore(stylesRaw)?.sections[sectionId];
6295
- if (!styleOverride?.verticalPadding && !styleOverride?.minHeight && !styleOverride?.spacing) {
6372
+ if (genSettings) {
6373
+ return { ...genSettings, ...headlineSize ? { headlineSize } : {} };
6374
+ }
6375
+ if (!styleOverride?.verticalPadding && !styleOverride?.minHeight && !styleOverride?.spacing && !headlineSize) {
6296
6376
  return void 0;
6297
6377
  }
6298
6378
  return {
6299
- verticalPadding: styleOverride.verticalPadding ?? legacyVerticalPaddingAlias(styleOverride.spacing),
6300
- minHeight: styleOverride.minHeight
6379
+ verticalPadding: styleOverride?.verticalPadding ?? legacyVerticalPaddingAlias(styleOverride?.spacing),
6380
+ minHeight: styleOverride?.minHeight,
6381
+ ...headlineSize ? { headlineSize } : {}
6301
6382
  };
6302
6383
  }
6303
6384
  function applyTreeToState(state, payload) {
@@ -17241,7 +17322,7 @@ function apiBase() {
17241
17322
  function bridgeVersion() {
17242
17323
  try {
17243
17324
  if (true) {
17244
- return "0.1.158";
17325
+ return "0.1.159";
17245
17326
  }
17246
17327
  } catch {
17247
17328
  }
@@ -17255,7 +17336,7 @@ function stampBridgeVersionOnDocument() {
17255
17336
  return;
17256
17337
  }
17257
17338
  try {
17258
- const v = true ? "0.1.158" : "";
17339
+ const v = true ? "0.1.159" : "";
17259
17340
  if (v) {
17260
17341
  document.documentElement.setAttribute("data-ohw-bridge-version", v);
17261
17342
  window.__OHW_BRIDGE_VERSION__ = v;
@@ -18164,6 +18245,89 @@ function CarouselOverlay({
18164
18245
  // src/ui/ai-section/AiSectionOverlay.tsx
18165
18246
  var import_react9 = require("react");
18166
18247
  var import_lucide_react7 = require("lucide-react");
18248
+
18249
+ // src/lib/ai-change-highlight.ts
18250
+ var STYLE_ID = "ohw-ai-changed-style";
18251
+ var MARK_ATTR = "data-ohw-ai-changed";
18252
+ var HIGHLIGHT_MS = 2200;
18253
+ var HIGHLIGHT_CSS = `
18254
+ @keyframes ohw-ai-changed-pulse {
18255
+ 0% { outline-color: rgba(0, 120, 229, 0.95); box-shadow: 0 0 0 5px rgba(0, 120, 229, 0.20); }
18256
+ 72% { outline-color: rgba(0, 120, 229, 0.95); box-shadow: 0 0 0 5px rgba(0, 120, 229, 0.12); }
18257
+ 100% { outline-color: rgba(0, 120, 229, 0); box-shadow: 0 0 0 5px rgba(0, 120, 229, 0); }
18258
+ }
18259
+ [${MARK_ATTR}] {
18260
+ outline: 2px solid rgba(0, 120, 229, 0.95) !important;
18261
+ outline-offset: 3px !important;
18262
+ animation: ohw-ai-changed-pulse ${HIGHLIGHT_MS}ms ease-out forwards !important;
18263
+ }
18264
+ @media (prefers-reduced-motion: reduce) {
18265
+ [${MARK_ATTR}] { animation: none !important; }
18266
+ }
18267
+ `;
18268
+ function ensureStyleSheet2() {
18269
+ if (document.getElementById(STYLE_ID)) return;
18270
+ const el = document.createElement("style");
18271
+ el.id = STYLE_ID;
18272
+ el.textContent = HIGHLIGHT_CSS;
18273
+ document.head.appendChild(el);
18274
+ }
18275
+ function targetsFor(keys, item) {
18276
+ const out = /* @__PURE__ */ new Set();
18277
+ for (const key of keys) {
18278
+ if (!key) continue;
18279
+ for (const el of Array.from(
18280
+ document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`)
18281
+ )) {
18282
+ out.add(el);
18283
+ }
18284
+ }
18285
+ if (item) {
18286
+ const section = document.querySelector(`[data-ohw-instance="${CSS.escape(item.sectionId)}"]`) ?? document.querySelector(`[data-ohw-section="${CSS.escape(item.sectionId)}"]`);
18287
+ const stamp = `${item.group}:${item.index}`;
18288
+ const el = section?.querySelector(`[data-ohw-item="${CSS.escape(stamp)}"]`);
18289
+ if (el) out.add(el);
18290
+ }
18291
+ return [...out];
18292
+ }
18293
+ var clearTimer = null;
18294
+ function clearChangeHighlight() {
18295
+ if (clearTimer !== null) {
18296
+ clearTimeout(clearTimer);
18297
+ clearTimer = null;
18298
+ }
18299
+ for (const el of Array.from(document.querySelectorAll(`[${MARK_ATTR}]`))) {
18300
+ el.removeAttribute(MARK_ATTR);
18301
+ }
18302
+ }
18303
+ function highlightChangedElements(keys, item) {
18304
+ clearChangeHighlight();
18305
+ const targets = targetsFor(keys, item);
18306
+ if (targets.length === 0) return 0;
18307
+ ensureStyleSheet2();
18308
+ for (const el of targets) el.setAttribute(MARK_ATTR, "");
18309
+ const rect = targets[0].getBoundingClientRect();
18310
+ if (rect.bottom < 0 || rect.top > window.innerHeight) {
18311
+ targets[0].scrollIntoView({ behavior: "smooth", block: "center" });
18312
+ }
18313
+ clearTimer = setTimeout(clearChangeHighlight, HIGHLIGHT_MS);
18314
+ return targets.length;
18315
+ }
18316
+ function installAiChangeHighlight() {
18317
+ const onMessage = (e) => {
18318
+ const data = e.data;
18319
+ if (data?.type !== "ow:ai-highlight") return;
18320
+ const keys = Array.isArray(data.keys) ? data.keys.filter((k) => typeof k === "string") : [];
18321
+ const raw = data.item;
18322
+ const item = raw && typeof raw.sectionId === "string" && typeof raw.group === "string" && typeof raw.index === "number" ? { sectionId: raw.sectionId, group: raw.group, index: raw.index } : void 0;
18323
+ const found = highlightChangedElements(keys, item);
18324
+ window.parent?.postMessage({ type: "ow:ai-highlight-done", found }, "*");
18325
+ };
18326
+ window.addEventListener("message", onMessage);
18327
+ return () => window.removeEventListener("message", onMessage);
18328
+ }
18329
+
18330
+ // src/ui/ai-section/AiSectionOverlay.tsx
18167
18331
  var import_jsx_runtime19 = require("react/jsx-runtime");
18168
18332
  var findSectionElement = findByInstanceId;
18169
18333
  function readRect(instanceId) {
@@ -18415,6 +18579,7 @@ function AiSectionOverlay({
18415
18579
  window.addEventListener("message", onMessage);
18416
18580
  return () => window.removeEventListener("message", onMessage);
18417
18581
  }, [postToParent2]);
18582
+ (0, import_react9.useEffect)(() => installAiChangeHighlight(), []);
18418
18583
  const [hoveredId, setHoveredId] = (0, import_react9.useState)(null);
18419
18584
  (0, import_react9.useEffect)(() => {
18420
18585
  const onMove = (e) => {
@@ -31328,9 +31493,11 @@ function OhhwellsBridge() {
31328
31493
  if (e.data?.type !== "ow:collect-section") return;
31329
31494
  const sectionId = e.data.sectionId;
31330
31495
  if (typeof sectionId !== "string" || !sectionId) return;
31331
- const foundEl = document.querySelector(
31332
- `[data-ohw-section="${CSS.escape(sectionId)}"]`
31496
+ const escapedSectionId = CSS.escape(sectionId);
31497
+ const instanceEl = document.querySelector(
31498
+ `[data-ohw-instance="${escapedSectionId}"]`
31333
31499
  );
31500
+ const foundEl = instanceEl ? sectionElementOf(instanceEl) : document.querySelector(`[data-ohw-section="${escapedSectionId}"]`);
31334
31501
  const sectionEl = foundEl && !foundEl.hasAttribute("data-ohw-ai-template-hidden") && !foundEl.hasAttribute("data-ohw-ai-removed") && !foundEl.hasAttribute("data-ohw-ai-replaced-by") ? foundEl : null;
31335
31502
  const nodes = sectionEl ? collectEditableNodes(void 0, sectionEl).filter(
31336
31503
  (n) => n.key && !n.key.startsWith("__ohw_") && !["meta", "sections", "video-setting"].includes(n.type)
@@ -31343,7 +31510,11 @@ function OhhwellsBridge() {
31343
31510
  width: box.width,
31344
31511
  height: box.height
31345
31512
  } : null;
31346
- const settings = resolveSectionSettingsContext(sectionId, aiSectionsRef.current, stylesRef.current);
31513
+ const settings = resolveSectionSettingsContext(
31514
+ sectionId,
31515
+ aiSectionsRef.current,
31516
+ stylesRef.current
31517
+ );
31347
31518
  const tree = resolveSectionTree(sectionId, aiSectionsRef.current);
31348
31519
  postToParentRef.current({
31349
31520
  type: "ow:section-nodes",
@@ -32074,7 +32245,7 @@ function OhhwellsBridge() {
32074
32245
  postToParent2({
32075
32246
  type: "ow:ready",
32076
32247
  version: "1",
32077
- bridgeVersion: "0.1.158",
32248
+ bridgeVersion: "0.1.159",
32078
32249
  path: pathname,
32079
32250
  nodes: collectEditableNodes(editContentRef.current),
32080
32251
  sections