@n-uf/placement 26.11.11 → 26.11.13
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 +56 -0
- package/README.md +158 -0
- package/dist/desk.d.ts +2 -1
- package/dist/panels.d.ts +3 -2
- package/dist/stack.d.ts +351 -0
- package/dist/stack.js +491 -0
- package/dist/stack.js.map +1 -0
- package/dist/target-D3PiLg44.d.ts +17 -0
- package/dist/{targets-B_U2Zf7x.d.ts → targets-B6eLC-52.d.ts} +2 -15
- package/dist/targets.d.ts +2 -1
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,62 @@
|
|
|
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.13
|
|
7
|
+
|
|
8
|
+
- `@n-uf/placement/stack`, floats (new exports; `fitStack`, `stackTargets` and the stack's stored form are unchanged, and
|
|
9
|
+
so are `./panels`, `./dock` and `./desk`). A float is an item above the pages, in the stage's own px (view space), so
|
|
10
|
+
the pages scrolling under it never move it; it has no pinned flag.
|
|
11
|
+
- `fitFloat(rect, stage, avoid?)`: the float's rect moved (never resized) inside the stage, then beside the docked
|
|
12
|
+
items it would cover, at the nearest clear place; `FloatFit` has `rect`, `clamped` (also when a position that wasn't a
|
|
13
|
+
number was replaced), `snapped`, `covers` (indexes into `avoid` it still covers; empty whenever a clear place exists,
|
|
14
|
+
which it finds, and not empty only when the stage has none) and `searchCapped`. A float larger than the stage keeps
|
|
15
|
+
its top-left corner on the stage's. The x's are tried nearest first and, for each, the stretches of y the rects
|
|
16
|
+
block are merged and skipped. Measured in a test run on a laptop: about 100 `avoid` rects 0.1 ms, 300 a few ms even
|
|
17
|
+
when no place is clear (6 ms median, 15 ms worst), 1,000 about 17 ms. A safety net stops the clear search after 3
|
|
18
|
+
million rect tests and sets `searchCapped` (the place found may then not be the nearest, or a clear place may exist that was not found); with no clear place
|
|
19
|
+
the least covered among the 2,048 nearest places is used.
|
|
20
|
+
- `stackFloatTarget({ id, stage, size, avoid?, label? })`: a free, priority 3 drop target in the shape
|
|
21
|
+
`@n-uf/motion/drag` takes, `kind: "float"`, id `float:<id>` (so it can't collide with `./desk`'s `"float"`; the
|
|
22
|
+
toolbar `floatTarget` in `./targets` keeps its name), whose `hit` covers the whole plane, so a pointer past the
|
|
23
|
+
stage's edge still hits it. `make(point, grab?)` gives the float's rect (clamped, clear of the docked items) for the
|
|
24
|
+
preview and for the drop: one answer, so a drop past the edge lands clamped and never cancels. A gap's `hit`
|
|
25
|
+
thinner than 8 px (twice the intent's 4 px breakthrough) can't take over from it.
|
|
26
|
+
- `storeFloats` / `readFloats`: `{ v: 1, floats: [{ id, x, y, width, height }] }` in stacking order; never throws,
|
|
27
|
+
drops what it can't use and lists it in `dropped`. `storeFloats` leaves out a float with a zero size or a bad number,
|
|
28
|
+
and of a repeated id keeps the last readable entry (the one on top); `readFloats` does the same and words a bad
|
|
29
|
+
version as the stack's reader does. It writes no `pinned`; one an old store has is read and ignored (listed as
|
|
30
|
+
`pinned:<id>`), and the float loads as a plain float.
|
|
31
|
+
- Exports: `fitFloat`, `stackFloatTarget`, `storeFloats`, `readFloats` and the types `StackFloat`, `FloatFit`,
|
|
32
|
+
`FloatTarget`, `StackFloatTargetInput`, `FloatDrop`, `StoredFloats`, `FloatsRead`.
|
|
33
|
+
|
|
34
|
+
## 26.11.12
|
|
35
|
+
|
|
36
|
+
- New entry `@n-uf/placement/stack`: the items along one edge of a stage (a column or a row), each a panel or a control
|
|
37
|
+
group with forms from largest to smallest. Pure, and not tied to `./panels` columns; `./panels`, `./dock` and `./desk`
|
|
38
|
+
are unchanged.
|
|
39
|
+
- `fitStack(input)`: one form, kind and rect per item. Every item starts in its largest form, or at `StackItem.from`.
|
|
40
|
+
While the smallest sizes don't fit the length, the item used longest ago (unkept before `kept`, the later in the
|
|
41
|
+
stack on a tie) takes its next form, panel `open` → `header` → `rail` → `menu`, group `row` → `stacked` → `icons`
|
|
42
|
+
→ `menu`; it doesn't go into the menu when that only lengthens a stack nothing else can shorten (`overflow`).
|
|
43
|
+
Spare length goes to the forms that `grows`, shared by their natural sizes. The stack's cross size is the widest
|
|
44
|
+
form that `setsCross` (a panel's `open`, by default), clamped, else the rail width (30).
|
|
45
|
+
- Cross-fit: a form that doesn't set the cross size and whose `cross.min` (default `cross.natural`) is over the
|
|
46
|
+
stack's takes its next form: a group alone is a rail of icons, a column with nothing open shrinks to a rail, and a
|
|
47
|
+
header with a small `cross.min` stays in a narrower column. It never steps an item into the menu: the item keeps
|
|
48
|
+
its last drawn form and a `too-wide` note says so. An item with no forms is left out (`no-forms`).
|
|
49
|
+
- Result: `items` (`form` and `from`/`to` in notes are indexes into the item's forms), `cross`, `menu` (the » entry's
|
|
50
|
+
rect and the ids in it) and coded `notes` (`form-down`, `to-menu`, `too-wide`, `no-forms`, `overflow`).
|
|
51
|
+
- `stackTargets(input, dragged)`: a drop target for every gap (before each item and after the last; the dragged id is
|
|
52
|
+
lifted out of the input first), in the shape `@n-uf/motion/drag` takes: `gap:<k>`, priority 2, `place`, `hit` (split
|
|
53
|
+
at the items' middles, across as wide as the larger of the stack and the drop's fit), `slot`, `marker` and the full
|
|
54
|
+
`fit` of the stack with the item inserted, so the preview is exactly the rect after the drop. `place.at` counts the
|
|
55
|
+
input's items, not `fit.items` (which leaves out an item with no forms): look the dragged item up in it by id.
|
|
56
|
+
- `storeStack` / `readStack` (`{ v: 1, order, kept, closed, used, forms }`): never throws, drops what it can't use
|
|
57
|
+
(including the `__proto__` key in `forms`, an object with no prototype) and lists it; an id listed twice in `used`
|
|
58
|
+
counts at its last place.
|
|
59
|
+
- Exports: `fitStack`, `stackTargets`, `withItem`, `formSetsCross`, `storeStack`, `readStack`, `createStack`,
|
|
60
|
+
`DEFAULT_RAIL`, `DEFAULT_MENU` and their types (`StackAxis`, `StackForm`, `StackItem`, `StackInput`, `StackFit`, …).
|
|
61
|
+
|
|
6
62
|
## 26.11.11
|
|
7
63
|
|
|
8
64
|
- `@n-uf/placement/panels`, drops into a stacked column at a position (opt-in; without it every target is what it was):
|
package/README.md
CHANGED
|
@@ -40,6 +40,11 @@ without importing each other: a target list from `@n-uf/placement/targets` is ex
|
|
|
40
40
|
room kept clear for a toolbar the app draws; their drop targets; and a stored form.
|
|
41
41
|
- **`/desk`**: desk presets (`docks`, `docksFull`, `dockTear`, `navigator`) as data on `/panels`: options and a
|
|
42
42
|
start state.
|
|
43
|
+
- **`/stack`**: the items along one edge, a column or a bar, each a panel or a control group with forms from largest to
|
|
44
|
+
smallest (open, header, rail icon, » menu; row, stacked, icons, » menu): one form and rect per item, giving way by
|
|
45
|
+
age, spare room to the panels that grow, a rail when nothing open sets the width; a drop target for every gap, each
|
|
46
|
+
with the exact solve a drop makes; a stored form; and floats (an item above the pages, in the stage's own px, kept
|
|
47
|
+
inside the stage and clear of the docked items, with its drop target and stored form). Not tied to `/panels`.
|
|
43
48
|
|
|
44
49
|
Rendering stays in the app: it draws the rects, measures its groups, and feeds pointer samples to a drag intent.
|
|
45
50
|
|
|
@@ -402,6 +407,159 @@ console.log(targets.some((t) => t.id === "float")); // false
|
|
|
402
407
|
the same way, offering only the places the preset allows (`presetInput` gives that input). `./dock` stays as it is for
|
|
403
408
|
now.
|
|
404
409
|
|
|
410
|
+
## Edge stacks
|
|
411
|
+
|
|
412
|
+
`@n-uf/placement/stack` lays out the items along one edge of a stage: a column (`axis: "column"`, a side region) or a
|
|
413
|
+
row (`"row"`, a bar). An item is a panel or a control group and declares its forms, largest first. Each form has a
|
|
414
|
+
structural `kind` (a panel's `open`, `header`, `rail`, `menu`; a group's `row`, `stacked`, `icons`, `menu`), a `main`
|
|
415
|
+
size along the stack (`min`, `natural`, `grows`) and a `cross` size. `fitStack(input)` picks one form per item and
|
|
416
|
+
places them; it is not tied to `./panels` columns, and nothing in it is a word.
|
|
417
|
+
|
|
418
|
+
- Every item starts in its largest form, or at `from` (an index into its forms; a panel the user folded by hand
|
|
419
|
+
starts at its header). While the smallest sizes don't fit the `length`, the item used longest ago (`used`: the
|
|
420
|
+
smaller, the older) takes its next form; unkept before `kept`, the later in the stack first on a tie. It keeps giving
|
|
421
|
+
way until its forms end, then the next item does. A `menu` form takes no room: the » entry does (`menu.main`,
|
|
422
|
+
default 28 px), while any item is in it; an item doesn't go into the menu when that only makes the stack longer and
|
|
423
|
+
nothing else can give way (`overflow`).
|
|
424
|
+
- Spare length goes to the forms that `grows`, shared by their natural sizes. With none, the items keep their
|
|
425
|
+
natural sizes from the start of the stack.
|
|
426
|
+
- The stack's cross size is the widest `cross.natural` among the forms that set it (a panel's `open`, by default;
|
|
427
|
+
`setsCross` overrides), clamped to `cross.min` and `max`. With none it is the rail, `cross.rail` (default 30 px).
|
|
428
|
+
- Cross-fit: a form that doesn't set the cross size and whose `cross.min` (default its `natural`) is over the stack's
|
|
429
|
+
takes its next form, so a group alone is a rail of icons and a column with nothing open shrinks to a rail. Give a
|
|
430
|
+
header a small `cross.min` and it stays in a column an open panel made narrower. Cross size never puts an item in
|
|
431
|
+
the menu: an item that is still too wide in its last drawn form keeps it, and `too-wide` says so (the app clips it).
|
|
432
|
+
Cross-fit and give-way repeat until nothing changes, because a panel folding can narrow the column.
|
|
433
|
+
- The solver has no open or closed state: it lays out the items it is given. An item with no forms is left out
|
|
434
|
+
(`no-forms`). Panel and group kinds may be mixed on one item; only `menu` and `open` mean anything to the solver.
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
import { fitStack, readStack, stackTargets, storeStack, type StackForm, type StackItem } from "@n-uf/placement/stack";
|
|
438
|
+
|
|
439
|
+
const form = (kind: StackForm["kind"], min: number, natural: number, cross: number, grows = false, crossMin?: number): StackForm => ({
|
|
440
|
+
kind,
|
|
441
|
+
main: { min, natural, ...(grows ? { grows } : {}) },
|
|
442
|
+
cross: { natural: cross, ...(crossMin === undefined ? {} : { min: crossMin }) },
|
|
443
|
+
});
|
|
444
|
+
const panel = (id: string, used: number): StackItem => ({
|
|
445
|
+
id,
|
|
446
|
+
used,
|
|
447
|
+
forms: [form("open", 90, 160, 240, true), form("header", 28, 28, 240, false, 100), form("rail", 24, 24, 30), form("menu", 0, 0, 0)],
|
|
448
|
+
});
|
|
449
|
+
const tools: StackItem = { id: "tools", used: 3, forms: [form("row", 96, 96, 180), form("stacked", 78, 78, 84), form("icons", 72, 72, 28), form("menu", 0, 0, 0)] };
|
|
450
|
+
const column = { axis: "column", length: 250, cross: { min: 120, max: 360 } } as const;
|
|
451
|
+
|
|
452
|
+
const fit = fitStack({ ...column, items: [panel("pages", 1), panel("findings", 2), tools] });
|
|
453
|
+
console.log(fit.items.map((p) => p.kind), fit.cross, fit.notes);
|
|
454
|
+
// [ 'header', 'open', 'row' ] 240 [ { code: 'form-down', id: 'pages', from: 0, to: 1 } ]
|
|
455
|
+
|
|
456
|
+
const alone = fitStack({ ...column, items: [tools] });
|
|
457
|
+
console.log(alone.items[0]!.kind, alone.cross); // icons 30
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
The result has, per item, `form` (an index into its forms), `kind` and `rect` (stack-local px: the stack starts at
|
|
461
|
+
0, 0); `cross`, the stack's size across; `menu` (the » entry's `rect` and the ids in it, or `null`; an item in the
|
|
462
|
+
menu has the entry's rect; `menu.items` are exactly the items whose kind is `menu`); and coded `notes`: `form-down`
|
|
463
|
+
(`id`, `from`, `to`: the item took a smaller form than the one it started in, by length or by cross size, as indexes
|
|
464
|
+
into its forms), `to-menu` (`id`), `too-wide` (`id`), `no-forms` (`id`) and `overflow` (`over` px: no item can give
|
|
465
|
+
more way and the stack is still too long; forms that don't end in a `menu` form can't give more).
|
|
466
|
+
|
|
467
|
+
`stackTargets(input, dragged)` takes the stack (an item of it with the dragged id is lifted out first, so a reorder
|
|
468
|
+
within a stack works) and gives a target for every gap, before each item and after the last, in the shape
|
|
469
|
+
`@n-uf/motion/drag` takes: `id` `gap:<k>`, priority 2, `place` `{ kind: "gap", at: k }`, `hit` (the stack split at
|
|
470
|
+
its items' middles, as wide across as the larger of the stack and the drop's fit; with every item in the menu only
|
|
471
|
+
the last gap has any length) and `slot`, the rect the dragged item gets.
|
|
472
|
+
`fit` is the full solve with the item inserted at k (`input` the stack that was solved), so the preview is exactly the
|
|
473
|
+
rect after the drop; `marker` is the line where the item's leading edge lands (a rect with no thickness across the
|
|
474
|
+
stack). The dragged item counts as just used, so the others give way before it, and a group lands in the form that
|
|
475
|
+
fits.
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
const targets = stackTargets({ ...column, items: [panel("pages", 1), panel("findings", 2)] }, tools);
|
|
479
|
+
console.log(targets.map((t) => t.id), targets[1]!.slot, targets[1]!.fit.items[1]!.kind);
|
|
480
|
+
// [ 'gap:0', 'gap:1', 'gap:2' ] { x: 0, y: 28, width: 240, height: 96 } row (Pages folds to its header to make room)
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
`storeStack(state)` and `readStack(data, known?)` keep what the user chose, as `{ v: 1, … }`: `order`, `kept`,
|
|
484
|
+
`closed`, `used` (the use order, oldest first, so a reload restores who gives way first) and `forms` (the largest form
|
|
485
|
+
index each item may take, `StackItem.from`; stored only from 1). Reading never throws: anything but an object of
|
|
486
|
+
version 1 is `{ ok: false, error }`; inside one, an id that isn't a string, repeats or (with `known`) isn't one the
|
|
487
|
+
consumer has, a `kept`, `closed`, `used` or `forms` entry for an item not in `order`, a form that isn't a whole number
|
|
488
|
+
from 1, the key `__proto__` in `forms` (`forms` is an object with no prototype; `constructor` and `prototype` are ids
|
|
489
|
+
like any other), and a field this version doesn't know are dropped and listed in `dropped`. An id listed twice in
|
|
490
|
+
`used` counts at its last place (the newest use wins).
|
|
491
|
+
|
|
492
|
+
```ts
|
|
493
|
+
const saved = JSON.stringify(storeStack({ order: ["pages", "tools"], kept: ["pages"], closed: [], used: ["pages", "tools"], forms: { tools: 1 } }));
|
|
494
|
+
console.log(saved); // {"v":1,"order":["pages","tools"],"kept":["pages"],"closed":[],"used":["pages","tools"],"forms":{"tools":1}}
|
|
495
|
+
console.log(readStack(JSON.parse(saved), ["pages", "tools", "findings"]).ok, readStack({ v: 2 }).ok); // true false
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Floats
|
|
499
|
+
|
|
500
|
+
An item that isn't docked is a float. It lies above the pages in the stage's own px (view space), so the pages scrolling
|
|
501
|
+
under it never move it, and it has no pinned flag: there is one kind of float, `{ id, rect }`. `./stack` keeps floats
|
|
502
|
+
apart from the stacks (an item is in a stack's order or in the floats, the app's choice) and offers three parts, all
|
|
503
|
+
pure.
|
|
504
|
+
|
|
505
|
+
- `fitFloat(rect, stage, avoid?)` gives the rect a float gets: moved (never resized) to lie inside the `stage`, then
|
|
506
|
+
beside any of the `avoid` rects (the docked items' rects, and the » entries', in the same px) it would cover, at the
|
|
507
|
+
nearest place that is clear and inside the stage. A float larger than the stage keeps its top-left corner on the
|
|
508
|
+
stage's. A clear place is found whenever one exists, and then `covers` is empty. Only when the stage has no clear
|
|
509
|
+
place for it, the float stays where it covers the least (among the 2,048 nearest candidate places) and `covers` lists
|
|
510
|
+
the `avoid` indexes it still covers. `FloatFit`: `rect`, `clamped` (also true when a position that wasn't a number was
|
|
511
|
+
replaced), `snapped`, `covers`, `searchCapped`. Fit the floats again whenever the stacks or the stage change: a stack
|
|
512
|
+
that grew may lie under one.
|
|
513
|
+
Cost: the candidate x's (every edge of the stage and of an `avoid` rect) are tried nearest first; for each, the
|
|
514
|
+
stretches of y the rects block are merged and skipped, so no clear place is missed however many lie between, and the
|
|
515
|
+
search stops when no later x can be nearer. Measured in a test run on a laptop: about 100 `avoid` rects 0.1 ms, 300
|
|
516
|
+
a few ms even when no place is clear (6 ms median, 15 ms worst), 1,000 about 17 ms. A safety net stops the clear
|
|
517
|
+
search after 3 million rect tests (thousands of rects) and sets `searchCapped`: the place found may then not be the
|
|
518
|
+
nearest, or a clear place may exist that was not found. Keep `avoid` to the docked items, not to every pixel.
|
|
519
|
+
- `stackFloatTarget({ id, stage, size, avoid?, label? })` is a drop target in the shape `@n-uf/motion/drag` takes: `id`
|
|
520
|
+
`float:<id>` (not `"float"`, which `./desk` uses) and `kind: "float"`, priority 3 (a stack's gaps, priority 2, win
|
|
521
|
+
where they are), `free` (no room is made for it) and a `hit` that covers the whole plane, so a pointer past the
|
|
522
|
+
stage's edge, above, below or beside it, still hits it and a float drop never cancels. `make(point, grab?)` is the one
|
|
523
|
+
answer for the preview and the drop: the float's rect with the pointer at `point` holding it at `grab` (its offset in
|
|
524
|
+
the float; default the middle), run through `fitFloat`. Draw `make(...).rect` as the preview, and land the float on
|
|
525
|
+
the same call at the release. The intent lets a higher priority target take over from the current one only when the
|
|
526
|
+
pointer is `breakthrough` px (4) inside it, so a gap zone thinner than 8 px (2 × the breakthrough) along either axis
|
|
527
|
+
can never take over from the float target: give the gaps' `hit` at least that much room (the lab widens a thin
|
|
528
|
+
stack's zone across, and the first and last gap's past the stack's ends).
|
|
529
|
+
- `storeFloats(floats)` and `readFloats(data, known?)`: `{ v: 1, floats: [{ id, x, y, width, height }] }`, in stacking
|
|
530
|
+
order (the last is on top). It writes no `pinned`. `storeFloats` leaves out, silently, a float whose position isn't a
|
|
531
|
+
finite number or whose size isn't over 0, and keeps the last readable entry of a repeated id (the one on top, at its
|
|
532
|
+
own place in the order). Reading never throws: anything but an object of version 1 with a `floats` array is
|
|
533
|
+
`{ ok: false, error }` (the version worded as the stack's reader words it, a string quoted); inside one, a float that
|
|
534
|
+
isn't an object, has no string id, isn't one the consumer has (with `known`) or has a position that isn't a finite
|
|
535
|
+
number or a size that isn't over 0 is dropped and listed in `dropped` as `float:<id>`; of a repeated id the last
|
|
536
|
+
readable entry stays and the earlier ones are listed the same way; a field this version doesn't know is listed as
|
|
537
|
+
`"<field>"` (a float's own as `float:<id>:<field>`). A `pinned` key, which an older store may have, is read and
|
|
538
|
+
ignored: the float loads as a plain float, at the rect it was stored with, and `pinned:<id>` is listed.
|
|
539
|
+
|
|
540
|
+
```ts
|
|
541
|
+
import { fitFloat, readFloats, stackFloatTarget, storeFloats } from "@n-uf/placement/stack";
|
|
542
|
+
|
|
543
|
+
const stage = { x: 0, y: 0, width: 900, height: 500 };
|
|
544
|
+
const docked = [{ x: 0, y: 32, width: 240, height: 468 }]; // a column of docked items, in the stage's px
|
|
545
|
+
|
|
546
|
+
const fit = fitFloat({ x: 100, y: 200, width: 200, height: 150 }, stage, docked);
|
|
547
|
+
console.log(fit.rect, fit.snapped); // { x: 240, y: 200, width: 200, height: 150 } true
|
|
548
|
+
|
|
549
|
+
const target = stackFloatTarget({ id: "notes", stage, size: { width: 200, height: 150 }, avoid: docked });
|
|
550
|
+
const drop = target.make({ x: 500, y: -400 }, { x: 20, y: 10 }); // the pointer is above the stage
|
|
551
|
+
console.log(drop.rect, drop.fit.clamped); // { x: 480, y: 0, width: 200, height: 150 } true
|
|
552
|
+
|
|
553
|
+
console.log(JSON.stringify(storeFloats([{ id: "notes", rect: drop.rect }]))); // {"v":1,"floats":[{"id":"notes","x":480,"y":0,"width":200,"height":150}]}
|
|
554
|
+
const old = readFloats({ v: 1, floats: [{ id: "notes", x: 480, y: 0, width: 200, height: 150, pinned: true }] });
|
|
555
|
+
console.log(old.ok && old.dropped); // [ 'pinned:notes' ]
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Freezing the layout needs nothing from the library: the freeze is the app's flag, and the app reads it once at the press.
|
|
559
|
+
A press on a grip while frozen (and Alt not held) never becomes a drag, so no target is built and nothing is dropped;
|
|
560
|
+
holding Alt shows the grips and everything works, a drag that began finishes. `fitStack` reads sizes, not what an item
|
|
561
|
+
says, so a count or a phase that leaves its forms' sizes alone moves no other item.
|
|
562
|
+
|
|
405
563
|
## Pane zones
|
|
406
564
|
|
|
407
565
|
`paneZone(rect, point, previous, options?)` says which of a pane's five zones a point is in: the centre rectangle
|
package/dist/desk.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { P as PanelsOptions, a as PanelDef, b as PanelsState, c as PanelTargetInput, d as PanelTarget, p as panelDrop, e as PanelDrop, l as layoutPanels, f as PanelsLayout } from './targets-
|
|
1
|
+
import { P as PanelsOptions, a as PanelDef, b as PanelsState, c as PanelTargetInput, d as PanelTarget, p as panelDrop, e as PanelDrop, l as layoutPanels, f as PanelsLayout } from './targets-B6eLC-52.js';
|
|
2
2
|
import './geometry-mL-GTRti.js';
|
|
3
|
+
import './target-D3PiLg44.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @n-uf/placement/desk: desk presets as data on `@n-uf/placement/panels`. A preset is options for the panels engine
|
package/dist/panels.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { b as PanelsState, S as Side, E as Edge, C as Clock, a as PanelDef } from './targets-
|
|
2
|
-
export { B as BAND_SIZE, g as Band, h as BandOption, i as COLUMN_REACH, j as Column, D as DEFAULT_PANELS_OPTIONS, k as DockOptions, m as EDGES, F as FLOAT_HEIGHT, n as FLOAT_MIN, o as FloatAt, G as GiveWay, I as IDENTITY_VIEW, e as PanelDrop, q as PanelKind, r as PanelPlace, s as PanelStop, t as PanelStopsOptions, d as PanelTarget, c as PanelTargetInput, f as PanelsLayout, u as PanelsNote, v as PanelsNoteCode, P as PanelsOptions, w as PanelsStart, x as Place, y as PlacedBand, z as PlacedColumn, A as PlacedPanel, H as PlacedRail, R as RAIL_EDGE, J as Reserve, K as ReserveEdge, L as SIDES, V as View, W as Where, M as activate, N as bandHeight, O as bandSize, Q as close, T as columnWidth, U as createPanels, X as defOf, Y as dock, Z as dockBand, _ as float, $ as floatSize, a0 as focus, a1 as giveWayOrder, a2 as homePlace, a3 as keep, l as layoutPanels, a4 as liftPanel, a5 as open, a6 as ownWidth, p as panelDrop, a7 as panelStops, a8 as panelTargets, a9 as pin, aa as placeRank, ab as resizeBand, ac as resizeColumn, ad as resizeFloat, ae as samePlaces, af as showTabs, ag as tick, ah as toPage, ai as toView, aj as toggleFold, ak as whereIs } from './targets-
|
|
1
|
+
import { b as PanelsState, S as Side, E as Edge, C as Clock, a as PanelDef } from './targets-B6eLC-52.js';
|
|
2
|
+
export { B as BAND_SIZE, g as Band, h as BandOption, i as COLUMN_REACH, j as Column, D as DEFAULT_PANELS_OPTIONS, k as DockOptions, m as EDGES, F as FLOAT_HEIGHT, n as FLOAT_MIN, o as FloatAt, G as GiveWay, I as IDENTITY_VIEW, e as PanelDrop, q as PanelKind, r as PanelPlace, s as PanelStop, t as PanelStopsOptions, d as PanelTarget, c as PanelTargetInput, f as PanelsLayout, u as PanelsNote, v as PanelsNoteCode, P as PanelsOptions, w as PanelsStart, x as Place, y as PlacedBand, z as PlacedColumn, A as PlacedPanel, H as PlacedRail, R as RAIL_EDGE, J as Reserve, K as ReserveEdge, L as SIDES, V as View, W as Where, M as activate, N as bandHeight, O as bandSize, Q as close, T as columnWidth, U as createPanels, X as defOf, Y as dock, Z as dockBand, _ as float, $ as floatSize, a0 as focus, a1 as giveWayOrder, a2 as homePlace, a3 as keep, l as layoutPanels, a4 as liftPanel, a5 as open, a6 as ownWidth, p as panelDrop, a7 as panelStops, a8 as panelTargets, a9 as pin, aa as placeRank, ab as resizeBand, ac as resizeColumn, ad as resizeFloat, ae as samePlaces, af as showTabs, ag as tick, ah as toPage, ai as toView, aj as toggleFold, ak as whereIs } from './targets-B6eLC-52.js';
|
|
3
3
|
import { R as Rect } from './geometry-mL-GTRti.js';
|
|
4
|
+
import './target-D3PiLg44.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The panels' stored form: `storePanels(state)` gives plain JSON-safe data (`{ v: 1, … }`); `readPanels(data, defs?)`
|
package/dist/stack.d.ts
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { R as Rect, P as Point, S as Size } from './geometry-mL-GTRti.js';
|
|
2
|
+
import { T as Target } from './target-D3PiLg44.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The edge stack's shapes. A stack is the items along one edge of a stage: a column (vertical, a side region) or a
|
|
6
|
+
* row (horizontal, a bar). An item is a panel or a control group; it declares its forms, largest first, and the
|
|
7
|
+
* solver (`fitStack`) picks one per item. Plain data in and out: no words, no time, no DOM.
|
|
8
|
+
*
|
|
9
|
+
* The form kinds are structural labels the app draws by; the solver reads only `menu` (a form with no room of its own)
|
|
10
|
+
* and, for the cross size, `open`. Panel and group kinds may be mixed on one item.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** `"column"` runs the stack down (its main size is a height, its cross size a width); `"row"` runs it across. */
|
|
14
|
+
type StackAxis = "column" | "row";
|
|
15
|
+
/** How a panel draws: open (header and body), a header only, a rail icon, or an entry in the » menu. */
|
|
16
|
+
type PanelFormKind = "open" | "header" | "rail" | "menu";
|
|
17
|
+
/** How a control group draws: a row of words, the words stacked, icons only, or an entry in the » menu. */
|
|
18
|
+
type GroupFormKind = "row" | "stacked" | "icons" | "menu";
|
|
19
|
+
type StackFormKind = PanelFormKind | GroupFormKind;
|
|
20
|
+
/** Along the stack: `min` is the least it can be drawn, `natural` what it asks for; `grows` takes spare length. */
|
|
21
|
+
interface MainSize {
|
|
22
|
+
readonly min: number;
|
|
23
|
+
readonly natural: number;
|
|
24
|
+
readonly grows?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** One way to draw an item. A `menu` form takes no room in the stack (the » entry stands for it). */
|
|
27
|
+
interface StackForm {
|
|
28
|
+
readonly kind: StackFormKind;
|
|
29
|
+
readonly main: MainSize;
|
|
30
|
+
/**
|
|
31
|
+
* Across the stack: `natural` is what this form asks for (it sets the stack's cross size when `setsCross`); `min`
|
|
32
|
+
* is the least it can be drawn across (default `natural`). A form that doesn't set the cross size takes its next
|
|
33
|
+
* form only when its `min` is over the stack's cross size, so a header stays in a column an open panel made
|
|
34
|
+
* narrow when it has a small `min`.
|
|
35
|
+
*/
|
|
36
|
+
readonly cross: {
|
|
37
|
+
readonly natural: number;
|
|
38
|
+
readonly min?: number;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Whether this form sets the stack's cross size (the column's width, the bar's height). Default: true for a
|
|
42
|
+
* panel's `open`, false for everything else (a group never sets a column's width).
|
|
43
|
+
*/
|
|
44
|
+
readonly setsCross?: boolean;
|
|
45
|
+
}
|
|
46
|
+
interface StackItem {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
/** Largest first. The solver starts at `from` and steps down one at a time. An item with none is left out. */
|
|
49
|
+
readonly forms: readonly StackForm[];
|
|
50
|
+
/** How recently it was used: the smaller, the longer ago, the sooner it gives way. */
|
|
51
|
+
readonly used: number;
|
|
52
|
+
/** Kept: gives way after every item that isn't. */
|
|
53
|
+
readonly kept?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* The first form the item may take, an index into `forms` (default 0; a panel folded by hand starts at its header).
|
|
56
|
+
* The solver never goes above it. `form` in the result and in the notes are indexes into `forms`, not into what is
|
|
57
|
+
* left after `from`.
|
|
58
|
+
*/
|
|
59
|
+
readonly from?: number;
|
|
60
|
+
}
|
|
61
|
+
/** The cross size a stack may take. With no form setting it, the stack is a `rail` wide (default {@link DEFAULT_RAIL}). */
|
|
62
|
+
interface CrossLimits {
|
|
63
|
+
readonly min: number;
|
|
64
|
+
readonly max: number;
|
|
65
|
+
readonly rail?: number;
|
|
66
|
+
}
|
|
67
|
+
interface StackInput {
|
|
68
|
+
readonly axis: StackAxis;
|
|
69
|
+
/** The stack's length along the axis. */
|
|
70
|
+
readonly length: number;
|
|
71
|
+
readonly cross: CrossLimits;
|
|
72
|
+
/** In order, from the start of the stack. */
|
|
73
|
+
readonly items: readonly StackItem[];
|
|
74
|
+
/** The » menu entry's size along the stack, taken only while an item is in the menu (default {@link DEFAULT_MENU}). */
|
|
75
|
+
readonly menu?: {
|
|
76
|
+
readonly main: number;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** The width of a stack nothing open holds, px. */
|
|
80
|
+
declare const DEFAULT_RAIL = 30;
|
|
81
|
+
/** The » menu entry's size along the stack, px. */
|
|
82
|
+
declare const DEFAULT_MENU = 28;
|
|
83
|
+
/** Whether a form sets the stack's cross size: its own say, else true for a panel's `open`. */
|
|
84
|
+
declare const formSetsCross: (f: StackForm) => boolean;
|
|
85
|
+
/** `input` with `item` inserted at index `at` (clamped to the items' range). */
|
|
86
|
+
declare function withItem(input: StackInput, item: StackItem, at: number): StackInput;
|
|
87
|
+
/** An item drawn: the form it took, its kind and its rect (stack-local px). One in the menu has the menu entry's rect. */
|
|
88
|
+
interface PlacedStackItem {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
/** Index into the item's `forms`. */
|
|
91
|
+
readonly form: number;
|
|
92
|
+
readonly kind: StackFormKind;
|
|
93
|
+
readonly rect: Rect;
|
|
94
|
+
}
|
|
95
|
+
interface StackMenu {
|
|
96
|
+
/** The » entry's rect. */
|
|
97
|
+
readonly rect: Rect;
|
|
98
|
+
/** The items in it, in the stack's order: exactly the items whose kind is `menu`. */
|
|
99
|
+
readonly items: readonly string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Why a stack looks as it does:
|
|
103
|
+
* - `form-down`: an item took a smaller form than the one it started in (`from`, an index into its forms), by length
|
|
104
|
+
* or by cross size.
|
|
105
|
+
* - `to-menu`: an item is in the » menu.
|
|
106
|
+
* - `too-wide`: an item's form doesn't set the cross size and its `cross.min` is over the stack's. Cross size never
|
|
107
|
+
* puts an item in the menu, so it keeps its last drawn form and the app clips it.
|
|
108
|
+
* - `no-forms`: an item with no forms, left out of `items`.
|
|
109
|
+
* - `overflow`: no item can give more way and the stack is still `over` px too long (forms that don't end in a `menu`
|
|
110
|
+
* form can't give more; neither can a stack where going into the menu would only make it longer).
|
|
111
|
+
*/
|
|
112
|
+
type StackNote = {
|
|
113
|
+
readonly code: "form-down";
|
|
114
|
+
readonly id: string;
|
|
115
|
+
readonly from: number;
|
|
116
|
+
readonly to: number;
|
|
117
|
+
} | {
|
|
118
|
+
readonly code: "to-menu";
|
|
119
|
+
readonly id: string;
|
|
120
|
+
} | {
|
|
121
|
+
readonly code: "too-wide";
|
|
122
|
+
readonly id: string;
|
|
123
|
+
} | {
|
|
124
|
+
readonly code: "no-forms";
|
|
125
|
+
readonly id: string;
|
|
126
|
+
} | {
|
|
127
|
+
readonly code: "overflow";
|
|
128
|
+
readonly over: number;
|
|
129
|
+
};
|
|
130
|
+
type StackNoteCode = StackNote["code"];
|
|
131
|
+
interface StackFit {
|
|
132
|
+
readonly axis: StackAxis;
|
|
133
|
+
readonly length: number;
|
|
134
|
+
/** The stack's size across: the widest `open` (clamped to the limits), or the rail. */
|
|
135
|
+
readonly cross: number;
|
|
136
|
+
/** One per input item that has forms, in order. */
|
|
137
|
+
readonly items: readonly PlacedStackItem[];
|
|
138
|
+
/** The » entry, or null while no item is in the menu. */
|
|
139
|
+
readonly menu: StackMenu | null;
|
|
140
|
+
/** `no-forms` first, then `form-down` per item in the order they gave way, `to-menu`, `too-wide`, and `overflow`. */
|
|
141
|
+
readonly notes: readonly StackNote[];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
declare function fitStack(input: StackInput): StackFit;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The drop targets for dragging an item into a stack, in the shape @n-uf/motion/drag takes. `stackTargets(input,
|
|
148
|
+
* dragged)` gives one target for every gap of the stack without the dragged item (an item of the input with its id
|
|
149
|
+
* is lifted out first, so a reorder within a stack works): before each item and after the last, so an empty stack has
|
|
150
|
+
* one. An item with no forms has no place of its own, but its gaps count.
|
|
151
|
+
*
|
|
152
|
+
* - `id` `gap:<k>`, priority 2, `place` `{ kind: "gap", at: k }` (k counts the input's items, the dragged one lifted
|
|
153
|
+
* out, including any with no forms; it is not an index into `fit.items`, which leaves those out: look the dragged
|
|
154
|
+
* item up there by its id, as `slot` already does).
|
|
155
|
+
* - `hit`: the gap's zone along the axis, the stack split at its items' middles (an item in the menu has no place of
|
|
156
|
+
* its own: the gaps next to it split the stretch where the stack's drawn items end; with every item in the menu only
|
|
157
|
+
* the last gap, "at the end", has any length, and the others are a point at the start). Across, it is the larger of
|
|
158
|
+
* the stack's current size and the size the drop gives it, so the pointer over the preview is over the target.
|
|
159
|
+
* - `fit`: the full `fitStack` of the stack with the dragged item inserted at k, and `input` the stack that was
|
|
160
|
+
* solved. The preview is `slot`, the dragged item's rect in `fit`: exactly the rect it gets after the drop, because
|
|
161
|
+
* the drop is that same solve. `marker` is the line where its leading edge lands: a rect with no thickness across
|
|
162
|
+
* the stack's cross size (the app draws it with one).
|
|
163
|
+
*
|
|
164
|
+
* The dragged item counts as just used: it is newer than every item in the stack, so the others give way before it.
|
|
165
|
+
* A group lands in the form that fits; a panel that would set a wider column makes room by that solve too. A dragged
|
|
166
|
+
* item with no forms has no targets.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
type StackPlace = {
|
|
170
|
+
readonly kind: "gap";
|
|
171
|
+
readonly at: number;
|
|
172
|
+
};
|
|
173
|
+
interface StackTarget extends Target {
|
|
174
|
+
readonly priority: 2;
|
|
175
|
+
/** The item dragged. */
|
|
176
|
+
readonly item: string;
|
|
177
|
+
readonly place: StackPlace;
|
|
178
|
+
/** The line where the dragged item's leading edge lands. */
|
|
179
|
+
readonly marker: Rect;
|
|
180
|
+
/** The stack with the dragged item inserted: what a drop here makes. */
|
|
181
|
+
readonly input: StackInput;
|
|
182
|
+
/** Its fit: the preview and the drop are both its rect for the dragged item. */
|
|
183
|
+
readonly fit: StackFit;
|
|
184
|
+
}
|
|
185
|
+
declare function stackTargets(input: StackInput, dragged: StackItem): StackTarget[];
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The stack's stored form: `storeStack(state)` gives plain JSON-safe data (`{ v: 1, order, kept, closed, used, forms
|
|
189
|
+
* }`); `readStack(data, known?)` reads parsed data back and never throws. Anything but an object of version 1 is
|
|
190
|
+
* `{ ok: false, error }`. Inside one it is lenient, as the panels' reader is: an id that isn't a string, is repeated
|
|
191
|
+
* or (with `known`) isn't one the consumer has is dropped and listed in `dropped`; a `kept`, `closed`, `used` or
|
|
192
|
+
* `forms` entry for an id that isn't in `order` is dropped; a form that isn't a whole number from 1 up is dropped;
|
|
193
|
+
* the key `__proto__` in `forms` is dropped (the other keys, `constructor` and `prototype` included, are ids like any
|
|
194
|
+
* other: `forms` is an object with no prototype, written and read); a field this version doesn't know is skipped and
|
|
195
|
+
* reported as `"<field>"`. An item the consumer has that the stored order lacks is no error: the consumer places it.
|
|
196
|
+
*
|
|
197
|
+
* - `kept`: items kept open (they give way last).
|
|
198
|
+
* - `closed`: items the user closed; their place in `order` is kept for when they open.
|
|
199
|
+
* - `used`: the use order, oldest to newest, so a reload restores who gives way first (an item's `used` is its index in
|
|
200
|
+
* it; one the list lacks is older than all). An id listed twice counts at its last place: the newest use wins.
|
|
201
|
+
* - `forms`: the user's chosen form per item, the index of the largest form it may take (`StackItem.from`). 0, the
|
|
202
|
+
* first, is not stored.
|
|
203
|
+
*/
|
|
204
|
+
interface StackState {
|
|
205
|
+
/** The items' order along the stack. */
|
|
206
|
+
readonly order: readonly string[];
|
|
207
|
+
/** Items kept open: they give way last. */
|
|
208
|
+
readonly kept: readonly string[];
|
|
209
|
+
/** Items the user closed. */
|
|
210
|
+
readonly closed: readonly string[];
|
|
211
|
+
/** The use order, oldest first. */
|
|
212
|
+
readonly used: readonly string[];
|
|
213
|
+
/** The form index the user chose per item (only those that chose one; absent means the first). */
|
|
214
|
+
readonly forms: Readonly<Record<string, number>>;
|
|
215
|
+
}
|
|
216
|
+
interface StoredStack {
|
|
217
|
+
readonly v: 1;
|
|
218
|
+
readonly order: string[];
|
|
219
|
+
readonly kept: string[];
|
|
220
|
+
readonly closed: string[];
|
|
221
|
+
readonly used: string[];
|
|
222
|
+
readonly forms: Record<string, number>;
|
|
223
|
+
}
|
|
224
|
+
type StackRead = {
|
|
225
|
+
readonly ok: true;
|
|
226
|
+
readonly state: StackState;
|
|
227
|
+
readonly dropped: readonly string[];
|
|
228
|
+
} | {
|
|
229
|
+
readonly ok: false;
|
|
230
|
+
readonly error: string;
|
|
231
|
+
};
|
|
232
|
+
/** A state with these items in this order, none kept or closed, used in that order, every form the first. */
|
|
233
|
+
declare const createStack: (order: readonly string[]) => StackState;
|
|
234
|
+
declare function storeStack(state: StackState): StoredStack;
|
|
235
|
+
declare function readStack(data: unknown, known?: readonly string[]): StackRead;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Floats for the edge stack: an item that isn't docked lies above the pages in the stage's own px (view space), so the
|
|
239
|
+
* pages scrolling under it never move it. A float has no pinned flag: there is one kind of float, and it is in view
|
|
240
|
+
* space. Pure, like the rest of `./stack`.
|
|
241
|
+
*
|
|
242
|
+
* - `fitFloat(rect, stage, avoid)`: the rect a float gets. It is moved (never resized) to lie inside the stage, then
|
|
243
|
+
* beside whatever docked content it would cover: the nearest place inside the stage that is clear of every `avoid`
|
|
244
|
+
* rect (the docked items' rects, in the same px). One larger than the stage keeps its top-left corner on the
|
|
245
|
+
* stage's; if no clear place exists the float stays where it covers the least and `covers` says which rects.
|
|
246
|
+
* A clear place is found whenever one exists: the x's are tried nearest first and, for each, the blocked stretches of
|
|
247
|
+
* y are merged and skipped, so no clear place is missed however many places lie between. Cost (measured in a test
|
|
248
|
+
* run on a laptop): about 100 docked rects 0.1 ms, 300 a few ms even when no place is clear (6 ms median, 15 ms
|
|
249
|
+
* worst), 1,000 about 17 ms; a safety net stops the clear search after 3 million rect tests and says so in
|
|
250
|
+
* `searchCapped`; a stage with no clear place looks at the 2,048 nearest places for the least covered.
|
|
251
|
+
* - `stackFloatTarget(input)`: a drop target in the shape `@n-uf/motion/drag` takes, free (no room is made for it),
|
|
252
|
+
* `kind` `"float"`, id `float:<item>`, whose `hit` covers the whole plane, so a pointer past the stage's edge still
|
|
253
|
+
* hits it (a float drop never cancels), at priority 3 so a docked stack's gaps win where they are. `make(point,
|
|
254
|
+
* grab)` is the one answer for the preview and the drop: the float's rect with the pointer holding it at `grab`,
|
|
255
|
+
* clamped and clear of the docked content.
|
|
256
|
+
* - `storeFloats` / `readFloats`: the stored form, `{ v: 1, floats: [{ id, x, y, width, height }] }`, in stacking
|
|
257
|
+
* order (the last is on top). It writes no `pinned`; one an old store has is read, ignored and listed.
|
|
258
|
+
*/
|
|
259
|
+
|
|
260
|
+
/** A float: the item's id and its rect in view space (the stage's px). */
|
|
261
|
+
interface StackFloat {
|
|
262
|
+
readonly id: string;
|
|
263
|
+
readonly rect: Rect;
|
|
264
|
+
}
|
|
265
|
+
interface FloatFit {
|
|
266
|
+
/** The float's rect: inside the stage and clear of the docked content where a clear place exists. */
|
|
267
|
+
readonly rect: Rect;
|
|
268
|
+
/** It was moved to lie inside the stage. */
|
|
269
|
+
readonly clamped: boolean;
|
|
270
|
+
/** It was moved beside the docked content it would have covered. */
|
|
271
|
+
readonly snapped: boolean;
|
|
272
|
+
/**
|
|
273
|
+
* Indexes into `avoid` of the rects it still covers. Empty whenever a clear place was found, which is whenever one
|
|
274
|
+
* exists (unless `searchCapped`); not empty only when the stage has no clear place for the float, and then it stays
|
|
275
|
+
* where it covers the least among the 2,048 nearest candidate places.
|
|
276
|
+
*/
|
|
277
|
+
readonly covers: readonly number[];
|
|
278
|
+
/** The safety net on the clear search was hit (thousands of rects): the place found may not be the nearest, or a clear place may exist that was not found. Normally false. */
|
|
279
|
+
readonly searchCapped: boolean;
|
|
280
|
+
}
|
|
281
|
+
declare function fitFloat(want: Rect, stage: Rect, avoid?: readonly Rect[]): FloatFit;
|
|
282
|
+
/** What a float drop makes: the same answer for the preview and for the release. */
|
|
283
|
+
interface FloatDrop {
|
|
284
|
+
/** The float's rect in view space. */
|
|
285
|
+
readonly rect: Rect;
|
|
286
|
+
readonly fit: FloatFit;
|
|
287
|
+
}
|
|
288
|
+
interface StackFloatTargetInput {
|
|
289
|
+
/** The item dragged. */
|
|
290
|
+
readonly id: string;
|
|
291
|
+
/** The stage, in view space. */
|
|
292
|
+
readonly stage: Rect;
|
|
293
|
+
/** The float's size: it is never resized. */
|
|
294
|
+
readonly size: Size;
|
|
295
|
+
/** The docked content to stay clear of: the docked items' rects (and the » entries'), in view space. */
|
|
296
|
+
readonly avoid?: readonly Rect[];
|
|
297
|
+
/** What the target is called (default "Float here"). */
|
|
298
|
+
readonly label?: string;
|
|
299
|
+
}
|
|
300
|
+
interface FloatTarget extends Target {
|
|
301
|
+
/** What kind of place it is, for a consumer that holds targets of several kinds. */
|
|
302
|
+
readonly kind: "float";
|
|
303
|
+
readonly priority: 3;
|
|
304
|
+
readonly free: true;
|
|
305
|
+
/** The item dragged. */
|
|
306
|
+
readonly item: string;
|
|
307
|
+
/**
|
|
308
|
+
* The drop with the pointer at `point` holding the float at `grab` (its offset from the float's top-left corner,
|
|
309
|
+
* default the middle): `rect` is the preview and the landing, clamped into the stage and clear of the docked content.
|
|
310
|
+
*/
|
|
311
|
+
make(point: Point, grab?: Point): FloatDrop;
|
|
312
|
+
}
|
|
313
|
+
declare function stackFloatTarget(input: StackFloatTargetInput): FloatTarget;
|
|
314
|
+
interface StoredFloats {
|
|
315
|
+
readonly v: 1;
|
|
316
|
+
readonly floats: {
|
|
317
|
+
id: string;
|
|
318
|
+
x: number;
|
|
319
|
+
y: number;
|
|
320
|
+
width: number;
|
|
321
|
+
height: number;
|
|
322
|
+
}[];
|
|
323
|
+
}
|
|
324
|
+
type FloatsRead = {
|
|
325
|
+
readonly ok: true;
|
|
326
|
+
readonly floats: StackFloat[];
|
|
327
|
+
readonly dropped: readonly string[];
|
|
328
|
+
} | {
|
|
329
|
+
readonly ok: false;
|
|
330
|
+
readonly error: string;
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* The floats as plain JSON-safe data, in the order given (the stacking order, the last on top). Never a `pinned`.
|
|
334
|
+
* What it can't read back is left out, silently: a float whose position isn't a finite number or whose size isn't over
|
|
335
|
+
* 0 (a zero-size float), and an earlier entry of a repeated id (the last readable entry of an id is the one on top,
|
|
336
|
+
* so it stays, at its own place in the order).
|
|
337
|
+
*/
|
|
338
|
+
declare function storeFloats(floats: readonly StackFloat[]): StoredFloats;
|
|
339
|
+
/**
|
|
340
|
+
* Reads parsed data back; never throws. Anything but an object of version 1 with a `floats` array is `{ ok: false,
|
|
341
|
+
* error }`. Inside one it is lenient: a float that isn't an object, has no string id, isn't one the
|
|
342
|
+
* consumer has (with `known`) or has a position or size that isn't a finite number (a size over 0) is dropped and
|
|
343
|
+
* listed in `dropped` as `float:<id>` (or `a <type> where a float goes`); a top-level field this version doesn't
|
|
344
|
+
* know is listed as `"<field>"`, and so is a float's own (`float:<id>:<field>`) while the float itself is kept.
|
|
345
|
+
* A `pinned` key (an old store's flag, whatever its value) is ignored: the float loads as a plain float, in view
|
|
346
|
+
* space as stored, and `pinned:<id>` is listed. A repeated id keeps its last readable entry (the list is in stacking
|
|
347
|
+
* order, the last on top); the earlier ones are dropped and listed as `float:<id>`.
|
|
348
|
+
*/
|
|
349
|
+
declare function readFloats(data: unknown, known?: readonly string[]): FloatsRead;
|
|
350
|
+
|
|
351
|
+
export { type CrossLimits, DEFAULT_MENU, DEFAULT_RAIL, type FloatDrop, type FloatFit, type FloatTarget, type FloatsRead, type GroupFormKind, type MainSize, type PanelFormKind, type PlacedStackItem, type StackAxis, type StackFit, type StackFloat, type StackFloatTargetInput, type StackForm, type StackFormKind, type StackInput, type StackItem, type StackMenu, type StackNote, type StackNoteCode, type StackPlace, type StackRead, type StackState, type StackTarget, type StoredFloats, type StoredStack, createStack, fitFloat, fitStack, formSetsCross, readFloats, readStack, stackFloatTarget, stackTargets, storeFloats, storeStack, withItem };
|