@n-uf/placement 26.11.8 → 26.11.10

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.
@@ -0,0 +1,759 @@
1
+ import {
2
+ rect
3
+ } from "./chunk-QMTNB2C3.js";
4
+
5
+ // src/panels/model.ts
6
+ var SIDES = ["left", "right"];
7
+ var EDGES = ["top", "bottom"];
8
+ var BAND_SIZE = { min: 120, max: 480, natural: 200 };
9
+ var IDENTITY_VIEW = { x: 0, y: 0, scale: 1 };
10
+ var DEFAULT_PANELS_OPTIONS = {
11
+ giveWay: { order: "oldest", by: "used" },
12
+ floats: "clamp",
13
+ fold: "rail",
14
+ floatVisible: 48,
15
+ pagesMin: 320,
16
+ view: IDENTITY_VIEW,
17
+ bar: 28,
18
+ rail: 36,
19
+ segment: 36,
20
+ railInset: 4,
21
+ tabs: 28,
22
+ bands: {},
23
+ pagesMinHeight: 240,
24
+ reserve: {}
25
+ };
26
+ var FLOAT_HEIGHT = 360;
27
+ var FLOAT_MIN = { width: 160, height: 120 };
28
+ var without = (list, x) => list.filter((y) => y !== x);
29
+ var withOnce = (list, x) => list.includes(x) ? [...list] : [...list, x];
30
+ function whereIs(state, id) {
31
+ for (const side of SIDES) {
32
+ const index = state.sides[side].findIndex((c) => c.panels.includes(id));
33
+ if (index >= 0) return { kind: "column", side, index };
34
+ }
35
+ for (const edge of EDGES) {
36
+ const index = state.bands?.[edge]?.panels.indexOf(id) ?? -1;
37
+ if (index >= 0) return { kind: "band", edge, index };
38
+ }
39
+ const float2 = state.floats.find((f) => f.id === id);
40
+ return float2 ? { kind: "float", float: float2 } : { kind: "none" };
41
+ }
42
+ var tick = (state) => Object.values(state.clock).reduce((m, c) => Math.max(m, c.opened, c.used), 0) + 1;
43
+ var bump = (state, id, opened) => {
44
+ const t = tick(state);
45
+ const was = state.clock[id] ?? { opened: 0, used: 0 };
46
+ return { ...state, clock: { ...state.clock, [id]: { opened: opened ? t : was.opened, used: t } } };
47
+ };
48
+ var defOf = (defs, id) => defs.find((d) => d.id === id);
49
+ function floatSize(def) {
50
+ if (def?.float) return { min: def.float.min, natural: def.float.natural };
51
+ const width = Math.max(FLOAT_MIN.width, def?.width.natural ?? FLOAT_MIN.width);
52
+ return { min: FLOAT_MIN, natural: { width, height: FLOAT_HEIGHT } };
53
+ }
54
+ var bandSize = (def) => ({ ...def?.band ?? BAND_SIZE });
55
+ function bandHeight(defs, band) {
56
+ if (!defs) return band.height;
57
+ const ds = band.panels.map((id) => bandSize(defOf(defs, id)));
58
+ const lo = Math.max(0, ...ds.map((d) => d.min));
59
+ const hi = Math.max(lo, Math.min(...ds.map((d) => d.max)));
60
+ return Math.min(Math.max(Number.isFinite(band.height) ? band.height : lo, lo), hi);
61
+ }
62
+ var withBand = (state, edge, band) => {
63
+ const { bands: _b, ...rest } = state;
64
+ const bands = { ...state.bands };
65
+ if (band && band.panels.length) bands[edge] = band;
66
+ else delete bands[edge];
67
+ return EDGES.some((e) => bands[e]) ? { ...rest, bands } : rest;
68
+ };
69
+ function ownWidth(defs, state, id) {
70
+ const def = defOf(defs, id);
71
+ const w = whereIs(state, id);
72
+ const lo = def?.width.min ?? 0;
73
+ const hi = Math.max(lo, def?.width.max ?? Infinity);
74
+ if (w.kind === "column") return Math.min(Math.max(state.sides[w.side][w.index].width, lo), hi);
75
+ return def?.width.natural ?? lo;
76
+ }
77
+ function createPanels(defs, start) {
78
+ const column = (ids) => {
79
+ const ds = ids.map((id) => defOf(defs, id));
80
+ const lo = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));
81
+ const hi = Math.max(lo, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));
82
+ const natural = Math.max(0, ...ds.map((d) => d?.width.natural ?? 0));
83
+ return { panels: [...ids], width: Math.min(Math.max(natural, lo), hi) };
84
+ };
85
+ const floats = (start.floats ?? []).map((f) => {
86
+ const n = floatSize(defOf(defs, f.id)).natural;
87
+ return { id: f.id, rect: { x: f.x, y: f.y, width: f.width ?? n.width, height: f.height ?? n.height }, ...f.pinned ? { pinned: true } : {} };
88
+ });
89
+ const sides = { left: (start.left ?? []).map(column), right: (start.right ?? []).map(column) };
90
+ const bands = {};
91
+ for (const edge of EDGES) {
92
+ const ids = start[edge] ?? [];
93
+ if (!ids.length) continue;
94
+ const natural = Math.max(0, ...ids.map((id) => bandSize(defOf(defs, id)).natural));
95
+ bands[edge] = { panels: [...ids], height: bandHeight(defs, { panels: ids, height: natural }) };
96
+ }
97
+ const order = [...sides.left, ...sides.right].flatMap((c) => c.panels).concat(EDGES.flatMap((e) => bands[e]?.panels ?? [])).concat(floats.map((f) => f.id));
98
+ const clock = {};
99
+ order.forEach((id, i) => clock[id] = { opened: i + 1, used: i + 1 });
100
+ const s = { sides, floats, folded: [...start.folded ?? []], kept: [...start.kept ?? []], closed: [...start.closed ?? []], clock };
101
+ return EDGES.some((e) => bands[e]) ? { ...s, bands } : s;
102
+ }
103
+ function liftPanel(state, id) {
104
+ const out = (c) => {
105
+ const { active: _a, ...rest } = c;
106
+ return { ...c.active === id ? rest : c, panels: without(c.panels, id) };
107
+ };
108
+ const lift = (cols) => cols.map(out).filter((c) => c.panels.length > 0);
109
+ let s = { ...state, sides: { left: lift(state.sides.left), right: lift(state.sides.right) }, floats: state.floats.filter((f) => f.id !== id) };
110
+ for (const edge of EDGES) {
111
+ const b = s.bands?.[edge];
112
+ if (b?.panels.includes(id)) s = withBand(s, edge, { ...b, panels: without(b.panels, id) });
113
+ }
114
+ return s;
115
+ }
116
+ function open(state, id, at) {
117
+ let s = { ...state, closed: without(state.closed, id) };
118
+ if (at && whereIs(s, id).kind === "none") {
119
+ if ("edge" in at) {
120
+ const b = s.bands?.[at.edge];
121
+ const panels = [...b?.panels ?? [], id];
122
+ s = withBand({ ...s, folded: s.folded.filter((x) => !panels.includes(x)) }, at.edge, { panels, height: b?.height ?? at.height ?? BAND_SIZE.natural });
123
+ } else s = { ...s, sides: { ...s.sides, [at.side]: [...s.sides[at.side], { panels: [id], width: at.width }] } };
124
+ }
125
+ const w = whereIs(s, id);
126
+ if (w.kind === "column" && s.sides[w.side][w.index].show === "tabs") s = { ...s, sides: { ...s.sides, [w.side]: s.sides[w.side].map((c, i) => i === w.index ? { ...c, active: id } : c) } };
127
+ return bump(s, id, true);
128
+ }
129
+ var close = (state, id) => ({ ...state, closed: withOnce(state.closed, id), kept: without(state.kept, id) });
130
+ function focus(state, id) {
131
+ const f = state.floats.find((x) => x.id === id);
132
+ const s = f ? { ...state, floats: [...state.floats.filter((x) => x !== f), f] } : state;
133
+ return bump(s, id, false);
134
+ }
135
+ function toggleFold(state, id) {
136
+ const w = whereIs(state, id);
137
+ if (w.kind === "band") {
138
+ const ids = state.bands[w.edge].panels;
139
+ const shown = ids.filter((x) => !state.closed.includes(x));
140
+ if ((shown.length ? shown : ids).every((x) => state.folded.includes(x))) return bump({ ...state, folded: state.folded.filter((x) => !ids.includes(x)) }, id, false);
141
+ return { ...state, folded: [...state.folded.filter((x) => !ids.includes(x)), ...ids] };
142
+ }
143
+ if (state.folded.includes(id)) return bump({ ...state, folded: without(state.folded, id) }, id, false);
144
+ return { ...state, folded: [...state.folded, id] };
145
+ }
146
+ function keep(state, id, on) {
147
+ if (!on) return { ...state, kept: without(state.kept, id) };
148
+ const k = whereIs(state, id).kind;
149
+ return k === "column" || k === "band" ? { ...state, kept: withOnce(state.kept, id) } : state;
150
+ }
151
+ function dockBand(state, id, edge, index, defs) {
152
+ const s = liftPanel(state, id);
153
+ const b = s.bands?.[edge];
154
+ const panels = [...b?.panels ?? []];
155
+ panels.splice(Math.max(0, Math.min(index, panels.length)), 0, id);
156
+ const height = b?.height ?? bandSize(defs ? defOf(defs, id) : void 0).natural;
157
+ const s1 = withBand(s, edge, { panels, height });
158
+ return bump({ ...s1, folded: s1.folded.filter((x) => !panels.includes(x)), closed: without(s1.closed, id) }, id, false);
159
+ }
160
+ function resizeBand(state, edge, height) {
161
+ const b = state.bands?.[edge];
162
+ if (!b || !Number.isFinite(height)) return state;
163
+ const t = tick(state);
164
+ const clock = { ...state.clock };
165
+ for (const id of b.panels) clock[id] = { opened: clock[id]?.opened ?? 0, used: t };
166
+ return { ...withBand(state, edge, { ...b, height: Math.max(0, height) }), clock };
167
+ }
168
+ function dock(state, id, side, index, options = {}) {
169
+ const w = whereIs(state, id);
170
+ const from = w.kind === "column" ? state.sides[w.side][w.index].width : 0;
171
+ const s = liftPanel(state, id);
172
+ const cols = [...s.sides[side]];
173
+ if (options.into && cols[index]) cols[index] = { ...cols[index], panels: [...cols[index].panels, id], ...cols[index].show === "tabs" ? { active: id } : {} };
174
+ else {
175
+ const at = Math.max(0, Math.min(index, cols.length));
176
+ cols.splice(at, 0, { panels: [id], width: options.width ?? from });
177
+ }
178
+ return bump({ ...s, sides: { ...s.sides, [side]: cols }, closed: without(s.closed, id) }, id, false);
179
+ }
180
+ function showTabs(state, side, index, on) {
181
+ const col = state.sides[side][index];
182
+ if (!col) return state;
183
+ const { show: _s, ...stack } = col;
184
+ return { ...state, sides: { ...state.sides, [side]: state.sides[side].map((c, i) => i === index ? on ? { ...col, show: "tabs" } : stack : c) } };
185
+ }
186
+ function activate(state, id) {
187
+ const w = whereIs(state, id);
188
+ if (w.kind !== "column") return state;
189
+ const sides = { ...state.sides, [w.side]: state.sides[w.side].map((c, i) => i === w.index ? { ...c, active: id } : c) };
190
+ return bump({ ...state, sides }, id, false);
191
+ }
192
+ function float(state, id, rect2, pinned) {
193
+ const was = state.floats.find((f2) => f2.id === id);
194
+ const on = pinned ?? !!was?.pinned;
195
+ const s = liftPanel(state, id);
196
+ const f = { id, rect: { ...rect2 }, ...on ? { pinned: true } : {} };
197
+ return bump({ ...s, floats: [...s.floats, f], kept: without(s.kept, id), closed: without(s.closed, id) }, id, false);
198
+ }
199
+ var toView = (r, v) => ({ ...r, x: v.x + r.x * v.scale, y: v.y + r.y * v.scale });
200
+ var toPage = (r, v) => ({ ...r, x: (r.x - v.x) / v.scale, y: (r.y - v.y) / v.scale });
201
+ function pin(state, id, on, view = IDENTITY_VIEW, shown) {
202
+ return {
203
+ ...state,
204
+ floats: state.floats.map((f) => {
205
+ if (f.id !== id || !!f.pinned === on) return f;
206
+ const seen = shown ? { ...f.rect, x: shown.x, y: shown.y } : f.pinned ? { ...f.rect } : toView(f.rect, view);
207
+ return on ? { id, rect: seen, pinned: true } : { id, rect: toPage(seen, view) };
208
+ })
209
+ };
210
+ }
211
+ function resizeColumn(state, side, index, width) {
212
+ const col = state.sides[side][index];
213
+ if (!col || !Number.isFinite(width)) return state;
214
+ const t = tick(state);
215
+ const clock = { ...state.clock };
216
+ for (const id of col.panels) clock[id] = { opened: clock[id]?.opened ?? 0, used: t };
217
+ return { ...state, sides: { ...state.sides, [side]: state.sides[side].map((c, i) => i === index ? { ...c, width: Math.max(0, width) } : c) }, clock };
218
+ }
219
+ function resizeFloat(state, id, rect2) {
220
+ if (!state.floats.some((f) => f.id === id)) return state;
221
+ return bump({ ...state, floats: state.floats.map((f) => f.id === id ? { ...f, rect: { ...rect2 } } : f) }, id, false);
222
+ }
223
+ function columnWidth(defs, col) {
224
+ if (!defs) return col.width;
225
+ const ds = col.panels.map((id) => defOf(defs, id));
226
+ const lo = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));
227
+ const hi = Math.max(lo, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));
228
+ return Math.min(Math.max(Number.isFinite(col.width) ? col.width : lo, lo), hi);
229
+ }
230
+ function samePlaces(a, b, defs) {
231
+ const cols = (s) => SIDES.map(
232
+ (side) => s.sides[side].map((c) => `${c.panels.join(",")}@${Math.round(columnWidth(defs, c))}${c.show === "tabs" ? `/tabs:${c.active ?? c.panels[0]}` : ""}`).join("|")
233
+ ).join("\u2016");
234
+ const fl = (s) => s.floats.map((f) => `${f.id}@${Math.round(f.rect.x)},${Math.round(f.rect.y)},${Math.round(f.rect.width)},${Math.round(f.rect.height)}${f.pinned ? "p" : ""}`).join("|");
235
+ const bs = (s) => EDGES.map((e) => {
236
+ const b2 = s.bands?.[e];
237
+ return b2 ? `${b2.panels.join(",")}@${Math.round(bandHeight(defs, b2))}` : "";
238
+ }).join("\u2016");
239
+ const set = (l) => [...l].sort().join(",");
240
+ return cols(a) === cols(b) && bs(a) === bs(b) && fl(a) === fl(b) && set(a.folded) === set(b.folded) && set(a.kept) === set(b.kept) && set(a.closed) === set(b.closed);
241
+ }
242
+
243
+ // src/panels/layout.ts
244
+ var clamp = (v, lo, hi) => Math.min(Math.max(v, lo), Math.max(lo, hi));
245
+ function giveWayOrder(cols, order) {
246
+ return [...cols].sort((a, b) => Number(a.kept) - Number(b.kept) || (order === "oldest" ? a.age - b.age : b.age - a.age) || a.index - b.index || SIDES.indexOf(a.side) - SIDES.indexOf(b.side));
247
+ }
248
+ function layoutPanels(defs, state, stage, options = {}) {
249
+ const opt = { ...DEFAULT_PANELS_OPTIONS, ...options };
250
+ const W = stage.width;
251
+ const H = stage.height;
252
+ const closed = new Set(state.closed);
253
+ const folded = new Set(state.folded);
254
+ const kept = new Set(state.kept);
255
+ const by = opt.giveWay.by;
256
+ const ride = opt.fold === "ride";
257
+ const px = (v) => typeof v === "number" && Number.isFinite(v) ? Math.max(0, v) : 0;
258
+ const reserveOpt = opt.reserve ?? {};
259
+ const bandOpts = opt.bands ?? {};
260
+ const minH = typeof opt.pagesMinHeight === "number" ? opt.pagesMinHeight : DEFAULT_PANELS_OPTIONS.pagesMinHeight;
261
+ const res = { top: px(reserveOpt.top), right: px(reserveOpt.right), bottom: px(reserveOpt.bottom), left: px(reserveOpt.left) };
262
+ const bandsIn = [];
263
+ const offNotes = [];
264
+ for (const edge of EDGES) {
265
+ const b = state.bands?.[edge];
266
+ if (!b) continue;
267
+ const panels = b.panels.filter((id) => !closed.has(id));
268
+ if (panels.length === 0) continue;
269
+ const o = bandOpts[edge];
270
+ if (!o) {
271
+ offNotes.push({ code: "band-off", edge, items: panels });
272
+ continue;
273
+ }
274
+ const ds = panels.map((id) => bandSize(defOf(defs, id)));
275
+ const min = Math.max(0, ...ds.map((d) => d.min));
276
+ const max = Math.max(min, Math.min(...ds.map((d) => d.max)));
277
+ const height = clamp(Number.isFinite(b.height) ? b.height : min, min, max);
278
+ const age = Math.max(...panels.map((id) => state.clock[id]?.[by] ?? 0));
279
+ bandsIn.push({ edge, panels, at: panels.map((id) => b.panels.indexOf(id)), min, max, height, hand: panels.every((id) => folded.has(id)), kept: panels.some((id) => kept.has(id)), age, mode: o.mode, span: o.span });
280
+ }
281
+ const bOrder = bandsIn.filter((b) => !b.hand).sort((a, b) => Number(a.kept) - Number(b.kept) || (opt.giveWay.order === "oldest" ? a.age - b.age : b.age - a.age) || EDGES.indexOf(b.edge) - EDGES.indexOf(a.edge));
282
+ const gh = { auto: /* @__PURE__ */ new Set(), heights: /* @__PURE__ */ new Map() };
283
+ const fitH = (list, room) => {
284
+ const order2 = bOrder.filter((b) => list.includes(b));
285
+ const hands = list.length - order2.length;
286
+ const fit2 = (k) => {
287
+ const auto = new Set(order2.slice(0, k));
288
+ const heights = new Map(order2.filter((b) => !auto.has(b)).map((b) => [b, b.height]));
289
+ let excess = [...heights.values()].reduce((a, b) => a + b, 0) + (hands + auto.size) * opt.bar - room;
290
+ for (const b of order2) {
291
+ if (excess <= 0 || auto.has(b)) continue;
292
+ const take = Math.min(excess, b.height - b.min);
293
+ if (take > 0) {
294
+ heights.set(b, b.height - take);
295
+ excess -= take;
296
+ }
297
+ }
298
+ return { auto, heights, excess };
299
+ };
300
+ let g2 = fit2(0);
301
+ for (let k = 1; g2.excess > 0 && k <= order2.length; k++) g2 = fit2(k);
302
+ for (const b of g2.auto) gh.auto.add(b);
303
+ for (const [b, h] of g2.heights) gh.heights.set(b, h);
304
+ };
305
+ const reservedIn = bandsIn.filter((b) => b.mode === "reserved");
306
+ const overlayIn = bandsIn.filter((b) => b.mode === "overlay");
307
+ fitH(reservedIn, H - res.top - res.bottom - Math.max(minH, overlayIn.length * opt.bar));
308
+ const bandH = (b) => b ? gh.heights.get(b) ?? opt.bar : 0;
309
+ const pagesH = H - res.top - res.bottom - reservedIn.reduce((a, b) => a + bandH(b), 0);
310
+ fitH(overlayIn, pagesH - minH);
311
+ const topB = bandsIn.find((b) => b.edge === "top");
312
+ const botB = bandsIn.find((b) => b.edge === "bottom");
313
+ const hT = bandH(topB);
314
+ const hB = bandH(botB);
315
+ const colTop = topB?.span === "full" ? (topB.mode === "overlay" ? res.top : 0) + hT : 0;
316
+ const colBot = botB?.span === "full" ? H - (botB.mode === "overlay" ? res.bottom : 0) - hB : H;
317
+ const CH = Math.max(0, colBot - colTop);
318
+ const cols = [];
319
+ for (const side of SIDES) {
320
+ state.sides[side].forEach((c, index) => {
321
+ const panels = c.panels.filter((id) => !closed.has(id));
322
+ if (panels.length === 0) return;
323
+ const ds = panels.map((id) => defOf(defs, id));
324
+ const min = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));
325
+ const max = Math.max(min, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));
326
+ const width = clamp(Number.isFinite(c.width) ? c.width : min, min, max);
327
+ const age = Math.max(...panels.map((id) => state.clock[id]?.[by] ?? 0));
328
+ const tabs = c.show === "tabs" ? { show: "tabs", active: c.active !== void 0 && panels.includes(c.active) ? c.active : panels[0] } : {};
329
+ cols.push({ side, index, panels, min, max, width, hand: panels.every((id) => folded.has(id)), kept: panels.some((id) => kept.has(id)), age, ...tabs });
330
+ });
331
+ }
332
+ const sectionHeights = (c, room) => {
333
+ const out = /* @__PURE__ */ new Map();
334
+ const open0 = c.panels.filter((id) => !folded.has(id));
335
+ const hOf = (id) => defOf(defs, id)?.height;
336
+ const auto = /* @__PURE__ */ new Set();
337
+ if (open0.some((id) => hOf(id))) {
338
+ const last = open0.at(-1);
339
+ const minOf = (id) => hOf(id)?.min ?? opt.bar;
340
+ const fits = () => (c.panels.length - open0.length + auto.size) * opt.bar + open0.filter((id) => !auto.has(id)).reduce((a, id) => a + minOf(id), 0) <= room;
341
+ const rank = (ids) => [...ids].sort((a, b) => {
342
+ const age = (id) => state.clock[id]?.[by] ?? 0;
343
+ return Number(kept.has(a)) - Number(kept.has(b)) || (opt.giveWay.order === "oldest" ? age(a) - age(b) : age(b) - age(a)) || c.panels.indexOf(a) - c.panels.indexOf(b);
344
+ });
345
+ for (const id of rank(open0.filter((x) => x !== last))) {
346
+ if (fits()) break;
347
+ if (minOf(id) > opt.bar) auto.add(id);
348
+ }
349
+ const open2 = open0.filter((id) => !auto.has(id));
350
+ const space = room - (c.panels.length - open2.length) * opt.bar;
351
+ const fixed = open2.filter((id) => id !== last && hOf(id));
352
+ const sharers = open2.filter((id) => id === last || !hOf(id));
353
+ const h = new Map(fixed.map((id) => [id, hOf(id).natural]));
354
+ let rest = space - fixed.reduce((a, id) => a + h.get(id), 0);
355
+ const need = sharers.reduce((a, id) => a + minOf(id), 0);
356
+ for (const id of rank(fixed)) {
357
+ if (rest >= need) break;
358
+ const take = Math.min(need - rest, h.get(id) - minOf(id));
359
+ h.set(id, h.get(id) - take);
360
+ rest += take;
361
+ }
362
+ if (rest >= need) {
363
+ let pool = [...sharers];
364
+ let left = rest;
365
+ for (; ; ) {
366
+ const share2 = left / pool.length;
367
+ const under = pool.filter((id) => minOf(id) > share2);
368
+ if (under.length === 0) {
369
+ for (const id of pool) h.set(id, share2);
370
+ break;
371
+ }
372
+ for (const id of under) h.set(id, minOf(id));
373
+ left -= under.reduce((a, id) => a + minOf(id), 0);
374
+ pool = pool.filter((id) => !under.includes(id));
375
+ }
376
+ } else {
377
+ const lastH = Math.max(0, Math.min(minOf(last), rest));
378
+ for (const id of sharers) h.set(id, id === last ? lastH : Math.max(0, rest - lastH) / (sharers.length - 1));
379
+ }
380
+ for (const id of c.panels) out.set(id, folded.has(id) ? { height: opt.bar, folded: "hand" } : auto.has(id) ? { height: opt.bar, folded: "auto" } : { height: Math.max(0, h.get(id)), folded: null });
381
+ return out;
382
+ }
383
+ const bars = c.panels.length - open0.length;
384
+ const share = Math.max(0, (room - bars * opt.bar) / open0.length);
385
+ for (const id of c.panels) out.set(id, folded.has(id) ? { height: opt.bar, folded: "hand" } : { height: share, folded: null });
386
+ return out;
387
+ };
388
+ const order = giveWayOrder(
389
+ cols.filter((c) => !c.hand),
390
+ opt.giveWay.order
391
+ );
392
+ const fit = (k) => {
393
+ const auto = new Set(order.slice(0, k));
394
+ const open2 = (side) => cols.some((c) => c.side === side && !c.hand && !auto.has(c));
395
+ const railed = (side) => cols.some((c) => c.side === side && (auto.has(c) || c.hand && !(ride && open2(side))));
396
+ const widths = new Map(order.filter((c) => !auto.has(c)).map((c) => [c, c.width]));
397
+ let excess = [...widths.values()].reduce((a, b) => a + b, 0) + SIDES.filter(railed).length * opt.rail + opt.pagesMin + res.left + res.right - W;
398
+ for (const c of order) {
399
+ if (excess <= 0 || auto.has(c)) continue;
400
+ const take = Math.min(excess, c.width - c.min);
401
+ if (take > 0) {
402
+ widths.set(c, c.width - take);
403
+ excess -= take;
404
+ }
405
+ }
406
+ return { auto, widths, excess };
407
+ };
408
+ let g = fit(0);
409
+ for (let k = 1; g.excess > 0 && k <= order.length; k++) g = fit(k);
410
+ const notes = [];
411
+ for (const c of order) {
412
+ const w = g.widths.get(c);
413
+ if (w !== void 0 && w < c.width) notes.push({ code: "column-shrunk", side: c.side, column: c.index, items: c.panels, from: c.width, to: w });
414
+ }
415
+ for (const c of order) if (g.auto.has(c)) notes.push({ code: c.kept ? "kept-folded" : "column-folded", side: c.side, column: c.index, items: c.panels });
416
+ const items = /* @__PURE__ */ new Map();
417
+ const placedCols = [];
418
+ const rails = {};
419
+ let x0 = 0;
420
+ let x1 = W;
421
+ for (const side of SIDES) {
422
+ const mine = cols.filter((c) => c.side === side);
423
+ const open2 = mine.filter((c) => !c.hand && !g.auto.has(c));
424
+ const host = ride ? open2[0] : void 0;
425
+ const riders = host ? mine.filter((c) => c.hand) : [];
426
+ const inRail = mine.filter((c) => c.hand && !riders.includes(c) || g.auto.has(c));
427
+ if (inRail.length) {
428
+ const r = side === "left" ? rect(0, colTop, opt.rail, CH) : rect(W - opt.rail, colTop, opt.rail, CH);
429
+ const segments = inRail.flatMap((c) => c.panels).map((id, i) => ({ id, rect: rect(r.x, colTop + opt.railInset + i * opt.segment, opt.rail, opt.segment) }));
430
+ rails[side] = { side, rect: r, segments };
431
+ for (const s of segments) {
432
+ const c = inRail.find((x) => x.panels.includes(s.id));
433
+ items.set(s.id, { rect: s.rect, kind: "segment", layer: 0, hidden: true, folded: c.hand ? "hand" : "auto", kept: kept.has(s.id), pinned: false, floating: false, side, column: c.index });
434
+ }
435
+ if (side === "left") x0 = opt.rail;
436
+ else x1 = W - opt.rail;
437
+ }
438
+ const at = /* @__PURE__ */ new Map();
439
+ for (const c of mine) {
440
+ const w = g.widths.get(c);
441
+ if (w === void 0 || riders.includes(c)) continue;
442
+ if (side === "left") {
443
+ at.set(c, rect(x0, colTop, w, CH));
444
+ x0 += w;
445
+ } else {
446
+ x1 -= w;
447
+ at.set(c, rect(x1, colTop, w, CH));
448
+ }
449
+ }
450
+ const riding = riders.flatMap((c) => c.panels.map((id) => ({ id, c })));
451
+ const top = riding.length * opt.bar;
452
+ for (const c of mine) {
453
+ const w = g.widths.get(c);
454
+ const folded1 = c.hand ? "hand" : g.auto.has(c) ? "auto" : null;
455
+ const base = { side, index: c.index, width: c.width, min: c.min, max: c.max, folded: folded1, kept: c.kept, panels: c.panels };
456
+ if (riders.includes(c)) {
457
+ const hr = at.get(host);
458
+ const first = riding.findIndex((x) => x.c === c);
459
+ c.panels.forEach(
460
+ (id, i) => items.set(id, { rect: rect(hr.x, colTop + (first + i) * opt.bar, hr.width, opt.bar), kind: "bar", layer: 0, hidden: false, folded: "hand", kept: kept.has(id), pinned: false, floating: false, side, column: c.index, rides: host.index })
461
+ );
462
+ placedCols.push({ ...base, rect: rect(hr.x, colTop + first * opt.bar, hr.width, c.panels.length * opt.bar), shrunk: false, rides: host.index });
463
+ continue;
464
+ }
465
+ const r = at.get(c) ?? rect(side === "left" ? x0 : x1, colTop, 0, CH);
466
+ const y0 = colTop + (c === host ? top : 0);
467
+ const tabbed = c.show === "tabs";
468
+ const strip = rect(r.x, y0, r.width, opt.tabs);
469
+ const shown = tabbed && w !== void 0 ? { strip, active: c.active } : {};
470
+ placedCols.push({ ...base, rect: r, shrunk: w !== void 0 && w < c.width, ...tabbed ? { show: "tabs" } : {}, ...shown });
471
+ if (w === void 0) continue;
472
+ const panel = (id, to, kind, f, more = {}) => {
473
+ items.set(id, { rect: to, kind, layer: 0, hidden: more.hidden ?? false, folded: f, kept: kept.has(id), pinned: false, floating: false, side, column: c.index, ...more.tab ? { tab: more.tab } : {} });
474
+ };
475
+ if (tabbed) {
476
+ const body = rect(r.x, y0 + opt.tabs, r.width, Math.max(0, colBot - y0 - opt.tabs));
477
+ const shade = folded.has(c.active);
478
+ const tw = r.width / c.panels.length;
479
+ c.panels.forEach((id, i) => {
480
+ const tab = rect(r.x + i * tw, y0, tw, opt.tabs);
481
+ if (id === c.active) panel(id, shade ? strip : body, shade ? "bar" : "column", shade ? "hand" : null, { tab });
482
+ else panel(id, body, "column", folded.has(id) ? "hand" : null, { tab, hidden: true });
483
+ });
484
+ continue;
485
+ }
486
+ const hs = sectionHeights(c, colBot - y0);
487
+ let y = y0;
488
+ for (const id of c.panels) {
489
+ const s = hs.get(id);
490
+ panel(id, rect(r.x, y, r.width, s.height), s.folded ? "bar" : "column", s.folded);
491
+ y += s.height;
492
+ }
493
+ for (const id of c.panels) if (hs.get(id).folded === "auto") notes.push({ code: "section-folded", side, column: c.index, items: [id] });
494
+ }
495
+ }
496
+ for (const b of bOrder) {
497
+ const h = gh.heights.get(b);
498
+ if (h !== void 0 && h < b.height) notes.push({ code: "band-shrunk", edge: b.edge, items: b.panels, from: b.height, to: h });
499
+ }
500
+ for (const b of bOrder) if (gh.auto.has(b)) notes.push({ code: b.kept ? "kept-folded" : "band-folded", edge: b.edge, items: b.panels });
501
+ const pw = Math.max(0, x1 - x0);
502
+ const pTop = topB?.mode === "reserved" ? hT : 0;
503
+ const pBot = botB?.mode === "reserved" ? H - hB : H;
504
+ const reserved = {};
505
+ const iTop = pTop + res.top + (topB?.mode === "overlay" ? hT : 0);
506
+ const iBot = pBot - res.bottom - (botB?.mode === "overlay" ? hB : 0);
507
+ if (res.top > 0) reserved.top = rect(x0, pTop, pw, res.top);
508
+ if (res.right > 0) reserved.right = rect(x0 + pw - res.right, iTop, res.right, Math.max(0, iBot - iTop));
509
+ if (res.bottom > 0) reserved.bottom = rect(x0, pBot - res.bottom, pw, res.bottom);
510
+ if (res.left > 0) reserved.left = rect(x0, iTop, res.left, Math.max(0, iBot - iTop));
511
+ const pages = rect(x0 + res.left, pTop + res.top, Math.max(0, pw - res.left - res.right), Math.max(0, pBot - res.bottom - pTop - res.top));
512
+ if (pages.width < opt.pagesMin) notes.push({ code: "pages-under-min", width: pages.width, min: opt.pagesMin });
513
+ if ((bandsIn.length || res.top + res.bottom > 0) && pages.height < minH - 1e-9) notes.push({ code: "pages-short", height: pages.height, min: minH });
514
+ const bands = {};
515
+ for (const b of bandsIn) {
516
+ const h = bandH(b);
517
+ const full = b.span === "full";
518
+ const over = b.mode === "overlay";
519
+ const y = b.edge === "top" ? over ? res.top : 0 : over ? H - res.bottom - h : H - h;
520
+ const r = full ? rect(0, y, W, h) : rect(x0, y, pw, h);
521
+ const f = b.hand ? "hand" : gh.auto.has(b) ? "auto" : null;
522
+ const hh = gh.heights.get(b);
523
+ bands[b.edge] = { edge: b.edge, rect: r, height: b.height, min: b.min, max: b.max, folded: f, shrunk: hh !== void 0 && hh < b.height, kept: b.kept, mode: b.mode, span: b.span, panels: b.panels };
524
+ const share = r.width / b.panels.length;
525
+ b.panels.forEach(
526
+ (id, i) => items.set(id, { rect: rect(r.x + i * share, r.y, share, h), kind: f ? "bar" : "band", layer: over ? 5 : 0, hidden: false, folded: f, kept: kept.has(id), pinned: false, floating: false, edge: b.edge, index: b.at[i] })
527
+ );
528
+ }
529
+ state.floats.forEach((f, i) => {
530
+ if (closed.has(f.id)) return;
531
+ const shaded = folded.has(f.id);
532
+ const at = shaded ? { ...f.rect, height: opt.bar } : f.rect;
533
+ const k = f.pinned ? 1 : opt.view.scale;
534
+ const r = { ...at };
535
+ if (opt.floats === "clamp") {
536
+ const lim = floatSize(defOf(defs, f.id)).min;
537
+ r.width = Math.max(lim.width, Math.min(r.width, W));
538
+ if (!shaded) r.height = Math.max(lim.height, Math.min(r.height, H));
539
+ if (r.width !== at.width || r.height !== at.height) notes.push({ code: "float-resized", items: [f.id] });
540
+ r.x = r.width <= W ? clamp(r.x, 0, (W - r.width) / k) : clamp(r.x, (opt.floatVisible - r.width) / k, (W - opt.floatVisible) / k);
541
+ r.y = r.height <= H ? clamp(r.y, 0, (H - r.height) / k) : clamp(r.y, 0, (H - opt.bar) / k);
542
+ if (r.x !== at.x || r.y !== at.y) notes.push({ code: "float-clamped", items: [f.id] });
543
+ }
544
+ const clamped = r.x !== at.x || r.y !== at.y || r.width !== at.width || r.height !== at.height;
545
+ items.set(f.id, {
546
+ rect: f.pinned ? r : toView(r, opt.view),
547
+ kind: shaded ? "bar" : "float",
548
+ layer: 10 + i,
549
+ hidden: false,
550
+ folded: shaded ? "hand" : null,
551
+ kept: false,
552
+ pinned: !!f.pinned,
553
+ floating: true,
554
+ ...clamped ? { clamped: true } : {}
555
+ });
556
+ });
557
+ notes.push(...offNotes);
558
+ return { items, columns: placedCols, rails, notes, pages, bands, reserved };
559
+ }
560
+
561
+ // src/panels/targets.ts
562
+ var COLUMN_REACH = 22;
563
+ var RAIL_EDGE = 10;
564
+ function placeRank(place) {
565
+ switch (place.kind) {
566
+ case "float":
567
+ return 3e3;
568
+ case "band":
569
+ return (place.edge === "top" ? 2e3 : 2500) + Math.min(place.index, 499);
570
+ case "rail":
571
+ return place.side === "left" ? 0 : 1999;
572
+ case "column":
573
+ return place.side === "left" ? 1 + 2 * place.index : 1998 - 2 * place.index;
574
+ case "into":
575
+ return place.side === "left" ? 2 + 2 * place.index : 1997 - 2 * place.index;
576
+ }
577
+ }
578
+ function homePlace(state, id) {
579
+ const w = whereIs(state, id);
580
+ if (w.kind === "float") return { kind: "float" };
581
+ if (w.kind === "none") return null;
582
+ if (w.kind === "band") return { kind: "band", edge: w.edge, index: w.index };
583
+ return state.sides[w.side][w.index].panels.length === 1 ? { kind: "column", side: w.side, index: w.index } : { kind: "into", side: w.side, index: w.index };
584
+ }
585
+ var cut = (x0, x1, lo, hi) => [Math.max(x0, lo), Math.min(x1, hi)];
586
+ function panelTargets(input) {
587
+ const { defs, state, id, stage } = input;
588
+ const opt = { ...DEFAULT_PANELS_OPTIONS, ...input.options };
589
+ const def = defOf(defs, id);
590
+ const s0 = liftPanel(state, id);
591
+ const l0 = layoutPanels(defs, s0, stage, opt);
592
+ const width = ownWidth(defs, state, id);
593
+ const W = stage.width;
594
+ const H = stage.height;
595
+ const R = COLUMN_REACH;
596
+ const bandOpts = opt.bands ?? {};
597
+ const reserve = opt.reserve ?? {};
598
+ const px = (v) => typeof v === "number" && Number.isFinite(v) ? Math.max(0, v) : 0;
599
+ const out = [];
600
+ const idOf = (place) => {
601
+ switch (place.kind) {
602
+ case "float":
603
+ return "float";
604
+ case "rail":
605
+ return `rail:${place.side}`;
606
+ case "band":
607
+ return s0.bands?.[place.edge] ? `band:${place.edge}:${place.index}` : `band:${place.edge}`;
608
+ default:
609
+ return `${place.kind}:${place.side}:${place.index}`;
610
+ }
611
+ };
612
+ const add = (place, priority, hit, make, free = false) => {
613
+ if (hit.width <= 0 || hit.height <= 0) return;
614
+ if (input.allows && !input.allows(id, place)) return;
615
+ if (place.kind !== "float" && samePlaces(make({ x: 0, y: 0 }, { x: 0, y: 0 }), state, defs)) return;
616
+ out.push({ id: idOf(place), priority, hit, panel: id, place, order: placeRank(place), make, ...free ? { free: true } : {} });
617
+ };
618
+ const fullTop = l0.bands.top?.span === "full" ? l0.bands.top.rect : null;
619
+ const fullBot = l0.bands.bottom?.span === "full" ? l0.bands.bottom.rect : null;
620
+ const top = fullTop ? fullTop.y + fullTop.height : 0;
621
+ const CH = Math.max(0, (fullBot ? fullBot.y : H) - top);
622
+ for (const side of SIDES) {
623
+ if (def?.sides && !def.sides.includes(side)) continue;
624
+ const left = side === "left";
625
+ const rail = l0.rails[side];
626
+ const edge = rail ? rail.rect.width : RAIL_EDGE;
627
+ const railHit = rail ? rail.rect : left ? rect(0, top, RAIL_EDGE, CH) : rect(W - RAIL_EDGE, top, RAIL_EDGE, CH);
628
+ add({ kind: "rail", side }, 1, railHit, () => {
629
+ const s = dock(state, id, side, 0, { width });
630
+ return { ...s, folded: [...s.folded.filter((x) => x !== id), id] };
631
+ });
632
+ const open2 = l0.columns.filter((c) => c.side === side && c.folded === null);
633
+ const lo = left ? edge : 0;
634
+ const hi = left ? W : W - edge;
635
+ const band = (x, outer, i) => {
636
+ const [a, b] = outer ? left ? cut(x, x + 2 * R, lo, hi) : cut(x - 2 * R, x, lo, hi) : cut(x - R, x + R, lo, hi);
637
+ add({ kind: "column", side, index: i }, 2, rect(a, top, b - a, CH), () => dock(state, id, side, i, { width }));
638
+ };
639
+ if (open2.length === 0) band(left ? l0.pages.x - px(reserve.left) : l0.pages.x + l0.pages.width + px(reserve.right), true, s0.sides[side].length);
640
+ open2.forEach((c, k) => {
641
+ band(left ? c.rect.x : c.rect.x + c.rect.width, k === 0, c.index);
642
+ add({ kind: "into", side, index: c.index }, 2, c.rect, () => dock(state, id, side, c.index, { into: true }));
643
+ });
644
+ const last = open2.at(-1);
645
+ if (last) band(left ? last.rect.x + last.rect.width : last.rect.x, false, last.index + 1);
646
+ }
647
+ const home = whereIs(state, id);
648
+ for (const e of EDGES) {
649
+ if (!bandOpts[e] || def?.sides && !def.sides.includes(e)) continue;
650
+ const pb = l0.bands[e];
651
+ const list = s0.bands?.[e]?.panels ?? [];
652
+ const make = (i) => () => dockBand(state, id, e, i, defs);
653
+ if (!pb) {
654
+ if (home.kind === "band" && home.edge === e && !s0.bands?.[e]) continue;
655
+ const p = l0.pages;
656
+ const h = Math.min(2 * opt.bar, p.height);
657
+ add({ kind: "band", edge: e, index: list.length }, 2, rect(p.x, e === "top" ? p.y : p.y + p.height - h, p.width, h), make(list.length));
658
+ continue;
659
+ }
660
+ const m = pb.panels.length;
661
+ const share = pb.rect.width / m;
662
+ for (let k = 0; k <= m; k++) {
663
+ const i = k < m ? list.indexOf(pb.panels[k]) : list.length;
664
+ const a = pb.rect.x + Math.max(0, k - 0.5) * share;
665
+ const b = pb.rect.x + Math.min(m, k + 0.5) * share;
666
+ add({ kind: "band", edge: e, index: i }, 2, rect(a, pb.rect.y, b - a, pb.rect.height), make(i));
667
+ }
668
+ }
669
+ if (def?.floats !== false) {
670
+ const was = state.floats.find((f) => f.id === id);
671
+ const size = was ? { width: was.rect.width, height: was.rect.height } : floatSize(def).natural;
672
+ const pinned = !!was?.pinned;
673
+ add(
674
+ { kind: "float" },
675
+ 3,
676
+ rect(0, 0, W, H),
677
+ (p, grab) => {
678
+ const at = rect(p.x - grab.x, p.y - grab.y, size.width, size.height);
679
+ const s = float(state, id, pinned ? at : toPage(at, opt.view), pinned);
680
+ const laid = layoutPanels(defs, s, stage, opt).items.get(id).rect;
681
+ const shown = s.folded.includes(id) ? { ...laid, width: at.width, height: at.height } : laid;
682
+ return float(state, id, pinned ? shown : toPage(shown, opt.view), pinned);
683
+ },
684
+ true
685
+ );
686
+ }
687
+ return out.sort((a, b) => a.order - b.order);
688
+ }
689
+ function panelDrop(input, target, p, grab) {
690
+ const opt = { ...DEFAULT_PANELS_OPTIONS, ...input.options };
691
+ const state = target.make(p, grab);
692
+ const layout = layoutPanels(input.defs, state, input.stage, opt);
693
+ const placed = layout.items.get(input.id);
694
+ const key = target.free ? `float:${Math.round(placed.rect.x)},${Math.round(placed.rect.y)}` : target.id;
695
+ return { target: target.id, place: target.place, key, state, layout, slot: placed.rect, hidden: placed.hidden, free: !!target.free };
696
+ }
697
+ function panelStops(targets, options = {}) {
698
+ const stops = [];
699
+ for (const t of targets) {
700
+ if (t.place.kind === "float") {
701
+ if (!options.floats) continue;
702
+ const at = options.floats === true ? { x: t.hit.x + t.hit.width / 2, y: t.hit.y + t.hit.height / 2 } : options.floats.at;
703
+ const grab = options.floats === true ? { x: 0, y: 0 } : options.floats.grab ?? { x: 0, y: 0 };
704
+ stops.push({ id: t.id, place: t.place, state: t.make(at, grab), home: false, order: t.order });
705
+ continue;
706
+ }
707
+ stops.push({ id: t.id, place: t.place, state: t.make({ x: 0, y: 0 }, { x: 0, y: 0 }), home: false, order: t.order });
708
+ }
709
+ const h = options.home;
710
+ if (h) stops.push({ id: "home", place: h.place, state: h.state, home: true, order: placeRank(h.place) + (h.place.kind === "float" ? 1 : 0.5) });
711
+ return stops.sort((a, b) => a.order - b.order).map(({ order: _order, ...s }) => s);
712
+ }
713
+
714
+ export {
715
+ SIDES,
716
+ EDGES,
717
+ BAND_SIZE,
718
+ IDENTITY_VIEW,
719
+ DEFAULT_PANELS_OPTIONS,
720
+ FLOAT_HEIGHT,
721
+ FLOAT_MIN,
722
+ whereIs,
723
+ tick,
724
+ defOf,
725
+ floatSize,
726
+ bandSize,
727
+ bandHeight,
728
+ ownWidth,
729
+ createPanels,
730
+ liftPanel,
731
+ open,
732
+ close,
733
+ focus,
734
+ toggleFold,
735
+ keep,
736
+ dockBand,
737
+ resizeBand,
738
+ dock,
739
+ showTabs,
740
+ activate,
741
+ float,
742
+ toView,
743
+ toPage,
744
+ pin,
745
+ resizeColumn,
746
+ resizeFloat,
747
+ columnWidth,
748
+ samePlaces,
749
+ giveWayOrder,
750
+ layoutPanels,
751
+ COLUMN_REACH,
752
+ RAIL_EDGE,
753
+ placeRank,
754
+ homePlace,
755
+ panelTargets,
756
+ panelDrop,
757
+ panelStops
758
+ };
759
+ //# sourceMappingURL=chunk-PJD5HKYX.js.map