@ohhwells/bridge 0.1.85-next.254 → 0.1.86-next.255
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 +317 -216
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +317 -216
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -144,6 +144,9 @@ function isRenderableTree(value) {
|
|
|
144
144
|
// src/lib/ai-sections-store.ts
|
|
145
145
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
146
146
|
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
147
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
148
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
149
|
+
}
|
|
147
150
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
148
151
|
function parseAiSectionsState(raw) {
|
|
149
152
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -255,6 +258,33 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
255
258
|
if (removed.includes(sectionId)) return state;
|
|
256
259
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
257
260
|
}
|
|
261
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
262
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
263
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
264
|
+
if (reapedIds.length === 0) {
|
|
265
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
266
|
+
}
|
|
267
|
+
const reaped = new Set(reapedIds);
|
|
268
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
269
|
+
const nextState = {
|
|
270
|
+
...state,
|
|
271
|
+
v: 1,
|
|
272
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
273
|
+
};
|
|
274
|
+
let nextStore = store;
|
|
275
|
+
if (store) {
|
|
276
|
+
const sections = {};
|
|
277
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
278
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
279
|
+
}
|
|
280
|
+
const nodes = {};
|
|
281
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
282
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
283
|
+
}
|
|
284
|
+
nextStore = { v: 1, sections, nodes };
|
|
285
|
+
}
|
|
286
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
287
|
+
}
|
|
258
288
|
|
|
259
289
|
// src/lib/brand-chrome.ts
|
|
260
290
|
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
@@ -637,6 +667,213 @@ function applyStylesToDom(store) {
|
|
|
637
667
|
var import_react_dom = require("react-dom");
|
|
638
668
|
var import_client = require("react-dom/client");
|
|
639
669
|
|
|
670
|
+
// src/lib/sections.ts
|
|
671
|
+
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
672
|
+
function isChromeSection(el) {
|
|
673
|
+
return el.matches("header, nav, footer, aside");
|
|
674
|
+
}
|
|
675
|
+
function titleCaseSectionId(id) {
|
|
676
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
677
|
+
}
|
|
678
|
+
function parseSectionsFromRoot(root) {
|
|
679
|
+
const seen = /* @__PURE__ */ new Set();
|
|
680
|
+
const sections = [];
|
|
681
|
+
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
682
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
683
|
+
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
684
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
685
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
686
|
+
continue;
|
|
687
|
+
seen.add(id);
|
|
688
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
689
|
+
sections.push({ id, label });
|
|
690
|
+
}
|
|
691
|
+
return sections;
|
|
692
|
+
}
|
|
693
|
+
function collectSectionsFromDom() {
|
|
694
|
+
if (typeof document === "undefined") return [];
|
|
695
|
+
return parseSectionsFromRoot(document);
|
|
696
|
+
}
|
|
697
|
+
function parseSectionsFromHtml(html) {
|
|
698
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
699
|
+
return parseSectionsFromRoot(doc);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// src/lib/section-instances.ts
|
|
703
|
+
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
704
|
+
var REMOVED_ATTR = "data-ohw-section-removed";
|
|
705
|
+
function isRemovedSection(el) {
|
|
706
|
+
return el.hasAttribute(REMOVED_ATTR);
|
|
707
|
+
}
|
|
708
|
+
function topLevelSections() {
|
|
709
|
+
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
710
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
function instanceIdOf(el) {
|
|
714
|
+
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
715
|
+
}
|
|
716
|
+
function findByInstanceId(instanceId) {
|
|
717
|
+
const escapedId = CSS.escape(instanceId);
|
|
718
|
+
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
719
|
+
}
|
|
720
|
+
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
721
|
+
const sections = topLevelSections();
|
|
722
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
723
|
+
if (index === -1) return null;
|
|
724
|
+
const dragged = sections[index];
|
|
725
|
+
const others = sections.filter((_, i) => i !== index);
|
|
726
|
+
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
727
|
+
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
728
|
+
return reordered.map((el, order) => ({
|
|
729
|
+
instanceId: instanceIdOf(el),
|
|
730
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
731
|
+
order,
|
|
732
|
+
pagePath: currentPath
|
|
733
|
+
}));
|
|
734
|
+
}
|
|
735
|
+
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
736
|
+
const sections = topLevelSections();
|
|
737
|
+
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
738
|
+
if (index === -1) return null;
|
|
739
|
+
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
740
|
+
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
741
|
+
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
742
|
+
if (!entries) return null;
|
|
743
|
+
applyPersistedOrder(entries);
|
|
744
|
+
return entries;
|
|
745
|
+
}
|
|
746
|
+
function syncRemovedFlags(entries) {
|
|
747
|
+
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
748
|
+
document.querySelectorAll(`[${REMOVED_ATTR}]`).forEach((el) => {
|
|
749
|
+
if (!removedIds.has(instanceIdOf(el))) {
|
|
750
|
+
el.style.removeProperty("display");
|
|
751
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
for (const id of removedIds) {
|
|
755
|
+
const el = findByInstanceId(id);
|
|
756
|
+
if (el) {
|
|
757
|
+
el.style.display = "none";
|
|
758
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function applyPersistedOrder(entries) {
|
|
763
|
+
syncRemovedFlags(entries);
|
|
764
|
+
if (entries.length === 0) return;
|
|
765
|
+
const sections = topLevelSections();
|
|
766
|
+
if (sections.length === 0) return;
|
|
767
|
+
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
768
|
+
const ordered = [...sections].sort((a, b) => {
|
|
769
|
+
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
770
|
+
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
771
|
+
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
772
|
+
if (aOrder === void 0) return 1;
|
|
773
|
+
if (bOrder === void 0) return -1;
|
|
774
|
+
return aOrder - bOrder;
|
|
775
|
+
});
|
|
776
|
+
let prev = null;
|
|
777
|
+
for (const el of ordered) {
|
|
778
|
+
if (prev) prev.after(el);
|
|
779
|
+
prev = el;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
783
|
+
if (!findByInstanceId(instanceId)) return null;
|
|
784
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
785
|
+
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
786
|
+
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
787
|
+
);
|
|
788
|
+
allSections.forEach((el, order) => {
|
|
789
|
+
const id = instanceIdOf(el);
|
|
790
|
+
if (!byId.has(id)) {
|
|
791
|
+
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
const target = byId.get(instanceId);
|
|
795
|
+
if (!target) return null;
|
|
796
|
+
byId.set(instanceId, { ...target, removed });
|
|
797
|
+
const entries = Array.from(byId.values());
|
|
798
|
+
applyPersistedOrder(entries);
|
|
799
|
+
return entries;
|
|
800
|
+
}
|
|
801
|
+
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
802
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
803
|
+
}
|
|
804
|
+
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
805
|
+
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
806
|
+
}
|
|
807
|
+
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
808
|
+
const original = findByInstanceId(instanceId);
|
|
809
|
+
if (!original) return null;
|
|
810
|
+
const clone = original.cloneNode(true);
|
|
811
|
+
clone.setAttribute("data-ohw-instance", newId);
|
|
812
|
+
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
813
|
+
original.insertAdjacentElement("afterend", clone);
|
|
814
|
+
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
815
|
+
const entries = topLevelSections().map((el, order) => {
|
|
816
|
+
const id = instanceIdOf(el);
|
|
817
|
+
return {
|
|
818
|
+
instanceId: id,
|
|
819
|
+
type: el.getAttribute("data-ohw-section") ?? "",
|
|
820
|
+
order,
|
|
821
|
+
pagePath: currentPath,
|
|
822
|
+
...byId.get(id)?.removed ? { removed: true } : {}
|
|
823
|
+
};
|
|
824
|
+
});
|
|
825
|
+
applyPersistedOrder(entries);
|
|
826
|
+
return { entries, keyRekeys };
|
|
827
|
+
}
|
|
828
|
+
function newInstanceId() {
|
|
829
|
+
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
830
|
+
}
|
|
831
|
+
function getPageSectionOrderEntries(raw, currentPath) {
|
|
832
|
+
if (!raw) return [];
|
|
833
|
+
try {
|
|
834
|
+
const entries = JSON.parse(raw);
|
|
835
|
+
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
836
|
+
} catch {
|
|
837
|
+
return [];
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
function rekeySectionSubtree(root, instanceId) {
|
|
841
|
+
const suffix = `::${instanceId}`;
|
|
842
|
+
const pairs = [];
|
|
843
|
+
const rekey = (el, attr) => {
|
|
844
|
+
const current = el.getAttribute(attr);
|
|
845
|
+
if (!current) return;
|
|
846
|
+
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
847
|
+
const next = `${base}${suffix}`;
|
|
848
|
+
el.setAttribute(attr, next);
|
|
849
|
+
pairs.push({ from: current, to: next });
|
|
850
|
+
};
|
|
851
|
+
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
852
|
+
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
853
|
+
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
854
|
+
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
855
|
+
return pairs;
|
|
856
|
+
}
|
|
857
|
+
function initSectionInstancesFromContent(content, currentPath) {
|
|
858
|
+
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
859
|
+
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
860
|
+
});
|
|
861
|
+
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
862
|
+
for (const entry of entries) {
|
|
863
|
+
if (entry.instanceId === entry.type) continue;
|
|
864
|
+
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
865
|
+
const original = document.querySelector(
|
|
866
|
+
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
867
|
+
);
|
|
868
|
+
if (!original) continue;
|
|
869
|
+
const clone = original.cloneNode(true);
|
|
870
|
+
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
871
|
+
rekeySectionSubtree(clone, entry.instanceId);
|
|
872
|
+
original.insertAdjacentElement("afterend", clone);
|
|
873
|
+
}
|
|
874
|
+
applyPersistedOrder(entries);
|
|
875
|
+
}
|
|
876
|
+
|
|
640
877
|
// src/ui/ai-tree/AiTreeRenderer.tsx
|
|
641
878
|
var import_react = __toESM(require("react"), 1);
|
|
642
879
|
var import_lucide_react = require("lucide-react");
|
|
@@ -2340,7 +2577,7 @@ function AiTreeRenderer({
|
|
|
2340
2577
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2341
2578
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
2342
2579
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
2343
|
-
var
|
|
2580
|
+
var REMOVED_ATTR2 = "data-ohw-ai-removed";
|
|
2344
2581
|
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
2345
2582
|
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
2346
2583
|
function readRootVar(name) {
|
|
@@ -2434,18 +2671,18 @@ function placeContainer(container, entry) {
|
|
|
2434
2671
|
}
|
|
2435
2672
|
function syncRemovedSections(state) {
|
|
2436
2673
|
const removed = new Set(state.removed ?? []);
|
|
2437
|
-
for (const el of document.querySelectorAll(`[${
|
|
2674
|
+
for (const el of document.querySelectorAll(`[${REMOVED_ATTR2}]`)) {
|
|
2438
2675
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
2439
2676
|
if (!removed.has(id)) {
|
|
2440
2677
|
el.style.removeProperty("display");
|
|
2441
|
-
el.removeAttribute(
|
|
2678
|
+
el.removeAttribute(REMOVED_ATTR2);
|
|
2442
2679
|
}
|
|
2443
2680
|
}
|
|
2444
2681
|
for (const id of removed) {
|
|
2445
2682
|
const section = findTemplateSection(id);
|
|
2446
2683
|
if (section && !section.hasAttribute(REPLACED_ATTR)) {
|
|
2447
2684
|
section.style.display = "none";
|
|
2448
|
-
section.setAttribute(
|
|
2685
|
+
section.setAttribute(REMOVED_ATTR2, "");
|
|
2449
2686
|
}
|
|
2450
2687
|
}
|
|
2451
2688
|
}
|
|
@@ -2462,7 +2699,7 @@ function syncTemplateHidden(state, pageHasSections) {
|
|
|
2462
2699
|
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
2463
2700
|
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
|
|
2464
2701
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
2465
|
-
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(
|
|
2702
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
|
|
2466
2703
|
el.style.display = "none";
|
|
2467
2704
|
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
2468
2705
|
}
|
|
@@ -2486,18 +2723,23 @@ function syncReplacedOriginals(state) {
|
|
|
2486
2723
|
}
|
|
2487
2724
|
}
|
|
2488
2725
|
var sectionOrderIndex = /* @__PURE__ */ new Map();
|
|
2726
|
+
var removedSectionIds = /* @__PURE__ */ new Set();
|
|
2489
2727
|
function setAiSectionOrder(raw, currentPath) {
|
|
2490
2728
|
const next = /* @__PURE__ */ new Map();
|
|
2729
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2491
2730
|
if (raw) {
|
|
2492
2731
|
try {
|
|
2493
2732
|
const entries = JSON.parse(raw);
|
|
2494
2733
|
for (const entry of entries) {
|
|
2495
|
-
if (
|
|
2734
|
+
if (entry.pagePath && entry.pagePath !== currentPath) continue;
|
|
2735
|
+
next.set(entry.instanceId, entry.order);
|
|
2736
|
+
if (entry.removed) removed.add(entry.instanceId);
|
|
2496
2737
|
}
|
|
2497
2738
|
} catch {
|
|
2498
2739
|
}
|
|
2499
2740
|
}
|
|
2500
2741
|
sectionOrderIndex = next;
|
|
2742
|
+
removedSectionIds = removed;
|
|
2501
2743
|
}
|
|
2502
2744
|
function applyExplicitOrder(entries) {
|
|
2503
2745
|
if (sectionOrderIndex.size === 0) return entries;
|
|
@@ -2533,6 +2775,18 @@ function orderByChain(sections) {
|
|
|
2533
2775
|
for (const root of roots) visit(root);
|
|
2534
2776
|
return out.length === sections.length ? out : sections;
|
|
2535
2777
|
}
|
|
2778
|
+
function syncSoftRemovedGenerated() {
|
|
2779
|
+
for (const [id, section] of mounted) {
|
|
2780
|
+
const el = section.container;
|
|
2781
|
+
if (removedSectionIds.has(id)) {
|
|
2782
|
+
el.style.display = "none";
|
|
2783
|
+
el.setAttribute(REMOVED_ATTR, "");
|
|
2784
|
+
} else if (el.hasAttribute(REMOVED_ATTR)) {
|
|
2785
|
+
el.style.removeProperty("display");
|
|
2786
|
+
el.removeAttribute(REMOVED_ATTR);
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2536
2790
|
function applyAiSectionsToDom(state, options) {
|
|
2537
2791
|
if (typeof document === "undefined") return;
|
|
2538
2792
|
const brandOverride = deriveBrandOverride();
|
|
@@ -2600,6 +2854,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2600
2854
|
syncReplacedOriginals(state);
|
|
2601
2855
|
syncRemovedSections(state);
|
|
2602
2856
|
syncTemplateHidden(state, pageSections.length > 0);
|
|
2857
|
+
syncSoftRemovedGenerated();
|
|
2603
2858
|
}
|
|
2604
2859
|
|
|
2605
2860
|
// src/useLinkHrefGuardian.ts
|
|
@@ -8560,215 +8815,6 @@ function CarouselOverlay({
|
|
|
8560
8815
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8561
8816
|
var import_react8 = require("react");
|
|
8562
8817
|
var import_lucide_react7 = require("lucide-react");
|
|
8563
|
-
|
|
8564
|
-
// src/lib/sections.ts
|
|
8565
|
-
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
8566
|
-
function isChromeSection(el) {
|
|
8567
|
-
return el.matches("header, nav, footer, aside");
|
|
8568
|
-
}
|
|
8569
|
-
function titleCaseSectionId(id) {
|
|
8570
|
-
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
8571
|
-
}
|
|
8572
|
-
function parseSectionsFromRoot(root) {
|
|
8573
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8574
|
-
const sections = [];
|
|
8575
|
-
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
8576
|
-
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
8577
|
-
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
8578
|
-
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
8579
|
-
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
8580
|
-
continue;
|
|
8581
|
-
seen.add(id);
|
|
8582
|
-
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
8583
|
-
sections.push({ id, label });
|
|
8584
|
-
}
|
|
8585
|
-
return sections;
|
|
8586
|
-
}
|
|
8587
|
-
function collectSectionsFromDom() {
|
|
8588
|
-
if (typeof document === "undefined") return [];
|
|
8589
|
-
return parseSectionsFromRoot(document);
|
|
8590
|
-
}
|
|
8591
|
-
function parseSectionsFromHtml(html) {
|
|
8592
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
8593
|
-
return parseSectionsFromRoot(doc);
|
|
8594
|
-
}
|
|
8595
|
-
|
|
8596
|
-
// src/lib/section-instances.ts
|
|
8597
|
-
var SECTION_ORDER_KEY = "__ohw_section_order";
|
|
8598
|
-
var REMOVED_ATTR2 = "data-ohw-section-removed";
|
|
8599
|
-
function isRemovedSection(el) {
|
|
8600
|
-
return el.hasAttribute(REMOVED_ATTR2);
|
|
8601
|
-
}
|
|
8602
|
-
function topLevelSections() {
|
|
8603
|
-
return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8604
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
|
|
8605
|
-
);
|
|
8606
|
-
}
|
|
8607
|
-
function instanceIdOf(el) {
|
|
8608
|
-
return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
|
|
8609
|
-
}
|
|
8610
|
-
function findByInstanceId(instanceId) {
|
|
8611
|
-
const escapedId = CSS.escape(instanceId);
|
|
8612
|
-
return document.querySelector(`[data-ohw-instance="${escapedId}"]`) ?? document.querySelector(`[data-ohw-section="${escapedId}"]:not([data-ohw-instance])`);
|
|
8613
|
-
}
|
|
8614
|
-
function planSectionMove(instanceId, targetIndex, currentPath) {
|
|
8615
|
-
const sections = topLevelSections();
|
|
8616
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8617
|
-
if (index === -1) return null;
|
|
8618
|
-
const dragged = sections[index];
|
|
8619
|
-
const others = sections.filter((_, i) => i !== index);
|
|
8620
|
-
const clamped = Math.max(0, Math.min(targetIndex, others.length));
|
|
8621
|
-
const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
|
|
8622
|
-
return reordered.map((el, order) => ({
|
|
8623
|
-
instanceId: instanceIdOf(el),
|
|
8624
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8625
|
-
order,
|
|
8626
|
-
pagePath: currentPath
|
|
8627
|
-
}));
|
|
8628
|
-
}
|
|
8629
|
-
function moveSectionInstance(instanceId, direction, currentPath) {
|
|
8630
|
-
const sections = topLevelSections();
|
|
8631
|
-
const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
|
|
8632
|
-
if (index === -1) return null;
|
|
8633
|
-
const siblingIndex = direction === "up" ? index - 1 : index + 1;
|
|
8634
|
-
if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
|
|
8635
|
-
const entries = planSectionMove(instanceId, siblingIndex, currentPath);
|
|
8636
|
-
if (!entries) return null;
|
|
8637
|
-
applyPersistedOrder(entries);
|
|
8638
|
-
return entries;
|
|
8639
|
-
}
|
|
8640
|
-
function syncRemovedFlags(entries) {
|
|
8641
|
-
const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
|
|
8642
|
-
document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
|
|
8643
|
-
if (!removedIds.has(instanceIdOf(el))) {
|
|
8644
|
-
el.style.removeProperty("display");
|
|
8645
|
-
el.removeAttribute(REMOVED_ATTR2);
|
|
8646
|
-
}
|
|
8647
|
-
});
|
|
8648
|
-
for (const id of removedIds) {
|
|
8649
|
-
const el = findByInstanceId(id);
|
|
8650
|
-
if (el) {
|
|
8651
|
-
el.style.display = "none";
|
|
8652
|
-
el.setAttribute(REMOVED_ATTR2, "");
|
|
8653
|
-
}
|
|
8654
|
-
}
|
|
8655
|
-
}
|
|
8656
|
-
function applyPersistedOrder(entries) {
|
|
8657
|
-
syncRemovedFlags(entries);
|
|
8658
|
-
if (entries.length === 0) return;
|
|
8659
|
-
const sections = topLevelSections();
|
|
8660
|
-
if (sections.length === 0) return;
|
|
8661
|
-
const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
|
|
8662
|
-
const ordered = [...sections].sort((a, b) => {
|
|
8663
|
-
const aOrder = orderIndex.get(instanceIdOf(a));
|
|
8664
|
-
const bOrder = orderIndex.get(instanceIdOf(b));
|
|
8665
|
-
if (aOrder === void 0 && bOrder === void 0) return 0;
|
|
8666
|
-
if (aOrder === void 0) return 1;
|
|
8667
|
-
if (bOrder === void 0) return -1;
|
|
8668
|
-
return aOrder - bOrder;
|
|
8669
|
-
});
|
|
8670
|
-
let prev = null;
|
|
8671
|
-
for (const el of ordered) {
|
|
8672
|
-
if (prev) prev.after(el);
|
|
8673
|
-
prev = el;
|
|
8674
|
-
}
|
|
8675
|
-
}
|
|
8676
|
-
function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
|
|
8677
|
-
if (!findByInstanceId(instanceId)) return null;
|
|
8678
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8679
|
-
const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
8680
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
|
|
8681
|
-
);
|
|
8682
|
-
allSections.forEach((el, order) => {
|
|
8683
|
-
const id = instanceIdOf(el);
|
|
8684
|
-
if (!byId.has(id)) {
|
|
8685
|
-
byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
|
|
8686
|
-
}
|
|
8687
|
-
});
|
|
8688
|
-
const target = byId.get(instanceId);
|
|
8689
|
-
if (!target) return null;
|
|
8690
|
-
byId.set(instanceId, { ...target, removed });
|
|
8691
|
-
const entries = Array.from(byId.values());
|
|
8692
|
-
applyPersistedOrder(entries);
|
|
8693
|
-
return entries;
|
|
8694
|
-
}
|
|
8695
|
-
function deleteSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8696
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, true);
|
|
8697
|
-
}
|
|
8698
|
-
function restoreSectionInstance(instanceId, currentPath, existingEntries) {
|
|
8699
|
-
return setSectionRemoved(instanceId, currentPath, existingEntries, false);
|
|
8700
|
-
}
|
|
8701
|
-
function duplicateSectionInstance(instanceId, newId, currentPath, existingEntries) {
|
|
8702
|
-
const original = findByInstanceId(instanceId);
|
|
8703
|
-
if (!original) return null;
|
|
8704
|
-
const clone = original.cloneNode(true);
|
|
8705
|
-
clone.setAttribute("data-ohw-instance", newId);
|
|
8706
|
-
const keyRekeys = rekeySectionSubtree(clone, newId);
|
|
8707
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8708
|
-
const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
|
|
8709
|
-
const entries = topLevelSections().map((el, order) => {
|
|
8710
|
-
const id = instanceIdOf(el);
|
|
8711
|
-
return {
|
|
8712
|
-
instanceId: id,
|
|
8713
|
-
type: el.getAttribute("data-ohw-section") ?? "",
|
|
8714
|
-
order,
|
|
8715
|
-
pagePath: currentPath,
|
|
8716
|
-
...byId.get(id)?.removed ? { removed: true } : {}
|
|
8717
|
-
};
|
|
8718
|
-
});
|
|
8719
|
-
applyPersistedOrder(entries);
|
|
8720
|
-
return { entries, keyRekeys };
|
|
8721
|
-
}
|
|
8722
|
-
function newInstanceId() {
|
|
8723
|
-
return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8724
|
-
}
|
|
8725
|
-
function getPageSectionOrderEntries(raw, currentPath) {
|
|
8726
|
-
if (!raw) return [];
|
|
8727
|
-
try {
|
|
8728
|
-
const entries = JSON.parse(raw);
|
|
8729
|
-
return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
|
|
8730
|
-
} catch {
|
|
8731
|
-
return [];
|
|
8732
|
-
}
|
|
8733
|
-
}
|
|
8734
|
-
function rekeySectionSubtree(root, instanceId) {
|
|
8735
|
-
const suffix = `::${instanceId}`;
|
|
8736
|
-
const pairs = [];
|
|
8737
|
-
const rekey = (el, attr) => {
|
|
8738
|
-
const current = el.getAttribute(attr);
|
|
8739
|
-
if (!current) return;
|
|
8740
|
-
const base = current.includes("::") ? current.slice(0, current.indexOf("::")) : current;
|
|
8741
|
-
const next = `${base}${suffix}`;
|
|
8742
|
-
el.setAttribute(attr, next);
|
|
8743
|
-
pairs.push({ from: current, to: next });
|
|
8744
|
-
};
|
|
8745
|
-
if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
|
|
8746
|
-
if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
|
|
8747
|
-
root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
|
|
8748
|
-
root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
|
|
8749
|
-
return pairs;
|
|
8750
|
-
}
|
|
8751
|
-
function initSectionInstancesFromContent(content, currentPath) {
|
|
8752
|
-
document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
|
|
8753
|
-
el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
|
|
8754
|
-
});
|
|
8755
|
-
const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
|
|
8756
|
-
for (const entry of entries) {
|
|
8757
|
-
if (entry.instanceId === entry.type) continue;
|
|
8758
|
-
if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
|
|
8759
|
-
const original = document.querySelector(
|
|
8760
|
-
`[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
|
|
8761
|
-
);
|
|
8762
|
-
if (!original) continue;
|
|
8763
|
-
const clone = original.cloneNode(true);
|
|
8764
|
-
clone.setAttribute("data-ohw-instance", entry.instanceId);
|
|
8765
|
-
rekeySectionSubtree(clone, entry.instanceId);
|
|
8766
|
-
original.insertAdjacentElement("afterend", clone);
|
|
8767
|
-
}
|
|
8768
|
-
applyPersistedOrder(entries);
|
|
8769
|
-
}
|
|
8770
|
-
|
|
8771
|
-
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
8772
8818
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
8773
8819
|
function findSectionElement(instanceId) {
|
|
8774
8820
|
const escaped = CSS.escape(instanceId);
|
|
@@ -20555,6 +20601,44 @@ function OhhwellsBridge() {
|
|
|
20555
20601
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
20556
20602
|
}, 400));
|
|
20557
20603
|
};
|
|
20604
|
+
const reapCommittedAiSections = (excludeIds) => {
|
|
20605
|
+
const aiState = parseAiSectionsState(aiSectionsRef.current);
|
|
20606
|
+
if (aiState.sections.length === 0) return [];
|
|
20607
|
+
let orderEntries = [];
|
|
20608
|
+
try {
|
|
20609
|
+
const parsed = JSON.parse(editContentRef.current[SECTION_ORDER_KEY] ?? "[]");
|
|
20610
|
+
if (Array.isArray(parsed)) orderEntries = parsed;
|
|
20611
|
+
} catch {
|
|
20612
|
+
return [];
|
|
20613
|
+
}
|
|
20614
|
+
const removedIds = orderEntries.filter((entry) => entry && typeof entry.instanceId === "string" && entry.removed).map((entry) => entry.instanceId);
|
|
20615
|
+
if (removedIds.length === 0) return [];
|
|
20616
|
+
const result = reapRemovedAiSections(aiState, parseStyleStore(stylesRef.current), removedIds, excludeIds);
|
|
20617
|
+
if (!result.changed) return [];
|
|
20618
|
+
const nodes = [];
|
|
20619
|
+
aiSectionsRef.current = serializeAiSectionsState(result.state);
|
|
20620
|
+
nodes.push({ key: AI_SECTIONS_KEY, text: aiSectionsRef.current });
|
|
20621
|
+
const reaped = new Set(result.reapedIds);
|
|
20622
|
+
const nextOrderJson = JSON.stringify(orderEntries.filter((entry) => !reaped.has(entry.instanceId)));
|
|
20623
|
+
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: nextOrderJson };
|
|
20624
|
+
setAiSectionOrder(nextOrderJson, window.location.pathname);
|
|
20625
|
+
nodes.push({ key: SECTION_ORDER_KEY, text: nextOrderJson });
|
|
20626
|
+
if (result.store) {
|
|
20627
|
+
stylesRef.current = JSON.stringify(result.store);
|
|
20628
|
+
nodes.push({ key: STYLE_STORE_KEY, text: stylesRef.current });
|
|
20629
|
+
}
|
|
20630
|
+
const nextContent = { ...editContentRef.current };
|
|
20631
|
+
for (const key of Object.keys(nextContent)) {
|
|
20632
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) && result.slotPrefixes.some((prefix) => key.startsWith(prefix)) && nextContent[key] !== "") {
|
|
20633
|
+
nextContent[key] = "";
|
|
20634
|
+
nodes.push({ key, text: "" });
|
|
20635
|
+
}
|
|
20636
|
+
}
|
|
20637
|
+
editContentRef.current = nextContent;
|
|
20638
|
+
applyAiSectionsToDom(result.state);
|
|
20639
|
+
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
20640
|
+
return nodes;
|
|
20641
|
+
};
|
|
20558
20642
|
const handleHydrate = (e) => {
|
|
20559
20643
|
if (e.data?.type !== "ow:hydrate") return;
|
|
20560
20644
|
const content = e.data.content;
|
|
@@ -20626,6 +20710,11 @@ function OhhwellsBridge() {
|
|
|
20626
20710
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
20627
20711
|
syncNavigationDragCursorAttrs();
|
|
20628
20712
|
enforceLinkHrefs();
|
|
20713
|
+
const hydrateReapExclude = /* @__PURE__ */ new Set();
|
|
20714
|
+
const hydratePendingUndo = pendingDeleteUndoRef.current;
|
|
20715
|
+
if (hydratePendingUndo?.sectionInstanceId) hydrateReapExclude.add(hydratePendingUndo.sectionInstanceId);
|
|
20716
|
+
const reapNodes = reapCommittedAiSections(hydrateReapExclude);
|
|
20717
|
+
if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
|
|
20629
20718
|
const hydratedHeight = document.body.scrollHeight;
|
|
20630
20719
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
20631
20720
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
@@ -20832,6 +20921,7 @@ function OhhwellsBridge() {
|
|
|
20832
20921
|
if (!entries) return;
|
|
20833
20922
|
const orderJson = JSON.stringify(entries);
|
|
20834
20923
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
|
|
20924
|
+
setAiSectionOrder(orderJson, window.location.pathname);
|
|
20835
20925
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
|
|
20836
20926
|
aiSectionApiRef.current?.clear();
|
|
20837
20927
|
window.dispatchEvent(new Event("resize"));
|
|
@@ -20840,6 +20930,7 @@ function OhhwellsBridge() {
|
|
|
20840
20930
|
const actionId = newInstanceId();
|
|
20841
20931
|
pendingDeleteUndoRef.current = {
|
|
20842
20932
|
actionId,
|
|
20933
|
+
sectionInstanceId: instanceId,
|
|
20843
20934
|
restore: () => {
|
|
20844
20935
|
const restoredEntries = getPageSectionOrderEntries(
|
|
20845
20936
|
editContentRef.current[SECTION_ORDER_KEY],
|
|
@@ -20849,6 +20940,7 @@ function OhhwellsBridge() {
|
|
|
20849
20940
|
if (!restored) return;
|
|
20850
20941
|
const restoredJson = JSON.stringify(restored);
|
|
20851
20942
|
editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
|
|
20943
|
+
setAiSectionOrder(restoredJson, window.location.pathname);
|
|
20852
20944
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
|
|
20853
20945
|
window.dispatchEvent(new Event("resize"));
|
|
20854
20946
|
const restoreHeight = document.body.scrollHeight;
|
|
@@ -21153,6 +21245,10 @@ function OhhwellsBridge() {
|
|
|
21153
21245
|
};
|
|
21154
21246
|
const handleSave = (e) => {
|
|
21155
21247
|
if (e.data?.type !== "ow:save") return;
|
|
21248
|
+
const pendingUndo = pendingDeleteUndoRef.current;
|
|
21249
|
+
const reapExclude = /* @__PURE__ */ new Set();
|
|
21250
|
+
if (pendingUndo?.sectionInstanceId) reapExclude.add(pendingUndo.sectionInstanceId);
|
|
21251
|
+
const reapNodes = reapCommittedAiSections(reapExclude);
|
|
21156
21252
|
const nodes = collectEditableNodes(editContentRef.current);
|
|
21157
21253
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
21158
21254
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
@@ -21172,6 +21268,11 @@ function OhhwellsBridge() {
|
|
|
21172
21268
|
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
21173
21269
|
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
21174
21270
|
});
|
|
21271
|
+
for (const reapNode of reapNodes) {
|
|
21272
|
+
if (reapNode.key.startsWith(AI_SLOT_KEY_PREFIX) && !nodes.some((n) => n.key === reapNode.key)) {
|
|
21273
|
+
nodes.push({ key: reapNode.key, type: "text", text: reapNode.text });
|
|
21274
|
+
}
|
|
21275
|
+
}
|
|
21175
21276
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
21176
21277
|
};
|
|
21177
21278
|
const handleInsertSection = (e) => {
|
|
@@ -21797,7 +21898,7 @@ function OhhwellsBridge() {
|
|
|
21797
21898
|
postToParent2({
|
|
21798
21899
|
type: "ow:ready",
|
|
21799
21900
|
version: "1",
|
|
21800
|
-
bridgeVersion: "0.1.
|
|
21901
|
+
bridgeVersion: "0.1.86",
|
|
21801
21902
|
path: pathname,
|
|
21802
21903
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21803
21904
|
sections
|