vue-dockable-desktop 1.0.1 → 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 +162 -0
- package/dist/core/layoutTree.d.ts +30 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +638 -573
- package/dist/index.js.map +1 -1
- package/dist/styles.css +178 -144
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,168 @@ 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
|
+
|
|
78
|
+
## [1.1.0] — 2026-09-18
|
|
79
|
+
|
|
80
|
+
**Parity: react-dockable-desktop 6.3.0.**
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- **`<VddDesktop :skin>` did nothing at all.** The stylesheet keyed its 104 skin selectors on
|
|
85
|
+
`data-workspace-skin` while the component emitted `data-vdd-skin`, so no skin rule had ever
|
|
86
|
+
matched in any published version: all seven skins painted identically to the default. The
|
|
87
|
+
stylesheet now uses the library's own `data-vdd-skin`, which is the name the component, its
|
|
88
|
+
test and [ADR 0008](docs/decisions/0008-css-prefix.md) already agreed on.
|
|
89
|
+
|
|
90
|
+
A consumer who wrote a custom skin against `[data-workspace-skin="…"]`, as the manual
|
|
91
|
+
previously showed, must rename it to `[data-vdd-skin="…"]`. Nothing can break in practice:
|
|
92
|
+
skins have never applied, so no such CSS was having any effect.
|
|
93
|
+
|
|
94
|
+
- **Skins would have been unusable in light mode**, which the rename alone would have shipped. A
|
|
95
|
+
skin's token block matches the workspace element as well as the root, and the colour scheme was
|
|
96
|
+
only on the root — so a skin's *dark* tokens were re-declared closer to the content than the
|
|
97
|
+
root's light ones and shadowed them: dark panels with dark text. `<VddDesktop>` now mirrors
|
|
98
|
+
`data-color-scheme` onto the workspace element beside the skin, which is how rdd has always done
|
|
99
|
+
it. Measured across seven skins × two schemes on four surfaces; every surface now flips.
|
|
100
|
+
|
|
101
|
+
- **The sidebar, its drawer and the workspace toolbar were unstyled in dark mode.** Twenty-nine
|
|
102
|
+
tokens — the whole `--vdd-sidebar-*` family, the rail's icon colours and the workspace toolbar's
|
|
103
|
+
button states — had their dark values only inside `[data-color-scheme="dark"]`, and that selector
|
|
104
|
+
never matches: dark is signalled by *removing* the attribute, as `useColorScheme()` documents. So
|
|
105
|
+
they were undefined exactly when they were needed, and fifteen of them are read with no `var()`
|
|
106
|
+
fallback, which drops the whole declaration instead of defaulting it. The strips had no
|
|
107
|
+
background, the drawer inherited black text, and **the selected rail icon had no colour at all**,
|
|
108
|
+
which is why it appeared not to render.
|
|
109
|
+
|
|
110
|
+
Dark is the base look, so those values now live on `:root` and the dark block is gone —
|
|
111
|
+
`[data-color-scheme="light"]` overrides them, which is all a scheme block should do. An
|
|
112
|
+
application that sets `data-color-scheme="dark"` explicitly sees no change. Reported from the
|
|
113
|
+
demo; it affects rdd too, whose own demo happens to set the attribute for both schemes and so
|
|
114
|
+
never shows it.
|
|
115
|
+
|
|
116
|
+
- **The sidebar rail did not fill its own column.** `.vdd-sidebar-strip-outer` is full height,
|
|
117
|
+
but it is a block wrapper — added in this port to own the width-collapse transition — and a
|
|
118
|
+
block does not stretch its child the way rdd's flex row did. So the strip inside it shrank to
|
|
119
|
+
its buttons, 216px of a 915px column, and its background covered only the icons while the rest
|
|
120
|
+
showed the host page through. It has `height: 100%` now.
|
|
121
|
+
|
|
122
|
+
- **A rail holding one tab collapsed that tab to its icon.** An active rail button takes
|
|
123
|
+
`width: var(--vdd-tab-btn-active-width, 100%)`, and that percentage resolves against the
|
|
124
|
+
shrink-to-fit tabs list; with a single tab there is no sibling to hold the list open, so button
|
|
125
|
+
and list both shrank to 26px against a normal 44px, putting the accent border 15px inboard of
|
|
126
|
+
the rail's edge. `.vdd-sidebar-tabs-list` now carries the same `min-width: 44px` floor that
|
|
127
|
+
`.vdd-sidebar-header-area` and `.vdd-sidebar-footer-area` already had for exactly this reason.
|
|
128
|
+
A rail with several tabs hid it, because the inactive buttons' own 44px kept the list open.
|
|
129
|
+
|
|
130
|
+
- **Text in a side panel was black on a dark background.** `.vdd-side-panel` set a background
|
|
131
|
+
and no foreground, so content teleported into a drawer inherited the host page's text colour —
|
|
132
|
+
the user agent's black. Measured at **1.18:1** in the demo's own Panel manager, against the
|
|
133
|
+
16.31:1 of the library's title beside it. `.vdd-modal-window`, `.vdd-workspace` and
|
|
134
|
+
`.vdd-sidebar-content-drawer` all set a colour; the drawer was simply missed. rdd has the same
|
|
135
|
+
omission, hidden in its demo by Bootstrap's page-wide theme, which this demo deliberately does
|
|
136
|
+
not import. An application that wants its own colour still sets it on its content or through
|
|
137
|
+
`createWorkspace({ classes: { sidePanelBody } })`.
|
|
138
|
+
|
|
139
|
+
- **The theming chapter documented three things that were not true**: the skin selector
|
|
140
|
+
(`data-workspace-skin`), the claim that *"the workspace publishes its scheme as
|
|
141
|
+
`data-color-scheme`"* — the library only ever reads it; your application sets it — and a
|
|
142
|
+
`createWorkspace({ windowClass, modalClass, … })` config shape that has never existed (it is
|
|
143
|
+
`classes: { window, modal, … }`).
|
|
144
|
+
|
|
145
|
+
### Added
|
|
146
|
+
|
|
147
|
+
- **A token reference**: all **119** tokens the library declares on `:root`, in sixteen groups,
|
|
148
|
+
with defaults and what each paints ([ch. 10](docs/manual/10-theming.md#token-reference)). A gate
|
|
149
|
+
checks it against the stylesheet in both directions, so a new token needs a row and a row cannot
|
|
150
|
+
outlive its token.
|
|
151
|
+
|
|
152
|
+
- **`:root` is now a complete inventory.** Six measurements and off-by-default effects that
|
|
153
|
+
existed only as `var()` fallbacks are declared at exactly those values, so nothing renders
|
|
154
|
+
differently — `--vdd-tab-accent-bar-width`, `--vdd-tab-btn-active-glow/-radius/-width`,
|
|
155
|
+
`--vdd-toolbar-accent-bar-width`, `--vdd-toolbar-btn-active-glow`. Together with the
|
|
156
|
+
twenty-nine folded out of the dark block, everything a skin may override is declared and
|
|
157
|
+
documented in one place.
|
|
158
|
+
|
|
159
|
+
- **Guidance for defining your own skin**, both of it learned by measurement: leave the selector
|
|
160
|
+
unqualified (`[data-vdd-skin="mono"]`, not `html[…]`, which cannot match the workspace element
|
|
161
|
+
and loses there), and import your stylesheet after the library's. The demo ships `mono` as a
|
|
162
|
+
worked example in both schemes, and the browser gate measures it beside the seven built-ins.
|
|
163
|
+
|
|
164
|
+
### Changed
|
|
165
|
+
|
|
166
|
+
- The M14 browser gate's skin step used to cycle the seven skins and assert nothing — which is how
|
|
167
|
+
this shipped. It now measures each skin in both schemes and fails if a surface does not change
|
|
168
|
+
between them or if a skin paints identically to the default. Two new source rules join it: every
|
|
169
|
+
`[data-*]` selector in the stylesheet must name an attribute a component emits (the rule that
|
|
170
|
+
would have caught this on day one), and the token reference must match the stylesheet. A third
|
|
171
|
+
rejects a token whose only declaration sits inside a colour-scheme block — the shape that left
|
|
172
|
+
the sidebar unstyled. The browser gate also measures the chrome *outside* the workspace now: the
|
|
173
|
+
first matrix sampled only inside it, and passed while the sidebar was unpainted. All are proven
|
|
174
|
+
non-vacuous by `gate:selftest`, now 87 rules.
|
|
175
|
+
|
|
14
176
|
## [1.0.1] — 2026-09-17
|
|
15
177
|
|
|
16
178
|
**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). */
|