vue-dockable-desktop 1.0.0 → 1.0.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,54 @@ correspondence lives, alongside the feature-by-feature map in [docs/PARITY.md](d
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [1.0.1] — 2026-09-17
15
+
16
+ **Parity: react-dockable-desktop 6.3.0.**
17
+
18
+ ### Fixed
19
+
20
+ - **A widget opened through `useFloatingWidgets()` discarded every placement gesture.** Dropping
21
+ a managed widget on another corner returned it to the corner `open()` named, and a stretched
22
+ one lost its stretch as soon as any other widget opened or closed. Template-declared widgets
23
+ and plain resizes were unaffected. Reported by a user.
24
+
25
+ `<VddPanelOverlay>` bound `placement` — a `defineModel` — as a fresh `{ anchor, stretch }`
26
+ literal with no `@update:placement`, and Vue re-syncs a model from its prop whenever the
27
+ prop's *identity* changes. Every render of the overlay therefore reset the widget, and the
28
+ overlay re-renders on exactly the wrong events: a drop clears `draggingId` in the same
29
+ function that applies the placement, and opening a widget bumps `managedVersion`.
30
+
31
+ The overlay now keeps a placement record per widget id and writes gestures straight back into
32
+ it. `anchor`, `stretch`, `width` and `height` on `open()` are **initial values** — as rdd's
33
+ `defaultAnchor`/`defaultStretch` are — so `open()` on an id that is already open refreshes its
34
+ content and leaves the widget where the user put it, and `close()` then `open()` is what
35
+ resets placement. No public API changed.
36
+
37
+ A port regression: rdd never makes the anchor controllable, and the only placement value it
38
+ lets a caller control is a primitive, so identity churn cannot arise there. Recorded as **R1**
39
+ in [`docs/PARITY.md`](docs/PARITY.md), with the underlying `defineModel` constraint amended
40
+ into [ADR 0005](docs/decisions/0005-vmodel.md). Pinned by PO31–PO35, four M14 gate rules, and
41
+ a real pointer drag in the demo's browser walkthrough — the gesture path into an overlay-owned
42
+ widget that no layer of either library's verification had ever driven.
43
+
44
+ - **In the demo, no camera marker on the main map could be clicked**, though the legend invited
45
+ it: a decorative polygon added after the markers covered the whole cluster and swallowed every
46
+ click. It is `interactive: false` now. Found by the new browser assertion trying to open a
47
+ widget the way a user does.
48
+
49
+ ### Changed
50
+
51
+ - The demo's camera widgets are opened through `useFloatingWidgets()` instead of a `v-for` over
52
+ `<VddFloatingWidget>`, so the managed path — the one that regressed — is demonstrated and
53
+ walked by the gate. The M14 capability rule now requires the composable itself rather than
54
+ accepting `@update:open`, which is what let the demo claim the capability without exercising
55
+ it.
56
+ - The M11 browser gate's stretch assertion was measuring the wrong thing: it expected a
57
+ full-width strip to be `panel - 16` and ignored the inline panel toolbars beside it, so a
58
+ strip that tracked its panel perfectly was reported as having stopped. It now asserts the
59
+ tracking claim as a delta and measures the toolbar band. No library behaviour was involved —
60
+ the failure reproduced identically against 1.0.0's source.
61
+
14
62
  ## [1.0.0] — 2026-09-16
15
63
 
16
64
  **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 725 tests.
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;