@measured/puck
Version:
The open-source visual editor for React
1,598 lines (1,541 loc) • 312 kB
JavaScript
import {
SlotRender,
SlotRenderPure,
__async,
__commonJS,
__objRest,
__spreadProps,
__spreadValues,
__toESM,
defaultAppState,
defaultSlots,
defaultViewports,
expandNode,
getChanged,
getSlotTransform,
init_react_import,
resolveComponentData,
rootAreaId,
rootDroppableId,
rootZone,
setupZone,
useFieldTransforms,
useSlots,
walkAppState,
walkField,
walkTree
} from "./chunk-62KOMFGG.mjs";
// ../../node_modules/classnames/index.js
var require_classnames = __commonJS({
"../../node_modules/classnames/index.js"(exports, module) {
"use strict";
init_react_import();
(function() {
"use strict";
var hasOwn = {}.hasOwnProperty;
function classNames() {
var classes = "";
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (arg) {
classes = appendClass(classes, parseValue(arg));
}
}
return classes;
}
function parseValue(arg) {
if (typeof arg === "string" || typeof arg === "number") {
return arg;
}
if (typeof arg !== "object") {
return "";
}
if (Array.isArray(arg)) {
return classNames.apply(null, arg);
}
if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes("[native code]")) {
return arg.toString();
}
var classes = "";
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes = appendClass(classes, key);
}
}
return classes;
}
function appendClass(value, newClass) {
if (!newClass) {
return value;
}
if (value) {
return value + " " + newClass;
}
return value + newClass;
}
if (typeof module !== "undefined" && module.exports) {
classNames.default = classNames;
module.exports = classNames;
} else if (typeof define === "function" && typeof define.amd === "object" && define.amd) {
define("classnames", [], function() {
return classNames;
});
} else {
window.classNames = classNames;
}
})();
}
});
// types/API/Overrides.ts
init_react_import();
var overrideKeys = [
"header",
"headerActions",
"fields",
"fieldLabel",
"drawer",
"drawerItem",
"componentOverlay",
"outline",
"puck",
"preview"
];
// components/ActionBar/index.tsx
init_react_import();
// lib/get-class-name-factory.ts
init_react_import();
var import_classnames = __toESM(require_classnames());
var getClassNameFactory = (rootClass, styles2, config = { baseClass: "" }) => (options = {}) => {
if (typeof options === "string") {
const descendant = options;
const style = styles2[`${rootClass}-${descendant}`];
if (style) {
return config.baseClass + styles2[`${rootClass}-${descendant}`] || "";
}
return "";
} else if (typeof options === "object") {
const modifiers = options;
const prefixedModifiers = {};
for (let modifier in modifiers) {
prefixedModifiers[styles2[`${rootClass}--${modifier}`]] = modifiers[modifier];
}
const c = styles2[rootClass];
return config.baseClass + (0, import_classnames.default)(__spreadValues({
[c]: !!c
}, prefixedModifiers));
} else {
return config.baseClass + styles2[rootClass] || "";
}
};
var get_class_name_factory_default = getClassNameFactory;
// css-module:/home/runner/work/puck/puck/packages/core/components/ActionBar/styles.module.css#css-module
init_react_import();
var styles_module_default = { "ActionBar": "_ActionBar_rvadt_1", "ActionBar-label": "_ActionBar-label_rvadt_18", "ActionBar-action": "_ActionBar-action_rvadt_30", "ActionBar-group": "_ActionBar-group_rvadt_38" };
// components/ActionBar/index.tsx
import { jsx, jsxs } from "react/jsx-runtime";
var getClassName = get_class_name_factory_default("ActionBar", styles_module_default);
var ActionBar = ({
label,
children
}) => /* @__PURE__ */ jsxs(
"div",
{
className: getClassName(),
onClick: (e) => {
e.stopPropagation();
},
children: [
label && /* @__PURE__ */ jsx(ActionBar.Group, { children: /* @__PURE__ */ jsx("div", { className: getClassName("label"), children: label }) }),
children
]
}
);
var Action = ({
children,
label,
onClick
}) => /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: getClassName("action"),
onClick,
title: label,
children
}
);
var Group = ({ children }) => /* @__PURE__ */ jsx("div", { className: getClassName("group"), children });
var Label = ({ label }) => /* @__PURE__ */ jsx("div", { className: getClassName("label"), children: label });
ActionBar.Action = Action;
ActionBar.Label = Label;
ActionBar.Group = Group;
// components/IconButton/IconButton.tsx
init_react_import();
import { useState } from "react";
// css-module:/home/runner/work/puck/puck/packages/core/components/IconButton/IconButton.module.css#css-module
init_react_import();
var IconButton_module_default = { "IconButton": "_IconButton_swpni_1", "IconButton--disabled": "_IconButton--disabled_swpni_20", "IconButton-title": "_IconButton-title_swpni_33" };
// components/Loader/index.tsx
init_react_import();
// lib/index.ts
init_react_import();
// lib/filter.ts
init_react_import();
// lib/data/reorder.ts
init_react_import();
var reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
// lib/data/replace.ts
init_react_import();
var replace = (list, index, newItem) => {
const result = Array.from(list);
result.splice(index, 1);
result.splice(index, 0, newItem);
return result;
};
// lib/use-reset-auto-zoom.ts
init_react_import();
// store/index.ts
init_react_import();
// reducer/index.ts
init_react_import();
// reducer/actions/set.ts
init_react_import();
var setAction = (state, action, appStore) => {
if (typeof action.state === "object") {
const newState = __spreadValues(__spreadValues({}, state), action.state);
if (action.state.indexes) {
return newState;
}
console.warn(
"`set` is expensive and may cause unnecessary re-renders. Consider using a more atomic action instead."
);
return walkAppState(newState, appStore.config);
}
return __spreadValues(__spreadValues({}, state), action.state(state));
};
// reducer/actions/insert.ts
init_react_import();
// lib/data/insert.ts
init_react_import();
var insert = (list, index, item) => {
const result = Array.from(list || []);
result.splice(index, 0, item);
return result;
};
// lib/generate-id.ts
init_react_import();
import { v4 as uuidv4 } from "uuid";
var generateId = (type) => type ? `${type}-${uuidv4()}` : uuidv4();
// lib/data/get-ids-for-parent.ts
init_react_import();
var getIdsForParent = (zoneCompound, state) => {
const [parentId] = zoneCompound.split(":");
const node = state.indexes.nodes[parentId];
return ((node == null ? void 0 : node.path) || []).map((p) => p.split(":")[0]);
};
// lib/data/populate-ids.ts
init_react_import();
var populateIds = (data, config, override = false) => {
const id = generateId(data.type);
return walkTree(
__spreadProps(__spreadValues({}, data), {
props: override ? __spreadProps(__spreadValues({}, data.props), { id }) : __spreadValues({}, data.props)
}),
config,
(contents) => contents.map((item) => {
const id2 = generateId(item.type);
return __spreadProps(__spreadValues({}, item), {
props: override ? __spreadProps(__spreadValues({}, item.props), { id: id2 }) : __spreadValues({ id: id2 }, item.props)
});
})
);
};
// reducer/actions/insert.ts
function insertAction(state, action, appStore) {
const id = action.id || generateId(action.componentType);
const emptyComponentData = populateIds(
{
type: action.componentType,
props: __spreadProps(__spreadValues({}, appStore.config.components[action.componentType].defaultProps || {}), {
id
})
},
appStore.config
);
const [parentId] = action.destinationZone.split(":");
const idsInPath = getIdsForParent(action.destinationZone, state);
return walkAppState(
state,
appStore.config,
(content, zoneCompound) => {
if (zoneCompound === action.destinationZone) {
return insert(
content || [],
action.destinationIndex,
emptyComponentData
);
}
return content;
},
(childItem, path) => {
if (childItem.props.id === id || childItem.props.id === parentId) {
return childItem;
} else if (idsInPath.includes(childItem.props.id)) {
return childItem;
} else if (path.includes(action.destinationZone)) {
return childItem;
}
return null;
}
);
}
// reducer/actions/replace.ts
init_react_import();
var replaceAction = (state, action, appStore) => {
const [parentId] = action.destinationZone.split(":");
const idsInPath = getIdsForParent(action.destinationZone, state);
const originalId = state.indexes.zones[action.destinationZone].contentIds[action.destinationIndex];
const idChanged = originalId !== action.data.props.id;
if (idChanged) {
throw new Error(
`Can't change the id during a replace action. Please us "remove" and "insert" to define a new node.`
);
}
const newSlotIds = [];
const data = walkTree(action.data, appStore.config, (contents, opts) => {
newSlotIds.push(`${opts.parentId}:${opts.propName}`);
return contents.map((item) => {
const id = generateId(item.type);
return __spreadProps(__spreadValues({}, item), {
props: __spreadValues({ id }, item.props)
});
});
});
const stateWithDeepSlotsRemoved = __spreadValues({}, state);
Object.keys(state.indexes.zones).forEach((zoneCompound) => {
const id = zoneCompound.split(":")[0];
if (id === originalId) {
if (!newSlotIds.includes(zoneCompound)) {
delete stateWithDeepSlotsRemoved.indexes.zones[zoneCompound];
}
}
});
return walkAppState(
stateWithDeepSlotsRemoved,
appStore.config,
(content, zoneCompound) => {
const newContent = [...content];
if (zoneCompound === action.destinationZone) {
newContent[action.destinationIndex] = data;
}
return newContent;
},
(childItem, path) => {
const pathIds = path.map((p) => p.split(":")[0]);
if (childItem.props.id === data.props.id) {
return data;
} else if (childItem.props.id === parentId) {
return childItem;
} else if (idsInPath.indexOf(childItem.props.id) > -1) {
return childItem;
} else if (pathIds.indexOf(data.props.id) > -1) {
return childItem;
}
return null;
}
);
};
// reducer/actions/replace-root.ts
init_react_import();
var replaceRootAction = (state, action, appStore) => {
return walkAppState(
state,
appStore.config,
(content) => content,
(childItem) => {
if (childItem.props.id === "root") {
return __spreadProps(__spreadValues({}, childItem), {
props: __spreadValues(__spreadValues({}, childItem.props), action.root.props),
readOnly: action.root.readOnly
});
}
return childItem;
}
);
};
// reducer/actions/duplicate.ts
init_react_import();
// lib/data/get-item.ts
init_react_import();
function getItem(selector, state) {
var _a, _b;
const zone = (_a = state.indexes.zones) == null ? void 0 : _a[selector.zone || rootDroppableId];
return zone ? (_b = state.indexes.nodes[zone.contentIds[selector.index]]) == null ? void 0 : _b.data : void 0;
}
// reducer/actions/duplicate.ts
function duplicateAction(state, action, appStore) {
const item = getItem(
{ index: action.sourceIndex, zone: action.sourceZone },
state
);
const idsInPath = getIdsForParent(action.sourceZone, state);
const newItem = __spreadProps(__spreadValues({}, item), {
props: __spreadProps(__spreadValues({}, item.props), {
id: generateId(item.type)
})
});
const modified = walkAppState(
state,
appStore.config,
(content, zoneCompound) => {
if (zoneCompound === action.sourceZone) {
return insert(content, action.sourceIndex + 1, item);
}
return content;
},
(childItem, path, index) => {
const zoneCompound = path[path.length - 1];
const parents = path.map((p) => p.split(":")[0]);
if (parents.indexOf(newItem.props.id) > -1) {
return __spreadProps(__spreadValues({}, childItem), {
props: __spreadProps(__spreadValues({}, childItem.props), {
id: generateId(childItem.type)
})
});
}
if (zoneCompound === action.sourceZone && index === action.sourceIndex + 1) {
return newItem;
}
const [sourceZoneParent] = action.sourceZone.split(":");
if (sourceZoneParent === childItem.props.id || idsInPath.indexOf(childItem.props.id) > -1) {
return childItem;
}
return null;
}
);
return __spreadProps(__spreadValues({}, modified), {
ui: __spreadProps(__spreadValues({}, modified.ui), {
itemSelector: {
index: action.sourceIndex + 1,
zone: action.sourceZone
}
})
});
}
// reducer/actions/reorder.ts
init_react_import();
// reducer/actions/move.ts
init_react_import();
// lib/data/remove.ts
init_react_import();
var remove = (list, index) => {
const result = Array.from(list);
result.splice(index, 1);
return result;
};
// reducer/actions/move.ts
var moveAction = (state, action, appStore) => {
if (action.sourceZone === action.destinationZone && action.sourceIndex === action.destinationIndex) {
return state;
}
const item = getItem(
{ zone: action.sourceZone, index: action.sourceIndex },
state
);
if (!item) return state;
const idsInSourcePath = getIdsForParent(action.sourceZone, state);
const idsInDestinationPath = getIdsForParent(action.destinationZone, state);
return walkAppState(
state,
appStore.config,
(content, zoneCompound) => {
if (zoneCompound === action.sourceZone && zoneCompound === action.destinationZone) {
return insert(
remove(content, action.sourceIndex),
action.destinationIndex,
item
);
} else if (zoneCompound === action.sourceZone) {
return remove(content, action.sourceIndex);
} else if (zoneCompound === action.destinationZone) {
return insert(content, action.destinationIndex, item);
}
return content;
},
(childItem, path) => {
const [sourceZoneParent] = action.sourceZone.split(":");
const [destinationZoneParent] = action.destinationZone.split(":");
const childId = childItem.props.id;
if (sourceZoneParent === childId || destinationZoneParent === childId || item.props.id === childId || idsInSourcePath.indexOf(childId) > -1 || idsInDestinationPath.indexOf(childId) > -1 || path.includes(action.destinationZone)) {
return childItem;
}
return null;
}
);
};
// reducer/actions/reorder.ts
var reorderAction = (state, action, appStore) => {
return moveAction(
state,
{
type: "move",
sourceIndex: action.sourceIndex,
sourceZone: action.destinationZone,
destinationIndex: action.destinationIndex,
destinationZone: action.destinationZone
},
appStore
);
};
// reducer/actions/remove.ts
init_react_import();
var removeAction = (state, action, appStore) => {
const item = getItem({ index: action.index, zone: action.zone }, state);
const nodesToDelete = Object.entries(state.indexes.nodes).reduce(
(acc, [nodeId, nodeData]) => {
const pathIds = nodeData.path.map((p) => p.split(":")[0]);
if (pathIds.includes(item.props.id)) {
return [...acc, nodeId];
}
return acc;
},
[item.props.id]
);
const newState = walkAppState(
state,
appStore.config,
(content, zoneCompound) => {
if (zoneCompound === action.zone) {
return remove(content, action.index);
}
return content;
}
);
Object.keys(newState.data.zones || {}).forEach((zoneCompound) => {
const parentId = zoneCompound.split(":")[0];
if (nodesToDelete.includes(parentId) && newState.data.zones) {
delete newState.data.zones[zoneCompound];
}
});
Object.keys(newState.indexes.zones).forEach((zoneCompound) => {
const parentId = zoneCompound.split(":")[0];
if (nodesToDelete.includes(parentId)) {
delete newState.indexes.zones[zoneCompound];
}
});
nodesToDelete.forEach((id) => {
delete newState.indexes.nodes[id];
});
return newState;
};
// reducer/actions/register-zone.ts
init_react_import();
var zoneCache = {};
function registerZoneAction(state, action) {
if (zoneCache[action.zone]) {
return __spreadProps(__spreadValues({}, state), {
data: __spreadProps(__spreadValues({}, state.data), {
zones: __spreadProps(__spreadValues({}, state.data.zones), {
[action.zone]: zoneCache[action.zone]
})
}),
indexes: __spreadProps(__spreadValues({}, state.indexes), {
zones: __spreadProps(__spreadValues({}, state.indexes.zones), {
[action.zone]: __spreadProps(__spreadValues({}, state.indexes.zones[action.zone]), {
contentIds: zoneCache[action.zone].map((item) => item.props.id),
type: "dropzone"
})
})
})
});
}
return __spreadProps(__spreadValues({}, state), { data: setupZone(state.data, action.zone) });
}
function unregisterZoneAction(state, action) {
const _zones = __spreadValues({}, state.data.zones || {});
const zoneIndex = __spreadValues({}, state.indexes.zones || {});
if (_zones[action.zone]) {
zoneCache[action.zone] = _zones[action.zone];
delete _zones[action.zone];
}
delete zoneIndex[action.zone];
return __spreadProps(__spreadValues({}, state), {
data: __spreadProps(__spreadValues({}, state.data), {
zones: _zones
}),
indexes: __spreadProps(__spreadValues({}, state.indexes), {
zones: zoneIndex
})
});
}
// reducer/actions/set-data.ts
init_react_import();
var setDataAction = (state, action, appStore) => {
if (typeof action.data === "object") {
console.warn(
"`setData` is expensive and may cause unnecessary re-renders. Consider using a more atomic action instead."
);
return walkAppState(
__spreadProps(__spreadValues({}, state), {
data: __spreadValues(__spreadValues({}, state.data), action.data)
}),
appStore.config
);
}
return walkAppState(
__spreadProps(__spreadValues({}, state), {
data: __spreadValues(__spreadValues({}, state.data), action.data(state.data))
}),
appStore.config
);
};
// reducer/actions/set-ui.ts
init_react_import();
var setUiAction = (state, action) => {
if (typeof action.ui === "object") {
return __spreadProps(__spreadValues({}, state), {
ui: __spreadValues(__spreadValues({}, state.ui), action.ui)
});
}
return __spreadProps(__spreadValues({}, state), {
ui: __spreadValues(__spreadValues({}, state.ui), action.ui(state.ui))
});
};
// lib/data/make-state-public.ts
init_react_import();
var makeStatePublic = (state) => {
const { data, ui } = state;
return { data, ui };
};
// reducer/actions.tsx
init_react_import();
// reducer/index.ts
function storeInterceptor(reducer, record, onAction) {
return (state, action) => {
const newAppState = reducer(state, action);
const isValidType = ![
"registerZone",
"unregisterZone",
"setData",
"setUi",
"set"
].includes(action.type);
if (typeof action.recordHistory !== "undefined" ? action.recordHistory : isValidType) {
if (record) record(newAppState);
}
onAction == null ? void 0 : onAction(action, makeStatePublic(newAppState), makeStatePublic(state));
return newAppState;
};
}
function createReducer({
record,
onAction,
appStore
}) {
return storeInterceptor(
(state, action) => {
if (action.type === "set") {
return setAction(state, action, appStore);
}
if (action.type === "insert") {
return insertAction(state, action, appStore);
}
if (action.type === "replace") {
return replaceAction(state, action, appStore);
}
if (action.type === "replaceRoot") {
return replaceRootAction(state, action, appStore);
}
if (action.type === "duplicate") {
return duplicateAction(state, action, appStore);
}
if (action.type === "reorder") {
return reorderAction(state, action, appStore);
}
if (action.type === "move") {
return moveAction(state, action, appStore);
}
if (action.type === "remove") {
return removeAction(state, action, appStore);
}
if (action.type === "registerZone") {
return registerZoneAction(state, action);
}
if (action.type === "unregisterZone") {
return unregisterZoneAction(state, action);
}
if (action.type === "setData") {
return setDataAction(state, action, appStore);
}
if (action.type === "setUi") {
return setUiAction(state, action);
}
return state;
},
record,
onAction
);
}
// store/index.ts
import { create as create2, useStore } from "zustand";
import { subscribeWithSelector as subscribeWithSelector2 } from "zustand/middleware";
import { createContext, useContext } from "react";
// store/slices/history.ts
init_react_import();
import { useEffect as useEffect2 } from "react";
// lib/use-hotkey.ts
init_react_import();
import { useEffect } from "react";
import { create } from "zustand";
import { subscribeWithSelector } from "zustand/middleware";
var keyCodeMap = {
ControlLeft: "ctrl",
ControlRight: "ctrl",
MetaLeft: "meta",
MetaRight: "meta",
ShiftLeft: "shift",
ShiftRight: "shift",
KeyA: "a",
KeyB: "b",
KeyC: "c",
KeyD: "d",
KeyE: "e",
KeyF: "f",
KeyG: "g",
KeyH: "h",
KeyI: "i",
KeyJ: "j",
KeyK: "k",
KeyL: "l",
KeyM: "m",
KeyN: "n",
KeyO: "o",
KeyP: "p",
KeyQ: "q",
KeyR: "r",
KeyS: "s",
KeyT: "t",
KeyU: "u",
KeyV: "v",
KeyW: "w",
KeyX: "x",
KeyY: "y",
KeyZ: "z"
};
var useHotkeyStore = create()(
subscribeWithSelector((set) => ({
held: {},
hold: (key) => set((s) => s.held[key] ? s : { held: __spreadProps(__spreadValues({}, s.held), { [key]: true }) }),
release: (key) => set((s) => s.held[key] ? { held: __spreadProps(__spreadValues({}, s.held), { [key]: false }) } : s),
reset: (held = {}) => set(() => ({ held })),
triggers: {}
}))
);
var monitorHotkeys = (doc) => {
const onKeyDown = (e) => {
const key = keyCodeMap[e.code];
if (key) {
useHotkeyStore.getState().hold(key);
const { held, triggers } = useHotkeyStore.getState();
Object.values(triggers).forEach(({ combo, cb }) => {
const conditionMet = Object.entries(combo).every(
([key2, value]) => value === !!held[key2]
) && Object.entries(held).every(
([key2, value]) => value === !!combo[key2]
);
if (conditionMet) {
e.preventDefault();
cb();
}
});
if (key !== "meta" && key !== "ctrl" && key !== "shift") {
useHotkeyStore.getState().release(key);
}
}
};
const onKeyUp = (e) => {
const key = keyCodeMap[e.code];
if (key) {
if (key === "meta") {
useHotkeyStore.getState().reset();
} else {
useHotkeyStore.getState().release(key);
}
}
};
const onVisibilityChanged = (e) => {
if (document.visibilityState === "hidden") {
useHotkeyStore.getState().reset();
}
};
doc.addEventListener("keydown", onKeyDown);
doc.addEventListener("keyup", onKeyUp);
doc.addEventListener("visibilitychange", onVisibilityChanged);
return () => {
doc.removeEventListener("keydown", onKeyDown);
doc.removeEventListener("keyup", onKeyUp);
doc.removeEventListener("visibilitychange", onVisibilityChanged);
};
};
var useMonitorHotkeys = () => {
useEffect(() => monitorHotkeys(document), []);
};
var useHotkey = (combo, cb) => {
useEffect(
() => useHotkeyStore.setState((s) => ({
triggers: __spreadProps(__spreadValues({}, s.triggers), {
[`${Object.keys(combo).join("+")}`]: { combo, cb }
})
})),
[]
);
};
// store/slices/history.ts
var EMPTY_HISTORY_INDEX = 0;
function debounce(func, timeout3 = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func(...args);
}, timeout3);
};
}
var tidyState = (state) => {
return __spreadProps(__spreadValues({}, state), {
ui: __spreadProps(__spreadValues({}, state.ui), {
field: {
focus: null
}
})
});
};
var createHistorySlice = (set, get) => {
const record = debounce((state) => {
const { histories, index } = get().history;
const history = {
state,
id: generateId("history")
};
const newHistories = [...histories.slice(0, index + 1), history];
set({
history: __spreadProps(__spreadValues({}, get().history), {
histories: newHistories,
index: newHistories.length - 1
})
});
}, 250);
return {
initialAppState: {},
index: EMPTY_HISTORY_INDEX,
histories: [],
hasPast: () => get().history.index > EMPTY_HISTORY_INDEX,
hasFuture: () => get().history.index < get().history.histories.length - 1,
prevHistory: () => {
const { history } = get();
return history.hasPast() ? history.histories[history.index - 1] : null;
},
nextHistory: () => {
const s = get().history;
return s.hasFuture() ? s.histories[s.index + 1] : null;
},
currentHistory: () => get().history.histories[get().history.index],
back: () => {
var _a;
const { history, dispatch } = get();
if (history.hasPast()) {
const state = tidyState(
((_a = history.prevHistory()) == null ? void 0 : _a.state) || history.initialAppState
);
dispatch({
type: "set",
state
});
set({ history: __spreadProps(__spreadValues({}, history), { index: history.index - 1 }) });
}
},
forward: () => {
var _a;
const { history, dispatch } = get();
if (history.hasFuture()) {
const state = (_a = history.nextHistory()) == null ? void 0 : _a.state;
dispatch({ type: "set", state: state ? tidyState(state) : {} });
set({ history: __spreadProps(__spreadValues({}, history), { index: history.index + 1 }) });
}
},
setHistories: (histories) => {
var _a;
const { dispatch, history } = get();
dispatch({
type: "set",
state: ((_a = histories[histories.length - 1]) == null ? void 0 : _a.state) || history.initialAppState
});
set({ history: __spreadProps(__spreadValues({}, history), { histories, index: histories.length - 1 }) });
},
setHistoryIndex: (index) => {
var _a;
const { dispatch, history } = get();
dispatch({
type: "set",
state: ((_a = history.histories[index]) == null ? void 0 : _a.state) || history.initialAppState
});
set({ history: __spreadProps(__spreadValues({}, history), { index }) });
},
record
};
};
function useRegisterHistorySlice(appStore, {
histories,
index,
initialAppState
}) {
useEffect2(
() => appStore.setState({
history: __spreadProps(__spreadValues({}, appStore.getState().history), {
histories,
index,
initialAppState
})
}),
[histories, index, initialAppState]
);
const back = () => {
appStore.getState().history.back();
};
const forward = () => {
appStore.getState().history.forward();
};
useHotkey({ meta: true, z: true }, back);
useHotkey({ meta: true, shift: true, z: true }, forward);
useHotkey({ meta: true, y: true }, forward);
useHotkey({ ctrl: true, z: true }, back);
useHotkey({ ctrl: true, shift: true, z: true }, forward);
useHotkey({ ctrl: true, y: true }, forward);
}
// store/slices/nodes.ts
init_react_import();
var createNodesSlice = (set, get) => ({
nodes: {},
registerNode: (id, node) => {
const s = get().nodes;
const emptyNode = {
id,
methods: {
sync: () => null,
hideOverlay: () => null,
showOverlay: () => null
},
element: null
};
const existingNode = s.nodes[id];
set({
nodes: __spreadProps(__spreadValues({}, s), {
nodes: __spreadProps(__spreadValues({}, s.nodes), {
[id]: __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, emptyNode), existingNode), node), {
id
})
})
})
});
},
unregisterNode: (id) => {
const s = get().nodes;
const existingNode = s.nodes[id];
if (existingNode) {
const newNodes = __spreadValues({}, s.nodes);
delete newNodes[id];
set({
nodes: __spreadProps(__spreadValues({}, s), {
nodes: newNodes
})
});
}
}
});
// store/slices/permissions.ts
init_react_import();
import { useEffect as useEffect3 } from "react";
// lib/data/flatten-data.ts
init_react_import();
var flattenData = (state, config) => {
const data = [];
walkAppState(
state,
config,
(content) => content,
(item) => {
data.push(item);
return null;
}
);
return data;
};
// store/slices/permissions.ts
var createPermissionsSlice = (set, get) => {
const resolvePermissions = (..._0) => __async(void 0, [..._0], function* (params = {}, force) {
const { state, permissions, config } = get();
const { cache, globalPermissions } = permissions;
const resolveDataForItem = (item2, force2 = false) => __async(void 0, null, function* () {
var _a, _b, _c;
const { config: config2, state: appState, setComponentLoading } = get();
const componentConfig = item2.type === "root" ? config2.root : config2.components[item2.type];
if (!componentConfig) {
return;
}
const initialPermissions = __spreadValues(__spreadValues({}, globalPermissions), componentConfig.permissions);
if (componentConfig.resolvePermissions) {
const changed = getChanged(item2, (_a = cache[item2.props.id]) == null ? void 0 : _a.lastData);
if (Object.values(changed).some((el) => el === true) || force2) {
const clearTimeout2 = setComponentLoading(item2.props.id, true, 50);
const resolvedPermissions = yield componentConfig.resolvePermissions(
item2,
{
changed,
lastPermissions: ((_b = cache[item2.props.id]) == null ? void 0 : _b.lastPermissions) || null,
permissions: initialPermissions,
appState: makeStatePublic(appState),
lastData: ((_c = cache[item2.props.id]) == null ? void 0 : _c.lastData) || null
}
);
const latest = get().permissions;
set({
permissions: __spreadProps(__spreadValues({}, latest), {
cache: __spreadProps(__spreadValues({}, latest.cache), {
[item2.props.id]: {
lastData: item2,
lastPermissions: resolvedPermissions
}
}),
resolvedPermissions: __spreadProps(__spreadValues({}, latest.resolvedPermissions), {
[item2.props.id]: resolvedPermissions
})
})
});
clearTimeout2();
}
}
});
const resolveDataForRoot = (force2 = false) => {
const { state: appState } = get();
resolveDataForItem(
// Shim the root data in by conforming to component data shape
{
type: "root",
props: __spreadProps(__spreadValues({}, appState.data.root.props), { id: "root" })
},
force2
);
};
const { item, type, root } = params;
if (item) {
yield resolveDataForItem(item, force);
} else if (type) {
flattenData(state, config).filter((item2) => item2.type === type).map((item2) => __async(void 0, null, function* () {
yield resolveDataForItem(item2, force);
}));
} else if (root) {
resolveDataForRoot(force);
} else {
flattenData(state, config).map((item2) => __async(void 0, null, function* () {
yield resolveDataForItem(item2, force);
}));
}
});
const refreshPermissions = (params) => resolvePermissions(params, true);
return {
cache: {},
globalPermissions: {
drag: true,
edit: true,
delete: true,
duplicate: true,
insert: true
},
resolvedPermissions: {},
getPermissions: ({ item, type, root } = {}) => {
const { config, permissions } = get();
const { globalPermissions, resolvedPermissions } = permissions;
if (item) {
const componentConfig = config.components[item.type];
const initialPermissions = __spreadValues(__spreadValues({}, globalPermissions), componentConfig == null ? void 0 : componentConfig.permissions);
const resolvedForItem = resolvedPermissions[item.props.id];
return resolvedForItem ? __spreadValues(__spreadValues({}, globalPermissions), resolvedForItem) : initialPermissions;
} else if (type) {
const componentConfig = config.components[type];
return __spreadValues(__spreadValues({}, globalPermissions), componentConfig == null ? void 0 : componentConfig.permissions);
} else if (root) {
const rootConfig = config.root;
const initialPermissions = __spreadValues(__spreadValues({}, globalPermissions), rootConfig == null ? void 0 : rootConfig.permissions);
const resolvedForItem = resolvedPermissions["root"];
return resolvedForItem ? __spreadValues(__spreadValues({}, globalPermissions), resolvedForItem) : initialPermissions;
}
return globalPermissions;
},
resolvePermissions,
refreshPermissions
};
};
var useRegisterPermissionsSlice = (appStore, globalPermissions) => {
useEffect3(() => {
const { permissions } = appStore.getState();
const { globalPermissions: existingGlobalPermissions } = permissions;
appStore.setState({
permissions: __spreadProps(__spreadValues({}, permissions), {
globalPermissions: __spreadValues(__spreadValues({}, existingGlobalPermissions), globalPermissions)
})
});
permissions.resolvePermissions();
}, [globalPermissions]);
useEffect3(() => {
return appStore.subscribe(
(s) => s.state.data,
() => {
appStore.getState().permissions.resolvePermissions();
}
);
}, []);
useEffect3(() => {
return appStore.subscribe(
(s) => s.config,
() => {
appStore.getState().permissions.resolvePermissions();
}
);
}, []);
};
// store/slices/fields.ts
init_react_import();
import { useCallback, useEffect as useEffect4 } from "react";
var createFieldsSlice = (_set, _get) => {
return {
fields: {},
loading: false,
lastResolvedData: {},
id: void 0
};
};
var useRegisterFieldsSlice = (appStore, id) => {
const resolveFields = useCallback(
(reset) => __async(void 0, null, function* () {
var _a, _b;
const { fields, lastResolvedData } = appStore.getState().fields;
const nodes = appStore.getState().state.indexes.nodes;
const node = nodes[id || "root"];
const componentData = node == null ? void 0 : node.data;
const parentNode = (node == null ? void 0 : node.parentId) ? nodes[node.parentId] : null;
const parent = (parentNode == null ? void 0 : parentNode.data) || null;
const { getComponentConfig, state } = appStore.getState();
const componentConfig = getComponentConfig(componentData == null ? void 0 : componentData.type);
if (!componentData || !componentConfig) return;
const defaultFields2 = componentConfig.fields || {};
const resolver = componentConfig.resolveFields;
let lastFields = fields;
if (reset) {
appStore.setState((s) => ({
fields: __spreadProps(__spreadValues({}, s.fields), { fields: defaultFields2, id })
}));
lastFields = defaultFields2;
}
if (resolver) {
const timeout3 = setTimeout(() => {
appStore.setState((s) => ({
fields: __spreadProps(__spreadValues({}, s.fields), { loading: true })
}));
}, 50);
const lastData = ((_a = lastResolvedData.props) == null ? void 0 : _a.id) === id ? lastResolvedData : null;
const changed = getChanged(componentData, lastData);
const newFields = yield resolver(componentData, {
changed,
fields: defaultFields2,
lastFields,
lastData,
appState: makeStatePublic(state),
parent
});
clearTimeout(timeout3);
if (((_b = appStore.getState().selectedItem) == null ? void 0 : _b.props.id) !== id) {
return;
}
appStore.setState({
fields: {
fields: newFields,
loading: false,
lastResolvedData: componentData,
id
}
});
} else {
appStore.setState((s) => ({
fields: __spreadProps(__spreadValues({}, s.fields), { fields: defaultFields2, id })
}));
}
}),
[id]
);
useEffect4(() => {
resolveFields(true);
return appStore.subscribe(
(s) => s.state.indexes.nodes[id || "root"],
() => resolveFields()
);
}, [id]);
};
// lib/data/to-root.ts
init_react_import();
var toRoot = (item) => {
if ("type" in item && item.type !== "root") {
throw new Error("Converting non-root item to root.");
}
const { readOnly } = item;
if (item.props) {
if ("id" in item.props) {
const _a = item.props, { id } = _a, props = __objRest(_a, ["id"]);
return { props, readOnly };
}
return { props: item.props, readOnly };
}
return { props: {}, readOnly };
};
// store/index.ts
var defaultPageFields = {
title: { type: "text" }
};
var createAppStore = (initialAppStore) => create2()(
subscribeWithSelector2((set, get) => {
var _a, _b;
return __spreadProps(__spreadValues({
state: defaultAppState,
config: { components: {} },
componentState: {},
plugins: [],
overrides: {},
viewports: defaultViewports,
zoomConfig: {
autoZoom: 1,
rootHeight: 0,
zoom: 1
},
status: "LOADING",
iframe: {},
metadata: {},
fieldTransforms: {}
}, initialAppStore), {
fields: createFieldsSlice(set, get),
history: createHistorySlice(set, get),
nodes: createNodesSlice(set, get),
permissions: createPermissionsSlice(set, get),
getComponentConfig: (type) => {
var _a2;
const { config, selectedItem } = get();
const rootFields = ((_a2 = config.root) == null ? void 0 : _a2.fields) || defaultPageFields;
return type && type !== "root" ? config.components[type] : selectedItem ? config.components[selectedItem.type] : __spreadProps(__spreadValues({}, config.root), { fields: rootFields });
},
selectedItem: ((_a = initialAppStore == null ? void 0 : initialAppStore.state) == null ? void 0 : _a.ui.itemSelector) ? getItem(
(_b = initialAppStore == null ? void 0 : initialAppStore.state) == null ? void 0 : _b.ui.itemSelector,
initialAppStore.state
) : null,
dispatch: (action) => set((s) => {
var _a2, _b2;
const { record } = get().history;
const dispatch = createReducer({
record,
appStore: s
});
const state = dispatch(s.state, action);
const selectedItem = state.ui.itemSelector ? getItem(state.ui.itemSelector, state) : null;
(_b2 = (_a2 = get()).onAction) == null ? void 0 : _b2.call(_a2, action, state, get().state);
return __spreadProps(__spreadValues({}, s), { state, selectedItem });
}),
setZoomConfig: (zoomConfig) => set({ zoomConfig }),
setStatus: (status) => set({ status }),
setComponentState: (componentState) => set({ componentState }),
pendingLoadTimeouts: {},
setComponentLoading: (id, loading = true, defer2 = 0) => {
const { setComponentState, pendingLoadTimeouts } = get();
const loadId = generateId();
const setLoading = () => {
var _a2;
const { componentState } = get();
setComponentState(__spreadProps(__spreadValues({}, componentState), {
[id]: __spreadProps(__spreadValues({}, componentState[id]), {
loadingCount: (((_a2 = componentState[id]) == null ? void 0 : _a2.loadingCount) || 0) + 1
})
}));
};
const unsetLoading = () => {
var _a2;
const { componentState } = get();
clearTimeout(timeout3);
delete pendingLoadTimeouts[loadId];
set({ pendingLoadTimeouts });
setComponentState(__spreadProps(__spreadValues({}, componentState), {
[id]: __spreadProps(__spreadValues({}, componentState[id]), {
loadingCount: Math.max(
(((_a2 = componentState[id]) == null ? void 0 : _a2.loadingCount) || 0) - 1,
0
)
})
}));
};
const timeout3 = setTimeout(() => {
if (loading) {
setLoading();
} else {
unsetLoading();
}
delete pendingLoadTimeouts[loadId];
set({ pendingLoadTimeouts });
}, defer2);
set({
pendingLoadTimeouts: __spreadProps(__spreadValues({}, pendingLoadTimeouts), {
[id]: timeout3
})
});
return unsetLoading;
},
unsetComponentLoading: (id) => {
const { setComponentLoading } = get();
setComponentLoading(id, false);
},
// Helper
setUi: (ui, recordHistory) => set((s) => {
const dispatch = createReducer({
record: () => {
},
appStore: s
});
const state = dispatch(s.state, {
type: "setUi",
ui,
recordHistory
});
const selectedItem = state.ui.itemSelector ? getItem(state.ui.itemSelector, state) : null;
return __spreadProps(__spreadValues({}, s), { state, selectedItem });
}),
resolveComponentData: (componentData, trigger) => __async(void 0, null, function* () {
const { config, metadata, setComponentLoading, permissions } = get();
const timeouts = {};
return yield resolveComponentData(
componentData,
config,
metadata,
(item) => {
const id = "id" in item.props ? item.props.id : "root";
timeouts[id] = setComponentLoading(id, true, 50);
},
(item) => __async(void 0, null, function* () {
const id = "id" in item.props ? item.props.id : "root";
if ("type" in item) {
yield permissions.refreshPermissions({ item });
} else {
yield permissions.refreshPermissions({ root: true });
}
timeouts[id]();
}),
trigger
);
}),
resolveAndCommitData: () => __async(void 0, null, function* () {
const { config, state, dispatch, resolveComponentData: resolveComponentData2 } = get();
walkAppState(
state,
config,
(content) => content,
(childItem) => {
resolveComponentData2(childItem, "load").then((resolved) => {
const { state: state2 } = get();
const node = state2.indexes.nodes[resolved.node.props.id];
if (node && resolved.didChange) {
if (resolved.node.props.id === "root") {
dispatch({
type: "replaceRoot",
root: toRoot(resolved.node)
});
} else {
const zoneCompound = `${node.parentId}:${node.zone}`;
const parentZone = state2.indexes.zones[zoneCompound];
const index = parentZone.contentIds.indexOf(
resolved.node.props.id
);
dispatch({
type: "replace",
data: resolved.node,
destinationIndex: index,
destinationZone: zoneCompound
});
}
}
});
return childItem;
}
);
})
});
})
);
var appStoreContext = createContext(createAppStore());
function useAppStore(selector) {
const context = useContext(appStoreContext);
return useStore(context, selector);
}
function useAppStoreApi() {
return useContext(appStoreContext);
}
// lib/get-zoom-config.ts
init_react_import();
// ../../node_modules/css-box-model/dist/css-box-model.esm.js
init_react_import();
// ../../node_modules/tiny-invariant/dist/esm/tiny-invariant.js
init_react_import();
var isProduction = process.env.NODE_ENV === "production";
var prefix = "Invariant failed";
function invariant(condition, message) {
if (condition) {
return;
}
if (isProduction) {
throw new Error(prefix);
}
var provided = typeof message === "function" ? message() : message;
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
throw new Error(value);
}
// ../../node_modules/css-box-model/dist/css-box-model.esm.js
var getRect = function getRect2(_ref) {
var top = _ref.top, right = _ref.right, bottom = _ref.bottom, left = _ref.left;
var width = right - left;
var height = bottom - top;
var rect = {
top,
right,
bottom,
left,
width,
height,
x: left,
y: top,
center: {
x: (right + left) / 2,
y: (bottom + top) / 2
}
};
return rect;
};
var expand = function expand2(target, expandBy) {
return {
top: target.top - expandBy.top,
left: target.left - expandBy.left,
bottom: target.bottom + expandBy.bottom,
right: target.right + expandBy.right
};
};
var shrink = function shrink2(target, shrinkBy) {
return {
top: target.top + shrinkBy.top,
left: target.left + shrinkBy.left,
bottom: target.bottom - shrinkBy.bottom,
right: target.right - shrinkBy.right
};
};
var noSpacing = {
top: 0,
right: 0,
bottom: 0,
left: 0
};
var createBox = function createBox2(_ref2) {
var borderBox = _ref2.borderBox, _ref2$margin = _ref2.margin, margin = _ref2$margin === void 0 ? noSpacing : _ref2$margin, _ref2$border = _ref2.border, border = _ref2$border === void 0 ? noSpacing : _ref2$border, _ref2$padding = _ref2.padding, padding = _ref2$padding === void 0 ? noSpacing : _ref2$padding;
var marginBox = getRect(expand(borderBox, margin));
var paddingBox = getRect(shrink(borderBox, border));
var contentBox = getRect(shrink(paddingBox, padding));
return {
marginBox,
borderBox: getRect(borderBox),
paddingBox,
contentBox,
margin,
border,
padding
};
};
var parse = function parse2(raw) {
var value = raw.slice(0, -2);
var suffix = raw.slice(-2);
if (suffix !== "px") {
return 0;
}
var result = Number(value);
!!isNaN(result) ? process.env.NODE_ENV !== "production" ? invariant(false, "Could not parse value [raw: " + raw + ", without suffix: " + value + "]") : invariant(false) : void 0;
return result;
};
var calculateBox = function calculateBox2(borderBox, styles2) {
var margin = {
top: parse(styles2.marginTop),
right: parse(styles2.marginRight),
bottom: parse(styles2.marginBottom),
left: parse(styles2.marginLeft)
};
var padding = {
top: parse(styles2.paddingTop),
right: parse(styles2.paddingRight),
bottom: parse(styles2.paddingBottom),
left: parse(styles2.paddingLeft)
};
var border = {
top: parse(styles2.borderTopWidth),
right: parse(styles2.borderRightWidth),
bottom: parse(styles2.borderBottomWidth),
left: parse(styles2.borderLeftWidth)
};
return createBox({
borderBox,
margin,
padding,
border
});
};
var getBox = function getBox2(el) {
var borderBox = el.getBoundingClientRect();
var styles2 = window.getComputedStyle(el);
return calculateBox(borderBox, styles2);
};
// lib/get-zoom-config.ts
var RESET_ZOOM_SMALLER_THAN_FRAME = true;
var getZoomConfig = (uiViewport, frame, zoom) => {
const box = getBox(frame);
const { width: frameWidth, height: frameHeight } = box.contentBox;
const viewportHeight = uiViewport.height === "auto" ? frameHeight : uiViewport.height;
let rootHeight = 0;
let autoZoom = 1;
if (uiViewport.width > frameWidth || viewportHeight > frameHeight) {
const widthZoom = Math.min(frameWidth / uiViewport.width, 1);
const heightZoom = Math.min(frameHeight / viewportHeight, 1);
zoom = widthZoom;
if (widthZoom < heightZoom) {
rootHeight = viewportHeight / zoom;
} else {
rootHeight = viewportHeight;
zoom = heightZoom;
}
autoZoom = zoom;
} else {
if (RESET_ZOOM_SMALLER_THAN_FRAME) {
autoZoom = 1;
zoom = 1;
rootHeight = viewportHeight;
}
}
return { autoZoom, rootHeight, zoom };
};
// lib/use-reset-auto-zoom.ts
var useResetAutoZoom = (frameRef) => {
const appStoreApi = useAppStoreApi();
const resetAutoZoom = (options) => {
const { state, zoomConfig, setZoomConfig } = appStoreApi.getState();
const { viewports } = state.ui;
cons