vue-dockable-desktop 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -11,6 +11,70 @@ correspondence lives, alongside the feature-by-feature map in [docs/PARITY.md](d
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [1.1.1] — 2026-09-19
15
+
16
+ **Parity: react-dockable-desktop 6.3.1.**
17
+
18
+ ### Fixed
19
+
20
+ - **Dragging the only docked panel onto its own group made it disappear.** With one panel in
21
+ the workspace, dropping it on its own drop cross — any side, the centre, or its own tab
22
+ strip — left the panel `docked` but in **no group**: no tab, nothing rendered, and still
23
+ listed as open. Re-opening it did nothing, because an already-open panel is only focused;
24
+ the only way back was to minimise and restore it, which returned it as a floating window.
25
+ Dropping it on a workspace edge left an empty group holding half the width instead.
26
+
27
+ The cause: the dock actions detach the panel before resolving the target, and detaching the
28
+ only panel of a group **deletes that group** — so the drop destroyed the very target it
29
+ named, and `splitLeafInTree` then had nothing to find. Dropping a lone panel onto its own
30
+ group is now a no-op, since the result would be the layout it already has. Guarded in the
31
+ store rather than in the drag layer, so `dockPanelToGroup`, `movePanelOrder` and
32
+ `dockPanelToWorkspaceEdge` are safe for any caller, not just the mouse. The same bug, in a
33
+ different shape, was [reported against react-dockable-desktop](https://github.com/felipecarrillo100/react-dockable-desktop)
34
+ and fixed there in 6.3.1 — there it duplicated the panel into two groups instead.
35
+
36
+ - **A dock into a group that no longer exists no longer loses the panel.** Emptying a group
37
+ removes it, so an id held across a layout change can name one that is gone; placing into it
38
+ left the panel in no group. `dockPanelToGroup` and `movePanelOrder` now ignore such a call
39
+ with a development warning.
40
+
41
+ - **Layouts already saved in the broken state are repaired when read.** `saveLayout()` wrote
42
+ the corrupted tree out, so the fault came back on every reload and a stored layout stayed
43
+ broken. Reading one now drops a panel listed in more than one group from all but the first,
44
+ prunes a group emptied by that unless it set `keepOnEmpty`, collapses a branch left with one
45
+ child, and puts a panel the layout calls docked but that no group lists back into the first
46
+ group, naming each repair in a development warning. Only what is *read* changes — the saved
47
+ format is untouched, so every rdd fixture still round-trips byte-identically.
48
+
49
+ - **`openPanel` recovers a panel that is in no group** instead of only focusing it — a safety
50
+ net, now that nothing should produce that state.
51
+
52
+ - **An emptied root group keeps its own identity.** Removing the last panel replaced the root
53
+ leaf with a fresh `group-default`, so a leaf the application had named, or had marked
54
+ `keepOnEmpty` or `canClose: false`, silently lost all three.
55
+
56
+ Covered by `test/store/selfDrop.test.ts` (20), the repair and the guard as pure functions in
57
+ `test/core/layoutTree.test.ts`, and three compatibility tests for layouts written by 1.1.0.
58
+ New M6 rules keep the guard in the store rather than in the drag layer, and new M4 rules keep
59
+ the repair on the shared read path.
60
+
61
+ ### Fixed — the gate harness itself
62
+
63
+ - **`npm run gate:selftest` was proving almost nothing.** It ran each gate as `node ${gate}`
64
+ while 77 of its 89 checks passed a gate that already began with `node`, so the command
65
+ executed was `node node scripts/gates/mN.mjs` — which fails whatever the mutation did, and a
66
+ failing gate is exactly what the harness reads as "this rule caught its violation". Those
67
+ rules were reported as proven without their gate ever running. The command is now used as
68
+ given, and a mutation that changes no bytes is reported as a miss in its own right, since a
69
+ stale anchor is the other way a check quietly stops testing anything.
70
+
71
+ With the harness honest, four checks were failing: two pinned `version = '1.0.0'`, stale
72
+ since 1.0.1, and now match any version; and two M14 capability checks were satisfied by
73
+ *prose* — the capability scan read whole files, so a doc comment or a `<code>onBeforeClose()`
74
+ in a paragraph counted as a demonstration. Capabilities that are called are now looked for in
75
+ script blocks with comments stripped, and the two that are bound in markup are matched on a
76
+ `<Vdd…>` tag. All 89 rules now genuinely fail when their rule is broken.
77
+
14
78
  ## [1.1.0] — 2026-09-18
15
79
 
16
80
  **Parity: react-dockable-desktop 6.3.0.**
@@ -56,6 +56,36 @@ export declare function findFirstLeafId(node: LayoutNode): string | null;
56
56
  export declare function findLeafForPanel(node: LayoutNode, id: string): string | null;
57
57
  /** A leaf by id, or `null`. */
58
58
  export declare function findLeaf(node: LayoutNode | null, leafId: string): LayoutLeafNode | null;
59
+ /**
60
+ * Is `panelId` the only panel in `leafId`?
61
+ *
62
+ * The question every dock action has to ask *before* it detaches anything. Detaching a panel
63
+ * deletes its leaf once that leaf is empty, so a drop onto the dragged panel's own leaf
64
+ * destroys the very target it names, and the placement that follows has nowhere to go.
65
+ * Dropping a lone panel onto itself is a no-op by definition: the result is the layout it
66
+ * already has.
67
+ */
68
+ export declare function isLoneOccupant(node: LayoutNode, leafId: string, panelId: string): boolean;
69
+ /**
70
+ * Heal a tree that lists a panel twice, or lists none of a docked panel.
71
+ *
72
+ * Both are states this library once produced and then *saved*: a lone docked panel dropped
73
+ * on its own group left rdd with the panel in two leaves and vdd with it in none, and
74
+ * `saveLayout()` wrote the result out, so the fault returned on every reload. Repairing on
75
+ * read means a layout stored by an affected version loads clean with nothing asked of the
76
+ * application. It changes only what is read; `saveLayout()`'s output is untouched, which is
77
+ * what keeps the format compatible (docs/decisions/0009-layout-json-compatibility.md).
78
+ *
79
+ * `repairs` is empty and the input object is returned unchanged when there is nothing wrong,
80
+ * so a healthy layout costs one walk and no allocation.
81
+ */
82
+ export declare function repairLayoutTree(gridRoot: LayoutNode, panels: Record<string, {
83
+ id: string;
84
+ state: PanelInfo['state'];
85
+ }>): {
86
+ gridRoot: LayoutNode;
87
+ repairs: string[];
88
+ };
59
89
  /** Whether a leaf exists in the tree. */
60
90
  export declare function leafExists(node: LayoutNode, leafId: string): boolean;
61
91
  /** Update the sizes of the branch at `path` (a list of child indices from the root). */