vue-dockable-desktop 1.0.0 → 1.1.0
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 +146 -0
- package/README.md +1 -1
- package/dist/components/VddFloatingWidget.vue.d.ts +6 -0
- package/dist/core/overlayState.d.ts +25 -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 +404 -388
- package/dist/index.js.map +1 -1
- package/dist/styles.css +178 -144
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,152 @@ correspondence lives, alongside the feature-by-feature map in [docs/PARITY.md](d
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [1.1.0] — 2026-09-18
|
|
15
|
+
|
|
16
|
+
**Parity: react-dockable-desktop 6.3.0.**
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **`<VddDesktop :skin>` did nothing at all.** The stylesheet keyed its 104 skin selectors on
|
|
21
|
+
`data-workspace-skin` while the component emitted `data-vdd-skin`, so no skin rule had ever
|
|
22
|
+
matched in any published version: all seven skins painted identically to the default. The
|
|
23
|
+
stylesheet now uses the library's own `data-vdd-skin`, which is the name the component, its
|
|
24
|
+
test and [ADR 0008](docs/decisions/0008-css-prefix.md) already agreed on.
|
|
25
|
+
|
|
26
|
+
A consumer who wrote a custom skin against `[data-workspace-skin="…"]`, as the manual
|
|
27
|
+
previously showed, must rename it to `[data-vdd-skin="…"]`. Nothing can break in practice:
|
|
28
|
+
skins have never applied, so no such CSS was having any effect.
|
|
29
|
+
|
|
30
|
+
- **Skins would have been unusable in light mode**, which the rename alone would have shipped. A
|
|
31
|
+
skin's token block matches the workspace element as well as the root, and the colour scheme was
|
|
32
|
+
only on the root — so a skin's *dark* tokens were re-declared closer to the content than the
|
|
33
|
+
root's light ones and shadowed them: dark panels with dark text. `<VddDesktop>` now mirrors
|
|
34
|
+
`data-color-scheme` onto the workspace element beside the skin, which is how rdd has always done
|
|
35
|
+
it. Measured across seven skins × two schemes on four surfaces; every surface now flips.
|
|
36
|
+
|
|
37
|
+
- **The sidebar, its drawer and the workspace toolbar were unstyled in dark mode.** Twenty-nine
|
|
38
|
+
tokens — the whole `--vdd-sidebar-*` family, the rail's icon colours and the workspace toolbar's
|
|
39
|
+
button states — had their dark values only inside `[data-color-scheme="dark"]`, and that selector
|
|
40
|
+
never matches: dark is signalled by *removing* the attribute, as `useColorScheme()` documents. So
|
|
41
|
+
they were undefined exactly when they were needed, and fifteen of them are read with no `var()`
|
|
42
|
+
fallback, which drops the whole declaration instead of defaulting it. The strips had no
|
|
43
|
+
background, the drawer inherited black text, and **the selected rail icon had no colour at all**,
|
|
44
|
+
which is why it appeared not to render.
|
|
45
|
+
|
|
46
|
+
Dark is the base look, so those values now live on `:root` and the dark block is gone —
|
|
47
|
+
`[data-color-scheme="light"]` overrides them, which is all a scheme block should do. An
|
|
48
|
+
application that sets `data-color-scheme="dark"` explicitly sees no change. Reported from the
|
|
49
|
+
demo; it affects rdd too, whose own demo happens to set the attribute for both schemes and so
|
|
50
|
+
never shows it.
|
|
51
|
+
|
|
52
|
+
- **The sidebar rail did not fill its own column.** `.vdd-sidebar-strip-outer` is full height,
|
|
53
|
+
but it is a block wrapper — added in this port to own the width-collapse transition — and a
|
|
54
|
+
block does not stretch its child the way rdd's flex row did. So the strip inside it shrank to
|
|
55
|
+
its buttons, 216px of a 915px column, and its background covered only the icons while the rest
|
|
56
|
+
showed the host page through. It has `height: 100%` now.
|
|
57
|
+
|
|
58
|
+
- **A rail holding one tab collapsed that tab to its icon.** An active rail button takes
|
|
59
|
+
`width: var(--vdd-tab-btn-active-width, 100%)`, and that percentage resolves against the
|
|
60
|
+
shrink-to-fit tabs list; with a single tab there is no sibling to hold the list open, so button
|
|
61
|
+
and list both shrank to 26px against a normal 44px, putting the accent border 15px inboard of
|
|
62
|
+
the rail's edge. `.vdd-sidebar-tabs-list` now carries the same `min-width: 44px` floor that
|
|
63
|
+
`.vdd-sidebar-header-area` and `.vdd-sidebar-footer-area` already had for exactly this reason.
|
|
64
|
+
A rail with several tabs hid it, because the inactive buttons' own 44px kept the list open.
|
|
65
|
+
|
|
66
|
+
- **Text in a side panel was black on a dark background.** `.vdd-side-panel` set a background
|
|
67
|
+
and no foreground, so content teleported into a drawer inherited the host page's text colour —
|
|
68
|
+
the user agent's black. Measured at **1.18:1** in the demo's own Panel manager, against the
|
|
69
|
+
16.31:1 of the library's title beside it. `.vdd-modal-window`, `.vdd-workspace` and
|
|
70
|
+
`.vdd-sidebar-content-drawer` all set a colour; the drawer was simply missed. rdd has the same
|
|
71
|
+
omission, hidden in its demo by Bootstrap's page-wide theme, which this demo deliberately does
|
|
72
|
+
not import. An application that wants its own colour still sets it on its content or through
|
|
73
|
+
`createWorkspace({ classes: { sidePanelBody } })`.
|
|
74
|
+
|
|
75
|
+
- **The theming chapter documented three things that were not true**: the skin selector
|
|
76
|
+
(`data-workspace-skin`), the claim that *"the workspace publishes its scheme as
|
|
77
|
+
`data-color-scheme`"* — the library only ever reads it; your application sets it — and a
|
|
78
|
+
`createWorkspace({ windowClass, modalClass, … })` config shape that has never existed (it is
|
|
79
|
+
`classes: { window, modal, … }`).
|
|
80
|
+
|
|
81
|
+
### Added
|
|
82
|
+
|
|
83
|
+
- **A token reference**: all **119** tokens the library declares on `:root`, in sixteen groups,
|
|
84
|
+
with defaults and what each paints ([ch. 10](docs/manual/10-theming.md#token-reference)). A gate
|
|
85
|
+
checks it against the stylesheet in both directions, so a new token needs a row and a row cannot
|
|
86
|
+
outlive its token.
|
|
87
|
+
|
|
88
|
+
- **`:root` is now a complete inventory.** Six measurements and off-by-default effects that
|
|
89
|
+
existed only as `var()` fallbacks are declared at exactly those values, so nothing renders
|
|
90
|
+
differently — `--vdd-tab-accent-bar-width`, `--vdd-tab-btn-active-glow/-radius/-width`,
|
|
91
|
+
`--vdd-toolbar-accent-bar-width`, `--vdd-toolbar-btn-active-glow`. Together with the
|
|
92
|
+
twenty-nine folded out of the dark block, everything a skin may override is declared and
|
|
93
|
+
documented in one place.
|
|
94
|
+
|
|
95
|
+
- **Guidance for defining your own skin**, both of it learned by measurement: leave the selector
|
|
96
|
+
unqualified (`[data-vdd-skin="mono"]`, not `html[…]`, which cannot match the workspace element
|
|
97
|
+
and loses there), and import your stylesheet after the library's. The demo ships `mono` as a
|
|
98
|
+
worked example in both schemes, and the browser gate measures it beside the seven built-ins.
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
|
|
102
|
+
- The M14 browser gate's skin step used to cycle the seven skins and assert nothing — which is how
|
|
103
|
+
this shipped. It now measures each skin in both schemes and fails if a surface does not change
|
|
104
|
+
between them or if a skin paints identically to the default. Two new source rules join it: every
|
|
105
|
+
`[data-*]` selector in the stylesheet must name an attribute a component emits (the rule that
|
|
106
|
+
would have caught this on day one), and the token reference must match the stylesheet. A third
|
|
107
|
+
rejects a token whose only declaration sits inside a colour-scheme block — the shape that left
|
|
108
|
+
the sidebar unstyled. The browser gate also measures the chrome *outside* the workspace now: the
|
|
109
|
+
first matrix sampled only inside it, and passed while the sidebar was unpainted. All are proven
|
|
110
|
+
non-vacuous by `gate:selftest`, now 87 rules.
|
|
111
|
+
|
|
112
|
+
## [1.0.1] — 2026-09-17
|
|
113
|
+
|
|
114
|
+
**Parity: react-dockable-desktop 6.3.0.**
|
|
115
|
+
|
|
116
|
+
### Fixed
|
|
117
|
+
|
|
118
|
+
- **A widget opened through `useFloatingWidgets()` discarded every placement gesture.** Dropping
|
|
119
|
+
a managed widget on another corner returned it to the corner `open()` named, and a stretched
|
|
120
|
+
one lost its stretch as soon as any other widget opened or closed. Template-declared widgets
|
|
121
|
+
and plain resizes were unaffected. Reported by a user.
|
|
122
|
+
|
|
123
|
+
`<VddPanelOverlay>` bound `placement` — a `defineModel` — as a fresh `{ anchor, stretch }`
|
|
124
|
+
literal with no `@update:placement`, and Vue re-syncs a model from its prop whenever the
|
|
125
|
+
prop's *identity* changes. Every render of the overlay therefore reset the widget, and the
|
|
126
|
+
overlay re-renders on exactly the wrong events: a drop clears `draggingId` in the same
|
|
127
|
+
function that applies the placement, and opening a widget bumps `managedVersion`.
|
|
128
|
+
|
|
129
|
+
The overlay now keeps a placement record per widget id and writes gestures straight back into
|
|
130
|
+
it. `anchor`, `stretch`, `width` and `height` on `open()` are **initial values** — as rdd's
|
|
131
|
+
`defaultAnchor`/`defaultStretch` are — so `open()` on an id that is already open refreshes its
|
|
132
|
+
content and leaves the widget where the user put it, and `close()` then `open()` is what
|
|
133
|
+
resets placement. No public API changed.
|
|
134
|
+
|
|
135
|
+
A port regression: rdd never makes the anchor controllable, and the only placement value it
|
|
136
|
+
lets a caller control is a primitive, so identity churn cannot arise there. Recorded as **R1**
|
|
137
|
+
in [`docs/PARITY.md`](docs/PARITY.md), with the underlying `defineModel` constraint amended
|
|
138
|
+
into [ADR 0005](docs/decisions/0005-vmodel.md). Pinned by PO31–PO35, four M14 gate rules, and
|
|
139
|
+
a real pointer drag in the demo's browser walkthrough — the gesture path into an overlay-owned
|
|
140
|
+
widget that no layer of either library's verification had ever driven.
|
|
141
|
+
|
|
142
|
+
- **In the demo, no camera marker on the main map could be clicked**, though the legend invited
|
|
143
|
+
it: a decorative polygon added after the markers covered the whole cluster and swallowed every
|
|
144
|
+
click. It is `interactive: false` now. Found by the new browser assertion trying to open a
|
|
145
|
+
widget the way a user does.
|
|
146
|
+
|
|
147
|
+
### Changed
|
|
148
|
+
|
|
149
|
+
- The demo's camera widgets are opened through `useFloatingWidgets()` instead of a `v-for` over
|
|
150
|
+
`<VddFloatingWidget>`, so the managed path — the one that regressed — is demonstrated and
|
|
151
|
+
walked by the gate. The M14 capability rule now requires the composable itself rather than
|
|
152
|
+
accepting `@update:open`, which is what let the demo claim the capability without exercising
|
|
153
|
+
it.
|
|
154
|
+
- The M11 browser gate's stretch assertion was measuring the wrong thing: it expected a
|
|
155
|
+
full-width strip to be `panel - 16` and ignored the inline panel toolbars beside it, so a
|
|
156
|
+
strip that tracked its panel perfectly was reported as having stopped. It now asserts the
|
|
157
|
+
tracking claim as a delta and measures the toolbar band. No library behaviour was involved —
|
|
158
|
+
the failure reproduced identically against 1.0.0's source.
|
|
159
|
+
|
|
14
160
|
## [1.0.0] — 2026-09-16
|
|
15
161
|
|
|
16
162
|
**Parity: react-dockable-desktop 6.3.0.**
|
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ npm install vue-dockable-desktop
|
|
|
34
34
|
|
|
35
35
|
Requires Vue 3.4+. No other runtime dependencies. The published package is
|
|
36
36
|
[`vue-dockable-desktop`](https://www.npmjs.com/package/vue-dockable-desktop); the public API
|
|
37
|
-
is pinned by `api-surface.json` and covered by
|
|
37
|
+
is pinned by `api-surface.json` and covered by 730 tests.
|
|
38
38
|
|
|
39
39
|
## Quick start
|
|
40
40
|
|
|
@@ -22,6 +22,12 @@ type __VLS_ModelProps = {
|
|
|
22
22
|
*
|
|
23
23
|
* Bind it and the caller owns placement — which is also the only way to persist it, since the
|
|
24
24
|
* library serialises nothing about inner widgets. Leave it off and the widget keeps its own.
|
|
25
|
+
*
|
|
26
|
+
* **If you bind it, the value must be stable or echoed back.** `defineModel` re-syncs from the
|
|
27
|
+
* prop whenever the prop's *identity* changes, so a fresh object literal — `:placement="{ anchor,
|
|
28
|
+
* stretch }"` — resets the widget on every render of the parent, with or without a listener, and
|
|
29
|
+
* gestures appear to work and then revert. Hold it in a `ref` and use `v-model:placement`, or
|
|
30
|
+
* write the emitted value back into whatever you bound.
|
|
25
31
|
*/
|
|
26
32
|
'placement'?: PanelFloatPlacement;
|
|
27
33
|
};
|
|
@@ -17,9 +17,23 @@ export interface ManagedWidget {
|
|
|
17
17
|
/** Rendered as the widget's content. */
|
|
18
18
|
component: Component;
|
|
19
19
|
props?: Record<string, unknown>;
|
|
20
|
+
/**
|
|
21
|
+
* The corner to dock to **on first open**, not live state.
|
|
22
|
+
*
|
|
23
|
+
* Seeded into the overlay's own placement record and owned there afterwards, so a gesture
|
|
24
|
+
* that moves the widget is not undone the next time the caller's state re-renders — and
|
|
25
|
+
* `open()` on a widget that is already open refreshes its content without yanking it back
|
|
26
|
+
* to this corner. `close()` then `open()` is what re-seeds it. rdd draws the same line,
|
|
27
|
+
* with `defaultAnchor` feeding a `useState`.
|
|
28
|
+
*
|
|
29
|
+
* @default 'top-right'
|
|
30
|
+
*/
|
|
20
31
|
anchor?: FloatAnchor;
|
|
32
|
+
/** Initial width in pixels. @default 320 */
|
|
21
33
|
width?: number;
|
|
34
|
+
/** Initial height in pixels. @default 240 */
|
|
22
35
|
height?: number;
|
|
36
|
+
/** Which axes span the panel **on first open**. As `anchor`, a seed rather than live state. */
|
|
23
37
|
stretch?: Stretch | null;
|
|
24
38
|
}
|
|
25
39
|
export interface OverlayStacks {
|
|
@@ -48,6 +62,15 @@ export interface PanelOverlayStore {
|
|
|
48
62
|
managed: Map<string, ManagedWidget>;
|
|
49
63
|
/** Bumped whenever `managed` changes, since a `Map` is not reactive by itself. */
|
|
50
64
|
managedVersion: Ref<number>;
|
|
65
|
+
/**
|
|
66
|
+
* Live placement of each managed widget, seeded by {@link PanelOverlayStore.openManaged}
|
|
67
|
+
* from the widget's own `anchor`/`stretch` and owned here from then on.
|
|
68
|
+
*
|
|
69
|
+
* Here rather than inside `<VddFloatingWidget>` because a managed widget's `placement` model
|
|
70
|
+
* has to be *bound* by the overlay — and a bound model is authoritative on every render, so
|
|
71
|
+
* whatever the overlay binds has to be the live value rather than a re-derived seed.
|
|
72
|
+
*/
|
|
73
|
+
managedPlacements: Record<string, PanelFloatPlacement>;
|
|
51
74
|
registerToolbar(position: ToolbarPosition, size: number): void;
|
|
52
75
|
unregisterToolbar(position: ToolbarPosition): void;
|
|
53
76
|
focus(id: string): void;
|
|
@@ -58,6 +81,8 @@ export interface PanelOverlayStore {
|
|
|
58
81
|
closeManaged(id: string): void;
|
|
59
82
|
closeAllManaged(): void;
|
|
60
83
|
managedIds(): string[];
|
|
84
|
+
/** Record what a gesture did to a managed widget's placement. */
|
|
85
|
+
setManagedPlacement(id: string, placement: PanelFloatPlacement): void;
|
|
61
86
|
}
|
|
62
87
|
export declare const PANEL_OVERLAY_KEY: InjectionKey<PanelOverlayStore>;
|
|
63
88
|
export declare function createPanelOverlayStore(): PanelOverlayStore;
|