@sevenfold/setto-client 0.14.0 → 0.16.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/chrome.d.ts +5 -3
- package/dist/guest-edit.d.ts +13 -7
- package/dist/index.d.ts +5 -3
- package/dist/modules/forms/field-tools.d.ts +35 -0
- package/dist/modules/forms/index.d.ts +1 -1
- package/dist/provider.d.ts +12 -0
- package/dist/section-context.d.ts +11 -6
- package/dist/setto-client.js +90 -1203
- package/dist/setto-client.js.map +1 -1
- package/package.json +1 -1
- package/dist/edit-mode/build-status.d.ts +0 -13
- package/dist/edit-mode/deployment-status.d.ts +0 -37
- package/dist/edit-mode/link-hint.d.ts +0 -5
- package/dist/edit-mode/section-toolbar.d.ts +0 -1
- package/dist/lib/color-utils.d.ts +0 -4
- package/dist/modules/forms/field-editor.d.ts +0 -29
- package/dist/preview-bar.d.ts +0 -29
package/dist/setto-client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import { useState, useRef, useEffect, useMemo,
|
|
3
|
+
import { useState, useRef, useEffect, useMemo, createContext, useContext, useCallback, useLayoutEffect, useSyncExternalStore, forwardRef, Fragment as Fragment$1, useId, useInsertionEffect } from "react";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import * as ReactDOM from "react-dom";
|
|
6
6
|
import { createPortal } from "react-dom";
|
|
@@ -21431,11 +21431,11 @@ function useSettoChromeSlot(name) {
|
|
|
21431
21431
|
slotListeners.delete(listener);
|
|
21432
21432
|
};
|
|
21433
21433
|
}, []);
|
|
21434
|
-
const Offered = slots.get(name)
|
|
21434
|
+
const Offered = slots.get(name);
|
|
21435
21435
|
return useMemo(() => {
|
|
21436
21436
|
if (!Offered) return null;
|
|
21437
|
-
return function SettoChromeSlot() {
|
|
21438
|
-
return /* @__PURE__ */ jsx(ChromeBoundary, { onError: () => retireSlot(name), children:
|
|
21437
|
+
return function SettoChromeSlot(props) {
|
|
21438
|
+
return /* @__PURE__ */ jsx(ChromeBoundary, { onError: () => retireSlot(name), children: React.createElement(Offered, props) });
|
|
21439
21439
|
};
|
|
21440
21440
|
}, [Offered, name]);
|
|
21441
21441
|
}
|
|
@@ -21452,6 +21452,7 @@ function SettoChrome() {
|
|
|
21452
21452
|
currentSite: null,
|
|
21453
21453
|
sitesLoaded: false,
|
|
21454
21454
|
editMode: false,
|
|
21455
|
+
guestEdit: false,
|
|
21455
21456
|
authLoading: true
|
|
21456
21457
|
}));
|
|
21457
21458
|
stateRef.current = () => ({
|
|
@@ -21464,6 +21465,7 @@ function SettoChrome() {
|
|
|
21464
21465
|
} : null,
|
|
21465
21466
|
sitesLoaded: setto.sites !== null,
|
|
21466
21467
|
editMode: setto.editMode,
|
|
21468
|
+
guestEdit: setto.guestEdit,
|
|
21467
21469
|
authLoading: setto.authLoading
|
|
21468
21470
|
});
|
|
21469
21471
|
useEffect(() => {
|
|
@@ -21550,7 +21552,7 @@ function withoutCheckoutIntent() {
|
|
|
21550
21552
|
}
|
|
21551
21553
|
const FAB_SIZE = 52;
|
|
21552
21554
|
const FAB_INSET = 16;
|
|
21553
|
-
const STYLE_ID$
|
|
21555
|
+
const STYLE_ID$2 = "setto-edit-layout";
|
|
21554
21556
|
const HTML_CLASS = "setto-edit-mode";
|
|
21555
21557
|
function useSettoDocumentLayout(active) {
|
|
21556
21558
|
useEffect(() => {
|
|
@@ -21559,19 +21561,24 @@ function useSettoDocumentLayout(active) {
|
|
|
21559
21561
|
html.classList.add(HTML_CLASS);
|
|
21560
21562
|
html.style.setProperty("--setto-fab-size", `${FAB_SIZE}px`);
|
|
21561
21563
|
html.style.setProperty("--setto-fab-inset", `${FAB_INSET}px`);
|
|
21562
|
-
let styleEl = document.getElementById(STYLE_ID$
|
|
21564
|
+
let styleEl = document.getElementById(STYLE_ID$2);
|
|
21563
21565
|
if (!styleEl) {
|
|
21564
21566
|
styleEl = document.createElement("style");
|
|
21565
|
-
styleEl.id = STYLE_ID$
|
|
21567
|
+
styleEl.id = STYLE_ID$2;
|
|
21566
21568
|
styleEl.textContent = `
|
|
21567
21569
|
html.setto-edit-mode {
|
|
21568
21570
|
width: 100%;
|
|
21569
21571
|
overflow-x: clip;
|
|
21570
21572
|
}
|
|
21571
21573
|
|
|
21574
|
+
/*
|
|
21575
|
+
* Anchored by its right edge, which is also what makes the menu open
|
|
21576
|
+
* leftwards: the pill grows and this corner does not move, so the
|
|
21577
|
+
* button somebody just tapped stays under their thumb.
|
|
21578
|
+
*/
|
|
21572
21579
|
html.setto-edit-mode #setto-toolbar-root {
|
|
21573
21580
|
position: fixed;
|
|
21574
|
-
|
|
21581
|
+
right: var(--setto-fab-inset);
|
|
21575
21582
|
bottom: var(--setto-fab-inset);
|
|
21576
21583
|
z-index: 2147483647;
|
|
21577
21584
|
}
|
|
@@ -21625,492 +21632,6 @@ function notifyLayoutChange() {
|
|
|
21625
21632
|
window.dispatchEvent(new Event("resize"));
|
|
21626
21633
|
});
|
|
21627
21634
|
}
|
|
21628
|
-
function isLinkContext(el) {
|
|
21629
|
-
const key = el.getAttribute("data-setto-key");
|
|
21630
|
-
if (key?.startsWith("lang.")) return false;
|
|
21631
|
-
if (el.closest("[data-setto-no-hint]")) return false;
|
|
21632
|
-
return !!(el.closest("a[href]") || el.closest("button"));
|
|
21633
|
-
}
|
|
21634
|
-
function activateLinkContext(el) {
|
|
21635
|
-
const anchor = el.closest("a[href]");
|
|
21636
|
-
if (anchor instanceof HTMLAnchorElement) {
|
|
21637
|
-
anchor.click();
|
|
21638
|
-
return;
|
|
21639
|
-
}
|
|
21640
|
-
const button = el.closest("button");
|
|
21641
|
-
if (button instanceof HTMLButtonElement) {
|
|
21642
|
-
button.click();
|
|
21643
|
-
}
|
|
21644
|
-
}
|
|
21645
|
-
const QUERY = "(hover: none) and (pointer: coarse)";
|
|
21646
|
-
function subscribe(onChange) {
|
|
21647
|
-
const mq = window.matchMedia(QUERY);
|
|
21648
|
-
mq.addEventListener("change", onChange);
|
|
21649
|
-
return () => mq.removeEventListener("change", onChange);
|
|
21650
|
-
}
|
|
21651
|
-
function getSnapshot() {
|
|
21652
|
-
return window.matchMedia(QUERY).matches;
|
|
21653
|
-
}
|
|
21654
|
-
function useCoarsePointer() {
|
|
21655
|
-
return useSyncExternalStore(subscribe, getSnapshot, () => false);
|
|
21656
|
-
}
|
|
21657
|
-
const MARGIN$2 = 10;
|
|
21658
|
-
const OFFSET$1 = 14;
|
|
21659
|
-
function hintLabel() {
|
|
21660
|
-
const isMac = navigator.platform.toUpperCase().includes("MAC");
|
|
21661
|
-
return isMac ? "⌘+klikk for å åpne" : "Ctrl+klikk for å åpne";
|
|
21662
|
-
}
|
|
21663
|
-
function placeTooltip(anchor, width, height) {
|
|
21664
|
-
const vw = window.innerWidth;
|
|
21665
|
-
const vh = window.innerHeight;
|
|
21666
|
-
let left = anchor.x + OFFSET$1;
|
|
21667
|
-
let top = anchor.y + OFFSET$1;
|
|
21668
|
-
if (left + width > vw - MARGIN$2) {
|
|
21669
|
-
left = anchor.x - width - OFFSET$1;
|
|
21670
|
-
}
|
|
21671
|
-
if (left < MARGIN$2) {
|
|
21672
|
-
left = MARGIN$2;
|
|
21673
|
-
}
|
|
21674
|
-
if (top + height > vh - MARGIN$2) {
|
|
21675
|
-
top = anchor.y - height - OFFSET$1;
|
|
21676
|
-
}
|
|
21677
|
-
if (top < MARGIN$2) {
|
|
21678
|
-
top = MARGIN$2;
|
|
21679
|
-
}
|
|
21680
|
-
return { left, top };
|
|
21681
|
-
}
|
|
21682
|
-
function EditLinkHint() {
|
|
21683
|
-
const coarsePointer = useCoarsePointer();
|
|
21684
|
-
const [anchor, setAnchor] = useState(null);
|
|
21685
|
-
const [position, setPosition] = useState(null);
|
|
21686
|
-
const tipRef = useRef(null);
|
|
21687
|
-
const text = hintLabel();
|
|
21688
|
-
useEffect(() => {
|
|
21689
|
-
if (coarsePointer) return;
|
|
21690
|
-
const onMove = (e) => {
|
|
21691
|
-
const target = e.target;
|
|
21692
|
-
if (!(target instanceof Element)) {
|
|
21693
|
-
setAnchor(null);
|
|
21694
|
-
return;
|
|
21695
|
-
}
|
|
21696
|
-
const editable = target.closest("[data-setto-key]");
|
|
21697
|
-
if (!(editable instanceof HTMLElement) || !isLinkContext(editable)) {
|
|
21698
|
-
setAnchor(null);
|
|
21699
|
-
return;
|
|
21700
|
-
}
|
|
21701
|
-
setAnchor({ x: e.clientX, y: e.clientY });
|
|
21702
|
-
};
|
|
21703
|
-
document.addEventListener("mousemove", onMove, true);
|
|
21704
|
-
return () => document.removeEventListener("mousemove", onMove, true);
|
|
21705
|
-
}, [coarsePointer]);
|
|
21706
|
-
useLayoutEffect(() => {
|
|
21707
|
-
if (!anchor || !tipRef.current) {
|
|
21708
|
-
setPosition(null);
|
|
21709
|
-
return;
|
|
21710
|
-
}
|
|
21711
|
-
const { width, height } = tipRef.current.getBoundingClientRect();
|
|
21712
|
-
setPosition(placeTooltip(anchor, width, height));
|
|
21713
|
-
}, [anchor, text]);
|
|
21714
|
-
if (coarsePointer || !anchor) return null;
|
|
21715
|
-
const style = {
|
|
21716
|
-
position: "fixed",
|
|
21717
|
-
left: position?.left ?? anchor.x + OFFSET$1,
|
|
21718
|
-
top: position?.top ?? anchor.y + OFFSET$1,
|
|
21719
|
-
visibility: position ? "visible" : "hidden",
|
|
21720
|
-
background: "#1a1a1a",
|
|
21721
|
-
color: "#fff",
|
|
21722
|
-
fontSize: 11,
|
|
21723
|
-
padding: "4px 8px",
|
|
21724
|
-
borderRadius: 4,
|
|
21725
|
-
pointerEvents: "none",
|
|
21726
|
-
whiteSpace: "nowrap",
|
|
21727
|
-
fontFamily: "system-ui, sans-serif",
|
|
21728
|
-
boxShadow: "0 2px 8px rgba(0,0,0,0.15)"
|
|
21729
|
-
};
|
|
21730
|
-
return /* @__PURE__ */ jsx("div", { ref: tipRef, style, children: text });
|
|
21731
|
-
}
|
|
21732
|
-
function colorsMatch(a, b) {
|
|
21733
|
-
const na = normalizeColor(a);
|
|
21734
|
-
const nb = normalizeColor(b);
|
|
21735
|
-
if (!na || !nb) return false;
|
|
21736
|
-
return na === nb;
|
|
21737
|
-
}
|
|
21738
|
-
function normalizeColor(color) {
|
|
21739
|
-
const trimmed = color.trim().toLowerCase();
|
|
21740
|
-
if (/^#[0-9a-f]{3}$/.test(trimmed)) {
|
|
21741
|
-
const [, r, g, b] = trimmed.match(/^#(.)(.)(.)$/) ?? [];
|
|
21742
|
-
return `#${r}${r}${g}${g}${b}${b}`;
|
|
21743
|
-
}
|
|
21744
|
-
if (/^#[0-9a-f]{6}$/.test(trimmed)) return trimmed;
|
|
21745
|
-
const rgb = trimmed.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
|
|
21746
|
-
if (rgb) {
|
|
21747
|
-
const [, r, g, b] = rgb;
|
|
21748
|
-
if (r === void 0 || g === void 0 || b === void 0) return null;
|
|
21749
|
-
const hex = (n) => Number(n).toString(16).padStart(2, "0");
|
|
21750
|
-
return `#${hex(r)}${hex(g)}${hex(b)}`;
|
|
21751
|
-
}
|
|
21752
|
-
return null;
|
|
21753
|
-
}
|
|
21754
|
-
function swatchBorder(color) {
|
|
21755
|
-
const n = normalizeColor(color);
|
|
21756
|
-
if (n === "#ffffff" || n === "#e6dccf") return "#ccc";
|
|
21757
|
-
return "transparent";
|
|
21758
|
-
}
|
|
21759
|
-
const SectionEditContext = createContext(null);
|
|
21760
|
-
function SectionEditProvider({ children }) {
|
|
21761
|
-
const [selectedId, setSelectedId] = useState(null);
|
|
21762
|
-
const selectSection = useCallback((id) => {
|
|
21763
|
-
setSelectedId(id);
|
|
21764
|
-
}, []);
|
|
21765
|
-
const value = useMemo(
|
|
21766
|
-
() => ({ selectedId, selectSection }),
|
|
21767
|
-
[selectedId, selectSection]
|
|
21768
|
-
);
|
|
21769
|
-
return /* @__PURE__ */ jsx(SectionEditContext.Provider, { value, children });
|
|
21770
|
-
}
|
|
21771
|
-
function useSectionEdit() {
|
|
21772
|
-
const ctx = useContext(SectionEditContext);
|
|
21773
|
-
if (!ctx) {
|
|
21774
|
-
throw new Error("useSectionEdit() must be used inside SectionEditProvider");
|
|
21775
|
-
}
|
|
21776
|
-
return ctx;
|
|
21777
|
-
}
|
|
21778
|
-
const SECTION_TOOLBAR_HEIGHT = 44;
|
|
21779
|
-
const GAP = 8;
|
|
21780
|
-
const MARGIN$1 = 8;
|
|
21781
|
-
function computePosition(targetEl, toolbarW, toolbarH) {
|
|
21782
|
-
const rect = targetEl.getBoundingClientRect();
|
|
21783
|
-
let left = rect.left + (rect.width - toolbarW) / 2;
|
|
21784
|
-
left = Math.max(MARGIN$1, Math.min(left, window.innerWidth - toolbarW - MARGIN$1));
|
|
21785
|
-
const top = Math.max(MARGIN$1, rect.top - toolbarH - GAP);
|
|
21786
|
-
return { top, left };
|
|
21787
|
-
}
|
|
21788
|
-
function BrandColorPicker({
|
|
21789
|
-
label,
|
|
21790
|
-
value,
|
|
21791
|
-
brandColors,
|
|
21792
|
-
open,
|
|
21793
|
-
onToggle,
|
|
21794
|
-
onSelect,
|
|
21795
|
-
popoverPlacement
|
|
21796
|
-
}) {
|
|
21797
|
-
const buttonRef = useRef(null);
|
|
21798
|
-
const popoverRef = useRef(null);
|
|
21799
|
-
const [popoverPos, setPopoverPos] = useState(null);
|
|
21800
|
-
const matched = brandColors.find((b) => colorsMatch(value, b.value));
|
|
21801
|
-
const displayColor = matched?.value ?? (value || "#cccccc");
|
|
21802
|
-
const displayLabel = matched?.label ?? label;
|
|
21803
|
-
useLayoutEffect(() => {
|
|
21804
|
-
if (!open || !buttonRef.current) {
|
|
21805
|
-
setPopoverPos(null);
|
|
21806
|
-
return;
|
|
21807
|
-
}
|
|
21808
|
-
const update = () => {
|
|
21809
|
-
const btn = buttonRef.current;
|
|
21810
|
-
const pop = popoverRef.current;
|
|
21811
|
-
if (!btn) return;
|
|
21812
|
-
const rect = btn.getBoundingClientRect();
|
|
21813
|
-
const popoverH = pop?.offsetHeight ?? 120;
|
|
21814
|
-
const popoverW = pop?.offsetWidth ?? 180;
|
|
21815
|
-
let top = popoverPlacement === "above" ? rect.top - popoverH - 6 : rect.bottom + 6;
|
|
21816
|
-
let left = rect.left;
|
|
21817
|
-
if (left + popoverW > window.innerWidth - 8) {
|
|
21818
|
-
left = window.innerWidth - popoverW - 8;
|
|
21819
|
-
}
|
|
21820
|
-
if (left < 8) left = 8;
|
|
21821
|
-
if (top < 8) top = rect.bottom + 6;
|
|
21822
|
-
if (top + popoverH > window.innerHeight - 8) {
|
|
21823
|
-
top = rect.top - popoverH - 6;
|
|
21824
|
-
}
|
|
21825
|
-
setPopoverPos({ top, left });
|
|
21826
|
-
};
|
|
21827
|
-
update();
|
|
21828
|
-
requestAnimationFrame(update);
|
|
21829
|
-
window.addEventListener("scroll", update, true);
|
|
21830
|
-
window.addEventListener("resize", update);
|
|
21831
|
-
return () => {
|
|
21832
|
-
window.removeEventListener("scroll", update, true);
|
|
21833
|
-
window.removeEventListener("resize", update);
|
|
21834
|
-
};
|
|
21835
|
-
}, [open, popoverPlacement, brandColors.length]);
|
|
21836
|
-
const popover = open ? /* @__PURE__ */ jsx(
|
|
21837
|
-
"div",
|
|
21838
|
-
{
|
|
21839
|
-
ref: popoverRef,
|
|
21840
|
-
role: "listbox",
|
|
21841
|
-
"aria-label": label,
|
|
21842
|
-
"data-setto-ui": true,
|
|
21843
|
-
style: {
|
|
21844
|
-
position: "fixed",
|
|
21845
|
-
top: popoverPos?.top ?? -9999,
|
|
21846
|
-
left: popoverPos?.left ?? 0,
|
|
21847
|
-
visibility: popoverPos ? "visible" : "hidden",
|
|
21848
|
-
zIndex: 2147483647,
|
|
21849
|
-
display: "grid",
|
|
21850
|
-
gridTemplateColumns: "repeat(4, 1fr)",
|
|
21851
|
-
gap: 4,
|
|
21852
|
-
padding: 8,
|
|
21853
|
-
background: "#fff",
|
|
21854
|
-
border: "1px solid #e0e0e0",
|
|
21855
|
-
borderRadius: 8,
|
|
21856
|
-
boxShadow: "0 8px 24px rgba(0,0,0,0.15)",
|
|
21857
|
-
minWidth: 160
|
|
21858
|
-
},
|
|
21859
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
21860
|
-
onClick: (e) => e.stopPropagation(),
|
|
21861
|
-
children: brandColors.map((brand) => {
|
|
21862
|
-
const selected = colorsMatch(value, brand.value);
|
|
21863
|
-
return /* @__PURE__ */ jsxs(
|
|
21864
|
-
"button",
|
|
21865
|
-
{
|
|
21866
|
-
type: "button",
|
|
21867
|
-
role: "option",
|
|
21868
|
-
"aria-selected": selected,
|
|
21869
|
-
title: brand.label,
|
|
21870
|
-
onClick: () => onSelect(brand.value),
|
|
21871
|
-
style: {
|
|
21872
|
-
display: "flex",
|
|
21873
|
-
flexDirection: "column",
|
|
21874
|
-
alignItems: "center",
|
|
21875
|
-
gap: 4,
|
|
21876
|
-
padding: 6,
|
|
21877
|
-
background: selected ? "#f5f3ff" : "transparent",
|
|
21878
|
-
border: selected ? "1px solid #640AFF" : "1px solid transparent",
|
|
21879
|
-
borderRadius: 6,
|
|
21880
|
-
cursor: "pointer"
|
|
21881
|
-
},
|
|
21882
|
-
children: [
|
|
21883
|
-
/* @__PURE__ */ jsx(
|
|
21884
|
-
"span",
|
|
21885
|
-
{
|
|
21886
|
-
"aria-hidden": true,
|
|
21887
|
-
style: {
|
|
21888
|
-
width: 24,
|
|
21889
|
-
height: 24,
|
|
21890
|
-
borderRadius: "50%",
|
|
21891
|
-
background: brand.value,
|
|
21892
|
-
border: `1px solid ${swatchBorder(brand.value)}`
|
|
21893
|
-
}
|
|
21894
|
-
}
|
|
21895
|
-
),
|
|
21896
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: 10, color: "#666", lineHeight: 1.2 }, children: brand.label })
|
|
21897
|
-
]
|
|
21898
|
-
},
|
|
21899
|
-
brand.value
|
|
21900
|
-
);
|
|
21901
|
-
})
|
|
21902
|
-
}
|
|
21903
|
-
) : null;
|
|
21904
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
21905
|
-
/* @__PURE__ */ jsxs(
|
|
21906
|
-
"button",
|
|
21907
|
-
{
|
|
21908
|
-
ref: buttonRef,
|
|
21909
|
-
type: "button",
|
|
21910
|
-
"data-setto-ui": true,
|
|
21911
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
21912
|
-
onClick: (e) => {
|
|
21913
|
-
e.stopPropagation();
|
|
21914
|
-
onToggle();
|
|
21915
|
-
},
|
|
21916
|
-
"aria-expanded": open,
|
|
21917
|
-
"aria-haspopup": "listbox",
|
|
21918
|
-
"aria-label": `${label}: ${displayLabel}`,
|
|
21919
|
-
title: `${label}: ${displayLabel}`,
|
|
21920
|
-
style: {
|
|
21921
|
-
display: "inline-flex",
|
|
21922
|
-
alignItems: "center",
|
|
21923
|
-
gap: 6,
|
|
21924
|
-
padding: "4px 8px 4px 6px",
|
|
21925
|
-
background: open ? "#f5f3ff" : "#f7f7f7",
|
|
21926
|
-
border: open ? "1px solid #640AFF" : "1px solid #e0e0e0",
|
|
21927
|
-
borderRadius: 6,
|
|
21928
|
-
cursor: "pointer",
|
|
21929
|
-
fontSize: 11,
|
|
21930
|
-
color: "#444",
|
|
21931
|
-
whiteSpace: "nowrap",
|
|
21932
|
-
flexShrink: 0
|
|
21933
|
-
},
|
|
21934
|
-
children: [
|
|
21935
|
-
/* @__PURE__ */ jsx(
|
|
21936
|
-
"span",
|
|
21937
|
-
{
|
|
21938
|
-
"aria-hidden": true,
|
|
21939
|
-
style: {
|
|
21940
|
-
width: 18,
|
|
21941
|
-
height: 18,
|
|
21942
|
-
borderRadius: "50%",
|
|
21943
|
-
background: displayColor,
|
|
21944
|
-
border: `1px solid ${swatchBorder(displayColor)}`,
|
|
21945
|
-
flexShrink: 0
|
|
21946
|
-
}
|
|
21947
|
-
}
|
|
21948
|
-
),
|
|
21949
|
-
/* @__PURE__ */ jsx("span", { children: label }),
|
|
21950
|
-
/* @__PURE__ */ jsx("span", { "aria-hidden": true, style: { color: "#999", fontSize: 10, lineHeight: 1 }, children: "▾" })
|
|
21951
|
-
]
|
|
21952
|
-
}
|
|
21953
|
-
),
|
|
21954
|
-
popover ? createPortal(popover, document.body) : null
|
|
21955
|
-
] });
|
|
21956
|
-
}
|
|
21957
|
-
function SectionToolbar() {
|
|
21958
|
-
const { themeStore, config } = useSetto();
|
|
21959
|
-
const { selectedId, selectSection } = useSectionEdit();
|
|
21960
|
-
const [pos, setPos] = useState(null);
|
|
21961
|
-
const [openField, setOpenField] = useState(null);
|
|
21962
|
-
const barRef = useRef(null);
|
|
21963
|
-
const schema = selectedId ? config.sectionSchemas?.[selectedId] : null;
|
|
21964
|
-
const brandColors = config.brandColors ?? [];
|
|
21965
|
-
useLayoutEffect(() => {
|
|
21966
|
-
if (!selectedId) {
|
|
21967
|
-
setPos(null);
|
|
21968
|
-
return;
|
|
21969
|
-
}
|
|
21970
|
-
const el = document.querySelector(
|
|
21971
|
-
`[data-setto-section="${selectedId}"]`
|
|
21972
|
-
);
|
|
21973
|
-
if (!el) {
|
|
21974
|
-
setPos(null);
|
|
21975
|
-
return;
|
|
21976
|
-
}
|
|
21977
|
-
const update = () => {
|
|
21978
|
-
const bar = barRef.current;
|
|
21979
|
-
if (!bar) return;
|
|
21980
|
-
const w = bar.offsetWidth;
|
|
21981
|
-
const h = bar.offsetHeight || SECTION_TOOLBAR_HEIGHT;
|
|
21982
|
-
setPos(computePosition(el, w, h));
|
|
21983
|
-
};
|
|
21984
|
-
update();
|
|
21985
|
-
requestAnimationFrame(update);
|
|
21986
|
-
window.addEventListener("scroll", update, true);
|
|
21987
|
-
window.addEventListener("resize", update);
|
|
21988
|
-
return () => {
|
|
21989
|
-
window.removeEventListener("scroll", update, true);
|
|
21990
|
-
window.removeEventListener("resize", update);
|
|
21991
|
-
};
|
|
21992
|
-
}, [selectedId, openField, schema?.fields.length]);
|
|
21993
|
-
useEffect(() => {
|
|
21994
|
-
setOpenField(null);
|
|
21995
|
-
}, [selectedId]);
|
|
21996
|
-
useEffect(() => {
|
|
21997
|
-
if (!openField) return;
|
|
21998
|
-
const close = (e) => {
|
|
21999
|
-
const target = e.target;
|
|
22000
|
-
if (barRef.current?.contains(target)) return;
|
|
22001
|
-
if (target instanceof Element && target.closest("[data-setto-ui]")) return;
|
|
22002
|
-
setOpenField(null);
|
|
22003
|
-
};
|
|
22004
|
-
document.addEventListener("mousedown", close);
|
|
22005
|
-
return () => document.removeEventListener("mousedown", close);
|
|
22006
|
-
}, [openField]);
|
|
22007
|
-
useEffect(() => {
|
|
22008
|
-
if (!selectedId) return;
|
|
22009
|
-
const onKey = (e) => {
|
|
22010
|
-
if (e.key !== "Escape") return;
|
|
22011
|
-
if (openField) {
|
|
22012
|
-
setOpenField(null);
|
|
22013
|
-
return;
|
|
22014
|
-
}
|
|
22015
|
-
selectSection(null);
|
|
22016
|
-
};
|
|
22017
|
-
window.addEventListener("keydown", onKey);
|
|
22018
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
22019
|
-
}, [selectedId, selectSection, openField]);
|
|
22020
|
-
if (!selectedId || !schema || !themeStore || brandColors.length === 0) {
|
|
22021
|
-
return null;
|
|
22022
|
-
}
|
|
22023
|
-
const colors = themeStore.getSection(selectedId);
|
|
22024
|
-
return /* @__PURE__ */ jsxs(
|
|
22025
|
-
"div",
|
|
22026
|
-
{
|
|
22027
|
-
ref: barRef,
|
|
22028
|
-
role: "toolbar",
|
|
22029
|
-
"data-setto-ui": true,
|
|
22030
|
-
"data-setto-theme-id": selectedId,
|
|
22031
|
-
"aria-label": `Farger — ${schema.label}`,
|
|
22032
|
-
style: {
|
|
22033
|
-
position: "fixed",
|
|
22034
|
-
top: pos?.top ?? -9999,
|
|
22035
|
-
left: pos?.left ?? 0,
|
|
22036
|
-
width: "max-content",
|
|
22037
|
-
maxWidth: `calc(100vw - ${MARGIN$1 * 2}px)`,
|
|
22038
|
-
minHeight: SECTION_TOOLBAR_HEIGHT,
|
|
22039
|
-
zIndex: 2147483646,
|
|
22040
|
-
display: "flex",
|
|
22041
|
-
alignItems: "center",
|
|
22042
|
-
gap: 8,
|
|
22043
|
-
padding: "0 12px",
|
|
22044
|
-
background: "#ffffff",
|
|
22045
|
-
border: "1px solid #e0e0e0",
|
|
22046
|
-
borderRadius: 8,
|
|
22047
|
-
boxShadow: "0 4px 20px rgba(0,0,0,0.12)",
|
|
22048
|
-
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
22049
|
-
fontSize: 12,
|
|
22050
|
-
pointerEvents: "auto",
|
|
22051
|
-
userSelect: "none",
|
|
22052
|
-
visibility: pos ? "visible" : "hidden"
|
|
22053
|
-
},
|
|
22054
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
22055
|
-
onClick: (e) => e.stopPropagation(),
|
|
22056
|
-
children: [
|
|
22057
|
-
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600, whiteSpace: "nowrap", flexShrink: 0 }, children: schema.label }),
|
|
22058
|
-
/* @__PURE__ */ jsx("span", { style: { color: "#ccc", flexShrink: 0 }, children: "·" }),
|
|
22059
|
-
/* @__PURE__ */ jsx(
|
|
22060
|
-
"div",
|
|
22061
|
-
{
|
|
22062
|
-
style: {
|
|
22063
|
-
display: "flex",
|
|
22064
|
-
alignItems: "center",
|
|
22065
|
-
gap: 6,
|
|
22066
|
-
flexWrap: "nowrap"
|
|
22067
|
-
},
|
|
22068
|
-
children: schema.fields.map((field) => /* @__PURE__ */ jsx(
|
|
22069
|
-
BrandColorPicker,
|
|
22070
|
-
{
|
|
22071
|
-
label: field.label,
|
|
22072
|
-
value: colors[field.key] ?? "",
|
|
22073
|
-
brandColors,
|
|
22074
|
-
open: openField === field.key,
|
|
22075
|
-
popoverPlacement: "below",
|
|
22076
|
-
onToggle: () => setOpenField((prev) => prev === field.key ? null : field.key),
|
|
22077
|
-
onSelect: (v) => {
|
|
22078
|
-
themeStore.set(selectedId, field.key, v);
|
|
22079
|
-
setOpenField(null);
|
|
22080
|
-
}
|
|
22081
|
-
},
|
|
22082
|
-
field.key
|
|
22083
|
-
))
|
|
22084
|
-
}
|
|
22085
|
-
),
|
|
22086
|
-
/* @__PURE__ */ jsx(
|
|
22087
|
-
"button",
|
|
22088
|
-
{
|
|
22089
|
-
type: "button",
|
|
22090
|
-
"data-setto-ui": true,
|
|
22091
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
22092
|
-
onClick: (e) => {
|
|
22093
|
-
e.stopPropagation();
|
|
22094
|
-
selectSection(null);
|
|
22095
|
-
},
|
|
22096
|
-
"aria-label": "Lukk",
|
|
22097
|
-
style: {
|
|
22098
|
-
flexShrink: 0,
|
|
22099
|
-
background: "transparent",
|
|
22100
|
-
border: "none",
|
|
22101
|
-
color: "#999",
|
|
22102
|
-
cursor: "pointer",
|
|
22103
|
-
fontSize: 16,
|
|
22104
|
-
lineHeight: 1,
|
|
22105
|
-
padding: "2px 6px"
|
|
22106
|
-
},
|
|
22107
|
-
children: "×"
|
|
22108
|
-
}
|
|
22109
|
-
)
|
|
22110
|
-
]
|
|
22111
|
-
}
|
|
22112
|
-
);
|
|
22113
|
-
}
|
|
22114
21635
|
function SettoMark({
|
|
22115
21636
|
size = 24,
|
|
22116
21637
|
letterColor = "#F2EBDF",
|
|
@@ -22175,6 +21696,8 @@ const pillStyle = {
|
|
|
22175
21696
|
function EditModeShell({ children, themeStore, active }) {
|
|
22176
21697
|
useSettoDocumentLayout(active);
|
|
22177
21698
|
const Toolbar = useSettoChromeSlot("toolbar");
|
|
21699
|
+
const SectionTools = useSettoChromeSlot("section-toolbar");
|
|
21700
|
+
const LinkHint = useSettoChromeSlot("link-hint");
|
|
22178
21701
|
const [toolbarRoot, setToolbarRoot] = useState(null);
|
|
22179
21702
|
const [hintRoot, setHintRoot] = useState(null);
|
|
22180
21703
|
const [sectionToolbarRoot, setSectionToolbarRoot] = useState(null);
|
|
@@ -22208,8 +21731,8 @@ function EditModeShell({ children, themeStore, active }) {
|
|
|
22208
21731
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22209
21732
|
children,
|
|
22210
21733
|
active && toolbarRoot ? createPortal(Toolbar ? /* @__PURE__ */ jsx(Toolbar, {}) : /* @__PURE__ */ jsx(ToolbarUnavailable, {}), toolbarRoot) : null,
|
|
22211
|
-
active && hintRoot ? createPortal(/* @__PURE__ */ jsx(
|
|
22212
|
-
active && sectionToolbarRoot && themeStore ? createPortal(/* @__PURE__ */ jsx(
|
|
21734
|
+
active && hintRoot && LinkHint ? createPortal(/* @__PURE__ */ jsx(LinkHint, {}), hintRoot) : null,
|
|
21735
|
+
active && sectionToolbarRoot && themeStore && SectionTools ? createPortal(/* @__PURE__ */ jsx(SectionTools, {}), sectionToolbarRoot) : null
|
|
22213
21736
|
] });
|
|
22214
21737
|
}
|
|
22215
21738
|
const SettoContext = createContext(null);
|
|
@@ -22256,6 +21779,16 @@ function SettoProvider({ config, children }) {
|
|
|
22256
21779
|
setStoreReady(true);
|
|
22257
21780
|
}, [i18n, config.theme]);
|
|
22258
21781
|
const editMode = !!session && !!access.currentSite && !onAdminRoute && !authLoading && !access.loading;
|
|
21782
|
+
const [selectedSectionId, setSelectedSectionId] = useState(null);
|
|
21783
|
+
const selectSection = useCallback((id) => setSelectedSectionId(id), []);
|
|
21784
|
+
const [guestEdit, setGuestEdit] = useState(false);
|
|
21785
|
+
useEffect(() => {
|
|
21786
|
+
if (editMode && guestEdit) setGuestEdit(false);
|
|
21787
|
+
}, [editMode, guestEdit]);
|
|
21788
|
+
useEffect(() => {
|
|
21789
|
+
document.documentElement.classList.toggle("setto-guest-editing", guestEdit);
|
|
21790
|
+
return () => document.documentElement.classList.remove("setto-guest-editing");
|
|
21791
|
+
}, [guestEdit]);
|
|
22259
21792
|
const value = {
|
|
22260
21793
|
config,
|
|
22261
21794
|
supabase,
|
|
@@ -22267,10 +21800,14 @@ function SettoProvider({ config, children }) {
|
|
|
22267
21800
|
sites: access.sites,
|
|
22268
21801
|
store: storeReady ? storeRef.current : null,
|
|
22269
21802
|
themeStore: storeReady ? themeStoreRef.current : null,
|
|
22270
|
-
assetStore: storeReady ? assetStoreRef.current : null
|
|
21803
|
+
assetStore: storeReady ? assetStoreRef.current : null,
|
|
21804
|
+
selectedSectionId,
|
|
21805
|
+
selectSection,
|
|
21806
|
+
guestEdit,
|
|
21807
|
+
setGuestEdit
|
|
22271
21808
|
};
|
|
22272
21809
|
const editShellActive = editMode && !!value.store;
|
|
22273
|
-
return /* @__PURE__ */ jsx(SettoContext.Provider, { value, children: /* @__PURE__ */ jsxs(
|
|
21810
|
+
return /* @__PURE__ */ jsx(SettoContext.Provider, { value, children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22274
21811
|
/* @__PURE__ */ jsx(EditModeShell, { active: editShellActive, themeStore: value.themeStore, children }),
|
|
22275
21812
|
/* @__PURE__ */ jsx(SettoChrome, {})
|
|
22276
21813
|
] }) });
|
|
@@ -22282,233 +21819,42 @@ function useSetto() {
|
|
|
22282
21819
|
}
|
|
22283
21820
|
return ctx;
|
|
22284
21821
|
}
|
|
22285
|
-
const GuestEditContext = createContext(null);
|
|
22286
21822
|
function GuestEditProvider({ children }) {
|
|
22287
|
-
const {
|
|
22288
|
-
const
|
|
22289
|
-
|
|
22290
|
-
useEffect(() => {
|
|
22291
|
-
if (editMode && active) setActive(false);
|
|
22292
|
-
}, [editMode, active]);
|
|
22293
|
-
useEffect(() => {
|
|
22294
|
-
document.documentElement.classList.toggle("setto-guest-editing", active);
|
|
22295
|
-
return () => document.documentElement.classList.remove("setto-guest-editing");
|
|
22296
|
-
}, [active]);
|
|
22297
|
-
const start = useCallback(() => setActive(true), []);
|
|
22298
|
-
const stop = useCallback(() => {
|
|
22299
|
-
setActive(false);
|
|
22300
|
-
selectSection(null);
|
|
22301
|
-
}, [selectSection]);
|
|
22302
|
-
return /* @__PURE__ */ jsxs(GuestEditContext.Provider, { value: { active, start, stop }, children: [
|
|
21823
|
+
const { guestEdit, themeStore } = useSetto();
|
|
21824
|
+
const SectionTools = useSettoChromeSlot("section-toolbar");
|
|
21825
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22303
21826
|
children,
|
|
22304
|
-
|
|
21827
|
+
guestEdit && themeStore && SectionTools ? createPortal(/* @__PURE__ */ jsx(SectionTools, {}), document.body) : null
|
|
22305
21828
|
] });
|
|
22306
21829
|
}
|
|
22307
21830
|
function useGuestEdit() {
|
|
22308
|
-
const
|
|
22309
|
-
|
|
22310
|
-
|
|
22311
|
-
|
|
22312
|
-
|
|
22313
|
-
|
|
22314
|
-
|
|
22315
|
-
}
|
|
22316
|
-
const PREVIEW_HOST = /(^|\.)site\.setto\.no$/i;
|
|
22317
|
-
function isPreviewHost(hostname) {
|
|
22318
|
-
return PREVIEW_HOST.test(hostname);
|
|
22319
|
-
}
|
|
22320
|
-
function previewBarState(input) {
|
|
22321
|
-
if (!input.onPreview || input.authLoading) return "hidden";
|
|
22322
|
-
if (input.hasSession && !input.sitesLoaded) return "hidden";
|
|
22323
|
-
if (!input.hasSession && input.soldPublic === null) return "hidden";
|
|
22324
|
-
const bought = input.paidMarker || input.currentSiteIsLive || input.soldPublic === true;
|
|
22325
|
-
if (bought) return "hidden";
|
|
22326
|
-
return input.hasSession && input.hasCurrentSite ? "owner" : "visitor";
|
|
22327
|
-
}
|
|
22328
|
-
function SettoPreviewBar() {
|
|
22329
|
-
const { supabase, api, config, session, authLoading, currentSite, sites, editMode } = useSetto();
|
|
22330
|
-
const [onPreview, setOnPreview] = useState(false);
|
|
22331
|
-
const [busy, setBusy] = useState(false);
|
|
22332
|
-
const [error, setError] = useState(null);
|
|
22333
|
-
const [paid, setPaid] = useState(false);
|
|
22334
|
-
const [soldPublic, setSoldPublic] = useState(null);
|
|
22335
|
-
useEffect(() => {
|
|
22336
|
-
setOnPreview(isPreviewHost(window.location.hostname));
|
|
22337
|
-
setPaid(new URLSearchParams(window.location.search).get("betaling") === "ok");
|
|
22338
|
-
}, []);
|
|
22339
|
-
useEffect(() => {
|
|
22340
|
-
if (!onPreview || session) return;
|
|
22341
|
-
let cancelled = false;
|
|
22342
|
-
fetch(`${config.apiUrl}/onboarding/sites/${config.siteId}/sold`, {
|
|
22343
|
-
headers: { Accept: "application/json" }
|
|
22344
|
-
}).then((r) => r.ok ? r.json() : null).then((d) => {
|
|
22345
|
-
if (!cancelled && d) setSoldPublic(d.sold === true);
|
|
22346
|
-
}).catch(() => {
|
|
22347
|
-
});
|
|
22348
|
-
return () => {
|
|
22349
|
-
cancelled = true;
|
|
22350
|
-
};
|
|
22351
|
-
}, [onPreview, session, config.apiUrl, config.siteId]);
|
|
22352
|
-
const signIn = () => {
|
|
22353
|
-
window.location.href = checkoutIntentUrl();
|
|
22354
|
-
};
|
|
22355
|
-
const next = () => {
|
|
22356
|
-
if (window.parent !== window) {
|
|
22357
|
-
window.parent.postMessage({ type: "setto:next", siteId: config.siteId }, "*");
|
|
22358
|
-
return;
|
|
22359
|
-
}
|
|
22360
|
-
signIn();
|
|
22361
|
-
};
|
|
22362
|
-
const publish = async () => {
|
|
22363
|
-
setBusy(true);
|
|
22364
|
-
setError(null);
|
|
22365
|
-
try {
|
|
22366
|
-
const token = (await supabase.auth.getSession()).data.session?.access_token;
|
|
22367
|
-
if (!token) {
|
|
22368
|
-
signIn();
|
|
22369
|
-
return;
|
|
22370
|
-
}
|
|
22371
|
-
const data = await api.request(
|
|
22372
|
-
`/onboarding/sites/${config.siteId}/checkout`,
|
|
22373
|
-
{
|
|
22374
|
-
method: "POST",
|
|
22375
|
-
// Back to the page they were looking at, not to a chat window.
|
|
22376
|
-
body: { returnTo: window.location.origin + window.location.pathname }
|
|
22377
|
-
},
|
|
22378
|
-
"checkout"
|
|
22379
|
-
);
|
|
22380
|
-
if (!data.url) throw new Error("checkout_failed");
|
|
22381
|
-
window.location.href = data.url;
|
|
22382
|
-
} catch (err) {
|
|
22383
|
-
const detail = err instanceof Error ? err.message : "";
|
|
22384
|
-
setError(
|
|
22385
|
-
detail.includes("already_paid") ? "Denne siden er allerede betalt." : detail.includes("not_found") ? "Fant ingen bestilling for denne siden på kontoen din." : detail.includes("stripe_not_configured") ? "Betaling er ikke satt opp ennå." : "Klarte ikke starte betalingen. Prøv igjen."
|
|
22386
|
-
);
|
|
22387
|
-
setBusy(false);
|
|
21831
|
+
const { guestEdit, setGuestEdit, selectSection } = useSetto();
|
|
21832
|
+
return {
|
|
21833
|
+
active: guestEdit,
|
|
21834
|
+
start: () => setGuestEdit(true),
|
|
21835
|
+
stop: () => {
|
|
21836
|
+
setGuestEdit(false);
|
|
21837
|
+
selectSection(null);
|
|
22388
21838
|
}
|
|
22389
21839
|
};
|
|
22390
|
-
const resumed = useRef(false);
|
|
22391
|
-
useEffect(() => {
|
|
22392
|
-
if (resumed.current || !onPreview || !session || !currentSite) return;
|
|
22393
|
-
if (!wantsCheckout()) return;
|
|
22394
|
-
if (paid || currentSite.status === "live") return;
|
|
22395
|
-
resumed.current = true;
|
|
22396
|
-
window.history.replaceState(null, "", withoutCheckoutIntent());
|
|
22397
|
-
void publish();
|
|
22398
|
-
}, [onPreview, session, currentSite, paid]);
|
|
22399
|
-
const state = previewBarState({
|
|
22400
|
-
onPreview,
|
|
22401
|
-
authLoading,
|
|
22402
|
-
hasSession: !!session,
|
|
22403
|
-
sitesLoaded: sites !== null,
|
|
22404
|
-
hasCurrentSite: !!currentSite,
|
|
22405
|
-
currentSiteIsLive: currentSite?.status === "live",
|
|
22406
|
-
soldPublic,
|
|
22407
|
-
paidMarker: paid
|
|
22408
|
-
});
|
|
22409
|
-
if (state === "hidden") return null;
|
|
22410
|
-
const owner = state === "owner";
|
|
22411
|
-
const name = currentSite?.display_name?.trim() || config.displayName?.trim() || config.siteId;
|
|
22412
|
-
return createPortal(
|
|
22413
|
-
/*
|
|
22414
|
-
* Lifted above the editor's floating button when edit mode is on, which
|
|
22415
|
-
* sits in the same corner band. Sideways would collide again the moment
|
|
22416
|
-
* its toolbar opens, since that expands rightward.
|
|
22417
|
-
*/
|
|
22418
|
-
/* @__PURE__ */ jsx(
|
|
22419
|
-
"div",
|
|
22420
|
-
{
|
|
22421
|
-
style: editMode ? { ...barStyle, bottom: "calc(max(16px, env(safe-area-inset-bottom, 0px)) + 68px)" } : barStyle,
|
|
22422
|
-
"data-setto-preview-bar": "",
|
|
22423
|
-
children: owner ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22424
|
-
/* @__PURE__ */ jsx("span", { style: dotStyle, "aria-hidden": true }),
|
|
22425
|
-
/* @__PURE__ */ jsxs("span", { style: labelStyle, children: [
|
|
22426
|
-
"Du forhåndsviser nå ",
|
|
22427
|
-
/* @__PURE__ */ jsx("strong", { style: { fontWeight: 600 }, children: name })
|
|
22428
|
-
] }),
|
|
22429
|
-
error && /* @__PURE__ */ jsx("span", { style: errorStyle, children: error }),
|
|
22430
|
-
/* @__PURE__ */ jsx("button", { type: "button", style: primaryStyle, onClick: publish, disabled: busy, children: busy ? "Åpner betaling …" : "Publiser" })
|
|
22431
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22432
|
-
/* @__PURE__ */ jsx("span", { style: dotStyle, "aria-hidden": true }),
|
|
22433
|
-
/* @__PURE__ */ jsx("span", { style: labelStyle, children: "Forhåndsvisning" }),
|
|
22434
|
-
/* @__PURE__ */ jsx("button", { type: "button", style: primaryStyle, onClick: next, children: "Neste" })
|
|
22435
|
-
] })
|
|
22436
|
-
}
|
|
22437
|
-
),
|
|
22438
|
-
document.body
|
|
22439
|
-
);
|
|
22440
21840
|
}
|
|
22441
|
-
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
22447
|
-
|
|
22448
|
-
|
|
22449
|
-
|
|
22450
|
-
|
|
22451
|
-
|
|
22452
|
-
|
|
22453
|
-
|
|
22454
|
-
|
|
22455
|
-
|
|
22456
|
-
|
|
22457
|
-
|
|
22458
|
-
boxShadow: "0 18px 40px -18px rgba(0, 0, 0, 0.65)",
|
|
22459
|
-
/*
|
|
22460
|
-
* A frosted rim, so the pill reads as an object on any page.
|
|
22461
|
-
*
|
|
22462
|
-
* The bar sits on sites Setto did not choose the colours for: on a dark hero
|
|
22463
|
-
* a dark pill disappears, and on a pale section its shadow is all that holds
|
|
22464
|
-
* it. A translucent white border with `padding-box` clipping lets the page
|
|
22465
|
-
* show through the rim itself, which separates the pill from either ground
|
|
22466
|
-
* without picking a side.
|
|
22467
|
-
*/
|
|
22468
|
-
border: "5px solid rgba(255, 255, 255, 0.22)",
|
|
22469
|
-
backgroundClip: "padding-box",
|
|
22470
|
-
backdropFilter: "blur(10px)",
|
|
22471
|
-
WebkitBackdropFilter: "blur(10px)"
|
|
22472
|
-
};
|
|
22473
|
-
const dotStyle = {
|
|
22474
|
-
width: 7,
|
|
22475
|
-
height: 7,
|
|
22476
|
-
borderRadius: "50%",
|
|
22477
|
-
background: "#c4502a",
|
|
22478
|
-
flex: "none"
|
|
22479
|
-
};
|
|
22480
|
-
const labelStyle = {
|
|
22481
|
-
whiteSpace: "nowrap",
|
|
22482
|
-
overflow: "hidden",
|
|
22483
|
-
textOverflow: "ellipsis"
|
|
22484
|
-
};
|
|
22485
|
-
const primaryStyle = {
|
|
22486
|
-
flex: "none",
|
|
22487
|
-
padding: "9px 18px",
|
|
22488
|
-
border: 0,
|
|
22489
|
-
borderRadius: 999,
|
|
22490
|
-
background: "#c4502a",
|
|
22491
|
-
color: "#fffdf8",
|
|
22492
|
-
font: "inherit",
|
|
22493
|
-
fontWeight: 600,
|
|
22494
|
-
cursor: "pointer"
|
|
22495
|
-
};
|
|
22496
|
-
const errorStyle = {
|
|
22497
|
-
color: "#ffb4a2",
|
|
22498
|
-
fontSize: 13,
|
|
22499
|
-
/*
|
|
22500
|
-
* Shrinkable, unlike the label beside it.
|
|
22501
|
-
*
|
|
22502
|
-
* `nowrap` on a flex child whose `min-width` is `auto` cannot shrink below
|
|
22503
|
-
* its own text, so on a 320px phone the error shouldered «Publiser» 19px
|
|
22504
|
-
* past the right edge of the screen and the bar clipped it — the button
|
|
22505
|
-
* that takes the money, unreachable, exactly when something had gone wrong.
|
|
22506
|
-
*/
|
|
22507
|
-
minWidth: 0,
|
|
22508
|
-
overflow: "hidden",
|
|
22509
|
-
textOverflow: "ellipsis",
|
|
22510
|
-
whiteSpace: "nowrap"
|
|
22511
|
-
};
|
|
21841
|
+
function isLinkContext(el) {
|
|
21842
|
+
const key = el.getAttribute("data-setto-key");
|
|
21843
|
+
if (key?.startsWith("lang.")) return false;
|
|
21844
|
+
if (el.closest("[data-setto-no-hint]")) return false;
|
|
21845
|
+
return !!(el.closest("a[href]") || el.closest("button"));
|
|
21846
|
+
}
|
|
21847
|
+
function activateLinkContext(el) {
|
|
21848
|
+
const anchor = el.closest("a[href]");
|
|
21849
|
+
if (anchor instanceof HTMLAnchorElement) {
|
|
21850
|
+
anchor.click();
|
|
21851
|
+
return;
|
|
21852
|
+
}
|
|
21853
|
+
const button = el.closest("button");
|
|
21854
|
+
if (button instanceof HTMLButtonElement) {
|
|
21855
|
+
button.click();
|
|
21856
|
+
}
|
|
21857
|
+
}
|
|
22512
21858
|
const MARGIN = 10;
|
|
22513
21859
|
const OFFSET = 8;
|
|
22514
21860
|
const MIN_TOUCH = 44;
|
|
@@ -22623,6 +21969,18 @@ function rangeFromPoint(doc, x, y) {
|
|
|
22623
21969
|
range.collapse(true);
|
|
22624
21970
|
return range;
|
|
22625
21971
|
}
|
|
21972
|
+
const QUERY = "(hover: none) and (pointer: coarse)";
|
|
21973
|
+
function subscribe(onChange) {
|
|
21974
|
+
const mq = window.matchMedia(QUERY);
|
|
21975
|
+
mq.addEventListener("change", onChange);
|
|
21976
|
+
return () => mq.removeEventListener("change", onChange);
|
|
21977
|
+
}
|
|
21978
|
+
function getSnapshot() {
|
|
21979
|
+
return window.matchMedia(QUERY).matches;
|
|
21980
|
+
}
|
|
21981
|
+
function useCoarsePointer() {
|
|
21982
|
+
return useSyncExternalStore(subscribe, getSnapshot, () => false);
|
|
21983
|
+
}
|
|
22626
21984
|
function T({ k }) {
|
|
22627
21985
|
const { t, i18n } = useTranslation();
|
|
22628
21986
|
const { editMode, store } = useSetto();
|
|
@@ -22745,6 +22103,10 @@ function toBcp47(code) {
|
|
|
22745
22103
|
if (base === "en") return "en";
|
|
22746
22104
|
return code;
|
|
22747
22105
|
}
|
|
22106
|
+
function useSectionEdit() {
|
|
22107
|
+
const { selectedSectionId, selectSection } = useSetto();
|
|
22108
|
+
return { selectedId: selectedSectionId, selectSection };
|
|
22109
|
+
}
|
|
22748
22110
|
function isTextEditClick(target) {
|
|
22749
22111
|
if (target.closest("[data-setto-key]")) return true;
|
|
22750
22112
|
if (target.closest("[data-setto-ui]")) return true;
|
|
@@ -23281,12 +22643,12 @@ function SettoImage({ srcKey, alt, className, style, ...rest }) {
|
|
|
23281
22643
|
)
|
|
23282
22644
|
] });
|
|
23283
22645
|
}
|
|
23284
|
-
const STYLE_ID$
|
|
22646
|
+
const STYLE_ID$1 = "setto-repeater-styles";
|
|
23285
22647
|
function useRepeaterStyles() {
|
|
23286
22648
|
useEffect(() => {
|
|
23287
|
-
if (document.getElementById(STYLE_ID$
|
|
22649
|
+
if (document.getElementById(STYLE_ID$1)) return;
|
|
23288
22650
|
const el = document.createElement("style");
|
|
23289
|
-
el.id = STYLE_ID$
|
|
22651
|
+
el.id = STYLE_ID$1;
|
|
23290
22652
|
el.textContent = `
|
|
23291
22653
|
.setto-repeater-remove {
|
|
23292
22654
|
opacity: 0;
|
|
@@ -23571,276 +22933,6 @@ function buildEnvelope(fields, values, extra) {
|
|
|
23571
22933
|
function settoSubmissionUrl(apiUrl, siteId, formId) {
|
|
23572
22934
|
return `${apiUrl.replace(/\/+$/, "")}/sites/${encodeURIComponent(siteId)}/forms/${encodeURIComponent(formId)}/submissions`;
|
|
23573
22935
|
}
|
|
23574
|
-
const STYLE_ID$1 = "setto-form-edit-styles";
|
|
23575
|
-
function useFormEditStyles() {
|
|
23576
|
-
useEffect(() => {
|
|
23577
|
-
if (document.getElementById(STYLE_ID$1)) return;
|
|
23578
|
-
const el = document.createElement("style");
|
|
23579
|
-
el.id = STYLE_ID$1;
|
|
23580
|
-
el.textContent = `
|
|
23581
|
-
.setto-form-field-tools {
|
|
23582
|
-
opacity: 0;
|
|
23583
|
-
transition: opacity 120ms ease;
|
|
23584
|
-
}
|
|
23585
|
-
.setto-form__field:hover .setto-form-field-tools,
|
|
23586
|
-
.setto-form__field:focus-within .setto-form-field-tools,
|
|
23587
|
-
.setto-form-field-tools[data-open] {
|
|
23588
|
-
opacity: 1;
|
|
23589
|
-
}
|
|
23590
|
-
@media (hover: none) {
|
|
23591
|
-
.setto-form-field-tools { opacity: 1; }
|
|
23592
|
-
}
|
|
23593
|
-
`;
|
|
23594
|
-
document.head.appendChild(el);
|
|
23595
|
-
}, []);
|
|
23596
|
-
}
|
|
23597
|
-
function FormFieldTools({
|
|
23598
|
-
field,
|
|
23599
|
-
index,
|
|
23600
|
-
count,
|
|
23601
|
-
autoOpen,
|
|
23602
|
-
onMove,
|
|
23603
|
-
onRemove,
|
|
23604
|
-
onChange
|
|
23605
|
-
}) {
|
|
23606
|
-
useFormEditStyles();
|
|
23607
|
-
const [open, setOpen] = useState(autoOpen === true);
|
|
23608
|
-
const gearRef = useRef(null);
|
|
23609
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
23610
|
-
/* @__PURE__ */ jsxs(
|
|
23611
|
-
"div",
|
|
23612
|
-
{
|
|
23613
|
-
"data-setto-ui": true,
|
|
23614
|
-
className: "setto-form-field-tools",
|
|
23615
|
-
style: toolsStyle,
|
|
23616
|
-
...open ? { "data-open": "" } : {},
|
|
23617
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
23618
|
-
onClick: (e) => e.stopPropagation(),
|
|
23619
|
-
children: [
|
|
23620
|
-
/* @__PURE__ */ jsx(ToolButton, { label: "Flytt opp", disabled: index === 0, onClick: () => onMove(-1), children: /* @__PURE__ */ jsx(ArrowIcon, { direction: "up" }) }),
|
|
23621
|
-
/* @__PURE__ */ jsx(
|
|
23622
|
-
ToolButton,
|
|
23623
|
-
{
|
|
23624
|
-
label: "Flytt ned",
|
|
23625
|
-
disabled: index === count - 1,
|
|
23626
|
-
onClick: () => onMove(1),
|
|
23627
|
-
children: /* @__PURE__ */ jsx(ArrowIcon, { direction: "down" })
|
|
23628
|
-
}
|
|
23629
|
-
),
|
|
23630
|
-
/* @__PURE__ */ jsx(
|
|
23631
|
-
ToolButton,
|
|
23632
|
-
{
|
|
23633
|
-
ref: gearRef,
|
|
23634
|
-
label: "Feltinnstillinger",
|
|
23635
|
-
active: open,
|
|
23636
|
-
onClick: () => setOpen((o) => !o),
|
|
23637
|
-
children: /* @__PURE__ */ jsx(GearIcon, {})
|
|
23638
|
-
}
|
|
23639
|
-
),
|
|
23640
|
-
/* @__PURE__ */ jsx(ToolButton, { label: "Fjern felt", disabled: count <= 1, onClick: onRemove, danger: true, children: "×" })
|
|
23641
|
-
]
|
|
23642
|
-
}
|
|
23643
|
-
),
|
|
23644
|
-
/* @__PURE__ */ jsx(
|
|
23645
|
-
FloatingPopover,
|
|
23646
|
-
{
|
|
23647
|
-
open,
|
|
23648
|
-
anchorRef: gearRef,
|
|
23649
|
-
onClose: () => setOpen(false),
|
|
23650
|
-
ariaLabel: "Feltinnstillinger",
|
|
23651
|
-
minWidth: 300,
|
|
23652
|
-
style: { width: 300, padding: 14 },
|
|
23653
|
-
children: /* @__PURE__ */ jsx(FieldSettings, { field, onChange })
|
|
23654
|
-
}
|
|
23655
|
-
)
|
|
23656
|
-
] });
|
|
23657
|
-
}
|
|
23658
|
-
function FieldSettings({ field, onChange }) {
|
|
23659
|
-
const [label, setLabel] = useState(field.label);
|
|
23660
|
-
const [placeholder, setPlaceholder] = useState(field.placeholder);
|
|
23661
|
-
const [options, setOptions] = useState(field.options.join("\n"));
|
|
23662
|
-
const [name, setName] = useState(field.name);
|
|
23663
|
-
useEffect(() => setLabel(field.label), [field.label]);
|
|
23664
|
-
useEffect(() => setPlaceholder(field.placeholder), [field.placeholder]);
|
|
23665
|
-
useEffect(() => setName(field.name), [field.name]);
|
|
23666
|
-
return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 10, fontSize: 13, color: "#222" }, children: [
|
|
23667
|
-
/* @__PURE__ */ jsx(Row, { label: "Type", children: /* @__PURE__ */ jsx(
|
|
23668
|
-
"select",
|
|
23669
|
-
{
|
|
23670
|
-
value: field.type,
|
|
23671
|
-
onChange: (e) => onChange({ type: e.target.value }),
|
|
23672
|
-
style: inputStyle$1,
|
|
23673
|
-
children: FORM_FIELD_TYPES.map((type) => /* @__PURE__ */ jsx("option", { value: type, children: FORM_FIELD_TYPE_LABELS[type] }, type))
|
|
23674
|
-
}
|
|
23675
|
-
) }),
|
|
23676
|
-
/* @__PURE__ */ jsx(Row, { label: "Etikett", children: /* @__PURE__ */ jsx(
|
|
23677
|
-
"input",
|
|
23678
|
-
{
|
|
23679
|
-
type: "text",
|
|
23680
|
-
value: label,
|
|
23681
|
-
onChange: (e) => setLabel(e.target.value),
|
|
23682
|
-
onBlur: () => label !== field.label && onChange({ label }),
|
|
23683
|
-
style: inputStyle$1
|
|
23684
|
-
}
|
|
23685
|
-
) }),
|
|
23686
|
-
fieldTypeHasPlaceholder(field.type) ? /* @__PURE__ */ jsx(Row, { label: "Plassholder", children: /* @__PURE__ */ jsx(
|
|
23687
|
-
"input",
|
|
23688
|
-
{
|
|
23689
|
-
type: "text",
|
|
23690
|
-
value: placeholder,
|
|
23691
|
-
onChange: (e) => setPlaceholder(e.target.value),
|
|
23692
|
-
onBlur: () => placeholder !== field.placeholder && onChange({ placeholder }),
|
|
23693
|
-
style: inputStyle$1
|
|
23694
|
-
}
|
|
23695
|
-
) }) : null,
|
|
23696
|
-
fieldTypeHasOptions(field.type) ? /* @__PURE__ */ jsx(Row, { label: "Alternativer", hint: "Ett per linje", children: /* @__PURE__ */ jsx(
|
|
23697
|
-
"textarea",
|
|
23698
|
-
{
|
|
23699
|
-
value: options,
|
|
23700
|
-
rows: 4,
|
|
23701
|
-
onChange: (e) => setOptions(e.target.value),
|
|
23702
|
-
onBlur: () => options !== field.options.join("\n") && onChange({ options }),
|
|
23703
|
-
style: { ...inputStyle$1, resize: "vertical", fontFamily: "inherit" }
|
|
23704
|
-
}
|
|
23705
|
-
) }) : null,
|
|
23706
|
-
/* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, cursor: "pointer" }, children: [
|
|
23707
|
-
/* @__PURE__ */ jsx(
|
|
23708
|
-
"input",
|
|
23709
|
-
{
|
|
23710
|
-
type: "checkbox",
|
|
23711
|
-
checked: field.required,
|
|
23712
|
-
onChange: (e) => onChange({ required: e.target.checked })
|
|
23713
|
-
}
|
|
23714
|
-
),
|
|
23715
|
-
"Må fylles ut"
|
|
23716
|
-
] }),
|
|
23717
|
-
/* @__PURE__ */ jsx(Row, { label: "Teknisk navn", hint: "Brukes i e-posten og i historikken", children: /* @__PURE__ */ jsx(
|
|
23718
|
-
"input",
|
|
23719
|
-
{
|
|
23720
|
-
type: "text",
|
|
23721
|
-
value: name,
|
|
23722
|
-
onChange: (e) => setName(e.target.value),
|
|
23723
|
-
onBlur: () => {
|
|
23724
|
-
const next = name.trim();
|
|
23725
|
-
if (next && next !== field.name) onChange({ name: next });
|
|
23726
|
-
else setName(field.name);
|
|
23727
|
-
},
|
|
23728
|
-
style: { ...inputStyle$1, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
|
|
23729
|
-
}
|
|
23730
|
-
) })
|
|
23731
|
-
] });
|
|
23732
|
-
}
|
|
23733
|
-
function Row({ label, hint, children }) {
|
|
23734
|
-
return /* @__PURE__ */ jsxs("label", { style: { display: "grid", gap: 4 }, children: [
|
|
23735
|
-
/* @__PURE__ */ jsxs("span", { style: { fontSize: 12, color: "#666" }, children: [
|
|
23736
|
-
label,
|
|
23737
|
-
hint ? /* @__PURE__ */ jsxs("span", { style: { color: "#999" }, children: [
|
|
23738
|
-
" · ",
|
|
23739
|
-
hint
|
|
23740
|
-
] }) : null
|
|
23741
|
-
] }),
|
|
23742
|
-
children
|
|
23743
|
-
] });
|
|
23744
|
-
}
|
|
23745
|
-
function ToolButton({ label, onClick, disabled, active, danger, children, ref }) {
|
|
23746
|
-
return /* @__PURE__ */ jsx(
|
|
23747
|
-
"button",
|
|
23748
|
-
{
|
|
23749
|
-
ref,
|
|
23750
|
-
type: "button",
|
|
23751
|
-
"data-setto-ui": true,
|
|
23752
|
-
"aria-label": label,
|
|
23753
|
-
title: label,
|
|
23754
|
-
disabled,
|
|
23755
|
-
onClick,
|
|
23756
|
-
style: {
|
|
23757
|
-
...toolBtnStyle,
|
|
23758
|
-
...active ? { background: "#640AFF", color: "#fff", borderColor: "#640AFF" } : {},
|
|
23759
|
-
...danger ? { fontSize: 16 } : {},
|
|
23760
|
-
...disabled ? { opacity: 0.35, cursor: "default" } : {}
|
|
23761
|
-
},
|
|
23762
|
-
children
|
|
23763
|
-
}
|
|
23764
|
-
);
|
|
23765
|
-
}
|
|
23766
|
-
function ArrowIcon({ direction }) {
|
|
23767
|
-
return /* @__PURE__ */ jsx(
|
|
23768
|
-
"svg",
|
|
23769
|
-
{
|
|
23770
|
-
width: "12",
|
|
23771
|
-
height: "12",
|
|
23772
|
-
viewBox: "0 0 24 24",
|
|
23773
|
-
fill: "none",
|
|
23774
|
-
stroke: "currentColor",
|
|
23775
|
-
strokeWidth: "2.5",
|
|
23776
|
-
strokeLinecap: "round",
|
|
23777
|
-
strokeLinejoin: "round",
|
|
23778
|
-
"aria-hidden": "true",
|
|
23779
|
-
style: direction === "down" ? { transform: "rotate(180deg)" } : void 0,
|
|
23780
|
-
children: /* @__PURE__ */ jsx("path", { d: "M12 19V5M5 12l7-7 7 7" })
|
|
23781
|
-
}
|
|
23782
|
-
);
|
|
23783
|
-
}
|
|
23784
|
-
function GearIcon() {
|
|
23785
|
-
return /* @__PURE__ */ jsxs(
|
|
23786
|
-
"svg",
|
|
23787
|
-
{
|
|
23788
|
-
width: "13",
|
|
23789
|
-
height: "13",
|
|
23790
|
-
viewBox: "0 0 24 24",
|
|
23791
|
-
fill: "none",
|
|
23792
|
-
stroke: "currentColor",
|
|
23793
|
-
strokeWidth: "2",
|
|
23794
|
-
strokeLinecap: "round",
|
|
23795
|
-
strokeLinejoin: "round",
|
|
23796
|
-
"aria-hidden": "true",
|
|
23797
|
-
children: [
|
|
23798
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" }),
|
|
23799
|
-
/* @__PURE__ */ jsx("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" })
|
|
23800
|
-
]
|
|
23801
|
-
}
|
|
23802
|
-
);
|
|
23803
|
-
}
|
|
23804
|
-
const toolsStyle = {
|
|
23805
|
-
position: "absolute",
|
|
23806
|
-
top: -12,
|
|
23807
|
-
right: 0,
|
|
23808
|
-
zIndex: 2,
|
|
23809
|
-
display: "flex",
|
|
23810
|
-
gap: 4,
|
|
23811
|
-
padding: 3,
|
|
23812
|
-
background: "#ffffff",
|
|
23813
|
-
border: "1px solid #e0e0e0",
|
|
23814
|
-
borderRadius: 999,
|
|
23815
|
-
boxShadow: "0 1px 4px rgba(0,0,0,0.18)",
|
|
23816
|
-
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif'
|
|
23817
|
-
};
|
|
23818
|
-
const toolBtnStyle = {
|
|
23819
|
-
display: "flex",
|
|
23820
|
-
alignItems: "center",
|
|
23821
|
-
justifyContent: "center",
|
|
23822
|
-
width: 24,
|
|
23823
|
-
height: 24,
|
|
23824
|
-
padding: 0,
|
|
23825
|
-
background: "transparent",
|
|
23826
|
-
border: "1px solid transparent",
|
|
23827
|
-
borderRadius: "50%",
|
|
23828
|
-
fontSize: 13,
|
|
23829
|
-
lineHeight: 1,
|
|
23830
|
-
color: "#444",
|
|
23831
|
-
cursor: "pointer"
|
|
23832
|
-
};
|
|
23833
|
-
const inputStyle$1 = {
|
|
23834
|
-
width: "100%",
|
|
23835
|
-
boxSizing: "border-box",
|
|
23836
|
-
padding: "6px 8px",
|
|
23837
|
-
border: "1px solid #d8d8d8",
|
|
23838
|
-
borderRadius: 6,
|
|
23839
|
-
fontSize: 13,
|
|
23840
|
-
color: "#222",
|
|
23841
|
-
background: "#fff",
|
|
23842
|
-
fontFamily: "inherit"
|
|
23843
|
-
};
|
|
23844
22936
|
const HONEYPOT_NAME = "website";
|
|
23845
22937
|
const warnedEndpointKeys = /* @__PURE__ */ new Set();
|
|
23846
22938
|
function cx(...parts) {
|
|
@@ -23856,6 +22948,7 @@ function SettoForm({
|
|
|
23856
22948
|
}) {
|
|
23857
22949
|
const { t, i18n } = useTranslation();
|
|
23858
22950
|
const { config, editMode, store } = useSetto();
|
|
22951
|
+
const FieldTools = useSettoChromeSlot("form-field-tools");
|
|
23859
22952
|
const guestEdit = useGuestEdit();
|
|
23860
22953
|
const editable = editMode || guestEdit.active;
|
|
23861
22954
|
const lng = i18n.language;
|
|
@@ -24103,8 +23196,8 @@ function SettoForm({
|
|
|
24103
23196
|
}
|
|
24104
23197
|
),
|
|
24105
23198
|
error ? /* @__PURE__ */ jsx("p", { id: errorId, className: cx("setto-form__field-error", classNames.fieldError), children: t(`form.validation.${error}`, { defaultValue: FIELD_ERROR_DEFAULTS[error] }) }) : null,
|
|
24106
|
-
editable && store ? /* @__PURE__ */ jsx(
|
|
24107
|
-
|
|
23199
|
+
editable && store && FieldTools ? /* @__PURE__ */ jsx(
|
|
23200
|
+
FieldTools,
|
|
24108
23201
|
{
|
|
24109
23202
|
field,
|
|
24110
23203
|
index,
|
|
@@ -25505,204 +24598,6 @@ function collectRelativeKeys(nodes, prefix, out) {
|
|
|
25505
24598
|
}
|
|
25506
24599
|
}
|
|
25507
24600
|
}
|
|
25508
|
-
const IN_PROGRESS_STATUSES = ["pending", "building"];
|
|
25509
|
-
function isDeploymentInProgress(status) {
|
|
25510
|
-
return IN_PROGRESS_STATUSES.includes(status);
|
|
25511
|
-
}
|
|
25512
|
-
const STALE_PENDING_MS = 20 * 60 * 1e3;
|
|
25513
|
-
const STALE_BUILDING_MS = 45 * 60 * 1e3;
|
|
25514
|
-
function isDeploymentStale(row) {
|
|
25515
|
-
if (row.status !== "pending" && row.status !== "building") return false;
|
|
25516
|
-
const now = Date.now();
|
|
25517
|
-
if (row.status === "pending") {
|
|
25518
|
-
return now - new Date(row.started_at).getTime() > STALE_PENDING_MS;
|
|
25519
|
-
}
|
|
25520
|
-
return now - new Date(row.updated_at).getTime() > STALE_BUILDING_MS;
|
|
25521
|
-
}
|
|
25522
|
-
async function fetchInProgressDeploymentId(supabase, siteId) {
|
|
25523
|
-
const { data } = await supabase.from("deployments").select("id, status, started_at, updated_at").eq("site_id", siteId).in("status", [...IN_PROGRESS_STATUSES]).order("started_at", { ascending: false }).limit(5);
|
|
25524
|
-
const rows = data ?? [];
|
|
25525
|
-
const fresh = rows.find((r) => !isDeploymentStale(r));
|
|
25526
|
-
return fresh?.id ?? null;
|
|
25527
|
-
}
|
|
25528
|
-
async function waitForDeploymentByCommit(supabase, siteId, commitSha, timeoutMs = 6e4) {
|
|
25529
|
-
const deadline = Date.now() + timeoutMs;
|
|
25530
|
-
while (Date.now() < deadline) {
|
|
25531
|
-
const { data } = await supabase.from("deployments").select("id").eq("site_id", siteId).eq("commit_sha", commitSha).order("started_at", { ascending: false }).limit(1).maybeSingle();
|
|
25532
|
-
if (data?.id) return data.id;
|
|
25533
|
-
await new Promise((r) => setTimeout(r, 2e3));
|
|
25534
|
-
}
|
|
25535
|
-
return null;
|
|
25536
|
-
}
|
|
25537
|
-
function useDeploymentStatus(supabase, deploymentId) {
|
|
25538
|
-
const [row, setRow] = useState(null);
|
|
25539
|
-
useEffect(() => {
|
|
25540
|
-
if (!deploymentId) {
|
|
25541
|
-
setRow(null);
|
|
25542
|
-
return;
|
|
25543
|
-
}
|
|
25544
|
-
let channel = null;
|
|
25545
|
-
let cancelled = false;
|
|
25546
|
-
const load = async () => {
|
|
25547
|
-
const { data } = await supabase.from("deployments").select("*").eq("id", deploymentId).maybeSingle();
|
|
25548
|
-
if (!cancelled && data) setRow(data);
|
|
25549
|
-
};
|
|
25550
|
-
void load();
|
|
25551
|
-
channel = supabase.channel(`setto-dep-${deploymentId}`).on(
|
|
25552
|
-
"postgres_changes",
|
|
25553
|
-
{
|
|
25554
|
-
event: "UPDATE",
|
|
25555
|
-
schema: "public",
|
|
25556
|
-
table: "deployments",
|
|
25557
|
-
filter: `id=eq.${deploymentId}`
|
|
25558
|
-
},
|
|
25559
|
-
(payload) => {
|
|
25560
|
-
setRow(payload.new);
|
|
25561
|
-
}
|
|
25562
|
-
).subscribe();
|
|
25563
|
-
return () => {
|
|
25564
|
-
cancelled = true;
|
|
25565
|
-
if (channel) supabase.removeChannel(channel);
|
|
25566
|
-
};
|
|
25567
|
-
}, [supabase, deploymentId]);
|
|
25568
|
-
return { row, status: row?.status ?? null };
|
|
25569
|
-
}
|
|
25570
|
-
function deploymentStepIndex(status) {
|
|
25571
|
-
switch (status) {
|
|
25572
|
-
case "pending":
|
|
25573
|
-
return 0;
|
|
25574
|
-
case "building":
|
|
25575
|
-
return 1;
|
|
25576
|
-
case "ready":
|
|
25577
|
-
return 2;
|
|
25578
|
-
default:
|
|
25579
|
-
return -1;
|
|
25580
|
-
}
|
|
25581
|
-
}
|
|
25582
|
-
function isDeploymentStepReached(status, i) {
|
|
25583
|
-
return deploymentStepIndex(status) >= i;
|
|
25584
|
-
}
|
|
25585
|
-
const STEPS = ["Committed", "Building", "Deployed"];
|
|
25586
|
-
const PROGRESS_STYLE_ID = "setto-publish-progress-styles";
|
|
25587
|
-
function usePublishProgressStyles() {
|
|
25588
|
-
useEffect(() => {
|
|
25589
|
-
if (document.getElementById(PROGRESS_STYLE_ID)) return;
|
|
25590
|
-
const el = document.createElement("style");
|
|
25591
|
-
el.id = PROGRESS_STYLE_ID;
|
|
25592
|
-
el.textContent = `
|
|
25593
|
-
@keyframes setto-step-pulse {
|
|
25594
|
-
0%, 100% { opacity: 1; transform: scaleY(1); }
|
|
25595
|
-
50% { opacity: 0.72; transform: scaleY(0.82); }
|
|
25596
|
-
}
|
|
25597
|
-
@keyframes setto-step-shimmer {
|
|
25598
|
-
0% { background-position: 120% 0; }
|
|
25599
|
-
100% { background-position: -120% 0; }
|
|
25600
|
-
}
|
|
25601
|
-
.setto-step-bar-active {
|
|
25602
|
-
animation: setto-step-pulse 1.5s ease-in-out infinite;
|
|
25603
|
-
transform-origin: center bottom;
|
|
25604
|
-
}
|
|
25605
|
-
.setto-step-bar-shimmer {
|
|
25606
|
-
background: linear-gradient(
|
|
25607
|
-
90deg,
|
|
25608
|
-
#640aff 0%,
|
|
25609
|
-
#8b5cf6 45%,
|
|
25610
|
-
#640aff 90%
|
|
25611
|
-
) !important;
|
|
25612
|
-
background-size: 220% 100% !important;
|
|
25613
|
-
animation: setto-step-shimmer 2.2s ease-in-out infinite;
|
|
25614
|
-
}
|
|
25615
|
-
.setto-step-label-active {
|
|
25616
|
-
animation: setto-step-pulse 1.5s ease-in-out infinite;
|
|
25617
|
-
}
|
|
25618
|
-
`;
|
|
25619
|
-
document.head.appendChild(el);
|
|
25620
|
-
}, []);
|
|
25621
|
-
}
|
|
25622
|
-
function PublishProgressSteps({
|
|
25623
|
-
status,
|
|
25624
|
-
compact,
|
|
25625
|
-
buildingElapsed
|
|
25626
|
-
}) {
|
|
25627
|
-
usePublishProgressStyles();
|
|
25628
|
-
const scopeId = useId().replace(/:/g, "");
|
|
25629
|
-
const errored = status === "error" || status === "canceled";
|
|
25630
|
-
const activeIndex = deploymentStepIndex(status);
|
|
25631
|
-
return /* @__PURE__ */ jsx(
|
|
25632
|
-
"div",
|
|
25633
|
-
{
|
|
25634
|
-
className: `setto-progress-${scopeId}`,
|
|
25635
|
-
style: {
|
|
25636
|
-
display: "flex",
|
|
25637
|
-
gap: compact ? 3 : 8,
|
|
25638
|
-
fontSize: compact ? 11 : 12,
|
|
25639
|
-
minWidth: compact ? 100 : 200
|
|
25640
|
-
},
|
|
25641
|
-
children: STEPS.map((label, i) => {
|
|
25642
|
-
const reached = isDeploymentStepReached(status, i);
|
|
25643
|
-
const active = activeIndex === i && !errored;
|
|
25644
|
-
const barClass = active ? "setto-step-bar-active setto-step-bar-shimmer" : void 0;
|
|
25645
|
-
return /* @__PURE__ */ jsxs("div", { style: { flex: 1, textAlign: "center", minWidth: 0 }, children: [
|
|
25646
|
-
/* @__PURE__ */ jsx(
|
|
25647
|
-
"div",
|
|
25648
|
-
{
|
|
25649
|
-
className: barClass,
|
|
25650
|
-
style: {
|
|
25651
|
-
height: compact ? 3 : 4,
|
|
25652
|
-
borderRadius: 2,
|
|
25653
|
-
background: errored ? "#fca5a5" : reached ? "#640AFF" : "#e5e5e5",
|
|
25654
|
-
marginBottom: compact ? 0 : 6,
|
|
25655
|
-
transition: "background 0.35s ease"
|
|
25656
|
-
}
|
|
25657
|
-
}
|
|
25658
|
-
),
|
|
25659
|
-
!compact ? /* @__PURE__ */ jsxs(
|
|
25660
|
-
"span",
|
|
25661
|
-
{
|
|
25662
|
-
className: active ? "setto-step-label-active" : void 0,
|
|
25663
|
-
style: {
|
|
25664
|
-
color: active ? "#1a1a1a" : "#888",
|
|
25665
|
-
fontWeight: active ? 500 : 400,
|
|
25666
|
-
display: "inline-block"
|
|
25667
|
-
},
|
|
25668
|
-
children: [
|
|
25669
|
-
label,
|
|
25670
|
-
active && status === "building" && buildingElapsed != null ? ` (${buildingElapsed}s)` : active ? " …" : ""
|
|
25671
|
-
]
|
|
25672
|
-
}
|
|
25673
|
-
) : null
|
|
25674
|
-
] }, label);
|
|
25675
|
-
})
|
|
25676
|
-
}
|
|
25677
|
-
);
|
|
25678
|
-
}
|
|
25679
|
-
function PublishProgressBar({ status, compact, href }) {
|
|
25680
|
-
const inner = /* @__PURE__ */ jsx(PublishProgressSteps, { status, compact });
|
|
25681
|
-
const wrapStyle = {
|
|
25682
|
-
fontSize: compact ? 11 : 12,
|
|
25683
|
-
minWidth: compact ? 100 : 200
|
|
25684
|
-
};
|
|
25685
|
-
if (href) {
|
|
25686
|
-
return /* @__PURE__ */ jsx(
|
|
25687
|
-
"a",
|
|
25688
|
-
{
|
|
25689
|
-
href,
|
|
25690
|
-
title: "Se publiseringsstatus",
|
|
25691
|
-
style: {
|
|
25692
|
-
...wrapStyle,
|
|
25693
|
-
display: "block",
|
|
25694
|
-
textDecoration: "none",
|
|
25695
|
-
color: "inherit",
|
|
25696
|
-
cursor: "pointer",
|
|
25697
|
-
borderRadius: 4,
|
|
25698
|
-
padding: compact ? "4px 2px" : void 0
|
|
25699
|
-
},
|
|
25700
|
-
children: inner
|
|
25701
|
-
}
|
|
25702
|
-
);
|
|
25703
|
-
}
|
|
25704
|
-
return /* @__PURE__ */ jsx("div", { style: wrapStyle, children: inner });
|
|
25705
|
-
}
|
|
25706
24601
|
export {
|
|
25707
24602
|
AuthGate,
|
|
25708
24603
|
BLOCK_REGISTRY,
|
|
@@ -25713,14 +24608,10 @@ export {
|
|
|
25713
24608
|
FAB_SIZE,
|
|
25714
24609
|
FORM_FIELD_TYPES,
|
|
25715
24610
|
FORM_FIELD_TYPE_LABELS,
|
|
24611
|
+
FloatingPopover,
|
|
25716
24612
|
GuestEditProvider,
|
|
25717
|
-
IN_PROGRESS_STATUSES,
|
|
25718
|
-
PublishProgressBar,
|
|
25719
|
-
PublishProgressSteps,
|
|
25720
24613
|
SETTO_BASE,
|
|
25721
24614
|
SETTO_MODULES,
|
|
25722
|
-
STALE_BUILDING_MS,
|
|
25723
|
-
STALE_PENDING_MS,
|
|
25724
24615
|
SettoAdminApp,
|
|
25725
24616
|
SettoAnimation,
|
|
25726
24617
|
SettoBlock,
|
|
@@ -25731,7 +24622,6 @@ export {
|
|
|
25731
24622
|
SettoIcon,
|
|
25732
24623
|
SettoImage,
|
|
25733
24624
|
SettoMark,
|
|
25734
|
-
SettoPreviewBar,
|
|
25735
24625
|
SettoProvider,
|
|
25736
24626
|
SettoRepeater,
|
|
25737
24627
|
SettoSection,
|
|
@@ -25742,28 +24632,25 @@ export {
|
|
|
25742
24632
|
checkoutIntentUrl,
|
|
25743
24633
|
currentAdminView,
|
|
25744
24634
|
extractContentKeys,
|
|
25745
|
-
|
|
24635
|
+
fieldTypeHasOptions,
|
|
24636
|
+
fieldTypeHasPlaceholder,
|
|
25746
24637
|
formFieldsPrefix,
|
|
25747
24638
|
isAdminDeploymentView,
|
|
25748
24639
|
isAdminPanelView,
|
|
25749
24640
|
isAdminRoute,
|
|
25750
|
-
isDeploymentInProgress,
|
|
25751
|
-
isDeploymentStale,
|
|
25752
24641
|
isFormFieldType,
|
|
25753
|
-
|
|
24642
|
+
isLinkContext,
|
|
25754
24643
|
nodeChildren,
|
|
25755
24644
|
parseBlockTree,
|
|
25756
|
-
previewBarState,
|
|
25757
24645
|
readLocaleFields,
|
|
25758
24646
|
settoSubmissionUrl,
|
|
25759
24647
|
siteHomeUrl,
|
|
25760
|
-
|
|
24648
|
+
useCoarsePointer,
|
|
25761
24649
|
useGuestEdit,
|
|
25762
24650
|
useSectionTheme,
|
|
25763
24651
|
useSetto,
|
|
25764
24652
|
useSettoChromeSlot,
|
|
25765
24653
|
validateBlockTree,
|
|
25766
|
-
waitForDeploymentByCommit,
|
|
25767
24654
|
wantsCheckout,
|
|
25768
24655
|
withoutCheckoutIntent
|
|
25769
24656
|
};
|