@n-uf/placement 26.11.7 → 26.11.8

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/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  Versions are calendar versions, `YY.M.R` (year, month of the release, counter within the month), shared with
4
4
  `@n-uf/motion`: both packages carry the same version, and a release bumps both.
5
5
 
6
+ ## 26.11.8
7
+
8
+ - `@n-uf/placement/panels`:
9
+ - Folded floats: a float folded by hand lays out as a title bar (`kind` `"bar"`, `folded` `"hand"`) at its own x, y
10
+ and width, `options.bar` tall, clamped as a bar, pinned or not. It is still a float to targets and drags; a drop
11
+ moves it and keeps its full size, and unfolding brings the full rect back (the stored rect never changes). A
12
+ folded docked panel dropped on the float target stays folded: it lands as a title bar at its natural float size.
13
+ - `options.fold`: `"rail"` (default, as before) or `"ride"`. Riding, a column folded by hand on a side that still
14
+ has an open column becomes title bars stacked on top of the side's first open column (`rides`: its index), as
15
+ wide as it; the open columns lie as if the folded one were gone, and its stored place and width are untouched.
16
+ When every column on the side is folded, the side shows its rail as before. Give-way's folds always go to the rail.
17
+ - `PlacedPanel` gains `floating` (open or folded float) and `rides`; `PlacedColumn` gains `rides`.
18
+ - `pin(…, shown)` takes only the position of `shown` and keeps the stored size, so pinning a folded or clamped
19
+ float keeps its full size.
20
+ - A column too short for its bars gives its open panels a height of 0, never a negative one.
21
+
6
22
  ## 26.11.7
7
23
 
8
24
  - New entry `@n-uf/placement/panels`: tool panels with string ids, as an app's side columns work. `./dock` is
package/README.md CHANGED
@@ -3,16 +3,16 @@
3
3
  > [!CAUTION]
4
4
  > ## Not yet stable
5
5
  >
6
- > **@n-uf/placement is young and still changing. Its API (the desk constructions, the toolbar model and the drop targets) is not final.**
6
+ > **@n-uf/placement is young and still changing. Its API (the desk constructions, the panel columns, the toolbar model and the drop targets) is not final.**
7
7
  >
8
8
  > Version numbers are dates (YY.M.R), not semantic versions, so any release may break things. Pin an exact version and read the [CHANGELOG](https://github.com/n-uf/motion/blob/main/packages/placement/CHANGELOG.md) before you upgrade.
9
9
 
10
10
  Site and live demos: [motion.n-uf.com](https://motion.n-uf.com)
11
11
 
12
- Where things go. State in, rects and drop targets out: a desk of docks, rails and palettes, toolbar groups in hosts
13
- and zones, and the drop targets for each. A tiling entry (a split tree with ratios, groups and workspaces) is
14
- planned. Pure functions over plain data: no DOM,
15
- no framework, no motion, no dependencies.
12
+ Where things go. State in, rects and drop targets out: a desk of docks, rails and palettes, panels in columns per
13
+ side that give way by age, toolbar groups in hosts and zones, and the drop targets for each. A tiling entry (a split
14
+ tree with ratios, groups and workspaces) is planned. Pure functions over plain data: no DOM, no framework, no
15
+ motion, no dependencies.
16
16
 
17
17
  ```sh
18
18
  npm i @n-uf/placement
@@ -160,9 +160,11 @@ console.log(stops.map((s) => (s.home ? "home" : s.id))); // [ 'g:top:start:0', '
160
160
  `@n-uf/placement/panels` lays out tool panels the way an app's side columns work: each side holds full-height
161
161
  columns from the outer edge inward, each column one or more panels and its own width (clamped to its panels'
162
162
  `min` and `max`). A panel folded by hand is a title bar; a column whose panels are all folded becomes segments of
163
- its side's rail. Panels may float instead, in page space (they move with the page's offset and scale) or pinned to
164
- the view. The output is geometry and structure only: each panel's rect, layer, `kind` (`column`, `bar`, `segment`,
165
- `float`) and its folded, kept and pinned flags, the columns, the rails, the pages' rect and coded notes. Chrome sizes
163
+ its side's rail, or with `fold: "ride"` bars on the side's first open column. Panels may float instead, in page space
164
+ (they move with the page's offset and scale) or pinned to the view; a folded float is a title bar where it floats, and
165
+ a folded panel torn off stays folded. The output is geometry and structure only: each panel's rect, layer, `kind`
166
+ (`column`, `bar`, `segment`, `float`; a folded float is a `bar`) and its folded, kept, pinned, floating and rides
167
+ flags, the columns, the rails, the pages' rect and coded notes. Chrome sizes
166
168
  (`bar`, `rail`, `segment`) are options.
167
169
 
168
170
  ```ts
@@ -196,7 +198,17 @@ even at its minimum size keeps its title bar and `floatVisible` (default 48) px
196
198
  size is screen px and never scales. A pinned float is clamped where it is; an unpinned one has its page-space position
197
199
  clamped so that its screen rect at pan 0 fits the view, so it still scrolls with the page. The clamp runs at layout
198
200
  time and the state keeps the stored rect, so a larger view brings a float back where it was. `"free"` never moves a
199
- float.
201
+ float. A float folded by hand (`toggleFold`) lays out as a title bar: `kind` `"bar"`, `folded` `"hand"`, at its own x,
202
+ y and width and `options.bar` tall, clamped as a bar. It is still a float (`floating: true`) to its targets and drags,
203
+ pinned or not, and unfolding brings its full rect back: the stored rect never changes.
204
+
205
+ **Folded columns** (`options.fold`, default `"rail"`): a column folded by hand goes to its side's rail. With `"ride"`,
206
+ it rides instead while its side still has an open column: its panels become title bars (`kind` `"bar"`, `rides`: the
207
+ host's index) stacked in column order on top of the side's first open column (outer edge first), as wide as it, and
208
+ the host's open panels share the rest of the height. The open columns lie as if the folded one were gone (the pages
209
+ gain its room), and its stored place and width are untouched, so unfolding puts it back as its own column. Only when
210
+ every column on a side is folded does the side show its rail. Give-way's folds (`column-folded`, `kept-folded`) go to
211
+ the rail in both modes.
200
212
 
201
213
  **Changes** are pure: `open`, `close`, `focus`, `toggleFold`, `keep`, `dock(state, id, side, index, { into?, width? })`,
202
214
  `float`, `pin(state, id, on, view?, shown?)` (pass the layout's rect as `shown` so a clamped float pins where it
@@ -8,6 +8,7 @@ var IDENTITY_VIEW = { x: 0, y: 0, scale: 1 };
8
8
  var DEFAULT_PANELS_OPTIONS = {
9
9
  giveWay: { order: "oldest", by: "used" },
10
10
  floats: "clamp",
11
+ fold: "rail",
11
12
  floatVisible: 48,
12
13
  pagesMin: 320,
13
14
  view: IDENTITY_VIEW,
@@ -115,7 +116,7 @@ function pin(state, id, on, view = IDENTITY_VIEW, shown) {
115
116
  ...state,
116
117
  floats: state.floats.map((f) => {
117
118
  if (f.id !== id || !!f.pinned === on) return f;
118
- const seen = shown ? { ...shown } : f.pinned ? { ...f.rect } : toView(f.rect, view);
119
+ const seen = shown ? { ...f.rect, x: shown.x, y: shown.y } : f.pinned ? { ...f.rect } : toView(f.rect, view);
119
120
  return on ? { id, rect: seen, pinned: true } : { id, rect: toPage(seen, view) };
120
121
  })
121
122
  };
@@ -159,6 +160,7 @@ function layoutPanels(defs, state, stage, options = {}) {
159
160
  const folded = new Set(state.folded);
160
161
  const kept = new Set(state.kept);
161
162
  const by = opt.giveWay.by;
163
+ const ride = opt.fold === "ride";
162
164
  const cols = [];
163
165
  for (const side of SIDES) {
164
166
  state.sides[side].forEach((c, index) => {
@@ -178,7 +180,8 @@ function layoutPanels(defs, state, stage, options = {}) {
178
180
  );
179
181
  const fit = (k) => {
180
182
  const auto = new Set(order.slice(0, k));
181
- const railed = (side) => cols.some((c) => c.side === side && (c.hand || auto.has(c)));
183
+ const open2 = (side) => cols.some((c) => c.side === side && !c.hand && !auto.has(c));
184
+ const railed = (side) => cols.some((c) => c.side === side && (auto.has(c) || c.hand && !(ride && open2(side))));
182
185
  const widths = new Map(order.filter((c) => !auto.has(c)).map((c) => [c, c.width]));
183
186
  let excess = [...widths.values()].reduce((a, b) => a + b, 0) + SIDES.filter(railed).length * opt.rail + opt.pagesMin - W;
184
187
  for (const c of order) {
@@ -206,38 +209,59 @@ function layoutPanels(defs, state, stage, options = {}) {
206
209
  let x1 = W;
207
210
  for (const side of SIDES) {
208
211
  const mine = cols.filter((c) => c.side === side);
209
- const inRail = mine.filter((c) => c.hand || g.auto.has(c));
212
+ const open2 = mine.filter((c) => !c.hand && !g.auto.has(c));
213
+ const host = ride ? open2[0] : void 0;
214
+ const riders = host ? mine.filter((c) => c.hand) : [];
215
+ const inRail = mine.filter((c) => c.hand && !riders.includes(c) || g.auto.has(c));
210
216
  if (inRail.length) {
211
217
  const r = side === "left" ? rect(0, 0, opt.rail, H) : rect(W - opt.rail, 0, opt.rail, H);
212
218
  const segments = inRail.flatMap((c) => c.panels).map((id, i) => ({ id, rect: rect(r.x, opt.railInset + i * opt.segment, opt.rail, opt.segment) }));
213
219
  rails[side] = { side, rect: r, segments };
214
220
  for (const s of segments) {
215
221
  const c = inRail.find((x) => x.panels.includes(s.id));
216
- 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, side, column: c.index });
222
+ 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 });
217
223
  }
218
224
  if (side === "left") x0 = opt.rail;
219
225
  else x1 = W - opt.rail;
220
226
  }
227
+ const at = /* @__PURE__ */ new Map();
221
228
  for (const c of mine) {
222
229
  const w = g.widths.get(c);
223
- let r;
224
- if (w === void 0) r = rect(side === "left" ? x0 : x1, 0, 0, H);
225
- else if (side === "left") {
226
- r = rect(x0, 0, w, H);
230
+ if (w === void 0 || riders.includes(c)) continue;
231
+ if (side === "left") {
232
+ at.set(c, rect(x0, 0, w, H));
227
233
  x0 += w;
228
234
  } else {
229
235
  x1 -= w;
230
- r = rect(x1, 0, w, H);
236
+ at.set(c, rect(x1, 0, w, H));
231
237
  }
232
- placedCols.push({ side, index: c.index, rect: r, width: c.width, min: c.min, max: c.max, folded: c.hand ? "hand" : g.auto.has(c) ? "auto" : null, shrunk: w !== void 0 && w < c.width, kept: c.kept, panels: c.panels });
238
+ }
239
+ const riding = riders.flatMap((c) => c.panels.map((id) => ({ id, c })));
240
+ const top = riding.length * opt.bar;
241
+ for (const c of mine) {
242
+ const w = g.widths.get(c);
243
+ const folded1 = c.hand ? "hand" : g.auto.has(c) ? "auto" : null;
244
+ const base = { side, index: c.index, width: c.width, min: c.min, max: c.max, folded: folded1, kept: c.kept, panels: c.panels };
245
+ if (riders.includes(c)) {
246
+ const hr = at.get(host);
247
+ const first = riding.findIndex((x) => x.c === c);
248
+ c.panels.forEach(
249
+ (id, i) => items.set(id, { rect: rect(hr.x, (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 })
250
+ );
251
+ placedCols.push({ ...base, rect: rect(hr.x, first * opt.bar, hr.width, c.panels.length * opt.bar), shrunk: false, rides: host.index });
252
+ continue;
253
+ }
254
+ const r = at.get(c) ?? rect(side === "left" ? x0 : x1, 0, 0, H);
255
+ placedCols.push({ ...base, rect: r, shrunk: w !== void 0 && w < c.width });
233
256
  if (w === void 0) continue;
257
+ const y0 = c === host ? top : 0;
234
258
  const bars = c.panels.filter((id) => folded.has(id)).length;
235
- const share = (H - bars * opt.bar) / (c.panels.length - bars);
236
- let y = 0;
259
+ const share = Math.max(0, (H - y0 - bars * opt.bar) / (c.panels.length - bars));
260
+ let y = y0;
237
261
  for (const id of c.panels) {
238
262
  const bar = folded.has(id);
239
263
  const h = bar ? opt.bar : share;
240
- items.set(id, { rect: rect(r.x, y, r.width, h), kind: bar ? "bar" : "column", layer: 0, hidden: false, folded: bar ? "hand" : null, kept: kept.has(id), pinned: false, side, column: c.index });
264
+ items.set(id, { rect: rect(r.x, y, r.width, h), kind: bar ? "bar" : "column", layer: 0, hidden: false, folded: bar ? "hand" : null, kept: kept.has(id), pinned: false, floating: false, side, column: c.index });
241
265
  y += h;
242
266
  }
243
267
  }
@@ -246,20 +270,31 @@ function layoutPanels(defs, state, stage, options = {}) {
246
270
  if (pages.width < opt.pagesMin) notes.push({ code: "pages-under-min", width: pages.width, min: opt.pagesMin });
247
271
  state.floats.forEach((f, i) => {
248
272
  if (closed.has(f.id)) return;
249
- const at = f.rect;
273
+ const shaded = folded.has(f.id);
274
+ const at = shaded ? { ...f.rect, height: opt.bar } : f.rect;
250
275
  const k = f.pinned ? 1 : opt.view.scale;
251
276
  const r = { ...at };
252
277
  if (opt.floats === "clamp") {
253
278
  const lim = floatSize(defOf(defs, f.id)).min;
254
279
  r.width = Math.max(lim.width, Math.min(r.width, W));
255
- r.height = Math.max(lim.height, Math.min(r.height, H));
280
+ if (!shaded) r.height = Math.max(lim.height, Math.min(r.height, H));
256
281
  if (r.width !== at.width || r.height !== at.height) notes.push({ code: "float-resized", items: [f.id] });
257
282
  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);
258
283
  r.y = r.height <= H ? clamp(r.y, 0, (H - r.height) / k) : clamp(r.y, 0, (H - opt.bar) / k);
259
284
  if (r.x !== at.x || r.y !== at.y) notes.push({ code: "float-clamped", items: [f.id] });
260
285
  }
261
286
  const clamped = r.x !== at.x || r.y !== at.y || r.width !== at.width || r.height !== at.height;
262
- items.set(f.id, { rect: f.pinned ? r : toView(r, opt.view), kind: "float", layer: 10 + i, hidden: false, folded: null, kept: false, pinned: !!f.pinned, ...clamped ? { clamped: true } : {} });
287
+ items.set(f.id, {
288
+ rect: f.pinned ? r : toView(r, opt.view),
289
+ kind: shaded ? "bar" : "float",
290
+ layer: 10 + i,
291
+ hidden: false,
292
+ folded: shaded ? "hand" : null,
293
+ kept: false,
294
+ pinned: !!f.pinned,
295
+ floating: true,
296
+ ...clamped ? { clamped: true } : {}
297
+ });
263
298
  });
264
299
  return { items, columns: placedCols, rails, notes, pages };
265
300
  }
@@ -339,7 +374,8 @@ function panelTargets(input) {
339
374
  (p, grab) => {
340
375
  const at = rect(p.x - grab.x, p.y - grab.y, size.width, size.height);
341
376
  const s = float(state, id, pinned ? at : toPage(at, opt.view), pinned);
342
- const shown = layoutPanels(defs, s, stage, opt).items.get(id).rect;
377
+ const laid = layoutPanels(defs, s, stage, opt).items.get(id).rect;
378
+ const shown = s.folded.includes(id) ? { ...laid, width: at.width, height: at.height } : laid;
343
379
  return float(state, id, pinned ? shown : toPage(shown, opt.view), pinned);
344
380
  },
345
381
  true
@@ -409,4 +445,4 @@ export {
409
445
  panelDrop,
410
446
  panelStops
411
447
  };
412
- //# sourceMappingURL=chunk-NNFNMIW4.js.map
448
+ //# sourceMappingURL=chunk-QR7MGDX6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/panels/model.ts","../src/panels/layout.ts","../src/panels/targets.ts"],"sourcesContent":["/**\n * The panels model: plain data and the pure changes on it.\n *\n * Panels have string ids. Each side holds full-height columns (outer edge first), each column one or more panels\n * top to bottom and its own width. A panel may instead float, in page space (it moves with the page) or pinned in\n * view space (it stays put). A logical clock per panel (opened, used) is what give-way reads; every change here that\n * counts as a use moves it on. Nothing here reads a host clock: the next tick is one past the latest in the state.\n */\nimport type { Rect, Size } from \"../geometry\";\n\nexport type Side = \"left\" | \"right\";\nexport const SIDES: readonly Side[] = [\"left\", \"right\"];\n\n/**\n * What a consumer says about a panel: its width limits docked, its size limits floating, and where it may go. No\n * words: names and titles are the consumer's.\n */\nexport interface PanelDef {\n readonly id: string;\n /** A docked column's width limits and its natural width. */\n readonly width: { readonly min: number; readonly max: number; readonly natural: number };\n /** A float's size limits and natural size (default: its natural width, 360 px tall, no smaller than 160 × 120). */\n readonly float?: { readonly min: Size; readonly natural: Size };\n /** Where it may dock (default: both sides). */\n readonly sides?: readonly Side[];\n /** May it float (default: yes). */\n readonly floats?: boolean;\n}\n\n/** A full-height column: its panels top to bottom, and its stored width (the layout clamps it to its panels' limits). */\nexport interface Column {\n readonly panels: readonly string[];\n readonly width: number;\n}\n\n/** A floating panel: `rect` in page space, or in view space when `pinned`. */\nexport interface FloatAt {\n readonly id: string;\n readonly rect: Rect;\n readonly pinned?: boolean;\n}\n\n/** Logical times: when a panel was last opened, and last used (opened, focused, moved or unfolded). */\nexport interface Clock {\n readonly opened: number;\n readonly used: number;\n}\n\nexport interface PanelsState {\n /** Each side's columns, from the outer edge inward. */\n readonly sides: Readonly<Record<Side, readonly Column[]>>;\n /** Floating panels; a later one is on top. */\n readonly floats: readonly FloatAt[];\n /** Folded by hand (give-way never writes this). */\n readonly folded: readonly string[];\n /** Docked panels kept open: their columns give way last. */\n readonly kept: readonly string[];\n /** Not shown at all (they keep their place, for when they open again). */\n readonly closed: readonly string[];\n readonly clock: Readonly<Record<string, Clock>>;\n}\n\n/** The page's offset and scale in the view: a page point p shows at `x + p.x * scale`, `y + p.y * scale`. */\nexport interface View {\n readonly x: number;\n readonly y: number;\n readonly scale: number;\n}\nexport const IDENTITY_VIEW: View = { x: 0, y: 0, scale: 1 };\n\n/** Who gives way first: the oldest or the newest, by when they were last used or last opened. */\nexport interface GiveWay {\n readonly order: \"oldest\" | \"newest\";\n readonly by: \"used\" | \"opened\";\n}\n\nexport interface PanelsOptions {\n /** Default: `{ order: \"oldest\", by: \"used\" }`, so the panel used longest ago gives way first. */\n readonly giveWay: GiveWay;\n /** \"clamp\" keeps floats in the view at layout time; \"free\" never moves them. Default \"clamp\". */\n readonly floats: \"clamp\" | \"free\";\n /**\n * Where a column folded by hand goes (default \"rail\"): to its side's rail, or (\"ride\") as title bars on top of the\n * side's first open column, until every column on that side is folded. Give-way's folds always go to the rail.\n */\n readonly fold: \"rail\" | \"ride\";\n /** How much of a float wider than the view stays in it, px (default 48). */\n readonly floatVisible: number;\n /** The pages' minimum width (default 320). */\n readonly pagesMin: number;\n /** The page's offset and scale (default: identity). */\n readonly view: View;\n /**\n * A title bar's height: a panel folded in a column, a folded float, a riding column, and the part of a float the\n * clamp keeps in the view (default 28).\n */\n readonly bar: number;\n /** A rail's width (default 36). */\n readonly rail: number;\n /** A rail segment's height, and the gap above the first one (defaults 36 and 4). */\n readonly segment: number;\n readonly railInset: number;\n}\n\nexport const DEFAULT_PANELS_OPTIONS: PanelsOptions = {\n giveWay: { order: \"oldest\", by: \"used\" },\n floats: \"clamp\",\n fold: \"rail\",\n floatVisible: 48,\n pagesMin: 320,\n view: IDENTITY_VIEW,\n bar: 28,\n rail: 36,\n segment: 36,\n railInset: 4,\n};\n\n/** A float's size when its def gives none: this tall, and never smaller than FLOAT_MIN. */\nexport const FLOAT_HEIGHT = 360;\nexport const FLOAT_MIN: Size = { width: 160, height: 120 };\n\n// --- reading the state ---------------------------------------------------------------------------------------------\n\nconst without = <T>(list: readonly T[], x: T): T[] => list.filter((y) => y !== x);\nconst withOnce = <T>(list: readonly T[], x: T): T[] => (list.includes(x) ? [...list] : [...list, x]);\n\n/** Where a panel is: a column (side and index), floating, or nowhere. */\nexport type Where = { readonly kind: \"column\"; readonly side: Side; readonly index: number } | { readonly kind: \"float\"; readonly float: FloatAt } | { readonly kind: \"none\" };\n\nexport function whereIs(state: PanelsState, id: string): Where {\n for (const side of SIDES) {\n const index = state.sides[side].findIndex((c) => c.panels.includes(id));\n if (index >= 0) return { kind: \"column\", side, index };\n }\n const float = state.floats.find((f) => f.id === id);\n return float ? { kind: \"float\", float } : { kind: \"none\" };\n}\n\n/** One past the latest logical time in the state. */\nexport const tick = (state: PanelsState): number => Object.values(state.clock).reduce((m, c) => Math.max(m, c.opened, c.used), 0) + 1;\n\nconst bump = (state: PanelsState, id: string, opened: boolean): PanelsState => {\n const t = tick(state);\n const was = state.clock[id] ?? { opened: 0, used: 0 };\n return { ...state, clock: { ...state.clock, [id]: { opened: opened ? t : was.opened, used: t } } };\n};\n\nexport const defOf = (defs: readonly PanelDef[], id: string): PanelDef | undefined => defs.find((d) => d.id === id);\n\n/** A float's size limits and natural size from its def. */\nexport function floatSize(def: PanelDef | undefined): { min: Size; natural: Size } {\n if (def?.float) return { min: def.float.min, natural: def.float.natural };\n const width = Math.max(FLOAT_MIN.width, def?.width.natural ?? FLOAT_MIN.width);\n return { min: FLOAT_MIN, natural: { width, height: FLOAT_HEIGHT } };\n}\n\n/**\n * A panel's own width, for a new column made for it: the width of the column it is in, clamped to its own limits;\n * floating or nowhere, its natural width.\n */\nexport function ownWidth(defs: readonly PanelDef[], state: PanelsState, id: string): number {\n const def = defOf(defs, id);\n const w = whereIs(state, id);\n const lo = def?.width.min ?? 0;\n const hi = Math.max(lo, def?.width.max ?? Infinity);\n if (w.kind === \"column\") return Math.min(Math.max(state.sides[w.side][w.index]!.width, lo), hi);\n return def?.width.natural ?? lo;\n}\n\n// --- building one --------------------------------------------------------------------------------------------------\n\nexport interface PanelsStart {\n /** Each side's columns from the outer edge inward, each a list of panel ids top to bottom. */\n readonly left?: readonly (readonly string[])[];\n readonly right?: readonly (readonly string[])[];\n /** Floating panels: where (page space, or view space when pinned); the size defaults to the def's natural size. */\n readonly floats?: readonly { readonly id: string; readonly x: number; readonly y: number; readonly width?: number; readonly height?: number; readonly pinned?: boolean }[];\n readonly folded?: readonly string[];\n readonly kept?: readonly string[];\n readonly closed?: readonly string[];\n}\n\n/**\n * A state from a plain start: each column as wide as the widest natural width of its panels (within their limits),\n * each float its natural size. The clock counts up in the order the panels are listed (left, right, floats), so the\n * last one listed is the newest.\n */\nexport function createPanels(defs: readonly PanelDef[], start: PanelsStart): PanelsState {\n const column = (ids: readonly string[]): Column => {\n const ds = ids.map((id) => defOf(defs, id));\n const lo = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));\n const hi = Math.max(lo, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));\n const natural = Math.max(0, ...ds.map((d) => d?.width.natural ?? 0));\n return { panels: [...ids], width: Math.min(Math.max(natural, lo), hi) };\n };\n const floats = (start.floats ?? []).map((f): FloatAt => {\n const n = floatSize(defOf(defs, f.id)).natural;\n 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 } : {}) };\n });\n const sides = { left: (start.left ?? []).map(column), right: (start.right ?? []).map(column) };\n const order = [...sides.left, ...sides.right].flatMap((c) => c.panels).concat(floats.map((f) => f.id));\n const clock: Record<string, Clock> = {};\n order.forEach((id, i) => (clock[id] = { opened: i + 1, used: i + 1 }));\n return { sides, floats, folded: [...(start.folded ?? [])], kept: [...(start.kept ?? [])], closed: [...(start.closed ?? [])], clock };\n}\n\n// --- changes -------------------------------------------------------------------------------------------------------\n\n/** The state with `id` taken out of its column (an emptied column goes) or the floats. Nothing else changes. */\nexport function liftPanel(state: PanelsState, id: string): PanelsState {\n const lift = (cols: readonly Column[]): Column[] => cols.map((c) => ({ ...c, panels: without(c.panels, id) })).filter((c) => c.panels.length > 0);\n return { ...state, sides: { left: lift(state.sides.left), right: lift(state.sides.right) }, floats: state.floats.filter((f) => f.id !== id) };\n}\n\n/**\n * Open a panel: it shows again where it was, and it is the newest opened and used. A panel placed nowhere goes into\n * a new innermost column on `at.side`, `at.width` wide; without `at` it stays placed nowhere.\n */\nexport function open(state: PanelsState, id: string, at?: { readonly side: Side; readonly width: number }): PanelsState {\n let s: PanelsState = { ...state, closed: without(state.closed, id) };\n if (at && whereIs(s, id).kind === \"none\") s = { ...s, sides: { ...s.sides, [at.side]: [...s.sides[at.side], { panels: [id], width: at.width }] } };\n return bump(s, id, true);\n}\n\n/** Close a panel: it isn't shown, keeps its place, and is no longer kept open. */\nexport const close = (state: PanelsState, id: string): PanelsState => ({ ...state, closed: withOnce(state.closed, id), kept: without(state.kept, id) });\n\n/** Focus a panel: it is the newest used; a float comes to the top. */\nexport function focus(state: PanelsState, id: string): PanelsState {\n const f = state.floats.find((x) => x.id === id);\n const s = f ? { ...state, floats: [...state.floats.filter((x) => x !== f), f] } : state;\n return bump(s, id, false);\n}\n\n/** Fold a panel to its title bar by hand, or unfold it (unfolding is a use). */\nexport function toggleFold(state: PanelsState, id: string): PanelsState {\n if (state.folded.includes(id)) return bump({ ...state, folded: without(state.folded, id) }, id, false);\n return { ...state, folded: [...state.folded, id] };\n}\n\n/** Keep a docked panel open (its column gives way last), or stop keeping it. A floating panel isn't kept. */\nexport function keep(state: PanelsState, id: string, on: boolean): PanelsState {\n if (!on) return { ...state, kept: without(state.kept, id) };\n return whereIs(state, id).kind === \"column\" ? { ...state, kept: withOnce(state.kept, id) } : state;\n}\n\nexport interface DockOptions {\n /** Stack into the column at `index` (at its bottom) instead of making a new column there. */\n readonly into?: boolean;\n /** A new column's width (default: the width of the column the panel leaves, else 0, which the layout clamps to the minimum). */\n readonly width?: number;\n}\n\n/**\n * Dock a panel on `side`: a new column at `index` (0 the outer edge; past the end, innermost), or with `into` at the\n * bottom of the column at `index` (counted once the panel is lifted out). It shows, it is the newest used, and it\n * keeps whether it is kept open.\n */\nexport function dock(state: PanelsState, id: string, side: Side, index: number, options: DockOptions = {}): PanelsState {\n const w = whereIs(state, id);\n const from = w.kind === \"column\" ? state.sides[w.side][w.index]!.width : 0;\n const s = liftPanel(state, id);\n const cols = [...s.sides[side]];\n if (options.into && cols[index]) cols[index] = { ...cols[index]!, panels: [...cols[index]!.panels, id] };\n else {\n const at = Math.max(0, Math.min(index, cols.length));\n cols.splice(at, 0, { panels: [id], width: options.width ?? from });\n }\n return bump({ ...s, sides: { ...s.sides, [side]: cols }, closed: without(s.closed, id) }, id, false);\n}\n\n/**\n * Float a panel at `rect` (page space; view space when pinned). A float stays pinned or not unless `pinned` says;\n * a docked panel floats unpinned. It shows, it is the newest used and on top, and it is no longer kept open.\n */\nexport function float(state: PanelsState, id: string, rect: Rect, pinned?: boolean): PanelsState {\n const was = state.floats.find((f) => f.id === id);\n const on = pinned ?? !!was?.pinned;\n const s = liftPanel(state, id);\n const f: FloatAt = { id, rect: { ...rect }, ...(on ? { pinned: true } : {}) };\n return bump({ ...s, floats: [...s.floats, f], kept: without(s.kept, id), closed: without(s.closed, id) }, id, false);\n}\n\n/** A page-space rect in view space, and back. */\nexport const toView = (r: Rect, v: View): Rect => ({ ...r, x: v.x + r.x * v.scale, y: v.y + r.y * v.scale });\nexport const toPage = (r: Rect, v: View): Rect => ({ ...r, x: (r.x - v.x) / v.scale, y: (r.y - v.y) / v.scale });\n\n/**\n * Pin a float to the view, or unpin it to the page. `view` is where the page is now (default: identity): the float\n * doesn't jump, its rect is converted between the two spaces. A float's size is never scaled.\n *\n * `shown` is where the float shows now, in view space (the layout's placed rect for it). When given, its position is\n * converted instead of the stored one, so a float the clamp moved stays where it shows rather than jumping to its\n * stored place. The size stays the stored one: a float folded to a bar, or shrunk by the clamp, keeps its full size.\n */\nexport function pin(state: PanelsState, id: string, on: boolean, view: View = IDENTITY_VIEW, shown?: Rect): PanelsState {\n return {\n ...state,\n floats: state.floats.map((f): FloatAt => {\n if (f.id !== id || !!f.pinned === on) return f;\n // In view space: where it shows, else where it is stored; at its stored size.\n const seen = shown ? { ...f.rect, x: shown.x, y: shown.y } : f.pinned ? { ...f.rect } : toView(f.rect, view);\n return on ? { id, rect: seen, pinned: true } : { id, rect: toPage(seen, view) };\n }),\n };\n}\n\n/**\n * Store a column's width (the layout clamps it to its panels' limits). Resizing is a use: the column's panels are\n * the newest used, so give-way takes room from the other columns, not from the one being resized.\n */\nexport function resizeColumn(state: PanelsState, side: Side, index: number, width: number): PanelsState {\n const col = state.sides[side][index];\n if (!col || !Number.isFinite(width)) return state;\n const t = tick(state);\n const clock = { ...state.clock };\n for (const id of col.panels) clock[id] = { opened: clock[id]?.opened ?? 0, used: t };\n return { ...state, sides: { ...state.sides, [side]: state.sides[side].map((c, i) => (i === index ? { ...c, width: Math.max(0, width) } : c)) }, clock };\n}\n\n/** Store a float's rect (its own space). Resizing is a use. */\nexport function resizeFloat(state: PanelsState, id: string, rect: Rect): PanelsState {\n if (!state.floats.some((f) => f.id === id)) return state;\n return bump({ ...state, floats: state.floats.map((f) => (f.id === id ? { ...f, rect: { ...rect } } : f)) }, id, false);\n}\n\n/** A column's width as the layout takes it: its stored width clamped to its panels' limits (with `defs`). */\nexport function columnWidth(defs: readonly PanelDef[] | undefined, col: Column): number {\n if (!defs) return col.width;\n const ds = col.panels.map((id) => defOf(defs, id));\n const lo = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));\n const hi = Math.max(lo, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));\n return Math.min(Math.max(Number.isFinite(col.width) ? col.width : lo, lo), hi);\n}\n\n/**\n * Two states place the panels the same (columns, their panels and widths, floats and their rects; the clock aside).\n * With `defs`, widths compare as the layout takes them (clamped to the panels' limits), so a stored width past a\n * column's max is the same place as that max.\n */\nexport function samePlaces(a: PanelsState, b: PanelsState, defs?: readonly PanelDef[]): boolean {\n const cols = (s: PanelsState): string => SIDES.map((side) => s.sides[side].map((c) => `${c.panels.join(\",\")}@${Math.round(columnWidth(defs, c))}`).join(\"|\")).join(\"‖\");\n const fl = (s: PanelsState): string => 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(\"|\");\n const set = (l: readonly string[]): string => [...l].sort().join(\",\");\n return cols(a) === cols(b) && fl(a) === fl(b) && set(a.folded) === set(b.folded) && set(a.kept) === set(b.kept) && set(a.closed) === set(b.closed);\n}\n","/**\n * `layoutPanels`: the panels' state, a stage and options in; geometry and structure out: every panel's rect, layer\n * and kind, the columns, the rails, the pages' rect, and coded notes on how it gave way. Pure: the same input always\n * lays out the same. How anything looks is the consumer's.\n *\n * - A column is full height and as wide as its stored width, clamped to its panels' limits. Inside it, a panel\n * folded by hand is a title bar (`options.bar` tall) and the open ones share the rest of the height equally.\n * - A column whose panels are all folded is railed: its panels become segments of its side's rail (one rail per\n * side, `options.rail` wide at the outer edge, segments in side order).\n * - With `options.fold` \"ride\", a column folded by hand on a side that still has an open column rides instead: its\n * panels become title bars stacked on top of the side's first open column (outer edge first), as wide as that\n * column, and its open panels share the rest of the height. The folded column keeps its stored place and width, and\n * the open columns lie as if it were gone. Only when every column on the side is folded does the side show its rail.\n * Give-way's folds always go to the rail.\n * - A float folded by hand is a title bar: its own x, y and width, `options.bar` tall, still a float (clamped as a\n * bar, `floating`); unfolding brings its full rect back, as the stored rect never changes.\n * - Give-way: when the open columns, the rails and `pagesMin` don't fit the stage width, columns shrink toward their\n * minimum, then whole columns fold to the rail, in the policy's order, until the pages fit. Columns holding a kept\n * panel come after every other column; if the pages still don't fit, they fold too (`kept-folded`). Folding by\n * give-way never writes `folded`, so a wider stage brings the column back.\n * - Floats: \"clamp\" keeps a float in the view at layout time (the state keeps the stored rect, so a larger view\n * brings it back where it was); \"free\" never moves one. A float's size is never scaled. A pinned float is in view\n * space and clamped against the view; an unpinned one has its position in page space, clamped so that its screen\n * rect at pan 0 fits the view, then moved by the view's offset and scale, so it scrolls with the page.\n */\nimport { rect, type Rect, type Size } from \"../geometry\";\nimport { DEFAULT_PANELS_OPTIONS, SIDES, defOf, floatSize, toView, type PanelDef, type PanelsOptions, type PanelsState, type Side } from \"./model\";\n\n/**\n * Where a panel is, structurally: an open part of a column, a folded title bar (in a column, riding on one, or a\n * folded float), a segment of a rail (the panel itself isn't laid out), or a float.\n */\nexport type PanelKind = \"column\" | \"bar\" | \"segment\" | \"float\";\n\nexport interface PlacedPanel {\n /** Stage px; for a segment, the segment's rect in its rail. */\n readonly rect: Rect;\n readonly kind: PanelKind;\n /** Columns and rails 0, floats 10 and up (a later float on top). */\n readonly layer: number;\n /** In a rail: there is no panel to lay out, only its segment. */\n readonly hidden: boolean;\n /** Folded by hand (a bar, or a segment of a column folded by hand), or by give-way (a segment). */\n readonly folded: null | \"hand\" | \"auto\";\n /** Kept open. */\n readonly kept: boolean;\n /** A pinned float. */\n readonly pinned: boolean;\n /** It floats (open, or folded to a bar). */\n readonly floating: boolean;\n /** Docked: its side and column index (the state's). */\n readonly side?: Side;\n readonly column?: number;\n /** A riding bar: the index of the column it rides on (`options.fold` \"ride\"). */\n readonly rides?: number;\n /** A float the clamp moved or resized. */\n readonly clamped?: boolean;\n}\n\nexport interface PlacedColumn {\n readonly side: Side;\n /** The column's index in the state. */\n readonly index: number;\n /** Its rect (zero wide when railed). */\n readonly rect: Rect;\n /** Its stored width clamped to its panels' limits, and those limits. */\n readonly width: number;\n readonly min: number;\n readonly max: number;\n /** null: open; \"hand\": all its panels folded by hand; \"auto\": folded by give-way. */\n readonly folded: null | \"hand\" | \"auto\";\n /** Shrunk by give-way below its width. */\n readonly shrunk: boolean;\n /** It holds a kept panel. */\n readonly kept: boolean;\n /** The shown panels, top to bottom. */\n readonly panels: readonly string[];\n /** Riding: the index of the column its bars ride on; its rect is the bars'. */\n readonly rides?: number;\n}\n\nexport interface PlacedRail {\n readonly side: Side;\n readonly rect: Rect;\n readonly segments: readonly { readonly id: string; readonly rect: Rect }[];\n}\n\nexport type PanelsNoteCode = \"column-shrunk\" | \"column-folded\" | \"kept-folded\" | \"pages-under-min\" | \"float-clamped\" | \"float-resized\";\n\n/** One note on a layout: a code and its data. */\nexport type PanelsNote =\n | { readonly code: \"column-shrunk\"; readonly side: Side; readonly column: number; readonly items: readonly string[]; readonly from: number; readonly to: number }\n | { readonly code: \"column-folded\" | \"kept-folded\"; readonly side: Side; readonly column: number; readonly items: readonly string[] }\n | { readonly code: \"pages-under-min\"; readonly width: number; readonly min: number }\n | { readonly code: \"float-clamped\" | \"float-resized\"; readonly items: readonly string[] };\n\nexport interface PanelsLayout {\n readonly items: Map<string, PlacedPanel>;\n /** The shown columns in side order (left outer → inner, then right outer → inner). */\n readonly columns: readonly PlacedColumn[];\n readonly rails: Partial<Record<Side, PlacedRail>>;\n readonly notes: readonly PanelsNote[];\n /** What is left for the documents. */\n readonly pages: Rect;\n}\n\ninterface Col {\n readonly side: Side;\n readonly index: number;\n readonly panels: readonly string[];\n readonly min: number;\n readonly max: number;\n readonly width: number;\n readonly hand: boolean;\n readonly kept: boolean;\n readonly age: number;\n}\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(Math.max(v, lo), Math.max(lo, hi));\n\n/** The order columns give way in: unkept before kept, then the policy (oldest or newest), outer first, left first. */\nexport function giveWayOrder<C extends { readonly side: Side; readonly index: number; readonly kept: boolean; readonly age: number }>(cols: readonly C[], order: \"oldest\" | \"newest\"): C[] {\n 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));\n}\n\nexport function layoutPanels(defs: readonly PanelDef[], state: PanelsState, stage: Size, options: Partial<PanelsOptions> = {}): PanelsLayout {\n const opt: PanelsOptions = { ...DEFAULT_PANELS_OPTIONS, ...options };\n const W = stage.width;\n const H = stage.height;\n const closed = new Set(state.closed);\n const folded = new Set(state.folded);\n const kept = new Set(state.kept);\n const by = opt.giveWay.by;\n const ride = opt.fold === \"ride\";\n\n // The shown columns.\n const cols: Col[] = [];\n for (const side of SIDES) {\n state.sides[side].forEach((c, index) => {\n const panels = c.panels.filter((id) => !closed.has(id));\n if (panels.length === 0) return;\n const ds = panels.map((id) => defOf(defs, id));\n const min = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));\n const max = Math.max(min, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));\n const width = clamp(Number.isFinite(c.width) ? c.width : min, min, max);\n const age = Math.max(...panels.map((id) => state.clock[id]?.[by] ?? 0));\n cols.push({ side, index, panels, min, max, width, hand: panels.every((id) => folded.has(id)), kept: panels.some((id) => kept.has(id)), age });\n });\n }\n\n // Give-way: fold the fewest columns in order that let the pages fit, shrinking the rest in order toward their minimum.\n const order = giveWayOrder(\n cols.filter((c) => !c.hand),\n opt.giveWay.order,\n );\n const fit = (k: number): { auto: Set<Col>; widths: Map<Col, number>; excess: number } => {\n const auto = new Set(order.slice(0, k));\n // Riding, a side's hand-folded columns need no rail while one of its columns stays open.\n const open = (side: Side): boolean => cols.some((c) => c.side === side && !c.hand && !auto.has(c));\n const railed = (side: Side): boolean => cols.some((c) => c.side === side && (auto.has(c) || (c.hand && !(ride && open(side)))));\n const widths = new Map(order.filter((c) => !auto.has(c)).map((c) => [c, c.width]));\n let excess = [...widths.values()].reduce((a, b) => a + b, 0) + SIDES.filter(railed).length * opt.rail + opt.pagesMin - W;\n for (const c of order) {\n if (excess <= 0 || auto.has(c)) continue;\n const take = Math.min(excess, c.width - c.min);\n if (take > 0) {\n widths.set(c, c.width - take);\n excess -= take;\n }\n }\n return { auto, widths, excess };\n };\n let g = fit(0);\n for (let k = 1; g.excess > 0 && k <= order.length; k++) g = fit(k);\n\n const notes: PanelsNote[] = [];\n for (const c of order) {\n const w = g.widths.get(c);\n if (w !== undefined && w < c.width) notes.push({ code: \"column-shrunk\", side: c.side, column: c.index, items: c.panels, from: c.width, to: w });\n }\n 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 });\n\n // Positions: rails at the outer edges, open columns inward from them, the pages between.\n const items = new Map<string, PlacedPanel>();\n const placedCols: PlacedColumn[] = [];\n const rails: Partial<Record<Side, PlacedRail>> = {};\n let x0 = 0;\n let x1 = W;\n for (const side of SIDES) {\n const mine = cols.filter((c) => c.side === side);\n const open = mine.filter((c) => !c.hand && !g.auto.has(c));\n // Riding: the side's hand-folded columns, while it has an open column to ride on (the first, outer edge first).\n const host = ride ? open[0] : undefined;\n const riders = host ? mine.filter((c) => c.hand) : [];\n const inRail = mine.filter((c) => (c.hand && !riders.includes(c)) || g.auto.has(c));\n if (inRail.length) {\n const r = side === \"left\" ? rect(0, 0, opt.rail, H) : rect(W - opt.rail, 0, opt.rail, H);\n const segments = inRail.flatMap((c) => c.panels).map((id, i) => ({ id, rect: rect(r.x, opt.railInset + i * opt.segment, opt.rail, opt.segment) }));\n rails[side] = { side, rect: r, segments };\n for (const s of segments) {\n const c = inRail.find((x) => x.panels.includes(s.id))!;\n 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 });\n }\n if (side === \"left\") x0 = opt.rail;\n else x1 = W - opt.rail;\n }\n // The open columns first (riding bars need their host's rect), then the folded ones in state order.\n const at = new Map<Col, Rect>();\n for (const c of mine) {\n const w = g.widths.get(c);\n if (w === undefined || riders.includes(c)) continue;\n if (side === \"left\") {\n at.set(c, rect(x0, 0, w, H));\n x0 += w;\n } else {\n x1 -= w;\n at.set(c, rect(x1, 0, w, H));\n }\n }\n const riding = riders.flatMap((c) => c.panels.map((id) => ({ id, c })));\n const top = riding.length * opt.bar;\n for (const c of mine) {\n const w = g.widths.get(c);\n const folded1 = c.hand ? \"hand\" : g.auto.has(c) ? \"auto\" : null;\n const base = { side, index: c.index, width: c.width, min: c.min, max: c.max, folded: folded1, kept: c.kept, panels: c.panels } as const;\n if (riders.includes(c)) {\n const hr = at.get(host!)!;\n const first = riding.findIndex((x) => x.c === c);\n c.panels.forEach((id, i) =>\n items.set(id, { rect: rect(hr.x, (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 }),\n );\n placedCols.push({ ...base, rect: rect(hr.x, first * opt.bar, hr.width, c.panels.length * opt.bar), shrunk: false, rides: host!.index });\n continue;\n }\n const r = at.get(c) ?? rect(side === \"left\" ? x0 : x1, 0, 0, H);\n placedCols.push({ ...base, rect: r, shrunk: w !== undefined && w < c.width });\n if (w === undefined) continue;\n // The host shares what the riding bars leave.\n const y0 = c === host ? top : 0;\n const bars = c.panels.filter((id) => folded.has(id)).length;\n const share = Math.max(0, (H - y0 - bars * opt.bar) / (c.panels.length - bars));\n let y = y0;\n for (const id of c.panels) {\n const bar = folded.has(id);\n const h = bar ? opt.bar : share;\n items.set(id, { rect: rect(r.x, y, r.width, h), kind: bar ? \"bar\" : \"column\", layer: 0, hidden: false, folded: bar ? \"hand\" : null, kept: kept.has(id), pinned: false, floating: false, side, column: c.index });\n y += h;\n }\n }\n }\n const pages = rect(x0, 0, Math.max(0, x1 - x0), H);\n if (pages.width < opt.pagesMin) notes.push({ code: \"pages-under-min\", width: pages.width, min: opt.pagesMin });\n\n // Floats, clamped unless free. A float's size is screen px in both spaces (never scaled); only an unpinned float's\n // position is in page space. The clamp keeps the SCREEN rect in the view: a pinned float where it is, an unpinned\n // one as it shows at pan 0, so it still scrolls with the page. In page units (k = the scale, 1 when pinned) a\n // screen interval [lo, hi] is [lo / k, hi / k].\n state.floats.forEach((f, i) => {\n if (closed.has(f.id)) return;\n // Folded by hand: a title bar at its own place and width (the stored rect keeps its height).\n const shaded = folded.has(f.id);\n const at = shaded ? { ...f.rect, height: opt.bar } : f.rect;\n const k = f.pinned ? 1 : opt.view.scale;\n const r = { ...at };\n if (opt.floats === \"clamp\") {\n const lim = floatSize(defOf(defs, f.id)).min;\n r.width = Math.max(lim.width, Math.min(r.width, W));\n if (!shaded) r.height = Math.max(lim.height, Math.min(r.height, H));\n if (r.width !== at.width || r.height !== at.height) notes.push({ code: \"float-resized\", items: [f.id] });\n // Fits: wholly in the view. Too big even at its minimum: its title bar stays in, and `floatVisible` px of its width.\n 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);\n r.y = r.height <= H ? clamp(r.y, 0, (H - r.height) / k) : clamp(r.y, 0, (H - opt.bar) / k);\n if (r.x !== at.x || r.y !== at.y) notes.push({ code: \"float-clamped\", items: [f.id] });\n }\n const clamped = r.x !== at.x || r.y !== at.y || r.width !== at.width || r.height !== at.height;\n items.set(f.id, {\n rect: f.pinned ? r : toView(r, opt.view),\n kind: shaded ? \"bar\" : \"float\",\n layer: 10 + i,\n hidden: false,\n folded: shaded ? \"hand\" : null,\n kept: false,\n pinned: !!f.pinned,\n floating: true,\n ...(clamped ? { clamped: true } : {}),\n });\n });\n\n return { items, columns: placedCols, rails, notes, pages };\n}\n","/**\n * The drop targets for dragging a panel, in the shape @n-uf/motion/drag takes (`{ id, priority, hit, slot?, free? }`),\n * worked out from the state with the panel lifted out:\n *\n * - `column:<side>:<i>` (priority 2): a band across the line between two columns (or a side's edge): a new column\n * there, as wide as the panel's own width.\n * - `into:<side>:<i>` (2): a column's area: the panel stacks at its bottom.\n * - `rail:<side>` (1): the side's rail, or its outer edge: the panel docks folded.\n * - `float` (3, free): anywhere; it floats where it is let go, kept in the view as the float option says.\n *\n * A place the panel may not take (its def's `sides` and `floats`, and `allows`) is no target, and neither is its own\n * place (a drop there changes nothing). Targets carry a structured `place`, never words: the consumer names them.\n */\nimport { rect, type Point, type Rect, type Size } from \"../geometry\";\nimport type { Target } from \"../targets/target\";\nimport { layoutPanels, type PanelsLayout } from \"./layout\";\nimport { DEFAULT_PANELS_OPTIONS, SIDES, defOf, dock, float, floatSize, liftPanel, ownWidth, samePlaces, toPage, whereIs, type PanelDef, type PanelsOptions, type PanelsState, type Side } from \"./model\";\n\n/** Where a drop puts a panel. `index` is a column index in the state with the panel lifted out. */\nexport type PanelPlace =\n | { readonly kind: \"column\"; readonly side: Side; readonly index: number }\n | { readonly kind: \"into\"; readonly side: Side; readonly index: number }\n | { readonly kind: \"rail\"; readonly side: Side }\n | { readonly kind: \"float\" };\n\nexport interface PanelTarget extends Target {\n /** The panel dragged. */\n readonly panel: string;\n readonly place: PanelPlace;\n /** Its rank in reading order (left to right across the stage, floating last). */\n readonly order: number;\n /** The state a drop here makes, with the pointer at `p` holding the panel at `grab` from its top-left corner. */\n readonly make: (p: Point, grab: Point) => PanelsState;\n}\n\nexport interface PanelTargetInput {\n readonly defs: readonly PanelDef[];\n /** The state as it is, the panel still in its place. */\n readonly state: PanelsState;\n readonly id: string;\n readonly stage: Size;\n readonly options?: Partial<PanelsOptions>;\n /** Places the panel may go beyond its def's rules (default: all of them). */\n readonly allows?: (id: string, place: PanelPlace) => boolean;\n}\n\n/** How far a column band reaches on each side of its line, px; how wide a side's edge takes a rail drop when it has no rail. */\nexport const COLUMN_REACH = 22;\nexport const RAIL_EDGE = 10;\n\n/** A place's rank in reading order: the left side outer to inner, the right side inner to outer, floating last. */\nexport function placeRank(place: PanelPlace): number {\n switch (place.kind) {\n case \"float\":\n return 3000;\n case \"rail\":\n return place.side === \"left\" ? 0 : 1999;\n case \"column\":\n return place.side === \"left\" ? 1 + 2 * place.index : 1998 - 2 * place.index;\n case \"into\":\n return place.side === \"left\" ? 2 + 2 * place.index : 1997 - 2 * place.index;\n }\n}\n\n/** Where a panel is now, as a place (a float, a column of its own, or stacked in one); null when placed nowhere. */\nexport function homePlace(state: PanelsState, id: string): PanelPlace | null {\n const w = whereIs(state, id);\n if (w.kind === \"float\") return { kind: \"float\" };\n if (w.kind === \"none\") return null;\n 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 };\n}\n\nconst cut = (x0: number, x1: number, lo: number, hi: number): [number, number] => [Math.max(x0, lo), Math.min(x1, hi)];\n\n/** The targets for dragging `input.id`, in reading order. */\nexport function panelTargets(input: PanelTargetInput): PanelTarget[] {\n const { defs, state, id, stage } = input;\n const opt: PanelsOptions = { ...DEFAULT_PANELS_OPTIONS, ...input.options };\n const def = defOf(defs, id);\n const s0 = liftPanel(state, id);\n const l0 = layoutPanels(defs, s0, stage, opt);\n const width = ownWidth(defs, state, id);\n const W = stage.width;\n const H = stage.height;\n const R = COLUMN_REACH;\n const out: PanelTarget[] = [];\n const add = (place: PanelPlace, priority: 1 | 2 | 3, hit: Rect, make: PanelTarget[\"make\"], free = false): void => {\n if (hit.width <= 0 || hit.height <= 0) return;\n if (input.allows && !input.allows(id, place)) return;\n // Its own place: a drop there changes nothing, so it is no target (the drag's home covers it).\n // Widths compare as laid out: a stored width past the column's limits is the same place as the limit.\n if (place.kind !== \"float\" && samePlaces(make({ x: 0, y: 0 }, { x: 0, y: 0 }), state, defs)) return;\n out.push({ id: place.kind === \"float\" ? \"float\" : place.kind === \"rail\" ? `rail:${place.side}` : `${place.kind}:${place.side}:${place.index}`, priority, hit, panel: id, place, order: placeRank(place), make, ...(free ? { free: true } : {}) });\n };\n\n for (const side of SIDES) {\n if (def?.sides && !def.sides.includes(side)) continue;\n const left = side === \"left\";\n const rail = l0.rails[side];\n const edge = rail ? rail.rect.width : RAIL_EDGE;\n // The rail (or the bare edge): dock folded, as the outermost column.\n const railHit = rail ? rail.rect : left ? rect(0, 0, RAIL_EDGE, H) : rect(W - RAIL_EDGE, 0, RAIL_EDGE, H);\n add({ kind: \"rail\", side }, 1, railHit, () => {\n const s = dock(state, id, side, 0, { width });\n return { ...s, folded: [...s.folded.filter((x) => x !== id), id] };\n });\n // The lines between the open columns, outer to inner, and each column's area.\n const open = l0.columns.filter((c) => c.side === side && c.folded === null);\n const lo = left ? edge : 0;\n const hi = left ? W : W - edge;\n const band = (x: number, outer: boolean, i: number): void => {\n // The outermost line reaches inward only: outward is the rail's.\n 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);\n add({ kind: \"column\", side, index: i }, 2, rect(a, 0, b - a, H), () => dock(state, id, side, i, { width }));\n };\n if (open.length === 0) band(left ? l0.pages.x : l0.pages.x + l0.pages.width, true, s0.sides[side].length);\n open.forEach((c, k) => {\n band(left ? c.rect.x : c.rect.x + c.rect.width, k === 0, c.index);\n add({ kind: \"into\", side, index: c.index }, 2, c.rect, () => dock(state, id, side, c.index, { into: true }));\n });\n const last = open.at(-1);\n if (last) band(left ? last.rect.x + last.rect.width : last.rect.x, false, last.index + 1);\n }\n\n if (def?.floats !== false) {\n const was = state.floats.find((f) => f.id === id);\n const size = was ? { width: was.rect.width, height: was.rect.height } : floatSize(def).natural;\n const pinned = !!was?.pinned;\n add(\n { kind: \"float\" },\n 3,\n rect(0, 0, W, H),\n (p, grab) => {\n // Let go at p (view space); stored where it shows once the float option has had its say.\n const at = rect(p.x - grab.x, p.y - grab.y, size.width, size.height);\n const s = float(state, id, pinned ? at : toPage(at, opt.view), pinned);\n const laid = layoutPanels(defs, s, stage, opt).items.get(id)!.rect;\n // A folded float shows as a bar: it moves to where the bar shows and keeps its full size for unfolding.\n const shown = s.folded.includes(id) ? { ...laid, width: at.width, height: at.height } : laid;\n return float(state, id, pinned ? shown : toPage(shown, opt.view), pinned);\n },\n true,\n );\n }\n return out.sort((a, b) => a.order - b.order);\n}\n\n/** A target's drop, laid out: where the panel lands. */\nexport interface PanelDrop {\n readonly target: string;\n readonly place: PanelPlace;\n /** Same key, same place (a float's key carries where it lands). */\n readonly key: string;\n readonly state: PanelsState;\n readonly layout: PanelsLayout;\n /** Where the panel lands (its rail segment when it docks folded). */\n readonly slot: Rect;\n /** It lands in a rail. */\n readonly hidden: boolean;\n /** It floats where it is let go: no room is made for it. */\n readonly free: boolean;\n}\n\n/** The drop on `target` with the pointer at `p` holding the panel at `grab`, laid out. */\nexport function panelDrop(input: PanelTargetInput, target: PanelTarget, p: Point, grab: Point): PanelDrop {\n const opt: PanelsOptions = { ...DEFAULT_PANELS_OPTIONS, ...input.options };\n const state = target.make(p, grab);\n const layout = layoutPanels(input.defs, state, input.stage, opt);\n const placed = layout.items.get(input.id)!;\n const key = target.free ? `float:${Math.round(placed.rect.x)},${Math.round(placed.rect.y)}` : target.id;\n return { target: target.id, place: target.place, key, state, layout, slot: placed.rect, hidden: placed.hidden, free: !!target.free };\n}\n\n// --- keyboard stops ------------------------------------------------------------------------------------------------\n\nexport interface PanelStop {\n /** The target's id (\"home\" for the panel's own place). */\n readonly id: string;\n readonly place: PanelPlace;\n /** The state a move here makes (the current one for home). */\n readonly state: PanelsState;\n readonly home: boolean;\n}\n\nexport interface PanelStopsOptions {\n /** The panel's own place (`homePlace`) and the state as it is: a stop of its own in its reading-order position. */\n readonly home?: { readonly place: PanelPlace; readonly state: PanelsState };\n /** Floating as a stop at the end (default: left out); `at` and `grab` as for a drop (default: the stage's middle, the corner). */\n readonly floats?: boolean | { readonly at: Point; readonly grab?: Point };\n}\n\n/** The panel's places in reading order, for the arrow keys and a \"Move to\" menu (`keyboardStops` calls this). */\nexport function panelStops(targets: readonly PanelTarget[], options: PanelStopsOptions = {}): PanelStop[] {\n const stops: (PanelStop & { order: number })[] = [];\n for (const t of targets) {\n if (t.place.kind === \"float\") {\n if (!options.floats) continue;\n const at = options.floats === true ? { x: t.hit.x + t.hit.width / 2, y: t.hit.y + t.hit.height / 2 } : options.floats.at;\n const grab = options.floats === true ? { x: 0, y: 0 } : (options.floats.grab ?? { x: 0, y: 0 });\n stops.push({ id: t.id, place: t.place, state: t.make(at, grab), home: false, order: t.order });\n continue;\n }\n stops.push({ id: t.id, place: t.place, state: t.make({ x: 0, y: 0 }, { x: 0, y: 0 }), home: false, order: t.order });\n }\n const h = options.home;\n // A float's home sits with the floats: last, after any float stop.\n 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) });\n return stops.sort((a, b) => a.order - b.order).map(({ order: _order, ...s }) => s);\n}\n"],"mappings":"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","names":["float","rect","f","open","open"]}
package/dist/panels.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PanelsState, S as Side, C as Clock, a as PanelDef } from './targets-BEqoVKbF.js';
2
- export { b as COLUMN_REACH, c as Column, D as DEFAULT_PANELS_OPTIONS, d as DockOptions, F as FLOAT_HEIGHT, e as FLOAT_MIN, f as FloatAt, G as GiveWay, I as IDENTITY_VIEW, g as PanelDrop, h as PanelKind, i as PanelPlace, j as PanelStop, k as PanelStopsOptions, l as PanelTarget, m as PanelTargetInput, n as PanelsLayout, o as PanelsNote, p as PanelsNoteCode, q as PanelsOptions, r as PanelsStart, s as PlacedColumn, t as PlacedPanel, u as PlacedRail, R as RAIL_EDGE, v as SIDES, V as View, W as Where, w as close, x as columnWidth, y as createPanels, z as defOf, A as dock, B as float, E as floatSize, H as focus, J as giveWayOrder, K as homePlace, L as keep, M as layoutPanels, N as liftPanel, O as open, Q as ownWidth, T as panelDrop, U as panelStops, X as panelTargets, Y as pin, Z as placeRank, _ as resizeColumn, $ as resizeFloat, a0 as samePlaces, a1 as tick, a2 as toPage, a3 as toView, a4 as toggleFold, a5 as whereIs } from './targets-BEqoVKbF.js';
1
+ import { P as PanelsState, S as Side, C as Clock, a as PanelDef } from './targets-DqhZf3XZ.js';
2
+ export { b as COLUMN_REACH, c as Column, D as DEFAULT_PANELS_OPTIONS, d as DockOptions, F as FLOAT_HEIGHT, e as FLOAT_MIN, f as FloatAt, G as GiveWay, I as IDENTITY_VIEW, g as PanelDrop, h as PanelKind, i as PanelPlace, j as PanelStop, k as PanelStopsOptions, l as PanelTarget, m as PanelTargetInput, n as PanelsLayout, o as PanelsNote, p as PanelsNoteCode, q as PanelsOptions, r as PanelsStart, s as PlacedColumn, t as PlacedPanel, u as PlacedRail, R as RAIL_EDGE, v as SIDES, V as View, W as Where, w as close, x as columnWidth, y as createPanels, z as defOf, A as dock, B as float, E as floatSize, H as focus, J as giveWayOrder, K as homePlace, L as keep, M as layoutPanels, N as liftPanel, O as open, Q as ownWidth, T as panelDrop, U as panelStops, X as panelTargets, Y as pin, Z as placeRank, _ as resizeColumn, $ as resizeFloat, a0 as samePlaces, a1 as tick, a2 as toPage, a3 as toView, a4 as toggleFold, a5 as whereIs } from './targets-DqhZf3XZ.js';
3
3
  import { R as Rect } from './geometry-mL-GTRti.js';
4
4
 
5
5
  /**
package/dist/panels.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  toView,
35
35
  toggleFold,
36
36
  whereIs
37
- } from "./chunk-NNFNMIW4.js";
37
+ } from "./chunk-QR7MGDX6.js";
38
38
  import "./chunk-QMTNB2C3.js";
39
39
 
40
40
  // src/panels/store.ts
@@ -79,13 +79,21 @@ interface PanelsOptions {
79
79
  readonly giveWay: GiveWay;
80
80
  /** "clamp" keeps floats in the view at layout time; "free" never moves them. Default "clamp". */
81
81
  readonly floats: "clamp" | "free";
82
+ /**
83
+ * Where a column folded by hand goes (default "rail"): to its side's rail, or ("ride") as title bars on top of the
84
+ * side's first open column, until every column on that side is folded. Give-way's folds always go to the rail.
85
+ */
86
+ readonly fold: "rail" | "ride";
82
87
  /** How much of a float wider than the view stays in it, px (default 48). */
83
88
  readonly floatVisible: number;
84
89
  /** The pages' minimum width (default 320). */
85
90
  readonly pagesMin: number;
86
91
  /** The page's offset and scale (default: identity). */
87
92
  readonly view: View;
88
- /** A title bar's height: a panel folded in a column, and the part of a float the clamp keeps in the view (default 28). */
93
+ /**
94
+ * A title bar's height: a panel folded in a column, a folded float, a riding column, and the part of a float the
95
+ * clamp keeps in the view (default 28).
96
+ */
89
97
  readonly bar: number;
90
98
  /** A rail's width (default 36). */
91
99
  readonly rail: number;
@@ -187,8 +195,9 @@ declare const toPage: (r: Rect, v: View) => Rect;
187
195
  * Pin a float to the view, or unpin it to the page. `view` is where the page is now (default: identity): the float
188
196
  * doesn't jump, its rect is converted between the two spaces. A float's size is never scaled.
189
197
  *
190
- * `shown` is where the float shows now, in view space (the layout's placed rect for it). When given, it is converted
191
- * instead of the stored rect, so a float the clamp moved stays where it shows rather than jumping to its stored place.
198
+ * `shown` is where the float shows now, in view space (the layout's placed rect for it). When given, its position is
199
+ * converted instead of the stored one, so a float the clamp moved stays where it shows rather than jumping to its
200
+ * stored place. The size stays the stored one: a float folded to a bar, or shrunk by the clamp, keeps its full size.
192
201
  */
193
202
  declare function pin(state: PanelsState, id: string, on: boolean, view?: View, shown?: Rect): PanelsState;
194
203
  /**
@@ -216,6 +225,13 @@ declare function samePlaces(a: PanelsState, b: PanelsState, defs?: readonly Pane
216
225
  * folded by hand is a title bar (`options.bar` tall) and the open ones share the rest of the height equally.
217
226
  * - A column whose panels are all folded is railed: its panels become segments of its side's rail (one rail per
218
227
  * side, `options.rail` wide at the outer edge, segments in side order).
228
+ * - With `options.fold` "ride", a column folded by hand on a side that still has an open column rides instead: its
229
+ * panels become title bars stacked on top of the side's first open column (outer edge first), as wide as that
230
+ * column, and its open panels share the rest of the height. The folded column keeps its stored place and width, and
231
+ * the open columns lie as if it were gone. Only when every column on the side is folded does the side show its rail.
232
+ * Give-way's folds always go to the rail.
233
+ * - A float folded by hand is a title bar: its own x, y and width, `options.bar` tall, still a float (clamped as a
234
+ * bar, `floating`); unfolding brings its full rect back, as the stored rect never changes.
219
235
  * - Give-way: when the open columns, the rails and `pagesMin` don't fit the stage width, columns shrink toward their
220
236
  * minimum, then whole columns fold to the rail, in the policy's order, until the pages fit. Columns holding a kept
221
237
  * panel come after every other column; if the pages still don't fit, they fold too (`kept-folded`). Folding by
@@ -227,8 +243,8 @@ declare function samePlaces(a: PanelsState, b: PanelsState, defs?: readonly Pane
227
243
  */
228
244
 
229
245
  /**
230
- * Where a panel is, structurally: an open part of a column, a folded title bar in a column, a segment of a rail
231
- * (the panel itself isn't laid out), or a float.
246
+ * Where a panel is, structurally: an open part of a column, a folded title bar (in a column, riding on one, or a
247
+ * folded float), a segment of a rail (the panel itself isn't laid out), or a float.
232
248
  */
233
249
  type PanelKind = "column" | "bar" | "segment" | "float";
234
250
  interface PlacedPanel {
@@ -245,9 +261,13 @@ interface PlacedPanel {
245
261
  readonly kept: boolean;
246
262
  /** A pinned float. */
247
263
  readonly pinned: boolean;
264
+ /** It floats (open, or folded to a bar). */
265
+ readonly floating: boolean;
248
266
  /** Docked: its side and column index (the state's). */
249
267
  readonly side?: Side;
250
268
  readonly column?: number;
269
+ /** A riding bar: the index of the column it rides on (`options.fold` "ride"). */
270
+ readonly rides?: number;
251
271
  /** A float the clamp moved or resized. */
252
272
  readonly clamped?: boolean;
253
273
  }
@@ -269,6 +289,8 @@ interface PlacedColumn {
269
289
  readonly kept: boolean;
270
290
  /** The shown panels, top to bottom. */
271
291
  readonly panels: readonly string[];
292
+ /** Riding: the index of the column its bars ride on; its rect is the bars'. */
293
+ readonly rides?: number;
272
294
  }
273
295
  interface PlacedRail {
274
296
  readonly side: Side;
package/dist/targets.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a6 as Target, l as PanelTarget, k as PanelStopsOptions, j as PanelStop } from './targets-BEqoVKbF.js';
1
+ import { a6 as Target, l as PanelTarget, k as PanelStopsOptions, j as PanelStop } from './targets-DqhZf3XZ.js';
2
2
  import { R as Rect, P as Point, S as Size } from './geometry-mL-GTRti.js';
3
3
  import { D as DeskState, g as Layout, a as Construction, O as Options } from './constructions-VDK_mwmz.js';
4
4
  import { Place, Arrangement, HostId, HostSpec, GroupSize } from './toolbar.js';
package/dist/targets.js CHANGED
@@ -38,7 +38,7 @@ import {
38
38
  } from "./chunk-WLMJ6JGO.js";
39
39
  import {
40
40
  panelStops
41
- } from "./chunk-NNFNMIW4.js";
41
+ } from "./chunk-QR7MGDX6.js";
42
42
  import {
43
43
  centre,
44
44
  overlap,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@n-uf/placement",
3
- "version": "26.11.7",
4
- "description": "Where things go: desk docks, rails and palettes, toolbar groups, and the drop targets for each. Pure state in, rects out. No DOM, no framework, no motion.",
3
+ "version": "26.11.8",
4
+ "description": "Where things go: desk docks, rails and palettes, panel columns, toolbar groups, and the drop targets for each. Pure state in, rects out. No DOM, no framework, no motion.",
5
5
  "keywords": [
6
6
  "layout",
7
7
  "docking",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/panels/model.ts","../src/panels/layout.ts","../src/panels/targets.ts"],"sourcesContent":["/**\n * The panels model: plain data and the pure changes on it.\n *\n * Panels have string ids. Each side holds full-height columns (outer edge first), each column one or more panels\n * top to bottom and its own width. A panel may instead float, in page space (it moves with the page) or pinned in\n * view space (it stays put). A logical clock per panel (opened, used) is what give-way reads; every change here that\n * counts as a use moves it on. Nothing here reads a host clock: the next tick is one past the latest in the state.\n */\nimport type { Rect, Size } from \"../geometry\";\n\nexport type Side = \"left\" | \"right\";\nexport const SIDES: readonly Side[] = [\"left\", \"right\"];\n\n/**\n * What a consumer says about a panel: its width limits docked, its size limits floating, and where it may go. No\n * words: names and titles are the consumer's.\n */\nexport interface PanelDef {\n readonly id: string;\n /** A docked column's width limits and its natural width. */\n readonly width: { readonly min: number; readonly max: number; readonly natural: number };\n /** A float's size limits and natural size (default: its natural width, 360 px tall, no smaller than 160 × 120). */\n readonly float?: { readonly min: Size; readonly natural: Size };\n /** Where it may dock (default: both sides). */\n readonly sides?: readonly Side[];\n /** May it float (default: yes). */\n readonly floats?: boolean;\n}\n\n/** A full-height column: its panels top to bottom, and its stored width (the layout clamps it to its panels' limits). */\nexport interface Column {\n readonly panels: readonly string[];\n readonly width: number;\n}\n\n/** A floating panel: `rect` in page space, or in view space when `pinned`. */\nexport interface FloatAt {\n readonly id: string;\n readonly rect: Rect;\n readonly pinned?: boolean;\n}\n\n/** Logical times: when a panel was last opened, and last used (opened, focused, moved or unfolded). */\nexport interface Clock {\n readonly opened: number;\n readonly used: number;\n}\n\nexport interface PanelsState {\n /** Each side's columns, from the outer edge inward. */\n readonly sides: Readonly<Record<Side, readonly Column[]>>;\n /** Floating panels; a later one is on top. */\n readonly floats: readonly FloatAt[];\n /** Folded by hand (give-way never writes this). */\n readonly folded: readonly string[];\n /** Docked panels kept open: their columns give way last. */\n readonly kept: readonly string[];\n /** Not shown at all (they keep their place, for when they open again). */\n readonly closed: readonly string[];\n readonly clock: Readonly<Record<string, Clock>>;\n}\n\n/** The page's offset and scale in the view: a page point p shows at `x + p.x * scale`, `y + p.y * scale`. */\nexport interface View {\n readonly x: number;\n readonly y: number;\n readonly scale: number;\n}\nexport const IDENTITY_VIEW: View = { x: 0, y: 0, scale: 1 };\n\n/** Who gives way first: the oldest or the newest, by when they were last used or last opened. */\nexport interface GiveWay {\n readonly order: \"oldest\" | \"newest\";\n readonly by: \"used\" | \"opened\";\n}\n\nexport interface PanelsOptions {\n /** Default: `{ order: \"oldest\", by: \"used\" }`, so the panel used longest ago gives way first. */\n readonly giveWay: GiveWay;\n /** \"clamp\" keeps floats in the view at layout time; \"free\" never moves them. Default \"clamp\". */\n readonly floats: \"clamp\" | \"free\";\n /** How much of a float wider than the view stays in it, px (default 48). */\n readonly floatVisible: number;\n /** The pages' minimum width (default 320). */\n readonly pagesMin: number;\n /** The page's offset and scale (default: identity). */\n readonly view: View;\n /** A title bar's height: a panel folded in a column, and the part of a float the clamp keeps in the view (default 28). */\n readonly bar: number;\n /** A rail's width (default 36). */\n readonly rail: number;\n /** A rail segment's height, and the gap above the first one (defaults 36 and 4). */\n readonly segment: number;\n readonly railInset: number;\n}\n\nexport const DEFAULT_PANELS_OPTIONS: PanelsOptions = {\n giveWay: { order: \"oldest\", by: \"used\" },\n floats: \"clamp\",\n floatVisible: 48,\n pagesMin: 320,\n view: IDENTITY_VIEW,\n bar: 28,\n rail: 36,\n segment: 36,\n railInset: 4,\n};\n\n/** A float's size when its def gives none: this tall, and never smaller than FLOAT_MIN. */\nexport const FLOAT_HEIGHT = 360;\nexport const FLOAT_MIN: Size = { width: 160, height: 120 };\n\n// --- reading the state ---------------------------------------------------------------------------------------------\n\nconst without = <T>(list: readonly T[], x: T): T[] => list.filter((y) => y !== x);\nconst withOnce = <T>(list: readonly T[], x: T): T[] => (list.includes(x) ? [...list] : [...list, x]);\n\n/** Where a panel is: a column (side and index), floating, or nowhere. */\nexport type Where = { readonly kind: \"column\"; readonly side: Side; readonly index: number } | { readonly kind: \"float\"; readonly float: FloatAt } | { readonly kind: \"none\" };\n\nexport function whereIs(state: PanelsState, id: string): Where {\n for (const side of SIDES) {\n const index = state.sides[side].findIndex((c) => c.panels.includes(id));\n if (index >= 0) return { kind: \"column\", side, index };\n }\n const float = state.floats.find((f) => f.id === id);\n return float ? { kind: \"float\", float } : { kind: \"none\" };\n}\n\n/** One past the latest logical time in the state. */\nexport const tick = (state: PanelsState): number => Object.values(state.clock).reduce((m, c) => Math.max(m, c.opened, c.used), 0) + 1;\n\nconst bump = (state: PanelsState, id: string, opened: boolean): PanelsState => {\n const t = tick(state);\n const was = state.clock[id] ?? { opened: 0, used: 0 };\n return { ...state, clock: { ...state.clock, [id]: { opened: opened ? t : was.opened, used: t } } };\n};\n\nexport const defOf = (defs: readonly PanelDef[], id: string): PanelDef | undefined => defs.find((d) => d.id === id);\n\n/** A float's size limits and natural size from its def. */\nexport function floatSize(def: PanelDef | undefined): { min: Size; natural: Size } {\n if (def?.float) return { min: def.float.min, natural: def.float.natural };\n const width = Math.max(FLOAT_MIN.width, def?.width.natural ?? FLOAT_MIN.width);\n return { min: FLOAT_MIN, natural: { width, height: FLOAT_HEIGHT } };\n}\n\n/**\n * A panel's own width, for a new column made for it: the width of the column it is in, clamped to its own limits;\n * floating or nowhere, its natural width.\n */\nexport function ownWidth(defs: readonly PanelDef[], state: PanelsState, id: string): number {\n const def = defOf(defs, id);\n const w = whereIs(state, id);\n const lo = def?.width.min ?? 0;\n const hi = Math.max(lo, def?.width.max ?? Infinity);\n if (w.kind === \"column\") return Math.min(Math.max(state.sides[w.side][w.index]!.width, lo), hi);\n return def?.width.natural ?? lo;\n}\n\n// --- building one --------------------------------------------------------------------------------------------------\n\nexport interface PanelsStart {\n /** Each side's columns from the outer edge inward, each a list of panel ids top to bottom. */\n readonly left?: readonly (readonly string[])[];\n readonly right?: readonly (readonly string[])[];\n /** Floating panels: where (page space, or view space when pinned); the size defaults to the def's natural size. */\n readonly floats?: readonly { readonly id: string; readonly x: number; readonly y: number; readonly width?: number; readonly height?: number; readonly pinned?: boolean }[];\n readonly folded?: readonly string[];\n readonly kept?: readonly string[];\n readonly closed?: readonly string[];\n}\n\n/**\n * A state from a plain start: each column as wide as the widest natural width of its panels (within their limits),\n * each float its natural size. The clock counts up in the order the panels are listed (left, right, floats), so the\n * last one listed is the newest.\n */\nexport function createPanels(defs: readonly PanelDef[], start: PanelsStart): PanelsState {\n const column = (ids: readonly string[]): Column => {\n const ds = ids.map((id) => defOf(defs, id));\n const lo = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));\n const hi = Math.max(lo, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));\n const natural = Math.max(0, ...ds.map((d) => d?.width.natural ?? 0));\n return { panels: [...ids], width: Math.min(Math.max(natural, lo), hi) };\n };\n const floats = (start.floats ?? []).map((f): FloatAt => {\n const n = floatSize(defOf(defs, f.id)).natural;\n 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 } : {}) };\n });\n const sides = { left: (start.left ?? []).map(column), right: (start.right ?? []).map(column) };\n const order = [...sides.left, ...sides.right].flatMap((c) => c.panels).concat(floats.map((f) => f.id));\n const clock: Record<string, Clock> = {};\n order.forEach((id, i) => (clock[id] = { opened: i + 1, used: i + 1 }));\n return { sides, floats, folded: [...(start.folded ?? [])], kept: [...(start.kept ?? [])], closed: [...(start.closed ?? [])], clock };\n}\n\n// --- changes -------------------------------------------------------------------------------------------------------\n\n/** The state with `id` taken out of its column (an emptied column goes) or the floats. Nothing else changes. */\nexport function liftPanel(state: PanelsState, id: string): PanelsState {\n const lift = (cols: readonly Column[]): Column[] => cols.map((c) => ({ ...c, panels: without(c.panels, id) })).filter((c) => c.panels.length > 0);\n return { ...state, sides: { left: lift(state.sides.left), right: lift(state.sides.right) }, floats: state.floats.filter((f) => f.id !== id) };\n}\n\n/**\n * Open a panel: it shows again where it was, and it is the newest opened and used. A panel placed nowhere goes into\n * a new innermost column on `at.side`, `at.width` wide; without `at` it stays placed nowhere.\n */\nexport function open(state: PanelsState, id: string, at?: { readonly side: Side; readonly width: number }): PanelsState {\n let s: PanelsState = { ...state, closed: without(state.closed, id) };\n if (at && whereIs(s, id).kind === \"none\") s = { ...s, sides: { ...s.sides, [at.side]: [...s.sides[at.side], { panels: [id], width: at.width }] } };\n return bump(s, id, true);\n}\n\n/** Close a panel: it isn't shown, keeps its place, and is no longer kept open. */\nexport const close = (state: PanelsState, id: string): PanelsState => ({ ...state, closed: withOnce(state.closed, id), kept: without(state.kept, id) });\n\n/** Focus a panel: it is the newest used; a float comes to the top. */\nexport function focus(state: PanelsState, id: string): PanelsState {\n const f = state.floats.find((x) => x.id === id);\n const s = f ? { ...state, floats: [...state.floats.filter((x) => x !== f), f] } : state;\n return bump(s, id, false);\n}\n\n/** Fold a panel to its title bar by hand, or unfold it (unfolding is a use). */\nexport function toggleFold(state: PanelsState, id: string): PanelsState {\n if (state.folded.includes(id)) return bump({ ...state, folded: without(state.folded, id) }, id, false);\n return { ...state, folded: [...state.folded, id] };\n}\n\n/** Keep a docked panel open (its column gives way last), or stop keeping it. A floating panel isn't kept. */\nexport function keep(state: PanelsState, id: string, on: boolean): PanelsState {\n if (!on) return { ...state, kept: without(state.kept, id) };\n return whereIs(state, id).kind === \"column\" ? { ...state, kept: withOnce(state.kept, id) } : state;\n}\n\nexport interface DockOptions {\n /** Stack into the column at `index` (at its bottom) instead of making a new column there. */\n readonly into?: boolean;\n /** A new column's width (default: the width of the column the panel leaves, else 0, which the layout clamps to the minimum). */\n readonly width?: number;\n}\n\n/**\n * Dock a panel on `side`: a new column at `index` (0 the outer edge; past the end, innermost), or with `into` at the\n * bottom of the column at `index` (counted once the panel is lifted out). It shows, it is the newest used, and it\n * keeps whether it is kept open.\n */\nexport function dock(state: PanelsState, id: string, side: Side, index: number, options: DockOptions = {}): PanelsState {\n const w = whereIs(state, id);\n const from = w.kind === \"column\" ? state.sides[w.side][w.index]!.width : 0;\n const s = liftPanel(state, id);\n const cols = [...s.sides[side]];\n if (options.into && cols[index]) cols[index] = { ...cols[index]!, panels: [...cols[index]!.panels, id] };\n else {\n const at = Math.max(0, Math.min(index, cols.length));\n cols.splice(at, 0, { panels: [id], width: options.width ?? from });\n }\n return bump({ ...s, sides: { ...s.sides, [side]: cols }, closed: without(s.closed, id) }, id, false);\n}\n\n/**\n * Float a panel at `rect` (page space; view space when pinned). A float stays pinned or not unless `pinned` says;\n * a docked panel floats unpinned. It shows, it is the newest used and on top, and it is no longer kept open.\n */\nexport function float(state: PanelsState, id: string, rect: Rect, pinned?: boolean): PanelsState {\n const was = state.floats.find((f) => f.id === id);\n const on = pinned ?? !!was?.pinned;\n const s = liftPanel(state, id);\n const f: FloatAt = { id, rect: { ...rect }, ...(on ? { pinned: true } : {}) };\n return bump({ ...s, floats: [...s.floats, f], kept: without(s.kept, id), closed: without(s.closed, id) }, id, false);\n}\n\n/** A page-space rect in view space, and back. */\nexport const toView = (r: Rect, v: View): Rect => ({ ...r, x: v.x + r.x * v.scale, y: v.y + r.y * v.scale });\nexport const toPage = (r: Rect, v: View): Rect => ({ ...r, x: (r.x - v.x) / v.scale, y: (r.y - v.y) / v.scale });\n\n/**\n * Pin a float to the view, or unpin it to the page. `view` is where the page is now (default: identity): the float\n * doesn't jump, its rect is converted between the two spaces. A float's size is never scaled.\n *\n * `shown` is where the float shows now, in view space (the layout's placed rect for it). When given, it is converted\n * instead of the stored rect, so a float the clamp moved stays where it shows rather than jumping to its stored place.\n */\nexport function pin(state: PanelsState, id: string, on: boolean, view: View = IDENTITY_VIEW, shown?: Rect): PanelsState {\n return {\n ...state,\n floats: state.floats.map((f): FloatAt => {\n if (f.id !== id || !!f.pinned === on) return f;\n // In view space: where it shows, else where it is stored.\n const seen = shown ? { ...shown } : f.pinned ? { ...f.rect } : toView(f.rect, view);\n return on ? { id, rect: seen, pinned: true } : { id, rect: toPage(seen, view) };\n }),\n };\n}\n\n/**\n * Store a column's width (the layout clamps it to its panels' limits). Resizing is a use: the column's panels are\n * the newest used, so give-way takes room from the other columns, not from the one being resized.\n */\nexport function resizeColumn(state: PanelsState, side: Side, index: number, width: number): PanelsState {\n const col = state.sides[side][index];\n if (!col || !Number.isFinite(width)) return state;\n const t = tick(state);\n const clock = { ...state.clock };\n for (const id of col.panels) clock[id] = { opened: clock[id]?.opened ?? 0, used: t };\n return { ...state, sides: { ...state.sides, [side]: state.sides[side].map((c, i) => (i === index ? { ...c, width: Math.max(0, width) } : c)) }, clock };\n}\n\n/** Store a float's rect (its own space). Resizing is a use. */\nexport function resizeFloat(state: PanelsState, id: string, rect: Rect): PanelsState {\n if (!state.floats.some((f) => f.id === id)) return state;\n return bump({ ...state, floats: state.floats.map((f) => (f.id === id ? { ...f, rect: { ...rect } } : f)) }, id, false);\n}\n\n/** A column's width as the layout takes it: its stored width clamped to its panels' limits (with `defs`). */\nexport function columnWidth(defs: readonly PanelDef[] | undefined, col: Column): number {\n if (!defs) return col.width;\n const ds = col.panels.map((id) => defOf(defs, id));\n const lo = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));\n const hi = Math.max(lo, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));\n return Math.min(Math.max(Number.isFinite(col.width) ? col.width : lo, lo), hi);\n}\n\n/**\n * Two states place the panels the same (columns, their panels and widths, floats and their rects; the clock aside).\n * With `defs`, widths compare as the layout takes them (clamped to the panels' limits), so a stored width past a\n * column's max is the same place as that max.\n */\nexport function samePlaces(a: PanelsState, b: PanelsState, defs?: readonly PanelDef[]): boolean {\n const cols = (s: PanelsState): string => SIDES.map((side) => s.sides[side].map((c) => `${c.panels.join(\",\")}@${Math.round(columnWidth(defs, c))}`).join(\"|\")).join(\"‖\");\n const fl = (s: PanelsState): string => 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(\"|\");\n const set = (l: readonly string[]): string => [...l].sort().join(\",\");\n return cols(a) === cols(b) && fl(a) === fl(b) && set(a.folded) === set(b.folded) && set(a.kept) === set(b.kept) && set(a.closed) === set(b.closed);\n}\n","/**\n * `layoutPanels`: the panels' state, a stage and options in; geometry and structure out: every panel's rect, layer\n * and kind, the columns, the rails, the pages' rect, and coded notes on how it gave way. Pure: the same input always\n * lays out the same. How anything looks is the consumer's.\n *\n * - A column is full height and as wide as its stored width, clamped to its panels' limits. Inside it, a panel\n * folded by hand is a title bar (`options.bar` tall) and the open ones share the rest of the height equally.\n * - A column whose panels are all folded is railed: its panels become segments of its side's rail (one rail per\n * side, `options.rail` wide at the outer edge, segments in side order).\n * - Give-way: when the open columns, the rails and `pagesMin` don't fit the stage width, columns shrink toward their\n * minimum, then whole columns fold to the rail, in the policy's order, until the pages fit. Columns holding a kept\n * panel come after every other column; if the pages still don't fit, they fold too (`kept-folded`). Folding by\n * give-way never writes `folded`, so a wider stage brings the column back.\n * - Floats: \"clamp\" keeps a float in the view at layout time (the state keeps the stored rect, so a larger view\n * brings it back where it was); \"free\" never moves one. A float's size is never scaled. A pinned float is in view\n * space and clamped against the view; an unpinned one has its position in page space, clamped so that its screen\n * rect at pan 0 fits the view, then moved by the view's offset and scale, so it scrolls with the page.\n */\nimport { rect, type Rect, type Size } from \"../geometry\";\nimport { DEFAULT_PANELS_OPTIONS, SIDES, defOf, floatSize, toView, type PanelDef, type PanelsOptions, type PanelsState, type Side } from \"./model\";\n\n/**\n * Where a panel is, structurally: an open part of a column, a folded title bar in a column, a segment of a rail\n * (the panel itself isn't laid out), or a float.\n */\nexport type PanelKind = \"column\" | \"bar\" | \"segment\" | \"float\";\n\nexport interface PlacedPanel {\n /** Stage px; for a segment, the segment's rect in its rail. */\n readonly rect: Rect;\n readonly kind: PanelKind;\n /** Columns and rails 0, floats 10 and up (a later float on top). */\n readonly layer: number;\n /** In a rail: there is no panel to lay out, only its segment. */\n readonly hidden: boolean;\n /** Folded by hand (a bar, or a segment of a column folded by hand), or by give-way (a segment). */\n readonly folded: null | \"hand\" | \"auto\";\n /** Kept open. */\n readonly kept: boolean;\n /** A pinned float. */\n readonly pinned: boolean;\n /** Docked: its side and column index (the state's). */\n readonly side?: Side;\n readonly column?: number;\n /** A float the clamp moved or resized. */\n readonly clamped?: boolean;\n}\n\nexport interface PlacedColumn {\n readonly side: Side;\n /** The column's index in the state. */\n readonly index: number;\n /** Its rect (zero wide when railed). */\n readonly rect: Rect;\n /** Its stored width clamped to its panels' limits, and those limits. */\n readonly width: number;\n readonly min: number;\n readonly max: number;\n /** null: open; \"hand\": all its panels folded by hand; \"auto\": folded by give-way. */\n readonly folded: null | \"hand\" | \"auto\";\n /** Shrunk by give-way below its width. */\n readonly shrunk: boolean;\n /** It holds a kept panel. */\n readonly kept: boolean;\n /** The shown panels, top to bottom. */\n readonly panels: readonly string[];\n}\n\nexport interface PlacedRail {\n readonly side: Side;\n readonly rect: Rect;\n readonly segments: readonly { readonly id: string; readonly rect: Rect }[];\n}\n\nexport type PanelsNoteCode = \"column-shrunk\" | \"column-folded\" | \"kept-folded\" | \"pages-under-min\" | \"float-clamped\" | \"float-resized\";\n\n/** One note on a layout: a code and its data. */\nexport type PanelsNote =\n | { readonly code: \"column-shrunk\"; readonly side: Side; readonly column: number; readonly items: readonly string[]; readonly from: number; readonly to: number }\n | { readonly code: \"column-folded\" | \"kept-folded\"; readonly side: Side; readonly column: number; readonly items: readonly string[] }\n | { readonly code: \"pages-under-min\"; readonly width: number; readonly min: number }\n | { readonly code: \"float-clamped\" | \"float-resized\"; readonly items: readonly string[] };\n\nexport interface PanelsLayout {\n readonly items: Map<string, PlacedPanel>;\n /** The shown columns in side order (left outer → inner, then right outer → inner). */\n readonly columns: readonly PlacedColumn[];\n readonly rails: Partial<Record<Side, PlacedRail>>;\n readonly notes: readonly PanelsNote[];\n /** What is left for the documents. */\n readonly pages: Rect;\n}\n\ninterface Col {\n readonly side: Side;\n readonly index: number;\n readonly panels: readonly string[];\n readonly min: number;\n readonly max: number;\n readonly width: number;\n readonly hand: boolean;\n readonly kept: boolean;\n readonly age: number;\n}\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(Math.max(v, lo), Math.max(lo, hi));\n\n/** The order columns give way in: unkept before kept, then the policy (oldest or newest), outer first, left first. */\nexport function giveWayOrder<C extends { readonly side: Side; readonly index: number; readonly kept: boolean; readonly age: number }>(cols: readonly C[], order: \"oldest\" | \"newest\"): C[] {\n 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));\n}\n\nexport function layoutPanels(defs: readonly PanelDef[], state: PanelsState, stage: Size, options: Partial<PanelsOptions> = {}): PanelsLayout {\n const opt: PanelsOptions = { ...DEFAULT_PANELS_OPTIONS, ...options };\n const W = stage.width;\n const H = stage.height;\n const closed = new Set(state.closed);\n const folded = new Set(state.folded);\n const kept = new Set(state.kept);\n const by = opt.giveWay.by;\n\n // The shown columns.\n const cols: Col[] = [];\n for (const side of SIDES) {\n state.sides[side].forEach((c, index) => {\n const panels = c.panels.filter((id) => !closed.has(id));\n if (panels.length === 0) return;\n const ds = panels.map((id) => defOf(defs, id));\n const min = Math.max(0, ...ds.map((d) => d?.width.min ?? 0));\n const max = Math.max(min, Math.min(...ds.map((d) => d?.width.max ?? Infinity)));\n const width = clamp(Number.isFinite(c.width) ? c.width : min, min, max);\n const age = Math.max(...panels.map((id) => state.clock[id]?.[by] ?? 0));\n cols.push({ side, index, panels, min, max, width, hand: panels.every((id) => folded.has(id)), kept: panels.some((id) => kept.has(id)), age });\n });\n }\n\n // Give-way: fold the fewest columns in order that let the pages fit, shrinking the rest in order toward their minimum.\n const order = giveWayOrder(\n cols.filter((c) => !c.hand),\n opt.giveWay.order,\n );\n const fit = (k: number): { auto: Set<Col>; widths: Map<Col, number>; excess: number } => {\n const auto = new Set(order.slice(0, k));\n const railed = (side: Side): boolean => cols.some((c) => c.side === side && (c.hand || auto.has(c)));\n const widths = new Map(order.filter((c) => !auto.has(c)).map((c) => [c, c.width]));\n let excess = [...widths.values()].reduce((a, b) => a + b, 0) + SIDES.filter(railed).length * opt.rail + opt.pagesMin - W;\n for (const c of order) {\n if (excess <= 0 || auto.has(c)) continue;\n const take = Math.min(excess, c.width - c.min);\n if (take > 0) {\n widths.set(c, c.width - take);\n excess -= take;\n }\n }\n return { auto, widths, excess };\n };\n let g = fit(0);\n for (let k = 1; g.excess > 0 && k <= order.length; k++) g = fit(k);\n\n const notes: PanelsNote[] = [];\n for (const c of order) {\n const w = g.widths.get(c);\n if (w !== undefined && w < c.width) notes.push({ code: \"column-shrunk\", side: c.side, column: c.index, items: c.panels, from: c.width, to: w });\n }\n 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 });\n\n // Positions: rails at the outer edges, open columns inward from them, the pages between.\n const items = new Map<string, PlacedPanel>();\n const placedCols: PlacedColumn[] = [];\n const rails: Partial<Record<Side, PlacedRail>> = {};\n let x0 = 0;\n let x1 = W;\n for (const side of SIDES) {\n const mine = cols.filter((c) => c.side === side);\n const inRail = mine.filter((c) => c.hand || g.auto.has(c));\n if (inRail.length) {\n const r = side === \"left\" ? rect(0, 0, opt.rail, H) : rect(W - opt.rail, 0, opt.rail, H);\n const segments = inRail.flatMap((c) => c.panels).map((id, i) => ({ id, rect: rect(r.x, opt.railInset + i * opt.segment, opt.rail, opt.segment) }));\n rails[side] = { side, rect: r, segments };\n for (const s of segments) {\n const c = inRail.find((x) => x.panels.includes(s.id))!;\n 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, side, column: c.index });\n }\n if (side === \"left\") x0 = opt.rail;\n else x1 = W - opt.rail;\n }\n for (const c of mine) {\n const w = g.widths.get(c);\n let r: Rect;\n if (w === undefined) r = rect(side === \"left\" ? x0 : x1, 0, 0, H);\n else if (side === \"left\") {\n r = rect(x0, 0, w, H);\n x0 += w;\n } else {\n x1 -= w;\n r = rect(x1, 0, w, H);\n }\n placedCols.push({ side, index: c.index, rect: r, width: c.width, min: c.min, max: c.max, folded: c.hand ? \"hand\" : g.auto.has(c) ? \"auto\" : null, shrunk: w !== undefined && w < c.width, kept: c.kept, panels: c.panels });\n if (w === undefined) continue;\n const bars = c.panels.filter((id) => folded.has(id)).length;\n const share = (H - bars * opt.bar) / (c.panels.length - bars);\n let y = 0;\n for (const id of c.panels) {\n const bar = folded.has(id);\n const h = bar ? opt.bar : share;\n items.set(id, { rect: rect(r.x, y, r.width, h), kind: bar ? \"bar\" : \"column\", layer: 0, hidden: false, folded: bar ? \"hand\" : null, kept: kept.has(id), pinned: false, side, column: c.index });\n y += h;\n }\n }\n }\n const pages = rect(x0, 0, Math.max(0, x1 - x0), H);\n if (pages.width < opt.pagesMin) notes.push({ code: \"pages-under-min\", width: pages.width, min: opt.pagesMin });\n\n // Floats, clamped unless free. A float's size is screen px in both spaces (never scaled); only an unpinned float's\n // position is in page space. The clamp keeps the SCREEN rect in the view: a pinned float where it is, an unpinned\n // one as it shows at pan 0, so it still scrolls with the page. In page units (k = the scale, 1 when pinned) a\n // screen interval [lo, hi] is [lo / k, hi / k].\n state.floats.forEach((f, i) => {\n if (closed.has(f.id)) return;\n const at = f.rect;\n const k = f.pinned ? 1 : opt.view.scale;\n const r = { ...at };\n if (opt.floats === \"clamp\") {\n const lim = floatSize(defOf(defs, f.id)).min;\n r.width = Math.max(lim.width, Math.min(r.width, W));\n r.height = Math.max(lim.height, Math.min(r.height, H));\n if (r.width !== at.width || r.height !== at.height) notes.push({ code: \"float-resized\", items: [f.id] });\n // Fits: wholly in the view. Too big even at its minimum: its title bar stays in, and `floatVisible` px of its width.\n 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);\n r.y = r.height <= H ? clamp(r.y, 0, (H - r.height) / k) : clamp(r.y, 0, (H - opt.bar) / k);\n if (r.x !== at.x || r.y !== at.y) notes.push({ code: \"float-clamped\", items: [f.id] });\n }\n const clamped = r.x !== at.x || r.y !== at.y || r.width !== at.width || r.height !== at.height;\n items.set(f.id, { rect: f.pinned ? r : toView(r, opt.view), kind: \"float\", layer: 10 + i, hidden: false, folded: null, kept: false, pinned: !!f.pinned, ...(clamped ? { clamped: true } : {}) });\n });\n\n return { items, columns: placedCols, rails, notes, pages };\n}\n","/**\n * The drop targets for dragging a panel, in the shape @n-uf/motion/drag takes (`{ id, priority, hit, slot?, free? }`),\n * worked out from the state with the panel lifted out:\n *\n * - `column:<side>:<i>` (priority 2): a band across the line between two columns (or a side's edge): a new column\n * there, as wide as the panel's own width.\n * - `into:<side>:<i>` (2): a column's area: the panel stacks at its bottom.\n * - `rail:<side>` (1): the side's rail, or its outer edge: the panel docks folded.\n * - `float` (3, free): anywhere; it floats where it is let go, kept in the view as the float option says.\n *\n * A place the panel may not take (its def's `sides` and `floats`, and `allows`) is no target, and neither is its own\n * place (a drop there changes nothing). Targets carry a structured `place`, never words: the consumer names them.\n */\nimport { rect, type Point, type Rect, type Size } from \"../geometry\";\nimport type { Target } from \"../targets/target\";\nimport { layoutPanels, type PanelsLayout } from \"./layout\";\nimport { DEFAULT_PANELS_OPTIONS, SIDES, defOf, dock, float, floatSize, liftPanel, ownWidth, samePlaces, toPage, whereIs, type PanelDef, type PanelsOptions, type PanelsState, type Side } from \"./model\";\n\n/** Where a drop puts a panel. `index` is a column index in the state with the panel lifted out. */\nexport type PanelPlace =\n | { readonly kind: \"column\"; readonly side: Side; readonly index: number }\n | { readonly kind: \"into\"; readonly side: Side; readonly index: number }\n | { readonly kind: \"rail\"; readonly side: Side }\n | { readonly kind: \"float\" };\n\nexport interface PanelTarget extends Target {\n /** The panel dragged. */\n readonly panel: string;\n readonly place: PanelPlace;\n /** Its rank in reading order (left to right across the stage, floating last). */\n readonly order: number;\n /** The state a drop here makes, with the pointer at `p` holding the panel at `grab` from its top-left corner. */\n readonly make: (p: Point, grab: Point) => PanelsState;\n}\n\nexport interface PanelTargetInput {\n readonly defs: readonly PanelDef[];\n /** The state as it is, the panel still in its place. */\n readonly state: PanelsState;\n readonly id: string;\n readonly stage: Size;\n readonly options?: Partial<PanelsOptions>;\n /** Places the panel may go beyond its def's rules (default: all of them). */\n readonly allows?: (id: string, place: PanelPlace) => boolean;\n}\n\n/** How far a column band reaches on each side of its line, px; how wide a side's edge takes a rail drop when it has no rail. */\nexport const COLUMN_REACH = 22;\nexport const RAIL_EDGE = 10;\n\n/** A place's rank in reading order: the left side outer to inner, the right side inner to outer, floating last. */\nexport function placeRank(place: PanelPlace): number {\n switch (place.kind) {\n case \"float\":\n return 3000;\n case \"rail\":\n return place.side === \"left\" ? 0 : 1999;\n case \"column\":\n return place.side === \"left\" ? 1 + 2 * place.index : 1998 - 2 * place.index;\n case \"into\":\n return place.side === \"left\" ? 2 + 2 * place.index : 1997 - 2 * place.index;\n }\n}\n\n/** Where a panel is now, as a place (a float, a column of its own, or stacked in one); null when placed nowhere. */\nexport function homePlace(state: PanelsState, id: string): PanelPlace | null {\n const w = whereIs(state, id);\n if (w.kind === \"float\") return { kind: \"float\" };\n if (w.kind === \"none\") return null;\n 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 };\n}\n\nconst cut = (x0: number, x1: number, lo: number, hi: number): [number, number] => [Math.max(x0, lo), Math.min(x1, hi)];\n\n/** The targets for dragging `input.id`, in reading order. */\nexport function panelTargets(input: PanelTargetInput): PanelTarget[] {\n const { defs, state, id, stage } = input;\n const opt: PanelsOptions = { ...DEFAULT_PANELS_OPTIONS, ...input.options };\n const def = defOf(defs, id);\n const s0 = liftPanel(state, id);\n const l0 = layoutPanels(defs, s0, stage, opt);\n const width = ownWidth(defs, state, id);\n const W = stage.width;\n const H = stage.height;\n const R = COLUMN_REACH;\n const out: PanelTarget[] = [];\n const add = (place: PanelPlace, priority: 1 | 2 | 3, hit: Rect, make: PanelTarget[\"make\"], free = false): void => {\n if (hit.width <= 0 || hit.height <= 0) return;\n if (input.allows && !input.allows(id, place)) return;\n // Its own place: a drop there changes nothing, so it is no target (the drag's home covers it).\n // Widths compare as laid out: a stored width past the column's limits is the same place as the limit.\n if (place.kind !== \"float\" && samePlaces(make({ x: 0, y: 0 }, { x: 0, y: 0 }), state, defs)) return;\n out.push({ id: place.kind === \"float\" ? \"float\" : place.kind === \"rail\" ? `rail:${place.side}` : `${place.kind}:${place.side}:${place.index}`, priority, hit, panel: id, place, order: placeRank(place), make, ...(free ? { free: true } : {}) });\n };\n\n for (const side of SIDES) {\n if (def?.sides && !def.sides.includes(side)) continue;\n const left = side === \"left\";\n const rail = l0.rails[side];\n const edge = rail ? rail.rect.width : RAIL_EDGE;\n // The rail (or the bare edge): dock folded, as the outermost column.\n const railHit = rail ? rail.rect : left ? rect(0, 0, RAIL_EDGE, H) : rect(W - RAIL_EDGE, 0, RAIL_EDGE, H);\n add({ kind: \"rail\", side }, 1, railHit, () => {\n const s = dock(state, id, side, 0, { width });\n return { ...s, folded: [...s.folded.filter((x) => x !== id), id] };\n });\n // The lines between the open columns, outer to inner, and each column's area.\n const open = l0.columns.filter((c) => c.side === side && c.folded === null);\n const lo = left ? edge : 0;\n const hi = left ? W : W - edge;\n const band = (x: number, outer: boolean, i: number): void => {\n // The outermost line reaches inward only: outward is the rail's.\n 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);\n add({ kind: \"column\", side, index: i }, 2, rect(a, 0, b - a, H), () => dock(state, id, side, i, { width }));\n };\n if (open.length === 0) band(left ? l0.pages.x : l0.pages.x + l0.pages.width, true, s0.sides[side].length);\n open.forEach((c, k) => {\n band(left ? c.rect.x : c.rect.x + c.rect.width, k === 0, c.index);\n add({ kind: \"into\", side, index: c.index }, 2, c.rect, () => dock(state, id, side, c.index, { into: true }));\n });\n const last = open.at(-1);\n if (last) band(left ? last.rect.x + last.rect.width : last.rect.x, false, last.index + 1);\n }\n\n if (def?.floats !== false) {\n const was = state.floats.find((f) => f.id === id);\n const size = was ? { width: was.rect.width, height: was.rect.height } : floatSize(def).natural;\n const pinned = !!was?.pinned;\n add(\n { kind: \"float\" },\n 3,\n rect(0, 0, W, H),\n (p, grab) => {\n // Let go at p (view space); stored where it shows once the float option has had its say.\n const at = rect(p.x - grab.x, p.y - grab.y, size.width, size.height);\n const s = float(state, id, pinned ? at : toPage(at, opt.view), pinned);\n const shown = layoutPanels(defs, s, stage, opt).items.get(id)!.rect;\n return float(state, id, pinned ? shown : toPage(shown, opt.view), pinned);\n },\n true,\n );\n }\n return out.sort((a, b) => a.order - b.order);\n}\n\n/** A target's drop, laid out: where the panel lands. */\nexport interface PanelDrop {\n readonly target: string;\n readonly place: PanelPlace;\n /** Same key, same place (a float's key carries where it lands). */\n readonly key: string;\n readonly state: PanelsState;\n readonly layout: PanelsLayout;\n /** Where the panel lands (its rail segment when it docks folded). */\n readonly slot: Rect;\n /** It lands in a rail. */\n readonly hidden: boolean;\n /** It floats where it is let go: no room is made for it. */\n readonly free: boolean;\n}\n\n/** The drop on `target` with the pointer at `p` holding the panel at `grab`, laid out. */\nexport function panelDrop(input: PanelTargetInput, target: PanelTarget, p: Point, grab: Point): PanelDrop {\n const opt: PanelsOptions = { ...DEFAULT_PANELS_OPTIONS, ...input.options };\n const state = target.make(p, grab);\n const layout = layoutPanels(input.defs, state, input.stage, opt);\n const placed = layout.items.get(input.id)!;\n const key = target.free ? `float:${Math.round(placed.rect.x)},${Math.round(placed.rect.y)}` : target.id;\n return { target: target.id, place: target.place, key, state, layout, slot: placed.rect, hidden: placed.hidden, free: !!target.free };\n}\n\n// --- keyboard stops ------------------------------------------------------------------------------------------------\n\nexport interface PanelStop {\n /** The target's id (\"home\" for the panel's own place). */\n readonly id: string;\n readonly place: PanelPlace;\n /** The state a move here makes (the current one for home). */\n readonly state: PanelsState;\n readonly home: boolean;\n}\n\nexport interface PanelStopsOptions {\n /** The panel's own place (`homePlace`) and the state as it is: a stop of its own in its reading-order position. */\n readonly home?: { readonly place: PanelPlace; readonly state: PanelsState };\n /** Floating as a stop at the end (default: left out); `at` and `grab` as for a drop (default: the stage's middle, the corner). */\n readonly floats?: boolean | { readonly at: Point; readonly grab?: Point };\n}\n\n/** The panel's places in reading order, for the arrow keys and a \"Move to\" menu (`keyboardStops` calls this). */\nexport function panelStops(targets: readonly PanelTarget[], options: PanelStopsOptions = {}): PanelStop[] {\n const stops: (PanelStop & { order: number })[] = [];\n for (const t of targets) {\n if (t.place.kind === \"float\") {\n if (!options.floats) continue;\n const at = options.floats === true ? { x: t.hit.x + t.hit.width / 2, y: t.hit.y + t.hit.height / 2 } : options.floats.at;\n const grab = options.floats === true ? { x: 0, y: 0 } : (options.floats.grab ?? { x: 0, y: 0 });\n stops.push({ id: t.id, place: t.place, state: t.make(at, grab), home: false, order: t.order });\n continue;\n }\n stops.push({ id: t.id, place: t.place, state: t.make({ x: 0, y: 0 }, { x: 0, y: 0 }), home: false, order: t.order });\n }\n const h = options.home;\n // A float's home sits with the floats: last, after any float stop.\n 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) });\n return stops.sort((a, b) => a.order - b.order).map(({ order: _order, ...s }) => s);\n}\n"],"mappings":"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","names":["float","rect","f","open"]}