@sevenfold/setto-client 0.5.0 → 0.6.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.
@@ -23786,6 +23786,236 @@ const removeBtnStyle = {
23786
23786
  boxShadow: "0 1px 4px rgba(0,0,0,0.18)",
23787
23787
  fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif'
23788
23788
  };
23789
+ function SettoForm({
23790
+ formId,
23791
+ fields,
23792
+ endpoint,
23793
+ endpointKey,
23794
+ className
23795
+ }) {
23796
+ const { t } = useTranslation();
23797
+ const [status, setStatus] = useState("idle");
23798
+ const [values, setValues] = useState(
23799
+ () => Object.fromEntries(fields.map((f) => [f.name, ""]))
23800
+ );
23801
+ const setField = useCallback(
23802
+ (name, value) => setValues((prev) => ({ ...prev, [name]: value })),
23803
+ []
23804
+ );
23805
+ const resolveEndpoint = () => {
23806
+ if (endpoint) return endpoint;
23807
+ if (endpointKey) {
23808
+ const resolved = t(endpointKey, { defaultValue: "" });
23809
+ return resolved && resolved !== endpointKey ? resolved : null;
23810
+ }
23811
+ return null;
23812
+ };
23813
+ const onSubmit = async (e) => {
23814
+ e.preventDefault();
23815
+ const url = resolveEndpoint();
23816
+ if (!url) {
23817
+ setStatus("error");
23818
+ return;
23819
+ }
23820
+ setStatus("submitting");
23821
+ try {
23822
+ const res = await fetch(url, {
23823
+ method: "POST",
23824
+ headers: { "Content-Type": "application/json" },
23825
+ body: JSON.stringify(values)
23826
+ });
23827
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
23828
+ setStatus("success");
23829
+ setValues(
23830
+ (prev) => Object.fromEntries(Object.keys(prev).map((k) => [k, ""]))
23831
+ );
23832
+ } catch {
23833
+ setStatus("error");
23834
+ }
23835
+ };
23836
+ if (status === "success") {
23837
+ return /* @__PURE__ */ jsx("div", { className, "data-setto-form-status": "success", children: /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(T, { k: `form.${formId}.success` }) }) });
23838
+ }
23839
+ return /* @__PURE__ */ jsxs("form", { className, onSubmit, "data-setto-form": formId, noValidate: true, children: [
23840
+ fields.map((field) => /* @__PURE__ */ jsxs("label", { "data-setto-form-field": field.name, children: [
23841
+ /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(T, { k: field.labelKey }) }),
23842
+ field.type === "textarea" ? /* @__PURE__ */ jsx(
23843
+ "textarea",
23844
+ {
23845
+ name: field.name,
23846
+ required: field.required,
23847
+ value: values[field.name] ?? "",
23848
+ placeholder: field.placeholderKey ? t(field.placeholderKey, { defaultValue: "" }) : void 0,
23849
+ onChange: (e) => setField(field.name, e.target.value)
23850
+ }
23851
+ ) : /* @__PURE__ */ jsx(
23852
+ "input",
23853
+ {
23854
+ type: field.type,
23855
+ name: field.name,
23856
+ required: field.required,
23857
+ value: values[field.name] ?? "",
23858
+ placeholder: field.placeholderKey ? t(field.placeholderKey, { defaultValue: "" }) : void 0,
23859
+ onChange: (e) => setField(field.name, e.target.value)
23860
+ }
23861
+ )
23862
+ ] }, field.name)),
23863
+ /* @__PURE__ */ jsx("button", { type: "submit", disabled: status === "submitting", children: /* @__PURE__ */ jsx(T, { k: `form.${formId}.submit` }) }),
23864
+ status === "error" ? /* @__PURE__ */ jsx("p", { "data-setto-form-status": "error", role: "alert", children: /* @__PURE__ */ jsx(T, { k: `form.${formId}.error` }) }) : null
23865
+ ] });
23866
+ }
23867
+ function SettoVideo({ srcKey, posterKey, title, className }) {
23868
+ const { t, i18n } = useTranslation();
23869
+ const { store } = useSetto();
23870
+ const src = store ? store.get(srcKey, i18n.language) : t(srcKey, { defaultValue: "" });
23871
+ const poster = posterKey ? store ? store.get(posterKey, i18n.language) : t(posterKey, { defaultValue: "" }) : void 0;
23872
+ if (!src) {
23873
+ return /* @__PURE__ */ jsx(
23874
+ "div",
23875
+ {
23876
+ className,
23877
+ "data-setto-video": srcKey,
23878
+ "data-setto-video-empty": "1"
23879
+ }
23880
+ );
23881
+ }
23882
+ const embed = toEmbedUrl(src);
23883
+ if (embed) {
23884
+ return /* @__PURE__ */ jsx(
23885
+ "iframe",
23886
+ {
23887
+ className,
23888
+ src: embed,
23889
+ title: title ?? "Video",
23890
+ loading: "lazy",
23891
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
23892
+ allowFullScreen: true,
23893
+ "data-setto-video": srcKey
23894
+ }
23895
+ );
23896
+ }
23897
+ return /* @__PURE__ */ jsx(
23898
+ "video",
23899
+ {
23900
+ className,
23901
+ src,
23902
+ poster,
23903
+ controls: true,
23904
+ preload: "metadata",
23905
+ "data-setto-video": srcKey
23906
+ }
23907
+ );
23908
+ }
23909
+ function toEmbedUrl(url) {
23910
+ try {
23911
+ const u = new URL(url);
23912
+ if (u.hostname === "youtu.be") {
23913
+ return `https://www.youtube.com/embed/${u.pathname.slice(1)}`;
23914
+ }
23915
+ if (u.hostname.endsWith("youtube.com")) {
23916
+ const v = u.searchParams.get("v");
23917
+ if (v) return `https://www.youtube.com/embed/${v}`;
23918
+ if (u.pathname.startsWith("/embed/")) return url;
23919
+ }
23920
+ if (u.hostname.endsWith("vimeo.com")) {
23921
+ const id = u.pathname.split("/").filter(Boolean).pop();
23922
+ if (id && /^\d+$/.test(id)) return `https://player.vimeo.com/video/${id}`;
23923
+ }
23924
+ return null;
23925
+ } catch {
23926
+ return null;
23927
+ }
23928
+ }
23929
+ const DEFAULT_DURATION = {
23930
+ fadeIn: 600,
23931
+ slideUp: 700,
23932
+ stagger: 700,
23933
+ scrollReveal: 700
23934
+ };
23935
+ function SettoAnimation({
23936
+ preset,
23937
+ delay = 0,
23938
+ duration,
23939
+ className,
23940
+ children
23941
+ }) {
23942
+ const ref = useRef(null);
23943
+ const [visible, setVisible] = useState(preset === "fadeIn" || preset === "slideUp");
23944
+ useEffect(() => {
23945
+ if (preset === "fadeIn" || preset === "slideUp") {
23946
+ const t = window.setTimeout(() => setVisible(true), delay);
23947
+ return () => window.clearTimeout(t);
23948
+ }
23949
+ const el = ref.current;
23950
+ if (!el || typeof IntersectionObserver === "undefined") {
23951
+ setVisible(true);
23952
+ return;
23953
+ }
23954
+ const io = new IntersectionObserver(
23955
+ (entries) => {
23956
+ for (const entry of entries) {
23957
+ if (entry.isIntersecting) {
23958
+ setVisible(true);
23959
+ io.disconnect();
23960
+ }
23961
+ }
23962
+ },
23963
+ { threshold: 0.15 }
23964
+ );
23965
+ io.observe(el);
23966
+ return () => io.disconnect();
23967
+ }, [preset, delay]);
23968
+ const reduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
23969
+ const ms = duration ?? DEFAULT_DURATION[preset];
23970
+ const transition = reduced ? void 0 : `opacity ${ms}ms ease-out ${delay}ms, transform ${ms}ms ease-out ${delay}ms`;
23971
+ const hiddenTransform = preset === "slideUp" || preset === "scrollReveal" ? "translateY(24px)" : "none";
23972
+ const style = reduced ? void 0 : {
23973
+ opacity: visible ? 1 : 0,
23974
+ transform: visible ? "none" : hiddenTransform,
23975
+ transition,
23976
+ willChange: "opacity, transform"
23977
+ };
23978
+ if (preset === "stagger") {
23979
+ return /* @__PURE__ */ jsx(
23980
+ "div",
23981
+ {
23982
+ ref,
23983
+ className,
23984
+ "data-setto-animation": preset,
23985
+ "data-setto-animation-visible": visible ? "1" : "0",
23986
+ children: wrapChildrenForStagger(children, visible, ms, delay, reduced)
23987
+ }
23988
+ );
23989
+ }
23990
+ return /* @__PURE__ */ jsx(
23991
+ "div",
23992
+ {
23993
+ ref,
23994
+ className,
23995
+ style,
23996
+ "data-setto-animation": preset,
23997
+ "data-setto-animation-visible": visible ? "1" : "0",
23998
+ children
23999
+ }
24000
+ );
24001
+ }
24002
+ function wrapChildrenForStagger(children, visible, ms, baseDelay, reduced) {
24003
+ if (reduced) return children;
24004
+ const arr = Array.isArray(children) ? children : [children];
24005
+ const step = 80;
24006
+ return arr.map((child, i) => /* @__PURE__ */ jsx(
24007
+ "div",
24008
+ {
24009
+ style: {
24010
+ opacity: visible ? 1 : 0,
24011
+ transform: visible ? "none" : "translateY(16px)",
24012
+ transition: `opacity ${ms}ms ease-out ${baseDelay + i * step}ms, transform ${ms}ms ease-out ${baseDelay + i * step}ms`
24013
+ },
24014
+ children: child
24015
+ },
24016
+ i
24017
+ ));
24018
+ }
23789
24019
  function authCallbackType() {
23790
24020
  const hash = window.location.hash.replace(/^#/, "");
23791
24021
  if (!hash) return null;
@@ -24386,20 +24616,504 @@ function depDotStyle(status) {
24386
24616
  flexShrink: 0
24387
24617
  };
24388
24618
  }
24619
+ const BLOCK_REGISTRY = {
24620
+ section: { allowedChildren: "any", themed: true, selectable: true },
24621
+ block: { allowedChildren: "any", themed: true, selectable: true },
24622
+ container: { allowedChildren: "any", themed: false, selectable: false },
24623
+ animation: { allowedChildren: "any", themed: false, selectable: false },
24624
+ repeater: { allowedChildren: "any", themed: false, selectable: false },
24625
+ text: { allowedChildren: null, themed: false, selectable: false },
24626
+ image: { allowedChildren: null, themed: false, selectable: false },
24627
+ icon: { allowedChildren: null, themed: false, selectable: false },
24628
+ form: { allowedChildren: null, themed: false, selectable: false },
24629
+ video: { allowedChildren: null, themed: false, selectable: false }
24630
+ };
24631
+ const BLOCK_TYPES = Object.keys(
24632
+ BLOCK_REGISTRY
24633
+ );
24634
+ function nodeChildren(node) {
24635
+ switch (node.type) {
24636
+ case "section":
24637
+ case "block":
24638
+ case "container":
24639
+ case "animation":
24640
+ return node.children;
24641
+ case "repeater":
24642
+ return node.itemTemplate;
24643
+ default:
24644
+ return [];
24645
+ }
24646
+ }
24647
+ const FIELD_TYPES = ["text", "email", "tel", "textarea"];
24648
+ const ANIMATION_PRESETS = ["fadeIn", "slideUp", "stagger", "scrollReveal"];
24649
+ function validateBlockTree(input) {
24650
+ const issues = [];
24651
+ if (!isRecord(input)) {
24652
+ return fail("$", "Block tree must be an object");
24653
+ }
24654
+ if (input.version !== "1") {
24655
+ issues.push({ path: "$.version", message: 'Expected version "1"' });
24656
+ }
24657
+ if (!Array.isArray(input.root)) {
24658
+ return fail("$.root", "root must be an array of block nodes");
24659
+ }
24660
+ const seenIds = /* @__PURE__ */ new Set();
24661
+ for (let i = 0; i < input.root.length; i++) {
24662
+ validateNode(input.root[i], `root[${i}]`, seenIds, issues);
24663
+ }
24664
+ return issues.length ? { ok: false, issues } : { ok: true };
24665
+ }
24666
+ function validateNode(raw, path, seenIds, issues) {
24667
+ if (!isRecord(raw)) {
24668
+ issues.push({ path, message: "Node must be an object" });
24669
+ return;
24670
+ }
24671
+ const type = raw.type;
24672
+ if (typeof type !== "string" || !(type in BLOCK_REGISTRY)) {
24673
+ issues.push({ path, message: `Unknown block type "${String(type)}"` });
24674
+ return;
24675
+ }
24676
+ if (typeof raw.id !== "string" || raw.id.length === 0) {
24677
+ issues.push({ path, message: "Node is missing a non-empty string id" });
24678
+ } else if (seenIds.has(raw.id)) {
24679
+ issues.push({ path, message: `Duplicate node id "${raw.id}"` });
24680
+ } else {
24681
+ seenIds.add(raw.id);
24682
+ }
24683
+ if (raw.className !== void 0 && typeof raw.className !== "string") {
24684
+ issues.push({ path: `${path}.className`, message: "className must be a string" });
24685
+ }
24686
+ validateTypeSpecific(raw, type, path, issues);
24687
+ const meta = BLOCK_REGISTRY[type];
24688
+ if (meta.allowedChildren === null && Array.isArray(raw.children) && raw.children.length > 0) {
24689
+ issues.push({ path, message: `Type "${type}" cannot have children` });
24690
+ return;
24691
+ }
24692
+ const children = nodeChildren(raw);
24693
+ if (meta.allowedChildren === null && children.length > 0) {
24694
+ issues.push({ path, message: `Type "${type}" cannot have children` });
24695
+ return;
24696
+ }
24697
+ for (let i = 0; i < children.length; i++) {
24698
+ const child = children[i];
24699
+ const childPath = type === "repeater" ? `${path}.itemTemplate[${i}]` : `${path}.children[${i}]`;
24700
+ validateNode(child, childPath, seenIds, issues);
24701
+ if (meta.allowedChildren !== "any" && meta.allowedChildren !== null && isRecord(child) && typeof child.type === "string" && !meta.allowedChildren.includes(child.type)) {
24702
+ issues.push({
24703
+ path: childPath,
24704
+ message: `Type "${child.type}" not allowed inside "${type}"`
24705
+ });
24706
+ }
24707
+ }
24708
+ }
24709
+ function validateTypeSpecific(raw, type, path, issues) {
24710
+ switch (type) {
24711
+ case "section":
24712
+ requireString(raw, "sectionId", path, issues);
24713
+ requireArray(raw, "children", path, issues);
24714
+ break;
24715
+ case "block":
24716
+ requireString(raw, "blockId", path, issues);
24717
+ requireArray(raw, "children", path, issues);
24718
+ break;
24719
+ case "container":
24720
+ requireArray(raw, "children", path, issues);
24721
+ break;
24722
+ case "text":
24723
+ requireString(raw, "k", path, issues);
24724
+ break;
24725
+ case "image":
24726
+ requireString(raw, "srcKey", path, issues);
24727
+ break;
24728
+ case "icon":
24729
+ requireString(raw, "k", path, issues);
24730
+ break;
24731
+ case "repeater":
24732
+ requireString(raw, "itemsKey", path, issues);
24733
+ requireArray(raw, "itemTemplate", path, issues);
24734
+ if (!isRecord(raw.defaultItem)) {
24735
+ issues.push({
24736
+ path: `${path}.defaultItem`,
24737
+ message: "defaultItem must be an object mapping field names to default strings"
24738
+ });
24739
+ } else {
24740
+ for (const [field, value] of Object.entries(raw.defaultItem)) {
24741
+ if (typeof value !== "string") {
24742
+ issues.push({
24743
+ path: `${path}.defaultItem.${field}`,
24744
+ message: "defaultItem values must be strings"
24745
+ });
24746
+ }
24747
+ }
24748
+ }
24749
+ break;
24750
+ case "form":
24751
+ requireString(raw, "formId", path, issues);
24752
+ if (!Array.isArray(raw.fields) || raw.fields.length === 0) {
24753
+ issues.push({ path: `${path}.fields`, message: "form must declare at least one field" });
24754
+ break;
24755
+ }
24756
+ for (let i = 0; i < raw.fields.length; i++) {
24757
+ validateFormField(raw.fields[i], `${path}.fields[${i}]`, issues);
24758
+ }
24759
+ if (raw.endpoint === void 0 && raw.endpointKey === void 0) {
24760
+ issues.push({
24761
+ path,
24762
+ message: "form must declare either endpoint or endpointKey"
24763
+ });
24764
+ }
24765
+ break;
24766
+ case "video":
24767
+ requireString(raw, "srcKey", path, issues);
24768
+ break;
24769
+ case "animation":
24770
+ requireArray(raw, "children", path, issues);
24771
+ if (typeof raw.preset !== "string" || !ANIMATION_PRESETS.includes(raw.preset)) {
24772
+ issues.push({
24773
+ path: `${path}.preset`,
24774
+ message: `preset must be one of ${ANIMATION_PRESETS.join(", ")}`
24775
+ });
24776
+ }
24777
+ break;
24778
+ }
24779
+ }
24780
+ function validateFormField(raw, path, issues) {
24781
+ if (!isRecord(raw)) {
24782
+ issues.push({ path, message: "field must be an object" });
24783
+ return;
24784
+ }
24785
+ if (typeof raw.name !== "string" || raw.name.length === 0) {
24786
+ issues.push({ path: `${path}.name`, message: "field.name must be a non-empty string" });
24787
+ }
24788
+ if (typeof raw.type !== "string" || !FIELD_TYPES.includes(raw.type)) {
24789
+ issues.push({
24790
+ path: `${path}.type`,
24791
+ message: `field.type must be one of ${FIELD_TYPES.join(", ")}`
24792
+ });
24793
+ }
24794
+ requireString(raw, "labelKey", path, issues);
24795
+ }
24796
+ function requireString(raw, field, path, issues) {
24797
+ const value = raw[field];
24798
+ if (typeof value !== "string" || value.length === 0) {
24799
+ issues.push({ path: `${path}.${field}`, message: `${field} must be a non-empty string` });
24800
+ }
24801
+ }
24802
+ function requireArray(raw, field, path, issues) {
24803
+ if (!Array.isArray(raw[field])) {
24804
+ issues.push({ path: `${path}.${field}`, message: `${field} must be an array` });
24805
+ }
24806
+ }
24807
+ function isRecord(value) {
24808
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24809
+ }
24810
+ function fail(path, message) {
24811
+ return { ok: false, issues: [{ path, message }] };
24812
+ }
24813
+ function parseBlockTree(input) {
24814
+ const result = validateBlockTree(input);
24815
+ if (!result.ok) {
24816
+ const first = result.issues[0];
24817
+ const detail = first ? `${first.path}: ${first.message}` : "unknown";
24818
+ throw new Error(`Invalid block tree at ${detail}`);
24819
+ }
24820
+ return input;
24821
+ }
24822
+ const IconRegistryContext = createContext(null);
24823
+ const RepeaterScopeContext = createContext(null);
24824
+ function SettoBlockTree({ tree, icons, validate = true }) {
24825
+ if (validate) {
24826
+ const result = validateBlockTree(tree);
24827
+ if (!result.ok) {
24828
+ const first = result.issues[0];
24829
+ const detail = first ? `${first.path}: ${first.message}` : "unknown";
24830
+ throw new Error(`Invalid block tree at ${detail}`);
24831
+ }
24832
+ }
24833
+ return /* @__PURE__ */ jsx(IconRegistryContext.Provider, { value: { icons }, children: tree.root.map((node) => /* @__PURE__ */ jsx(RenderNode, { node }, node.id)) });
24834
+ }
24835
+ function RenderNode({ node }) {
24836
+ switch (node.type) {
24837
+ case "section":
24838
+ return /* @__PURE__ */ jsx(SettoSection, { sectionId: node.sectionId, className: node.className, children: renderChildren(node.children) });
24839
+ case "block":
24840
+ return /* @__PURE__ */ jsx(SettoBlock, { blockId: node.blockId, className: node.className, children: renderChildren(node.children) });
24841
+ case "container":
24842
+ return renderContainer(node.tag ?? "div", node.className, renderChildren(node.children));
24843
+ case "animation":
24844
+ return /* @__PURE__ */ jsx(
24845
+ SettoAnimation,
24846
+ {
24847
+ preset: node.preset,
24848
+ delay: node.delay,
24849
+ duration: node.duration,
24850
+ className: node.className,
24851
+ children: renderChildren(node.children)
24852
+ }
24853
+ );
24854
+ case "repeater":
24855
+ return /* @__PURE__ */ jsx(
24856
+ SettoRepeater,
24857
+ {
24858
+ itemsKey: node.itemsKey,
24859
+ defaultItem: node.defaultItem,
24860
+ itemLabel: node.itemLabel,
24861
+ className: node.className,
24862
+ children: (itemKey) => /* @__PURE__ */ jsx(
24863
+ RepeaterScopeContext.Provider,
24864
+ {
24865
+ value: { itemsKey: node.itemsKey, itemKey },
24866
+ children: renderChildren(node.itemTemplate)
24867
+ }
24868
+ )
24869
+ }
24870
+ );
24871
+ case "text":
24872
+ return /* @__PURE__ */ jsx(TextLeaf, { node });
24873
+ case "image":
24874
+ return /* @__PURE__ */ jsx(ImageLeaf, { node });
24875
+ case "icon":
24876
+ return /* @__PURE__ */ jsx(IconLeaf, { node });
24877
+ case "form":
24878
+ return /* @__PURE__ */ jsx(
24879
+ SettoForm,
24880
+ {
24881
+ formId: node.formId,
24882
+ fields: node.fields,
24883
+ endpoint: node.endpoint,
24884
+ endpointKey: node.endpointKey,
24885
+ className: node.className
24886
+ }
24887
+ );
24888
+ case "video":
24889
+ return /* @__PURE__ */ jsx(VideoLeaf, { node });
24890
+ }
24891
+ }
24892
+ function renderChildren(children) {
24893
+ return children.map((child) => /* @__PURE__ */ jsx(RenderNode, { node: child }, child.id));
24894
+ }
24895
+ function TextLeaf({ node }) {
24896
+ const k = useScopedKey(node.k);
24897
+ const inner = /* @__PURE__ */ jsx(T, { k });
24898
+ if (!node.as) {
24899
+ return node.className ? /* @__PURE__ */ jsx("span", { className: node.className, children: inner }) : inner;
24900
+ }
24901
+ return renderTag(node.as, node.className, inner);
24902
+ }
24903
+ function ImageLeaf({ node }) {
24904
+ const srcKey = useScopedKey(node.srcKey);
24905
+ return /* @__PURE__ */ jsx(SettoImage, { srcKey, alt: node.alt, className: node.className });
24906
+ }
24907
+ function VideoLeaf({ node }) {
24908
+ const srcKey = useScopedKey(node.srcKey);
24909
+ const posterKey = useScopedKey(node.posterKey ?? "");
24910
+ return /* @__PURE__ */ jsx(
24911
+ SettoVideo,
24912
+ {
24913
+ srcKey,
24914
+ posterKey: node.posterKey ? posterKey : void 0,
24915
+ title: node.title,
24916
+ className: node.className
24917
+ }
24918
+ );
24919
+ }
24920
+ function IconLeaf({ node }) {
24921
+ const registry = useContext(IconRegistryContext);
24922
+ const k = useScopedKey(node.k);
24923
+ if (!registry) {
24924
+ throw new Error("SettoBlockTree must be mounted with an `icons` prop for icon nodes");
24925
+ }
24926
+ return /* @__PURE__ */ jsx(
24927
+ SettoIcon,
24928
+ {
24929
+ k,
24930
+ icons: registry.icons,
24931
+ size: node.size,
24932
+ className: node.className
24933
+ }
24934
+ );
24935
+ }
24936
+ function useScopedKey(key) {
24937
+ const scope = useContext(RepeaterScopeContext);
24938
+ if (!scope) return key;
24939
+ return `${scope.itemsKey}.${scope.itemKey}.${key}`;
24940
+ }
24941
+ function renderTag(tag, className, children) {
24942
+ switch (tag) {
24943
+ case "h1":
24944
+ return /* @__PURE__ */ jsx("h1", { className, children });
24945
+ case "h2":
24946
+ return /* @__PURE__ */ jsx("h2", { className, children });
24947
+ case "h3":
24948
+ return /* @__PURE__ */ jsx("h3", { className, children });
24949
+ case "h4":
24950
+ return /* @__PURE__ */ jsx("h4", { className, children });
24951
+ case "h5":
24952
+ return /* @__PURE__ */ jsx("h5", { className, children });
24953
+ case "h6":
24954
+ return /* @__PURE__ */ jsx("h6", { className, children });
24955
+ case "p":
24956
+ return /* @__PURE__ */ jsx("p", { className, children });
24957
+ case "span":
24958
+ return /* @__PURE__ */ jsx("span", { className, children });
24959
+ case "div":
24960
+ return /* @__PURE__ */ jsx("div", { className, children });
24961
+ case "label":
24962
+ return /* @__PURE__ */ jsx("label", { className, children });
24963
+ case "em":
24964
+ return /* @__PURE__ */ jsx("em", { className, children });
24965
+ case "strong":
24966
+ return /* @__PURE__ */ jsx("strong", { className, children });
24967
+ }
24968
+ }
24969
+ function renderContainer(tag, className, children) {
24970
+ switch (tag) {
24971
+ case "div":
24972
+ return /* @__PURE__ */ jsx("div", { className, children });
24973
+ case "section":
24974
+ return /* @__PURE__ */ jsx("section", { className, children });
24975
+ case "header":
24976
+ return /* @__PURE__ */ jsx("header", { className, children });
24977
+ case "footer":
24978
+ return /* @__PURE__ */ jsx("footer", { className, children });
24979
+ case "main":
24980
+ return /* @__PURE__ */ jsx("main", { className, children });
24981
+ case "aside":
24982
+ return /* @__PURE__ */ jsx("aside", { className, children });
24983
+ case "nav":
24984
+ return /* @__PURE__ */ jsx("nav", { className, children });
24985
+ case "article":
24986
+ return /* @__PURE__ */ jsx("article", { className, children });
24987
+ case "ul":
24988
+ return /* @__PURE__ */ jsx("ul", { className, children });
24989
+ case "ol":
24990
+ return /* @__PURE__ */ jsx("ol", { className, children });
24991
+ case "li":
24992
+ return /* @__PURE__ */ jsx("li", { className, children });
24993
+ case "p":
24994
+ return /* @__PURE__ */ jsx("p", { className, children });
24995
+ case "span":
24996
+ return /* @__PURE__ */ jsx("span", { className, children });
24997
+ }
24998
+ }
24999
+ function extractContentKeys(tree) {
25000
+ const out = {
25001
+ keys: /* @__PURE__ */ new Set(),
25002
+ themeIds: /* @__PURE__ */ new Set(),
25003
+ repeaters: []
25004
+ };
25005
+ for (const node of tree.root) {
25006
+ walk(node, out, null);
25007
+ }
25008
+ return out;
25009
+ }
25010
+ function walk(node, out, repeaterCtx) {
25011
+ switch (node.type) {
25012
+ case "section":
25013
+ out.themeIds.add(node.sectionId);
25014
+ for (const child of node.children) walk(child, out, repeaterCtx);
25015
+ return;
25016
+ case "block":
25017
+ out.themeIds.add(node.blockId);
25018
+ for (const child of node.children) walk(child, out, repeaterCtx);
25019
+ return;
25020
+ case "container":
25021
+ case "animation":
25022
+ for (const child of node.children) walk(child, out, repeaterCtx);
25023
+ return;
25024
+ case "text":
25025
+ out.keys.add(scopedKey(node.k, repeaterCtx));
25026
+ return;
25027
+ case "image":
25028
+ out.keys.add(scopedKey(node.srcKey, repeaterCtx));
25029
+ return;
25030
+ case "icon":
25031
+ out.keys.add(scopedKey(node.k, repeaterCtx));
25032
+ return;
25033
+ case "video":
25034
+ out.keys.add(scopedKey(node.srcKey, repeaterCtx));
25035
+ if (node.posterKey) out.keys.add(scopedKey(node.posterKey, repeaterCtx));
25036
+ return;
25037
+ case "form":
25038
+ out.keys.add(`form.${node.formId}.submit`);
25039
+ out.keys.add(`form.${node.formId}.success`);
25040
+ if (node.endpointKey) out.keys.add(node.endpointKey);
25041
+ for (const field of node.fields) {
25042
+ out.keys.add(field.labelKey);
25043
+ if (field.placeholderKey) out.keys.add(field.placeholderKey);
25044
+ }
25045
+ return;
25046
+ case "repeater":
25047
+ recordRepeater(node, out);
25048
+ for (const child of node.itemTemplate) {
25049
+ walk(child, out, { itemsKey: node.itemsKey });
25050
+ }
25051
+ return;
25052
+ }
25053
+ }
25054
+ function scopedKey(key, repeaterCtx) {
25055
+ if (!repeaterCtx) return key;
25056
+ return `${repeaterCtx.itemsKey}.*.${key}`;
25057
+ }
25058
+ function recordRepeater(node, out) {
25059
+ const fields = Object.keys(node.defaultItem);
25060
+ const itemKeys = [];
25061
+ collectRelativeKeys(node.itemTemplate, "", itemKeys);
25062
+ out.repeaters.push({
25063
+ itemsKey: node.itemsKey,
25064
+ fields,
25065
+ itemKeys
25066
+ });
25067
+ }
25068
+ function collectRelativeKeys(nodes, prefix, out) {
25069
+ for (const node of nodes) {
25070
+ switch (node.type) {
25071
+ case "text":
25072
+ case "icon":
25073
+ out.push(node.k);
25074
+ break;
25075
+ case "image":
25076
+ out.push(node.srcKey);
25077
+ break;
25078
+ case "video":
25079
+ out.push(node.srcKey);
25080
+ if (node.posterKey) {
25081
+ out.push(node.posterKey);
25082
+ }
25083
+ break;
25084
+ case "section":
25085
+ case "block":
25086
+ case "container":
25087
+ case "animation":
25088
+ collectRelativeKeys(node.children, prefix, out);
25089
+ break;
25090
+ }
25091
+ }
25092
+ }
24389
25093
  export {
24390
25094
  AuthGate,
25095
+ BLOCK_REGISTRY,
25096
+ BLOCK_TYPES,
24391
25097
  GuestEditProvider,
24392
25098
  SETTO_BASE,
24393
25099
  SettoAdminApp,
25100
+ SettoAnimation,
24394
25101
  SettoBlock,
25102
+ SettoBlockTree,
25103
+ SettoForm,
24395
25104
  SettoIcon,
24396
25105
  SettoImage,
24397
25106
  SettoProvider,
24398
25107
  SettoRepeater,
24399
25108
  SettoSection,
25109
+ SettoVideo,
24400
25110
  T,
25111
+ extractContentKeys,
25112
+ nodeChildren,
25113
+ parseBlockTree,
24401
25114
  useGuestEdit,
24402
25115
  useSectionTheme,
24403
- useSetto
25116
+ useSetto,
25117
+ validateBlockTree
24404
25118
  };
24405
25119
  //# sourceMappingURL=setto-client.js.map