@pixldocs/canvas-renderer 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -618,6 +618,42 @@ function applyStackReflowToPageTree(children) {
618
618
  function constrainChildrenToGroupBounds(_group, _pageChildren) {
619
619
  return /* @__PURE__ */ new Map();
620
620
  }
621
+ function stripCrossTemplateMetadata(node) {
622
+ const cleaned = { ...node };
623
+ if (cleaned.repeatableSection && typeof cleaned.repeatableSection === "object") {
624
+ const { formDefId: _f, formDefSectionPrefix: _p, ...keep } = cleaned.repeatableSection;
625
+ cleaned.repeatableSection = keep;
626
+ }
627
+ return cleaned;
628
+ }
629
+ function reIdSubtree(nodes) {
630
+ const idMap = /* @__PURE__ */ new Map();
631
+ idMap.set(PAGE_BACKGROUND_ELEMENT_ID, PAGE_BACKGROUND_ELEMENT_ID);
632
+ const cloneOne = (node) => {
633
+ if (isGroup(node)) {
634
+ const g = node;
635
+ const newId2 = generateId("group");
636
+ idMap.set(g.id, newId2);
637
+ return {
638
+ ...stripCrossTemplateMetadata(g),
639
+ id: newId2,
640
+ children: (g.children ?? []).map(cloneOne)
641
+ };
642
+ }
643
+ const prefix = node.type === "text" ? "text" : node.type === "image" ? "img" : node.type === "shape" ? "shape" : node.type === "line" ? "line" : "el";
644
+ const newId = generateId(prefix);
645
+ idMap.set(node.id, newId);
646
+ return {
647
+ ...stripCrossTemplateMetadata(node),
648
+ id: newId
649
+ };
650
+ };
651
+ return { nodes: nodes.map(cloneOne), idMap };
652
+ }
653
+ function rewriteFieldMappings(mappings, idMap) {
654
+ if (!(mappings == null ? void 0 : mappings.length)) return [];
655
+ return mappings.filter((m) => idMap.has(m.elementId)).map((m) => ({ ...m, elementId: idMap.get(m.elementId) }));
656
+ }
621
657
  const defaultProjectSettings = {
622
658
  showGrid: false,
623
659
  snapToGrid: false,
@@ -1972,16 +2008,48 @@ const useEditorStore = zustand.create((set, get) => ({
1972
2008
  return { canvas: nextCanvas, ...committed };
1973
2009
  }),
1974
2010
  deletePage: (pageId) => set((state) => {
2011
+ var _a;
1975
2012
  if (state.canvas.pages.length <= 1) return {};
2013
+ const deletedPage = state.canvas.pages.find((p) => p.id === pageId);
1976
2014
  const newPages = state.canvas.pages.filter((p) => p.id !== pageId);
1977
2015
  const currentPageDeleted = state.canvas.currentPageId === pageId;
1978
2016
  const newCurrentPageId = currentPageDeleted ? newPages[0].id : state.canvas.currentPageId;
1979
- const nextCanvas = {
2017
+ const deletedElementIds = new Set(getAllElementIds((deletedPage == null ? void 0 : deletedPage.children) ?? []));
2018
+ const remainingElementIds = /* @__PURE__ */ new Set();
2019
+ for (const p of newPages) for (const id of getAllElementIds(p.children ?? [])) remainingElementIds.add(id);
2020
+ for (const id of remainingElementIds) deletedElementIds.delete(id);
2021
+ let nextCanvas = {
1980
2022
  ...state.canvas,
1981
2023
  pages: newPages,
1982
2024
  currentPageId: newCurrentPageId,
1983
2025
  selectedIds: currentPageDeleted ? [] : state.canvas.selectedIds
1984
2026
  };
2027
+ if (nextCanvas.themeConfig && deletedElementIds.size > 0) {
2028
+ const remainingProps = nextCanvas.themeConfig.properties.filter((p) => !deletedElementIds.has(p.elementId));
2029
+ if (remainingProps.length !== nextCanvas.themeConfig.properties.length) {
2030
+ const removedPropIds = new Set(
2031
+ nextCanvas.themeConfig.properties.filter((p) => deletedElementIds.has(p.elementId)).map((p) => p.id)
2032
+ );
2033
+ nextCanvas = {
2034
+ ...nextCanvas,
2035
+ themeConfig: {
2036
+ ...nextCanvas.themeConfig,
2037
+ properties: remainingProps,
2038
+ variants: nextCanvas.themeConfig.variants.map((v) => {
2039
+ const values = { ...v.values };
2040
+ for (const pid of removedPropIds) delete values[pid];
2041
+ return { ...v, values };
2042
+ })
2043
+ }
2044
+ };
2045
+ }
2046
+ }
2047
+ if (((_a = nextCanvas.dynamicFields) == null ? void 0 : _a.length) && deletedElementIds.size > 0) {
2048
+ nextCanvas = {
2049
+ ...nextCanvas,
2050
+ dynamicFields: nextCanvas.dynamicFields.map((f) => ({ ...f, mappings: (f.mappings ?? []).filter((m) => !deletedElementIds.has(m.elementId)) })).filter((f) => (f.mappings ?? []).length > 0)
2051
+ };
2052
+ }
1985
2053
  const committed = commitFromState(state, nextCanvas);
1986
2054
  return { canvas: nextCanvas, ...committed };
1987
2055
  }),
@@ -2008,6 +2076,64 @@ const useEditorStore = zustand.create((set, get) => ({
2008
2076
  const committed = commitFromState(state, nextCanvas);
2009
2077
  return { canvas: nextCanvas, ...committed };
2010
2078
  }),
2079
+ pastePage: (payload) => {
2080
+ let resultPageId = null;
2081
+ set((state) => {
2082
+ const { nodes: freshChildren, idMap } = reIdSubtree(payload.page.children ?? []);
2083
+ const freshPage = {
2084
+ id: generateId("page"),
2085
+ name: payload.page.name,
2086
+ children: freshChildren,
2087
+ settings: { ...defaultPageSettings, ...payload.page.settings ?? {} }
2088
+ };
2089
+ const carriedFields = (payload.dynamicFields ?? []).map((f) => ({ ...f, mappings: rewriteFieldMappings(f.mappings, idMap) })).filter((f) => f.mappings.length > 0);
2090
+ const carriedTheme = (payload.themeProperties ?? []).filter((t) => idMap.has(t.property.elementId)).map((t) => ({ ...t, property: { ...t.property, elementId: idMap.get(t.property.elementId) } }));
2091
+ const currentIndex = state.canvas.pages.findIndex((p) => p.id === state.canvas.currentPageId);
2092
+ const insertAt = currentIndex >= 0 ? currentIndex + 1 : state.canvas.pages.length;
2093
+ const newPages = [...state.canvas.pages];
2094
+ newPages.splice(insertAt, 0, freshPage);
2095
+ const existingFields = state.canvas.dynamicFields ?? [];
2096
+ const mergedFields = [...existingFields];
2097
+ const taken = new Set(mergedFields.map((f) => f.id));
2098
+ for (const incoming of carriedFields) {
2099
+ let candidate = incoming.id;
2100
+ let n = 2;
2101
+ while (taken.has(candidate)) {
2102
+ candidate = `${incoming.id}_${n++}`;
2103
+ }
2104
+ taken.add(candidate);
2105
+ mergedFields.push({ ...incoming, id: candidate });
2106
+ }
2107
+ let themeConfig = state.canvas.themeConfig;
2108
+ if (carriedTheme.length > 0) {
2109
+ themeConfig = themeConfig ? {
2110
+ properties: [...themeConfig.properties],
2111
+ variants: themeConfig.variants.map((v) => ({ ...v, values: { ...v.values } }))
2112
+ } : createEmptyThemeConfig();
2113
+ for (const carried of carriedTheme) {
2114
+ const newProp = { ...carried.property, id: generateId("themeprop") };
2115
+ themeConfig.properties.push(newProp);
2116
+ if (carried.defaultValue !== void 0) {
2117
+ for (const v of themeConfig.variants) {
2118
+ v.values[newProp.id] = carried.defaultValue;
2119
+ }
2120
+ }
2121
+ }
2122
+ }
2123
+ const nextCanvas = {
2124
+ ...state.canvas,
2125
+ pages: newPages,
2126
+ currentPageId: freshPage.id,
2127
+ selectedIds: [],
2128
+ dynamicFields: mergedFields,
2129
+ themeConfig
2130
+ };
2131
+ resultPageId = freshPage.id;
2132
+ const committed = commitFromState(state, nextCanvas);
2133
+ return { canvas: nextCanvas, ...committed };
2134
+ });
2135
+ return resultPageId;
2136
+ },
2011
2137
  renamePage: (pageId, name) => set((state) => {
2012
2138
  const trimmedName = name.trim();
2013
2139
  if (!trimmedName) return {};
@@ -9934,17 +10060,16 @@ function splitNestedForOverflow(flowStack, stayChildren, overflowChildren, overf
9934
10060
  }
9935
10061
  return { stayChildren: newStay, overflowChildren: newOverflow };
9936
10062
  }
9937
- function applyContentBoundsPagination(config) {
10063
+ function paginateSinglePage(sourcePage, pageOffsetIndex) {
9938
10064
  var _a, _b, _c, _d, _e, _f;
9939
- const pages = config.pages ?? [];
9940
- if (pages.length === 0) return config;
9941
- const firstPage = pages[0];
9942
- const contentTop = (_a = firstPage.settings) == null ? void 0 : _a.contentTop;
9943
- const contentBottom = (_b = firstPage.settings) == null ? void 0 : _b.contentBottom;
9944
- if (contentTop == null || contentBottom == null || contentBottom <= contentTop) return config;
9945
- const pageChildren = firstPage.children ?? [];
10065
+ const contentTop = (_a = sourcePage.settings) == null ? void 0 : _a.contentTop;
10066
+ const contentBottom = (_b = sourcePage.settings) == null ? void 0 : _b.contentBottom;
10067
+ if (contentTop == null || contentBottom == null || contentBottom <= contentTop) {
10068
+ return [sourcePage];
10069
+ }
10070
+ const pageChildren = sourcePage.children ?? [];
9946
10071
  const allFlowStacks = findAllFlowStacks(pageChildren);
9947
- if (allFlowStacks.length === 0) return config;
10072
+ if (allFlowStacks.length === 0) return [sourcePage];
9948
10073
  const stackResults = [];
9949
10074
  let anyOverflow = false;
9950
10075
  for (const flowStack of allFlowStacks) {
@@ -9961,25 +10086,26 @@ function applyContentBoundsPagination(config) {
9961
10086
  }
9962
10087
  stackResults.push({ flowStack, flowStackIndex, stayChildren, overflowChildren });
9963
10088
  }
9964
- if (!anyOverflow) return config;
10089
+ if (!anyOverflow) return [sourcePage];
9965
10090
  const flowStackIds = new Set(allFlowStacks.map((s) => s.id));
9966
- let newFirstRoot = pageChildren.map((node) => {
10091
+ let newSourceRoot = pageChildren.map((node) => {
9967
10092
  if (!flowStackIds.has(node.id)) return node;
9968
10093
  const result = stackResults.find((r) => r.flowStack.id === node.id);
9969
10094
  const newStack = { ...result.flowStack, children: result.stayChildren };
9970
10095
  return applyStackReflowToPageTree([newStack])[0];
9971
10096
  });
9972
- newFirstRoot = applyStackReflowToPageTree(newFirstRoot);
9973
- const newFirstPage = {
9974
- ...firstPage,
9975
- children: newFirstRoot
10097
+ newSourceRoot = applyStackReflowToPageTree(newSourceRoot);
10098
+ const newSourcePage = {
10099
+ ...sourcePage,
10100
+ children: newSourceRoot
9976
10101
  };
9977
- const resultPages = [newFirstPage];
10102
+ const resultPages = [newSourcePage];
9978
10103
  let currentOverflows = stackResults.filter((r) => r.overflowChildren.length > 0).map((r) => ({ flowStack: r.flowStack, overflowChildren: r.overflowChildren }));
9979
10104
  let currentPageIndex = 1;
9980
10105
  const MAX_CONTINUATION_PAGES = 50;
9981
10106
  while (currentOverflows.length > 0 && currentPageIndex < MAX_CONTINUATION_PAGES) {
9982
- const contPage = buildContinuationPage(firstPage, currentOverflows, contentTop, currentPageIndex);
10107
+ const continuationGlobalIndex = pageOffsetIndex * 1e3 + currentPageIndex;
10108
+ const contPage = buildContinuationPage(sourcePage, currentOverflows, contentTop, continuationGlobalIndex);
9983
10109
  resultPages.push(contPage);
9984
10110
  const contChildren = contPage.children ?? [];
9985
10111
  const contFlowStacks = findAllFlowStacks(contChildren);
@@ -10047,6 +10173,20 @@ function applyContentBoundsPagination(config) {
10047
10173
  if (flowChildCount === 0 && !hasContent) resultPages.pop();
10048
10174
  else break;
10049
10175
  }
10176
+ return resultPages;
10177
+ }
10178
+ function applyContentBoundsPagination(config) {
10179
+ const pages = config.pages ?? [];
10180
+ if (pages.length === 0) return config;
10181
+ const resultPages = [];
10182
+ let mutated = false;
10183
+ for (let i = 0; i < pages.length; i++) {
10184
+ const sourcePage = pages[i];
10185
+ const paginated = paginateSinglePage(sourcePage, i);
10186
+ if (paginated.length !== 1 || paginated[0] !== sourcePage) mutated = true;
10187
+ resultPages.push(...paginated);
10188
+ }
10189
+ if (!mutated) return config;
10050
10190
  return { ...config, pages: resultPages };
10051
10191
  }
10052
10192
  async function fetchRow(supabaseUrl, anonKey, table, id) {
@@ -10351,9 +10491,9 @@ function normalizeConfigForEC2Parity(config) {
10351
10491
  if (isStack && node.stackSpacing == null) node.stackSpacing = 8;
10352
10492
  if (node.type === "text") {
10353
10493
  const overflowPolicy = String(node.overflowPolicy ?? "grow-and-push");
10354
- const fontSize = typeof node.fontSize === "number" ? node.fontSize : 16;
10355
- if (overflowPolicy === "auto-shrink" && fontSize >= 24) node.overflowPolicy = "grow-and-push";
10356
- delete node.height;
10494
+ if (overflowPolicy !== "auto-shrink") {
10495
+ delete node.height;
10496
+ }
10357
10497
  }
10358
10498
  if (Array.isArray(node.children)) {
10359
10499
  delete node.height;