Skip to content

Commit 2d3d62a

Browse files
authored
refactor: add new insert constraints (#4499)
Here added new constraints format which will allow us build more expressive lookups and matchers for internal logic and components constraints. For now added only ancestor, parent and self matchers with $eq, $neq, $in, $nin operations. Closes #2193 "$in" operation works like "or".
1 parent e06de53 commit 2d3d62a

31 files changed

+1113
-71
lines changed

apps/builder/app/shared/instance-utils.test.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { Project } from "@webstudio-is/project";
99
import { createDefaultPages } from "@webstudio-is/project-build";
1010
import { $, ws, renderJsx, ExpressionValue } from "@webstudio-is/sdk/testing";
1111
import { parseCss } from "@webstudio-is/css-data";
12+
import { coreMetas } from "@webstudio-is/react-sdk";
1213
import * as defaultMetas from "@webstudio-is/sdk-components-react/metas";
1314
import type {
1415
Asset,
@@ -66,7 +67,9 @@ registerContainers();
6667

6768
$pages.set(createDefaultPages({ rootInstanceId: "", systemDataSourceId: "" }));
6869

69-
const defaultMetasMap = new Map(Object.entries(defaultMetas));
70+
const defaultMetasMap = new Map(
71+
Object.entries({ ...defaultMetas, ...coreMetas })
72+
);
7073
$registeredComponentMetas.set(defaultMetasMap);
7174

7275
const createFragment = (

apps/builder/app/shared/instance-utils.ts

Lines changed: 46 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ import { serverSyncStore } from "./sync";
6363
import { setDifference, setUnion } from "./shim";
6464
import { breakCyclesMutable, findCycles } from "@webstudio-is/project-build";
6565
import { $awareness, $selectedPage, selectInstance } from "./awareness";
66+
import {
67+
findClosestContainer,
68+
findClosestInstanceMatchingFragment,
69+
} from "./matcher";
6670

6771
export const updateWebstudioData = (mutate: (data: WebstudioData) => void) => {
6872
serverSyncStore.createTransaction(
@@ -419,63 +423,6 @@ export const findClosestDroppableComponentIndex = ({
419423
return -1;
420424
};
421425

422-
const findClosestDroppableTarget = (
423-
metas: Map<string, WsComponentMeta>,
424-
instances: Instances,
425-
instanceSelector: InstanceSelector,
426-
insertConstraints: InsertConstraints
427-
): undefined | DroppableTarget => {
428-
const droppableIndex = findClosestDroppableComponentIndex({
429-
metas,
430-
constraints: insertConstraints,
431-
instances,
432-
instanceSelector,
433-
// We want to always allow dropping into the root.
434-
// For example when body has text content
435-
// and the only viable option is to insert at the end.
436-
allowInsertIntoTextContainer: instanceSelector.length === 1,
437-
});
438-
if (droppableIndex === -1) {
439-
return;
440-
}
441-
442-
const dropTargetParentInstance = instances.get(
443-
instanceSelector[droppableIndex + 1]
444-
);
445-
let dropTargetInstance = instances.get(instanceSelector[droppableIndex]);
446-
// skip collection item when inserting something and go straight into collection instance
447-
if (
448-
dropTargetInstance === undefined &&
449-
dropTargetParentInstance?.component === collectionComponent
450-
) {
451-
instanceSelector = instanceSelector.slice(1);
452-
dropTargetInstance = dropTargetParentInstance;
453-
}
454-
if (dropTargetInstance === undefined) {
455-
return;
456-
}
457-
458-
if (droppableIndex === 0) {
459-
return {
460-
parentSelector: instanceSelector,
461-
position: "end",
462-
};
463-
}
464-
465-
const dropTargetSelector = instanceSelector.slice(droppableIndex);
466-
if (dropTargetInstance === undefined) {
467-
return;
468-
}
469-
const lastChildInstanceId = instanceSelector[droppableIndex - 1];
470-
const lastChildPosition = dropTargetInstance.children.findIndex(
471-
(child) => child.type === "id" && child.value === lastChildInstanceId
472-
);
473-
return {
474-
parentSelector: dropTargetSelector,
475-
position: lastChildPosition + 1,
476-
};
477-
};
478-
479426
export const insertInstanceChildrenMutable = (
480427
data: WebstudioData,
481428
children: Instance["children"],
@@ -1613,16 +1560,50 @@ export const findClosestInsertable = (
16131560
}
16141561
const metas = $registeredComponentMetas.get();
16151562
const instances = $instances.get();
1616-
const rootInstanceIds = fragment.children
1617-
.filter((child) => child.type === "id")
1618-
.map((child) => child.value);
1619-
const newInstances = new Map(
1620-
fragment.instances.map((instance) => [instance.id, instance])
1621-
);
1622-
return findClosestDroppableTarget(
1563+
const closestContainerIndex = findClosestContainer({
16231564
metas,
16241565
instances,
16251566
instanceSelector,
1626-
computeInstancesConstraints(metas, newInstances, rootInstanceIds)
1567+
});
1568+
if (closestContainerIndex === -1) {
1569+
return;
1570+
}
1571+
let insertableIndex = findClosestInstanceMatchingFragment({
1572+
metas,
1573+
instances,
1574+
instanceSelector: instanceSelector.slice(closestContainerIndex),
1575+
fragment,
1576+
});
1577+
if (insertableIndex === -1) {
1578+
return;
1579+
}
1580+
1581+
// adjust with container lookup
1582+
insertableIndex = insertableIndex + closestContainerIndex;
1583+
const parentSelector = instanceSelector.slice(insertableIndex);
1584+
if (insertableIndex === 0) {
1585+
return {
1586+
parentSelector,
1587+
position: "end",
1588+
};
1589+
}
1590+
const instance = instances.get(instanceSelector[insertableIndex]);
1591+
if (instance === undefined) {
1592+
return;
1593+
}
1594+
// skip collection item when inserting something and go straight into collection instance
1595+
if (instance?.component === collectionComponent && insertableIndex === 1) {
1596+
return {
1597+
parentSelector,
1598+
position: "end",
1599+
};
1600+
}
1601+
const lastChildInstanceId = instanceSelector[insertableIndex - 1];
1602+
const lastChildPosition = instance.children.findIndex(
1603+
(child) => child.type === "id" && child.value === lastChildInstanceId
16271604
);
1605+
return {
1606+
parentSelector,
1607+
position: lastChildPosition + 1,
1608+
};
16281609
};

0 commit comments

Comments
 (0)