alinea
Version:
[](https://npmjs.org/package/alinea) [](https://packagephobia.com/result?p=alinea)
1,061 lines (1,048 loc) • 44.6 kB
JavaScript
import {
useAtomValue
} from "../../chunks/chunk-WF77DMLN.js";
import "../../chunks/chunk-OBOPLPUQ.js";
import "../../chunks/chunk-U5RRZUYZ.js";
// node_modules/@headless-tree/core/lib/esm/utils.js
var memo = (fn, deps) => {
let value;
let oldDeps = null;
return () => {
const newDeps = deps();
if (!value) {
value = fn(...newDeps);
oldDeps = newDeps;
return value;
}
const match = oldDeps && oldDeps.length === newDeps.length && !oldDeps.some((dep, i) => dep !== newDeps[i]);
if (match) {
return value;
}
value = fn(...newDeps);
oldDeps = newDeps;
return value;
};
};
function functionalUpdate(updater, input) {
return typeof updater === "function" ? updater(input) : updater;
}
function makeStateUpdater(key, instance) {
return (updater) => {
instance.setState((old) => {
return Object.assign(Object.assign({}, old), { [key]: functionalUpdate(updater, old[key]) });
});
};
}
var poll = (fn, interval = 100, timeout = 1e3) => new Promise((resolve) => {
let clear;
const i = setInterval(() => {
if (fn()) {
resolve();
clearInterval(i);
clearTimeout(clear);
}
}, interval);
clear = setTimeout(() => {
clearInterval(i);
}, timeout);
});
// node_modules/@headless-tree/core/lib/esm/features/tree/feature.js
var __awaiter = function(thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function(resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var treeFeature = {
key: "tree",
getInitialState: (initialState) => Object.assign({ expandedItems: [], focusedItem: null }, initialState),
getDefaultConfig: (defaultConfig, tree) => Object.assign({ setExpandedItems: makeStateUpdater("expandedItems", tree), setFocusedItem: makeStateUpdater("focusedItem", tree) }, defaultConfig),
stateHandlerNames: {
expandedItems: "setExpandedItems",
focusedItem: "setFocusedItem"
},
createTreeInstance: (prev, instance) => Object.assign(Object.assign({}, prev), {
retrieveItemData: () => {
throw new Error("No data-loader registered");
},
retrieveChildrenIds: () => {
throw new Error("No data-loader registered");
},
isItemExpanded: (itemId) => instance.getState().expandedItems.includes(itemId),
getItemsMeta: () => {
const { rootItemId } = instance.getConfig();
const { expandedItems } = instance.getState();
const flatItems = [];
const recursiveAdd = (itemId, parentId, level, setSize, posInSet) => {
var _a;
flatItems.push({
itemId,
level,
index: flatItems.length,
parentId,
setSize,
posInSet
});
if (expandedItems.includes(itemId)) {
const children2 = (_a = instance.retrieveChildrenIds(itemId)) !== null && _a !== void 0 ? _a : [];
let i2 = 0;
for (const childId of children2) {
recursiveAdd(childId, itemId, level + 1, children2.length, i2++);
}
}
};
const children = instance.retrieveChildrenIds(rootItemId);
let i = 0;
for (const itemId of children) {
recursiveAdd(itemId, rootItemId, 0, children.length, i++);
}
return flatItems;
},
expandItem: (itemId) => {
var _a;
if (!instance.getItemInstance(itemId).isFolder()) {
return;
}
if ((_a = instance.getState().loadingItems) === null || _a === void 0 ? void 0 : _a.includes(itemId)) {
return;
}
instance.applySubStateUpdate("expandedItems", (expandedItems) => [
...expandedItems,
itemId
]);
instance.rebuildTree();
},
collapseItem: (itemId) => {
if (!instance.getItemInstance(itemId).isFolder()) {
return;
}
instance.applySubStateUpdate("expandedItems", (expandedItems) => expandedItems.filter((id) => id !== itemId));
instance.rebuildTree();
},
// TODO memo
getFocusedItem: () => {
var _a, _b;
return (_b = instance.getItemInstance((_a = instance.getState().focusedItem) !== null && _a !== void 0 ? _a : "")) !== null && _b !== void 0 ? _b : instance.getItems()[0];
},
focusItem: (itemId) => {
instance.applySubStateUpdate("focusedItem", itemId);
},
focusNextItem: () => {
const { index } = instance.getFocusedItem().getItemMeta();
const nextIndex = Math.min(index + 1, instance.getItems().length - 1);
instance.focusItem(instance.getItems()[nextIndex].getId());
},
focusPreviousItem: () => {
const { index } = instance.getFocusedItem().getItemMeta();
const nextIndex = Math.max(index - 1, 0);
instance.focusItem(instance.getItems()[nextIndex].getId());
},
updateDomFocus: () => {
setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
const focusedItem = instance.getFocusedItem();
(_b = (_a = instance.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, focusedItem);
yield poll(() => focusedItem.getElement() !== null, 20);
const focusedElement = focusedItem.getElement();
if (!focusedElement)
return;
focusedElement.focus();
}));
},
getContainerProps: () => {
var _a;
return Object.assign(Object.assign({}, (_a = prev.getContainerProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "tree", ariaLabel: "", ariaActivedescendant: "" });
}
}),
createItemInstance: (prev, item, tree) => Object.assign(Object.assign({}, prev), {
isLoading: () => {
throw new Error("No data-loader registered");
},
scrollTo: (scrollIntoViewArg) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
(_b = (_a = tree.getConfig()).scrollToItem) === null || _b === void 0 ? void 0 : _b.call(_a, item);
yield poll(() => item.getElement() !== null, 20);
item.getElement().scrollIntoView(scrollIntoViewArg);
}),
getId: () => item.getItemMeta().itemId,
getProps: () => {
var _a;
const itemMeta = item.getItemMeta();
return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": "false", "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: item.getMemoizedProp("tree/onClick", () => (e) => {
item.setFocused();
item.primaryAction();
if (e.ctrlKey || e.shiftKey || e.metaKey) {
return;
}
if (!item.isFolder()) {
return;
}
if (item.isExpanded()) {
item.collapse();
} else {
item.expand();
}
}) });
},
expand: () => tree.expandItem(item.getItemMeta().itemId),
collapse: () => tree.collapseItem(item.getItemMeta().itemId),
getItemData: () => tree.retrieveItemData(item.getItemMeta().itemId),
isExpanded: () => tree.getState().expandedItems.includes(item.getItemMeta().itemId),
isFocused: () => tree.getState().focusedItem === item.getItemMeta().itemId || tree.getState().focusedItem === null && item.getItemMeta().index === 0,
isFolder: () => item.getItemMeta().level === -1 || tree.getConfig().isItemFolder(item),
getItemName: () => {
const config = tree.getConfig();
return config.getItemName(item);
},
setFocused: () => tree.focusItem(item.getItemMeta().itemId),
primaryAction: () => {
var _a, _b;
return (_b = (_a = tree.getConfig()).onPrimaryAction) === null || _b === void 0 ? void 0 : _b.call(_a, item);
},
getParent: memo((itemMeta) => {
for (let i = itemMeta.index - 1; i >= 0; i--) {
const potentialParent = tree.getItems()[i];
if (potentialParent.getItemMeta().level < itemMeta.level) {
return potentialParent;
}
}
return tree.getItemInstance(tree.getConfig().rootItemId);
}, () => [item.getItemMeta()]),
// TODO remove
getIndexInParent: () => item.getItemMeta().posInSet,
getChildren: () => tree.retrieveChildrenIds(item.getItemMeta().itemId).map((id) => tree.getItemInstance(id)),
getTree: () => tree,
getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1],
getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1],
getMemoizedProp: (name, create, deps) => {
var _a, _b, _c, _d, _e;
var _f, _g;
const data = item.getDataRef();
const memoizedValue = (_a = data.current.memoizedValues) === null || _a === void 0 ? void 0 : _a[name];
if (memoizedValue && (!deps || ((_c = (_b = data.current.memoizedDeps) === null || _b === void 0 ? void 0 : _b[name]) === null || _c === void 0 ? void 0 : _c.every((d, i) => d === deps[i])))) {
return memoizedValue;
}
(_d = (_f = data.current).memoizedDeps) !== null && _d !== void 0 ? _d : _f.memoizedDeps = {};
(_e = (_g = data.current).memoizedValues) !== null && _e !== void 0 ? _e : _g.memoizedValues = {};
const value = create();
data.current.memoizedDeps[name] = deps;
data.current.memoizedValues[name] = value;
return value;
}
}),
hotkeys: {
focusNextItem: {
hotkey: "ArrowDown",
canRepeat: true,
preventDefault: true,
isEnabled: (tree) => {
var _a, _b;
return !((_b = (_a = tree.isSearchOpen) === null || _a === void 0 ? void 0 : _a.call(tree)) !== null && _b !== void 0 ? _b : false) && !tree.getState().dnd;
},
handler: (e, tree) => {
tree.focusNextItem();
tree.updateDomFocus();
}
},
focusPreviousItem: {
hotkey: "ArrowUp",
canRepeat: true,
preventDefault: true,
isEnabled: (tree) => {
var _a, _b;
return !((_b = (_a = tree.isSearchOpen) === null || _a === void 0 ? void 0 : _a.call(tree)) !== null && _b !== void 0 ? _b : false) && !tree.getState().dnd;
},
handler: (e, tree) => {
tree.focusPreviousItem();
tree.updateDomFocus();
}
},
expandOrDown: {
hotkey: "ArrowRight",
canRepeat: true,
handler: (e, tree) => {
const item = tree.getFocusedItem();
if (item.isExpanded() || !item.isFolder()) {
tree.focusNextItem();
tree.updateDomFocus();
} else {
item.expand();
}
}
},
collapseOrUp: {
hotkey: "ArrowLeft",
canRepeat: true,
handler: (e, tree) => {
var _a;
const item = tree.getFocusedItem();
if ((!item.isExpanded() || !item.isFolder()) && item.getItemMeta().level !== 0) {
(_a = item.getParent()) === null || _a === void 0 ? void 0 : _a.setFocused();
tree.updateDomFocus();
} else {
item.collapse();
}
}
},
focusFirstItem: {
hotkey: "Home",
handler: (e, tree) => {
tree.focusItem(tree.getItems()[0].getId());
tree.updateDomFocus();
}
},
focusLastItem: {
hotkey: "End",
handler: (e, tree) => {
tree.focusItem(tree.getItems()[tree.getItems().length - 1].getId());
tree.updateDomFocus();
}
}
}
};
// node_modules/@headless-tree/core/lib/esm/core/create-tree.js
var buildItemInstance = (features, tree, itemId) => {
var _a, _b;
const itemInstance = {};
for (const feature of features) {
Object.assign(itemInstance, (_b = (_a = feature.createItemInstance) === null || _a === void 0 ? void 0 : _a.call(feature, Object.assign({}, itemInstance), itemInstance, tree, itemId)) !== null && _b !== void 0 ? _b : {});
}
return itemInstance;
};
var verifyFeatures = (features) => {
var _a;
const loadedFeatures = features === null || features === void 0 ? void 0 : features.map((feature) => feature.key);
for (const feature of features !== null && features !== void 0 ? features : []) {
const missingDependency = (_a = feature.deps) === null || _a === void 0 ? void 0 : _a.find((dep) => !(loadedFeatures === null || loadedFeatures === void 0 ? void 0 : loadedFeatures.includes(dep)));
if (missingDependency) {
throw new Error(`${feature.key} needs ${missingDependency}`);
}
}
};
var compareFeatures = (feature1, feature2) => {
var _a;
if (feature2.key && ((_a = feature1.overwrites) === null || _a === void 0 ? void 0 : _a.includes(feature2.key))) {
return 1;
}
return -1;
};
var sortFeatures = (features = []) => features.sort(compareFeatures);
var createTree = (initialConfig) => {
var _a, _b, _c, _d, _e;
const treeInstance = {};
const additionalFeatures = [
treeFeature,
...sortFeatures(initialConfig.features)
];
verifyFeatures(additionalFeatures);
let state = additionalFeatures.reduce((acc, feature) => {
var _a2, _b2;
return (_b2 = (_a2 = feature.getInitialState) === null || _a2 === void 0 ? void 0 : _a2.call(feature, acc, treeInstance)) !== null && _b2 !== void 0 ? _b2 : acc;
}, (_b = (_a = initialConfig.initialState) !== null && _a !== void 0 ? _a : initialConfig.state) !== null && _b !== void 0 ? _b : {});
let config = additionalFeatures.reduce((acc, feature) => {
var _a2, _b2;
return (_b2 = (_a2 = feature.getDefaultConfig) === null || _a2 === void 0 ? void 0 : _a2.call(feature, acc, treeInstance)) !== null && _b2 !== void 0 ? _b2 : acc;
}, initialConfig);
const stateHandlerNames = additionalFeatures.reduce((acc, feature) => Object.assign(Object.assign({}, acc), feature.stateHandlerNames), {});
let treeElement;
const treeDataRef = { current: {} };
const itemInstancesMap = {};
let itemInstances = [];
const itemElementsMap = {};
const itemDataRefs = {};
let itemMetaMap = {};
const hotkeyPresets = {};
const rebuildItemMeta = (main) => {
itemInstances = [];
itemMetaMap = {};
const rootInstance = buildItemInstance([main, ...additionalFeatures], treeInstance, config.rootItemId);
itemInstancesMap[config.rootItemId] = rootInstance;
itemMetaMap[config.rootItemId] = {
itemId: config.rootItemId,
index: -1,
parentId: null,
level: -1,
posInSet: 0,
setSize: 1
};
for (const item of treeInstance.getItemsMeta()) {
itemMetaMap[item.itemId] = item;
if (!itemInstancesMap[item.itemId]) {
const instance = buildItemInstance([main, ...additionalFeatures], treeInstance, item.itemId);
itemInstancesMap[item.itemId] = instance;
itemInstances.push(instance);
} else {
itemInstances.push(itemInstancesMap[item.itemId]);
}
}
console.log("REBUILT");
};
const eachFeature = (fn) => {
for (const feature of additionalFeatures) {
fn(feature);
}
};
const mainFeature = {
key: "main",
createTreeInstance: (prev) => Object.assign(Object.assign({}, prev), { getState: () => state, setState: (updater) => {
var _a2;
(_a2 = config.setState) === null || _a2 === void 0 ? void 0 : _a2.call(config, state);
}, applySubStateUpdate: (stateName, updater) => {
state[stateName] = typeof updater === "function" ? updater(state[stateName]) : updater;
config[stateHandlerNames[stateName]](state[stateName]);
}, rebuildTree: () => {
var _a2;
rebuildItemMeta(mainFeature);
(_a2 = config.setState) === null || _a2 === void 0 ? void 0 : _a2.call(config, state);
}, getConfig: () => config, setConfig: (updater) => {
config = typeof updater === "function" ? updater(config) : updater;
if (config.state) {
state = Object.assign(Object.assign({}, state), config.state);
}
}, getItemInstance: (itemId) => itemInstancesMap[itemId], getItems: () => itemInstances, registerElement: (element) => {
if (treeElement === element) {
return;
}
if (treeElement && !element) {
eachFeature((feature) => {
var _a2;
return (_a2 = feature.onTreeUnmount) === null || _a2 === void 0 ? void 0 : _a2.call(feature, treeInstance, treeElement);
});
} else if (!treeElement && element) {
eachFeature((feature) => {
var _a2;
return (_a2 = feature.onTreeMount) === null || _a2 === void 0 ? void 0 : _a2.call(feature, treeInstance, element);
});
}
treeElement = element;
}, getElement: () => treeElement, getDataRef: () => treeDataRef, getHotkeyPresets: () => hotkeyPresets }),
createItemInstance: (prev, instance, _, itemId) => Object.assign(Object.assign({}, prev), {
registerElement: (element) => {
if (itemElementsMap[itemId] === element) {
return;
}
const oldElement = itemElementsMap[itemId];
if (oldElement && !element) {
eachFeature((feature) => {
var _a2;
return (_a2 = feature.onItemUnmount) === null || _a2 === void 0 ? void 0 : _a2.call(feature, instance, oldElement, treeInstance);
});
} else if (!oldElement && element) {
eachFeature((feature) => {
var _a2;
return (_a2 = feature.onItemMount) === null || _a2 === void 0 ? void 0 : _a2.call(feature, instance, element, treeInstance);
});
}
itemElementsMap[itemId] = element;
},
getElement: () => itemElementsMap[itemId],
// eslint-disable-next-line no-return-assign
getDataRef: () => {
var _a2;
return (_a2 = itemDataRefs[itemId]) !== null && _a2 !== void 0 ? _a2 : itemDataRefs[itemId] = { current: {} };
},
getItemMeta: () => itemMetaMap[itemId]
})
};
const features = [mainFeature, ...additionalFeatures];
for (const feature of features) {
Object.assign(treeInstance, (_d = (_c = feature.createTreeInstance) === null || _c === void 0 ? void 0 : _c.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _d !== void 0 ? _d : {});
Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
}
rebuildItemMeta(mainFeature);
return treeInstance;
};
// node_modules/@headless-tree/core/lib/esm/features/drag-and-drop/types.js
var DropTargetPosition;
(function(DropTargetPosition2) {
DropTargetPosition2["Top"] = "top";
DropTargetPosition2["Bottom"] = "bottom";
DropTargetPosition2["Item"] = "item";
})(DropTargetPosition || (DropTargetPosition = {}));
// node_modules/@headless-tree/core/lib/esm/features/selection/feature.js
var selectionFeature = {
key: "selection",
getInitialState: (initialState) => Object.assign({ selectedItems: [] }, initialState),
getDefaultConfig: (defaultConfig, tree) => Object.assign({ setSelectedItems: makeStateUpdater("selectedItems", tree) }, defaultConfig),
stateHandlerNames: {
selectedItems: "setSelectedItems"
},
createTreeInstance: (prev, instance) => Object.assign(Object.assign({}, prev), {
setSelectedItems: (selectedItems) => {
instance.applySubStateUpdate("selectedItems", selectedItems);
},
// TODO memo
getSelectedItems: () => {
return instance.getState().selectedItems.map(instance.getItemInstance);
}
}),
createItemInstance: (prev, item, tree) => Object.assign(Object.assign({}, prev), { select: () => {
const { selectedItems } = tree.getState();
tree.setSelectedItems(selectedItems.includes(item.getItemMeta().itemId) ? selectedItems : [...selectedItems, item.getItemMeta().itemId]);
}, deselect: () => {
const { selectedItems } = tree.getState();
tree.setSelectedItems(selectedItems.filter((id) => id !== item.getItemMeta().itemId));
}, isSelected: () => {
const { selectedItems } = tree.getState();
return selectedItems.includes(item.getItemMeta().itemId);
}, selectUpTo: (ctrl) => {
const indexA = item.getItemMeta().index;
const indexB = tree.getFocusedItem().getItemMeta().index;
const [a, b] = indexA < indexB ? [indexA, indexB] : [indexB, indexA];
const newSelectedItems = tree.getItems().slice(a, b + 1).map((treeItem) => treeItem.getItemMeta().itemId);
if (!ctrl) {
tree.setSelectedItems(newSelectedItems);
return;
}
const { selectedItems } = tree.getState();
const uniqueSelectedItems = [
.../* @__PURE__ */ new Set([...selectedItems, ...newSelectedItems])
];
tree.setSelectedItems(uniqueSelectedItems);
}, toggleSelect: () => {
if (item.isSelected()) {
item.deselect();
} else {
item.select();
}
}, getProps: () => Object.assign(Object.assign({}, prev.getProps()), { "aria-selected": item.isSelected() ? "true" : "false", onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
var _a, _b;
if (e.shiftKey) {
item.selectUpTo(e.ctrlKey || e.metaKey);
} else if (e.ctrlKey || e.metaKey) {
item.toggleSelect();
} else {
tree.setSelectedItems([item.getItemMeta().itemId]);
}
(_b = (_a = prev.getProps()).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
}) }) }),
hotkeys: {
// setSelectedItem: {
// hotkey: "space",
// handler: (e, tree) => {
// tree.setSelectedItems([tree.getFocusedItem().getId()]);
// },
// },
toggleSelectItem: {
hotkey: "ctrl+space",
handler: (e, tree) => {
tree.getFocusedItem().toggleSelect();
}
},
selectUpwards: {
hotkey: "shift+ArrowUp",
handler: () => {
}
},
selectDownwards: {
hotkey: "shift+ArrowDown",
handler: () => {
}
},
selectUpwardsCtrl: {
hotkey: "shift+ctrl+ArrowUp",
handler: () => {
}
},
selectDownwardsCtrl: {
hotkey: "shift+ctrl+ArrowUp",
handler: () => {
}
},
selectAll: {
hotkey: "Control+a",
preventDefault: true,
handler: (e, tree) => {
tree.setSelectedItems(tree.getItems().map((item) => item.getId()));
}
}
}
};
// node_modules/@headless-tree/core/lib/esm/features/async-data-loader/feature.js
var asyncDataLoaderFeature = {
key: "async-data-loader",
getInitialState: (initialState) => Object.assign({ loadingItems: [] }, initialState),
getDefaultConfig: (defaultConfig, tree) => Object.assign({ setLoadingItems: makeStateUpdater("loadingItems", tree) }, defaultConfig),
stateHandlerNames: {
loadingItems: "setLoadingItems"
},
createTreeInstance: (prev, instance) => Object.assign(Object.assign({}, prev), { retrieveItemData: (itemId) => {
var _a, _b, _c, _d, _e;
var _f, _g;
const config = instance.getConfig();
const dataRef = instance.getDataRef();
(_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : _f.itemData = {};
(_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : _g.childrenIds = {};
if (dataRef.current.itemData[itemId]) {
return dataRef.current.itemData[itemId];
}
if (!instance.getState().loadingItems.includes(itemId)) {
instance.applySubStateUpdate("loadingItems", (loadingItems) => [
...loadingItems,
itemId
]);
(_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getItem(itemId).then((item) => {
var _a2;
dataRef.current.itemData[itemId] = item;
(_a2 = config.onLoadedItem) === null || _a2 === void 0 ? void 0 : _a2.call(config, itemId, item);
instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
});
}
return (_e = (_d = config.createLoadingItemData) === null || _d === void 0 ? void 0 : _d.call(config)) !== null && _e !== void 0 ? _e : null;
}, retrieveChildrenIds: (itemId) => {
var _a, _b, _c, _d, _e;
var _f, _g;
const config = instance.getConfig();
const dataRef = instance.getDataRef();
(_a = (_f = dataRef.current).itemData) !== null && _a !== void 0 ? _a : _f.itemData = {};
(_b = (_g = dataRef.current).childrenIds) !== null && _b !== void 0 ? _b : _g.childrenIds = {};
if (dataRef.current.childrenIds[itemId]) {
return dataRef.current.childrenIds[itemId];
}
if (instance.getState().loadingItems.includes(itemId)) {
return [];
}
instance.applySubStateUpdate("loadingItems", (loadingItems) => [
...loadingItems,
itemId
]);
if ((_c = config.asyncDataLoader) === null || _c === void 0 ? void 0 : _c.getChildrenWithData) {
(_d = config.asyncDataLoader) === null || _d === void 0 ? void 0 : _d.getChildrenWithData(itemId).then((children) => {
var _a2, _b2;
for (const { id, data } of children) {
dataRef.current.itemData[id] = data;
(_a2 = config.onLoadedItem) === null || _a2 === void 0 ? void 0 : _a2.call(config, id, data);
}
const childrenIds = children.map(({ id }) => id);
dataRef.current.childrenIds[itemId] = childrenIds;
(_b2 = config.onLoadedChildren) === null || _b2 === void 0 ? void 0 : _b2.call(config, itemId, childrenIds);
instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
instance.rebuildTree();
});
} else {
(_e = config.asyncDataLoader) === null || _e === void 0 ? void 0 : _e.getChildren(itemId).then((childrenIds) => {
var _a2;
dataRef.current.childrenIds[itemId] = childrenIds;
(_a2 = config.onLoadedChildren) === null || _a2 === void 0 ? void 0 : _a2.call(config, itemId, childrenIds);
instance.applySubStateUpdate("loadingItems", (loadingItems) => loadingItems.filter((id) => id !== itemId));
instance.rebuildTree();
});
}
return [];
}, invalidateItemData: (itemId) => {
var _a;
const dataRef = instance.getDataRef();
(_a = dataRef.current.itemData) === null || _a === void 0 ? true : delete _a[itemId];
instance.retrieveItemData(itemId);
}, invalidateChildrenIds: (itemId) => {
var _a;
const dataRef = instance.getDataRef();
(_a = dataRef.current.childrenIds) === null || _a === void 0 ? true : delete _a[itemId];
instance.retrieveChildrenIds(itemId);
} }),
createItemInstance: (prev, item, tree) => Object.assign(Object.assign({}, prev), { isLoading: () => tree.getState().loadingItems.includes(item.getItemMeta().itemId), invalidateItemData: () => tree.invalidateItemData(item.getItemMeta().itemId), invalidateChildrenIds: () => tree.invalidateChildrenIds(item.getItemMeta().itemId) })
};
// node_modules/@headless-tree/core/lib/esm/features/drag-and-drop/utils.js
var getDragCode = ({ item, childIndex }) => `${item.getId()}__${childIndex !== null && childIndex !== void 0 ? childIndex : "none"}`;
var getDropOffset = (e, item) => {
var _a;
const bb = (_a = item.getElement()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
return bb ? (e.pageY - bb.top) / bb.height : 0.5;
};
var canDrop = (dataTransfer, target, tree) => {
var _a, _b, _c, _d;
const draggedItems = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems;
const config = tree.getConfig();
if (draggedItems && !((_c = (_b = config.canDrop) === null || _b === void 0 ? void 0 : _b.call(config, draggedItems, target)) !== null && _c !== void 0 ? _c : true)) {
return false;
}
if (!draggedItems && dataTransfer && !((_d = config.canDropForeignDragObject) === null || _d === void 0 ? void 0 : _d.call(config, dataTransfer, target))) {
return false;
}
return true;
};
var getDropTargetPosition = (offset, topLinePercentage, bottomLinePercentage) => {
if (offset < topLinePercentage) {
return DropTargetPosition.Top;
}
if (offset > bottomLinePercentage) {
return DropTargetPosition.Bottom;
}
return DropTargetPosition.Item;
};
var getDropTarget = (e, item, tree, canDropInbetween = tree.getConfig().canDropInbetween) => {
var _a, _b, _c, _d;
const config = tree.getConfig();
const draggedItems = (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggedItems) !== null && _b !== void 0 ? _b : [];
const itemTarget = { item, childIndex: null, insertionIndex: null };
const parentTarget = {
item: item.getParent(),
childIndex: null,
insertionIndex: null
};
if (!canDropInbetween) {
if (!canDrop(e.dataTransfer, parentTarget, tree)) {
return getDropTarget(e, item.getParent(), tree, false);
}
return itemTarget;
}
const canDropInside = canDrop(e.dataTransfer, itemTarget, tree);
const offset = getDropOffset(e, item);
const pos = canDropInside ? getDropTargetPosition(offset, (_c = config.topLinePercentage) !== null && _c !== void 0 ? _c : 0.3, (_d = config.bottomLinePercentage) !== null && _d !== void 0 ? _d : 0.7) : getDropTargetPosition(offset, 0.5, 0.5);
if (pos === DropTargetPosition.Item) {
return itemTarget;
}
if (!canDrop(e.dataTransfer, parentTarget, tree)) {
return getDropTarget(e, item.getParent(), tree, false);
}
const childIndex = item.getIndexInParent() + (pos === DropTargetPosition.Top ? 0 : 1);
const numberOfDragItemsBeforeTarget = item.getParent().getChildren().slice(0, childIndex).reduce((counter, child) => child && (draggedItems === null || draggedItems === void 0 ? void 0 : draggedItems.some((i) => i.getId() === child.getId())) ? ++counter : counter, 0);
return {
item: item.getParent(),
childIndex,
// TODO performance could be improved by computing this only when dragcode changed
insertionIndex: childIndex - numberOfDragItemsBeforeTarget
};
};
// node_modules/@headless-tree/core/lib/esm/features/drag-and-drop/feature.js
var dragAndDropFeature = {
key: "dragAndDrop",
deps: ["selection"],
getDefaultConfig: (defaultConfig, tree) => Object.assign({ canDrop: (_, target) => target.item.isFolder(), canDropForeignDragObject: () => false, setDndState: makeStateUpdater("dnd", tree) }, defaultConfig),
stateHandlerNames: {
dnd: "setDndState"
},
createTreeInstance: (prev, tree) => Object.assign(Object.assign({}, prev), { getDropTarget: () => {
var _a, _b;
return (_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.dragTarget) !== null && _b !== void 0 ? _b : null;
}, getDragLineData: () => {
var _a, _b, _c, _d, _e;
const target = tree.getDropTarget();
const intend = ((_a = target === null || target === void 0 ? void 0 : target.item.getItemMeta().level) !== null && _a !== void 0 ? _a : 0) + 1;
if (!target || target.childIndex === null)
return null;
const children = target.item.getChildren();
if (target.childIndex === children.length) {
const bb2 = (_c = (_b = children[target.childIndex - 1]) === null || _b === void 0 ? void 0 : _b.getElement()) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect();
if (bb2) {
return {
intend,
top: bb2.bottom,
left: bb2.left,
right: bb2.right
};
}
}
const bb = (_e = (_d = children[target.childIndex]) === null || _d === void 0 ? void 0 : _d.getElement()) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();
if (bb) {
return {
intend,
top: bb.top,
left: bb.left,
right: bb.right
};
}
return null;
} }),
createItemInstance: (prev, item, tree) => Object.assign(Object.assign({}, prev), { getProps: () => {
var _a, _b, _c;
return Object.assign(Object.assign({}, prev.getProps()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: item.getMemoizedProp("dnd/onDragStart", () => (e) => {
var _a2, _b2, _c2;
const selectedItems = tree.getSelectedItems();
const items = selectedItems.includes(item) ? selectedItems : [item];
const config = tree.getConfig();
if (!selectedItems.includes(item)) {
tree.setSelectedItems([item.getItemMeta().itemId]);
}
if (!((_b2 = (_a2 = config.canDrag) === null || _a2 === void 0 ? void 0 : _a2.call(config, items)) !== null && _b2 !== void 0 ? _b2 : true)) {
e.preventDefault();
return;
}
if (config.createForeignDragObject) {
const { format, data } = config.createForeignDragObject(items);
(_c2 = e.dataTransfer) === null || _c2 === void 0 ? void 0 : _c2.setData(format, data);
}
tree.applySubStateUpdate("dnd", {
draggedItems: items,
draggingOverItem: tree.getFocusedItem()
});
}), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
var _a2, _b2, _c2;
const target = getDropTarget(e, item, tree);
const dataRef = tree.getDataRef();
if (!((_a2 = tree.getState().dnd) === null || _a2 === void 0 ? void 0 : _a2.draggedItems) && !((_c2 = (_b2 = tree.getConfig()).canDropForeignDragObject) === null || _c2 === void 0 ? void 0 : _c2.call(_b2, e.dataTransfer, target))) {
return;
}
if (!canDrop(e.dataTransfer, target, tree)) {
return;
}
e.preventDefault();
const nextDragCode = getDragCode(target);
if (nextDragCode === dataRef.current.lastDragCode) {
return;
}
dataRef.current.lastDragCode = nextDragCode;
tree.applySubStateUpdate("dnd", (state) => Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item }));
}), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
const dataRef = tree.getDataRef();
dataRef.current.lastDragCode = "no-drag";
tree.applySubStateUpdate("dnd", (state) => Object.assign(Object.assign({}, state), { draggingOverItem: void 0, dragTarget: void 0 }));
}), onDragEnd: item.getMemoizedProp("dnd/onDragEnd", () => (e) => {
var _a2, _b2, _c2;
const draggedItems = (_a2 = tree.getState().dnd) === null || _a2 === void 0 ? void 0 : _a2.draggedItems;
tree.applySubStateUpdate("dnd", null);
if (e.dataTransfer.dropEffect === "none" || !draggedItems) {
return;
}
(_c2 = (_b2 = tree.getConfig()).onCompleteForeignDrop) === null || _c2 === void 0 ? void 0 : _c2.call(_b2, draggedItems);
}), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
var _a2, _b2, _c2;
const dataRef = tree.getDataRef();
const target = getDropTarget(e, item, tree);
if (!canDrop(e.dataTransfer, target, tree)) {
return;
}
e.preventDefault();
const config = tree.getConfig();
const draggedItems = (_a2 = tree.getState().dnd) === null || _a2 === void 0 ? void 0 : _a2.draggedItems;
dataRef.current.lastDragCode = void 0;
tree.applySubStateUpdate("dnd", null);
if (draggedItems) {
(_b2 = config.onDrop) === null || _b2 === void 0 ? void 0 : _b2.call(config, draggedItems, target);
} else {
(_c2 = config.onDropForeignDragObject) === null || _c2 === void 0 ? void 0 : _c2.call(config, e.dataTransfer, target);
}
}) });
}, isDropTarget: () => {
const target = tree.getDropTarget();
return target ? target.item.getId() === item.getId() : false;
}, isDropTargetAbove: () => {
const target = tree.getDropTarget();
if (!target || target.childIndex === null || target.item !== item.getParent())
return false;
return target.childIndex === item.getItemMeta().posInSet;
}, isDropTargetBelow: () => {
const target = tree.getDropTarget();
if (!target || target.childIndex === null || target.item !== item.getParent())
return false;
return target.childIndex - 1 === item.getItemMeta().posInSet;
}, isDraggingOver: () => {
var _a, _b;
return ((_b = (_a = tree.getState().dnd) === null || _a === void 0 ? void 0 : _a.draggingOverItem) === null || _b === void 0 ? void 0 : _b.getId()) === item.getId();
} })
};
// node_modules/@headless-tree/react/lib/esm/index.js
import { useState } from "react";
var useTree = (config) => {
const [tree] = useState(() => ({ current: createTree(config) }));
const [state, setState] = useState(() => tree.current.getState());
tree.current.setConfig((prev) => Object.assign(Object.assign(Object.assign({}, prev), config), { state: Object.assign(Object.assign({}, state), config.state), setState: (state2) => {
var _a;
setState(state2);
(_a = config.setState) === null || _a === void 0 ? void 0 : _a.call(config, state2);
} }));
return tree.current;
};
// src/dashboard/view/EntryTree.tsx
import { EntryPhase, Type } from "alinea/core";
import { Icon, fromModule, px } from "alinea/ui";
import { IcOutlineDescription } from "alinea/ui/icons/IcOutlineDescription";
import { IcRoundArchive } from "alinea/ui/icons/IcRoundArchive";
import { IcRoundEdit } from "alinea/ui/icons/IcRoundEdit";
import { IcRoundKeyboardArrowDown } from "alinea/ui/icons/IcRoundKeyboardArrowDown";
import { IcRoundKeyboardArrowRight } from "alinea/ui/icons/IcRoundKeyboardArrowRight";
import { IcRoundTranslate } from "alinea/ui/icons/IcRoundTranslate";
import { useEffect, useRef } from "react";
import { changedEntriesAtom, graphAtom } from "../atoms/DbAtoms.js";
import {
rootId,
useEntryTreeProvider
} from "../atoms/EntryAtoms.js";
import { entryLocationAtom } from "../atoms/NavigationAtoms.js";
import { useConfig } from "../hook/UseConfig.js";
import { useLocale } from "../hook/UseLocale.js";
import { useNav } from "../hook/UseNav.js";
import { useRoot } from "../hook/UseRoot.js";
import { useNavigate } from "../util/HashRouter.js";
// src/dashboard/view/EntryTree.module.scss
var EntryTree_module_default = {
"tree": "alinea-EntryTree-tree",
"tree-item": "alinea-EntryTree-tree-item",
"treeItem": "alinea-EntryTree-tree-item",
"tree-item-icon": "alinea-EntryTree-tree-item-icon",
"treeItemIcon": "alinea-EntryTree-tree-item-icon",
"is-selected": "alinea-EntryTree-is-selected",
"isSelected": "alinea-EntryTree-is-selected",
"is-drop": "alinea-EntryTree-is-drop",
"isDrop": "alinea-EntryTree-is-drop",
"is-dropAbove": "alinea-EntryTree-is-dropAbove",
"isDropAbove": "alinea-EntryTree-is-dropAbove",
"is-dropBelow": "alinea-EntryTree-is-dropBelow",
"isDropBelow": "alinea-EntryTree-is-dropBelow",
"tree-item-label": "alinea-EntryTree-tree-item-label",
"treeItemLabel": "alinea-EntryTree-tree-item-label",
"tree-item-label-itemName": "alinea-EntryTree-tree-item-label-itemName",
"treeItemLabelItemName": "alinea-EntryTree-tree-item-label-itemName",
"is-untranslated": "alinea-EntryTree-is-untranslated",
"isUntranslated": "alinea-EntryTree-is-untranslated",
"tree-item-arrow": "alinea-EntryTree-tree-item-arrow",
"treeItemArrow": "alinea-EntryTree-tree-item-arrow",
"tree-title": "alinea-EntryTree-tree-title",
"treeTitle": "alinea-EntryTree-tree-title",
"tree-status": "alinea-EntryTree-tree-status",
"treeStatus": "alinea-EntryTree-tree-status",
"is-draft": "alinea-EntryTree-is-draft",
"isDraft": "alinea-EntryTree-is-draft"
};
// src/dashboard/view/EntryTree.tsx
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { createElement } from "react";
var styles = fromModule(EntryTree_module_default);
function selectedEntry(locale, item) {
return item.entries.find((entry) => entry.locale === locale) ?? item.entries[0];
}
function EntryTreeItem({ item, data }) {
const { entryId } = useAtomValue(entryLocationAtom);
const locale = useLocale();
const { schema } = useConfig();
const currentData = useRef(data);
const itemData = data ?? currentData.current;
if (!itemData)
return null;
currentData.current = itemData;
const selected = selectedEntry(locale, itemData);
const { icon } = Type.meta(schema[selected.type]);
const isDraft = selected.phase === EntryPhase.Draft;
const isUntranslated = locale && selected.locale !== locale;
const isArchived = selected.phase === EntryPhase.Archived;
const isSelected = entryId && itemData.id === entryId;
return /* @__PURE__ */ createElement(
"div",
{
...item.getProps(),
ref: item.registerElement,
className: styles.tree.item({
untranslated: isUntranslated,
selected: isSelected,
drop: item.isDropTarget() && item.isDraggingOver(),
dropAbove: item.isDropTargetAbove() && item.isDraggingOver(),
dropBelow: item.isDropTargetBelow() && item.isDraggingOver()
}),
key: item.getId(),
"data-id": item.getId()
},
/* @__PURE__ */ jsxs(
"button",
{
className: styles.tree.item.label(),
title: selectedEntry(locale, itemData).title,
style: { paddingLeft: px((item.getItemMeta().level + 1) * 12) },
children: [
/* @__PURE__ */ jsx("span", { className: styles.tree.item.icon(), children: /* @__PURE__ */ jsx(
Icon,
{
icon: isUntranslated ? IcRoundTranslate : icon ?? IcOutlineDescription
}
) }),
/* @__PURE__ */ jsx("span", { className: styles.tree.item.label.itemName(), children: selectedEntry(locale, itemData).title }),
item.isFolder() && /* @__PURE__ */ jsx("span", { className: styles.tree.item.arrow(), children: item.isExpanded() ? /* @__PURE__ */ jsx(Icon, { icon: IcRoundKeyboardArrowDown, size: 18 }) : /* @__PURE__ */ jsx(Icon, { icon: IcRoundKeyboardArrowRight, size: 18 }) }),
!isUntranslated && isDraft && /* @__PURE__ */ jsx("span", { className: styles.tree.status({ draft: true }), children: /* @__PURE__ */ jsx(Icon, { icon: IcRoundEdit }) }),
!isUntranslated && isArchived && /* @__PURE__ */ jsx("span", { className: styles.tree.status({ archived: true }), children: /* @__PURE__ */ jsx(Icon, { icon: IcRoundArchive, size: 18 }) })
]
}
)
);
}
function EntryTree({ i18nId: entryId, selected = [] }) {
const graph = useAtomValue(graphAtom);
const root = useRoot();
const treeProvider = useEntryTreeProvider();
const navigate = useNavigate();
const nav = useNav();
const locale = useLocale();
const tree = useTree({
rootItemId: rootId(root.name),
canDropInbetween: true,
onDrop(items, target) {
return treeProvider.onDrop(items, target);
},
asyncDataLoader: treeProvider,
getItemName: (item) => item.getItemData() && selectedEntry(locale, item.getItemData()).title,
isItemFolder: (item) => item.getItemData() && Boolean(item.getItemData().isFolder),
onPrimaryAction: (item) => {
navigate(nav.entry({ entryId: item.getId() }));
},
initialState: {
expandedItems: selected
},
state: {
selectedItems: entryId ? [entryId] : []
},
features: [
asyncDataLoaderFeature,
selectionFeature,
dragAndDropFeature
// hotkeysCoreFeature
]
});
const changed = useAtomValue(changedEntriesAtom);
useEffect(() => {
;
(async () => {
for (const id of selected) {
await treeProvider.getChildren(id).then(() => new Promise(requestAnimationFrame));
tree.expandItem(id);
}
})();
}, [selected.join()]);
useEffect(() => {
tree.invalidateChildrenIds(rootId(root.name));
}, [treeProvider]);
useEffect(() => {
for (const i18nId of changed) {
try {
const item = tree.getItemInstance(i18nId);
if (!item) {
tree.invalidateChildrenIds(rootId(root.name));
continue;
}
const parent = item.getParent();
const parentId = parent?.getId();
if (parentId)
tree.invalidateChildrenIds(parentId);
tree.invalidateChildrenIds(i18nId);
tree.invalidateItemData(i18nId);
} catch (e) {
console.error(e);
}
}
}, [changed]);
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", { ref: tree.registerElement, className: styles.tree(), children: tree.getItems().map((item, i) => {
const data = item.getItemData();
return /* @__PURE__ */ jsx(EntryTreeItem, { item, data }, item.getId());
}) }) });
}
export {
EntryTree
};