@frebreco/canvas 0.2.0-next.1 → 0.3.0-next.1
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/package.json +1 -1
- package/src/shared/layout.ts +44 -3
package/package.json
CHANGED
package/src/shared/layout.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* new frame's rect and patches for the frames that make room: frames later in
|
|
13
13
|
* the row shift right, rows further down shift down. Nothing outside the
|
|
14
14
|
* anchor's cluster moves. Anything placed away from other frames stays free.
|
|
15
|
+
* A frame leaving (moved or removed) closes its gap the same way, reversed.
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
18
|
export interface Rect {
|
|
@@ -178,10 +179,50 @@ export function placeNear(
|
|
|
178
179
|
);
|
|
179
180
|
}
|
|
180
181
|
|
|
181
|
-
/**
|
|
182
|
+
/**
|
|
183
|
+
* A frame leaves its place: the frames after it in its row close the gap, or,
|
|
184
|
+
* when it was alone in its row, the rows below move up into it.
|
|
185
|
+
*/
|
|
182
186
|
export function lift(rects: ReadonlyArray<Rect>, id: string): Patch[] {
|
|
183
|
-
const { row, frame } = locate(rects, id);
|
|
184
|
-
|
|
187
|
+
const { cluster: c, row, frame } = locate(rects, id);
|
|
188
|
+
if (row.length > 1)
|
|
189
|
+
return row.filter((f) => f.x > frame.x).map((f) => ({ id: f.id, x: f.x - frame.w - GAP }));
|
|
190
|
+
const below = c.rows.slice(c.rows.indexOf(row) + 1).flat();
|
|
191
|
+
if (below.length === 0) return [];
|
|
192
|
+
const dy = Math.min(...below.map((f) => f.y)) - frame.y;
|
|
193
|
+
return below.map((f) => ({ id: f.id, y: f.y - dy }));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Whether placing next to `target` goes in between two frames — two of a
|
|
198
|
+
* row, or two rows — and if so the gap's centre line (`w` or `h` is 0), for a
|
|
199
|
+
* drop's preview. `movingId`, the frame being placed, is no neighbour.
|
|
200
|
+
*/
|
|
201
|
+
export function insertion(
|
|
202
|
+
rects: ReadonlyArray<Rect>,
|
|
203
|
+
target: Target,
|
|
204
|
+
movingId?: string,
|
|
205
|
+
): Box | null {
|
|
206
|
+
const rest = rects.filter((f) => f.id !== movingId);
|
|
207
|
+
const { cluster: c, row, frame: anchor } = locate(rest, target.anchor);
|
|
208
|
+
switch (target.side) {
|
|
209
|
+
case "right":
|
|
210
|
+
case "left": {
|
|
211
|
+
const i = row.indexOf(anchor);
|
|
212
|
+
const [l, r] = target.side === "right" ? [anchor, row[i + 1]] : [row[i - 1], anchor];
|
|
213
|
+
if (!l || !r) return null;
|
|
214
|
+
const y = Math.min(l.y, r.y);
|
|
215
|
+
return { x: (l.x + l.w + r.x) / 2, y, w: 0, h: Math.max(l.y + l.h, r.y + r.h) - y };
|
|
216
|
+
}
|
|
217
|
+
case "below":
|
|
218
|
+
case "above": {
|
|
219
|
+
const i = c.rows.indexOf(row);
|
|
220
|
+
const [upper, lower] = target.side === "below" ? [row, c.rows[i + 1]] : [c.rows[i - 1], row];
|
|
221
|
+
if (!upper || !lower) return null;
|
|
222
|
+
const y = (rowBottom(upper) + Math.min(...lower.map((f) => f.y))) / 2;
|
|
223
|
+
return { x: c.bounds.x, y, w: c.bounds.w, h: 0 };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
185
226
|
}
|
|
186
227
|
|
|
187
228
|
/** Where a frame being dragged would snap to: next to the nearest frame within reach. */
|