vue-dockable-desktop 1.8.1 → 1.9.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 CHANGED
@@ -11,6 +11,78 @@ correspondence lives, alongside the feature-by-feature map in [docs/PARITY.md](d
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [1.9.0] — 2026-10-06
15
+
16
+ **Parity: react-dockable-desktop 7.8.0.** More control over how the desktop looks and where panels
17
+ open, all opt-in: without the new options, nothing changes. Same names as rdd 7.8.0, in Vue's idiom.
18
+
19
+ ### Added
20
+
21
+ - **Your own empty-workspace view.** `<VddDesktop>` takes a `#empty-workspace` slot, shown while no
22
+ panel is docked in place of the built-in message: a welcome screen, a logo, "Open a file"
23
+ buttons. Floating windows still show over it, and a window can still be dropped onto it to dock.
24
+ Empty groups inside a split keep the built-in message.
25
+ - **Open a panel beside another.** `openPanel(id, component, { dockTo: { panel, position, size } })`
26
+ docks a new panel as a tab in that panel's group (`position: 'center'`) or in a new group split
27
+ off on one side, taking `size` (0.1–0.9) of the split. It wins over `initialTarget`. If the
28
+ target isn't docked, the panel is placed as usual and a warning says why.
29
+ - **State attributes for your CSS.** Tabs carry `data-vdd-selected`, `data-vdd-focused` and
30
+ `data-vdd-dirty`; floating windows carry `data-vdd-focused` and `data-vdd-maximized`. Each is
31
+ present only while it is true. The existing classes are unchanged.
32
+ - **Per-kind classes.** `className` and `tabClassName` in a kind's `defaultOptions` add your class
33
+ to every panel of that kind (on its content element, which moves with it) and to its tab.
34
+ - **`keepAlive: false`**, per kind: the component unmounts while the panel is an unselected tab or
35
+ minimised, and mounts afresh when shown. Its own state is lost each time, and in such a panel
36
+ `onUnmounted` means hidden, not closed; a guard it registered with `onBeforeClose` is inactive
37
+ while it is unmounted, though its dirty flag still applies. The default is unchanged: panels
38
+ stay mounted. Recorded as [ADR 0021](docs/decisions/0021-opt-in-unmount-while-hidden.md), which
39
+ amends 0002 for kinds that opt in.
40
+
41
+ ### Docs
42
+
43
+ - Theming (Chapter 10): **Your own empty-workspace view**, **Styling by state and by panel kind**,
44
+ and **Using it with Vuetify, PrimeVue, Bootstrap or Tailwind** (dark mode, the library's
45
+ z-index layers, why a framework popup opened inside one of the library's modals appears behind
46
+ it and the fixes, overriding styles). Layout (Chapter 4): **Opening beside another panel**.
47
+ Panels (Chapter 3): the new registration options and **Freeing a hidden panel**. Concepts
48
+ (Chapter 2) notes the `keepAlive: false` exception beside the zero-unmount guarantee.
49
+ - `PARITY.md`: the rdd 7.8.0 trace.
50
+
51
+ ### Tests
52
+
53
+ - `test/components/releaseA.test.ts` (15 tests): the empty-workspace slot (shown and gone as panels
54
+ dock and close; empty groups inside a split keep the built-in message), the state attributes on
55
+ tabs and windows, `dockTo` (sides, centre, size clamping, winning over `initialTarget`, the
56
+ fallback and its warning, no effect on an open panel), the per-kind classes (also after
57
+ floating), and `keepAlive: false` (unmount and fresh remount, the default unchanged, no leak
58
+ over 50 hide/show cycles). Each was seen failing with its feature broken.
59
+ - M13's browser tour gains a step that shows the playground's `#empty-workspace` view, so the new
60
+ `.vdd-empty-workspace` rule is checked against a real render (the gate first failed on it as a
61
+ dead rule, which is what it is for).
62
+
63
+ ## [1.8.2] — 2026-10-06
64
+
65
+ **Parity: react-dockable-desktop 7.7.3** (code health). Neither of rdd's last two releases needs a
66
+ port: 7.7.2 fixed panels re-rendering on every workspace change, which vdd never did (each panel
67
+ host reads only its own entry), and 7.7.3 is rdd's own lint and dead-code tooling. This release is
68
+ vdd's matching lint cleanup. No API or behaviour change; the built code differs only in the
69
+ explicit `undefined` prop defaults below.
70
+
71
+ ### Internal
72
+
73
+ - **A lint warning now fails the gate.** ESLint runs with `--max-warnings 0` in the standing gate
74
+ (CI), `npm run verify` and `npm run lint`. Warnings never failed anything before, and 721 had
75
+ built up.
76
+ - **Template-layout rules are off.** `vue/max-attributes-per-line` and five other Vue
77
+ template-formatting rules accounted for 706 of the 721: they only reflow markup, and the
78
+ templates keep their own consistent layout.
79
+ - The 12 optional props without a default (`VddAlert`'s `okLabel`, `VddConfirm`'s callbacks, the
80
+ icon props, and others) declare `undefined` explicitly in `withDefaults`, as `icon` already did.
81
+ Their behaviour is unchanged.
82
+ - The demo's Markdown preview: the `v-html` lint exemption now covers the right line, and its
83
+ comment no longer calls the output sanitised. It isn't: `rehype-raw` passes raw HTML through,
84
+ which is acceptable in a demo that renders only what is typed into its own editor.
85
+
14
86
  ## [1.8.1] — 2026-10-05
15
87
 
16
88
  **Parity: react-dockable-desktop 7.7.1.** Two desktops on one page no longer strip each other's
@@ -14,6 +14,8 @@ type __VLS_Props = {
14
14
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
15
15
  icon: Component | null;
16
16
  alertType: AlertType;
17
+ onSettled: () => void;
18
+ okLabel: Label;
17
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
20
  declare const _default: typeof __VLS_export;
19
21
  export default _default;
@@ -19,8 +19,12 @@ type __VLS_Props = {
19
19
  };
20
20
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
21
21
  icon: Component | null;
22
+ alert: string;
22
23
  alertType: AlertType;
24
+ onCancel: () => void;
23
25
  yesNo: boolean;
26
+ onOk: () => void;
27
+ onSettled: (ok: boolean) => void;
24
28
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
25
29
  declare const _default: typeof __VLS_export;
26
30
  export default _default;
@@ -15,7 +15,11 @@ type __VLS_Props = {
15
15
  /** Fallback icon for panels that register none. */
16
16
  defaultPanelIcon?: unknown;
17
17
  };
18
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
18
+ declare var __VLS_13: {};
19
+ type __VLS_Slots = {} & {
20
+ 'empty-workspace'?: (props: typeof __VLS_13) => any;
21
+ };
22
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
19
23
  taskbarContextMenu: (panelId: string, event: MouseEvent | PointerEvent) => any;
20
24
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
21
25
  onTaskbarContextMenu?: ((panelId: string, event: MouseEvent | PointerEvent) => any) | undefined;
@@ -23,6 +27,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
23
27
  skin: string;
24
28
  animations: boolean;
25
29
  taskbar: TaskbarVisibility;
30
+ defaultPanelIcon: undefined;
26
31
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
32
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
27
33
  declare const _default: typeof __VLS_export;
28
34
  export default _default;
35
+ type __VLS_WithSlots<T, S> = T & {
36
+ new (): {
37
+ $slots: S;
38
+ };
39
+ };
@@ -45,6 +45,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
45
45
  }>, {
46
46
  width: number;
47
47
  height: number;
48
+ icon: Component;
48
49
  stretchable: boolean;
49
50
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
50
51
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -2,6 +2,16 @@ import type { LayoutLeafNode } from '../types';
2
2
  type __VLS_Props = {
3
3
  leaf: LayoutLeafNode;
4
4
  };
5
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
5
+ declare var __VLS_16: {};
6
+ type __VLS_Slots = {} & {
7
+ 'empty-workspace'?: (props: typeof __VLS_16) => any;
8
+ };
9
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
6
11
  declare const _default: typeof __VLS_export;
7
12
  export default _default;
13
+ type __VLS_WithSlots<T, S> = T & {
14
+ new (): {
15
+ $slots: S;
16
+ };
17
+ };
@@ -15,6 +15,7 @@ type __VLS_Slots = {} & {
15
15
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
16
16
  variant: ToolbarVariant;
17
17
  buttonVariant: ButtonVariant;
18
+ buttonSize: number;
18
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
19
20
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
20
21
  declare const _default: typeof __VLS_export;
@@ -12,6 +12,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
12
12
  onContextMenu?: ((panelId: string, event: MouseEvent | PointerEvent) => any) | undefined;
13
13
  }>, {
14
14
  visibility: TaskbarVisibility;
15
+ defaultIcon: undefined;
15
16
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
16
17
  declare const _default: typeof __VLS_export;
17
18
  export default _default;
@@ -25,6 +25,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
25
25
  width: number;
26
26
  position: ToastPosition;
27
27
  animation: "slide" | "fade" | "none";
28
+ adapter: ToastAdapter;
28
29
  pauseOnHover: boolean;
29
30
  defaultDuration: number;
30
31
  defaultClosable: boolean;
@@ -21,6 +21,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
21
21
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
22
22
  onSelect?: ((result: SearchResult) => any) | undefined;
23
23
  }>, {
24
+ placeholder: string;
24
25
  debounce: number;
25
26
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
26
27
  declare const _default: typeof __VLS_export;
@@ -3,6 +3,16 @@ type __VLS_Props = {
3
3
  node: LayoutNode;
4
4
  path: number[];
5
5
  };
6
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare var __VLS_9: {};
7
+ type __VLS_Slots = {} & {
8
+ 'empty-workspace'?: (props: typeof __VLS_9) => any;
9
+ };
10
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
12
  declare const _default: typeof __VLS_export;
8
13
  export default _default;
14
+ type __VLS_WithSlots<T, S> = T & {
15
+ new (): {
16
+ $slots: S;
17
+ };
18
+ };
@@ -32,6 +32,22 @@ export interface PanelDefaultOptions {
32
32
  * @see docs/decisions/0014-preserve-scroll-and-focus.md
33
33
  */
34
34
  preserveScroll?: boolean;
35
+ /**
36
+ * Class added to each panel of this kind, on its own content element (`.vdd-panel-content`),
37
+ * which moves with the panel between groups, windows and the taskbar preview. (1.9.0)
38
+ */
39
+ className?: string;
40
+ /** Class added to the tab of each panel of this kind. (1.9.0) */
41
+ tabClassName?: string;
42
+ /**
43
+ * `false` unmounts the panel's component while it is hidden (an unselected tab, or minimised)
44
+ * and mounts it afresh when shown, to free what a heavy, rarely shown panel holds. Its own
45
+ * state is lost each time, and a guard it registered with `onBeforeClose` is not active while
46
+ * it is unmounted (its dirty flag still is). Its tab, title and lifecycle continue, and the
47
+ * taskbar shows a letter tile instead of a live preview. @default true
48
+ * @see docs/decisions/0021-opt-in-unmount-while-hidden.md
49
+ */
50
+ keepAlive?: boolean;
35
51
  }
36
52
  /** A registered panel kind. */
37
53
  export interface PanelRegistryEntry {
@@ -74,6 +74,18 @@ export interface OpenPanelOptions<P extends object = Record<string, unknown>> {
74
74
  props?: P;
75
75
  /** If another open panel of the same `component` has this key, focus that one instead. */
76
76
  dedupeKey?: string;
77
+ /**
78
+ * Dock the new panel beside an open, docked panel: in that panel's group (`position: 'center'`,
79
+ * as a tab) or in a new group split off on one side of it. `size` is the new group's share of
80
+ * that split, from 0.1 to 0.9 (the workspace's split ratio when omitted). Wins over
81
+ * `initialTarget`. If `panel` is not docked (not open, floating or minimised), the new panel is
82
+ * placed as usual and a warning says why. Applies only to a newly opened panel. (1.9.0)
83
+ */
84
+ dockTo?: {
85
+ panel: string;
86
+ position: DropPosition;
87
+ size?: number;
88
+ };
77
89
  }
78
90
  /** The live workspace state. */
79
91
  export interface WorkspaceState {