react-dockable-desktop 2.0.0 → 3.0.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/dist/index.d.cts CHANGED
@@ -1,5 +1,4 @@
1
- import * as React$1 from 'react';
2
- import React__default, { ComponentType, ReactNode } from 'react';
1
+ import React$1, { ComponentType, Context, Provider, ReactNode } from 'react';
3
2
 
4
3
  /**
5
4
  * @file WindowManager.tsx
@@ -10,9 +9,9 @@ import React__default, { ComponentType, ReactNode } from 'react';
10
9
 
11
10
  interface WindowManagerProps {
12
11
  skin?: string;
13
- defaultPanelIcon?: React__default.ReactNode;
12
+ defaultPanelIcon?: React$1.ReactNode;
14
13
  }
15
- declare const WindowManager: React__default.FC<WindowManagerProps>;
14
+ declare const WindowManager: React$1.FC<WindowManagerProps>;
16
15
 
17
16
  /**
18
17
  * Represents a registered component configuration template inside the panel catalog registry.
@@ -249,6 +248,15 @@ interface ContextMenuPredefinedMessage {
249
248
  type MessageFormatter = (msg: ContextMenuPredefinedMessage) => string;
250
249
  /** Orientation modifier indicating split directions. */
251
250
  type SplitOrientation = 'horizontal' | 'vertical';
251
+ /** The four cardinal directions a panel can be docked relative to another. */
252
+ type SplitDirection = 'left' | 'right' | 'top' | 'bottom';
253
+ /** All possible drop positions — cardinal directions plus center (same group). */
254
+ type DropPosition = SplitDirection | 'center';
255
+ /** The target leaf and position for a drag-and-drop dock operation. */
256
+ interface DropTarget {
257
+ leafId: string;
258
+ position: DropPosition;
259
+ }
252
260
  /**
253
261
  * Grid layout branch node containing nested splits and relative flex sizes.
254
262
  */
@@ -488,8 +496,9 @@ interface WindowActions {
488
496
  * Restores a previously serialized workspace from a JSON string.
489
497
  * Replaces the entire current layout — all panels not in the snapshot are closed.
490
498
  * @param layoutJson - JSON string produced by {@link saveLayout}.
499
+ * @returns `true` if the layout was successfully parsed and applied, `false` otherwise.
491
500
  */
492
- loadLayout: (layoutJson: string) => void;
501
+ loadLayout: (layoutJson: string) => boolean;
493
502
  /**
494
503
  * Publishes an event to the inter-panel pub/sub event bus.
495
504
  * @param event - Event name string.
@@ -515,7 +524,7 @@ interface WindowActions {
515
524
  * @param targetLeafId - Leaf group ID to split.
516
525
  * @param position - Which side of the target to split and dock into.
517
526
  */
518
- dockPanelToGroup: (id: string, targetLeafId: string, position: 'left' | 'right' | 'top' | 'bottom' | 'center') => void;
527
+ dockPanelToGroup: (id: string, targetLeafId: string, position: DropPosition) => void;
519
528
  /**
520
529
  * Reorders a panel's tab index within a docked leaf group.
521
530
  * @param panelId - Panel instance ID to move.
@@ -568,7 +577,7 @@ interface WindowActions {
568
577
  * @param id - Panel instance ID.
569
578
  * @param position - Edge to dock to.
570
579
  */
571
- dockPanelToWorkspaceEdge: (id: string, position: 'left' | 'right' | 'top' | 'bottom') => void;
580
+ dockPanelToWorkspaceEdge: (id: string, position: SplitDirection) => void;
572
581
  /**
573
582
  * Overrides the workspace layout direction.
574
583
  * @param dir - `'ltr'` or `'rtl'`.
@@ -604,7 +613,7 @@ declare const useStyleClasses: () => StyleClasses;
604
613
  */
605
614
  declare const useRegistry: () => PanelRegistryClass;
606
615
  interface WindowManagerProviderProps {
607
- children: React__default.ReactNode;
616
+ children: React$1.ReactNode;
608
617
  /** WorkspaceClient instance created outside the React tree. When provided, its registry
609
618
  * and config take precedence over the individual props below. */
610
619
  client?: WorkspaceClient;
@@ -618,26 +627,9 @@ interface WindowManagerProviderProps {
618
627
  windowClass?: string;
619
628
  windowBodyClass?: string;
620
629
  }
621
- declare const WindowManagerProvider: React__default.FC<WindowManagerProviderProps>;
622
- /**
623
- * React hook to subscribe to the live {@link WindowState} inside a component.
624
- * The component re-renders whenever the state changes.
625
- *
626
- * For imperative reads without a subscription, use {@link WorkspaceClient} methods
627
- * like `isOpen()` and `getOpenPanelIds()` instead.
628
- *
629
- * @group Hooks
630
- * @returns The current workspace state tree.
631
- * @throws Error if used outside of a {@link WindowManagerProvider}.
632
- * @example
633
- * ```tsx
634
- * function PanelList() {
635
- * const { panels } = useWindowManagerState();
636
- * return <ul>{Object.keys(panels).map(id => <li key={id}>{id}</li>)}</ul>;
637
- * }
638
- * ```
639
- */
640
- declare const useWindowManagerState: () => WindowState;
630
+ declare const WindowManagerProvider: React$1.FC<WindowManagerProviderProps>;
631
+ declare function useWindowManagerState(): WindowState;
632
+ declare function useWindowManagerState<T>(selector: (state: WindowState) => T): T;
641
633
  /**
642
634
  * React hook to retrieve all layout mutation actions.
643
635
  * Returns the public {@link WindowActions} interface.
@@ -667,15 +659,45 @@ declare const formatLabel: (label: string | ContextMenuPredefinedMessage | undef
667
659
  /**
668
660
  * React hook providing pub-sub helper methods for inter-panel event messaging.
669
661
  */
670
- declare const usePanelContext: () => {
671
- publish: (event: string, data: any) => void;
672
- subscribe: (event: string, callback: (data: any) => void) => () => void;
673
- };
662
+ declare const usePanelContext: () => Pick<WindowActions, "publish" | "subscribe">;
674
663
  /**
675
664
  * React hook to fetch the localizable predefined message map catalog.
676
665
  */
677
- declare const usePredefinedMessages: () => Record<"floatWindow" | "minimizePanel" | "closeTab" | "restorePanel" | "maximizePanel" | "closePanel" | "dockWindow" | "minimize" | "maximize" | "restoreSize" | "close" | "closeEmptyGroup" | "anchorToRightEdge" | "anchorToBottomEdge" | "windowAnchoringOptions" | "unsavedChangesTitle" | "unsavedChangesMessage" | "discardChanges" | "cancel" | "yes" | "no" | "ok" | "closePanelTooltip" | "closeTooltip", ContextMenuPredefinedMessage>;
666
+ declare const usePredefinedMessages: () => Record<PredefinedMessageKey, ContextMenuPredefinedMessage>;
667
+ /**
668
+ * React hook to retrieve the panel instance ID for the component currently rendered inside
669
+ * the dockable desktop. Works for docked, floating, modal, and side-panel containers.
670
+ * Opt-in — components that don't need the ID require no changes.
671
+ *
672
+ * @group Hooks
673
+ * @returns The unique panel instance ID string.
674
+ * @example
675
+ * ```tsx
676
+ * function MyPanel() {
677
+ * const panelId = usePanelId();
678
+ * const { closePanel } = useWindowManagerActions();
679
+ * return <button onClick={() => closePanel(panelId)}>Close</button>;
680
+ * }
681
+ * ```
682
+ */
683
+ declare const usePanelId: () => string;
678
684
 
685
+ /** Built-in lifecycle events always available on the WorkspaceClient event bus. */
686
+ interface BuiltInPanelEvents {
687
+ 'panel:opened': {
688
+ id: string;
689
+ component: string;
690
+ };
691
+ 'panel:closed': {
692
+ id: string;
693
+ };
694
+ 'panel:minimized': {
695
+ id: string;
696
+ };
697
+ 'panel:restored': {
698
+ id: string;
699
+ };
700
+ }
679
701
  /** Per-panel definition supplied to WorkspaceClient constructor. */
680
702
  interface PanelDefinition {
681
703
  component: ComponentType<any>;
@@ -710,15 +732,12 @@ interface WorkspaceClientConfig {
710
732
  *
711
733
  * @remarks
712
734
  * Calls made before the provider mounts are queued and replayed automatically
713
- * in order once `_connect()` fires. If the client is never connected to a
714
- * provider (e.g. `client={workspace}` was forgotten), a console warning is
715
- * emitted in development after 1 second.
716
- *
717
- * `subscribe()` and `saveLayout()` return values immediately and cannot be
718
- * queued — they return safe defaults (`() => {}` and `''`) when disconnected.
735
+ * in order once `_connect()` fires. Duplicate `openPanel` calls for the same
736
+ * ID are deduplicated while queued. Subscriptions made before mount are
737
+ * buffered and re-registered on each connect/reconnect.
719
738
  *
720
739
  * @example
721
- * const workspace = new WorkspaceClient({
740
+ * const workspace = new WorkspaceClient<MyEvents>({
722
741
  * panels: {
723
742
  * map: { component: MapPanel },
724
743
  * editor: { component: EditorPanel, defaultOptions: { title: 'Code Editor' } },
@@ -735,7 +754,7 @@ interface WorkspaceClientConfig {
735
754
  * workspace.openPanel('map-1', 'map');
736
755
  * workspace.focusPanel('map-1');
737
756
  */
738
- declare class WorkspaceClient {
757
+ declare class WorkspaceClient<TUserEvents extends Record<string, unknown> = Record<string, unknown>> {
739
758
  /** Scoped panel registry — fully independent from the global singleton. */
740
759
  readonly registry: PanelRegistryClass;
741
760
  /** Serialised layout to restore on mount, or null to start with an empty canvas. */
@@ -743,9 +762,14 @@ declare class WorkspaceClient {
743
762
  /** Non-rendering configuration forwarded to the provider. */
744
763
  readonly config: Pick<WorkspaceClientConfig, 'formatMessage' | 'predefinedMessages' | 'dir'>;
745
764
  private _actions;
765
+ private _initialized;
746
766
  /** Calls queued before _connect() fires — replayed in order on first connect. */
747
767
  private _pendingCalls;
748
- /** DEV-only timer that warns if _connect() is never called within 1 second. */
768
+ /** Tracks openPanel IDs in the pending queue to prevent duplicates before mount. */
769
+ private _pendingOpenPanelIds;
770
+ /** Subscriptions buffered before connect — re-registered on every connect/reconnect. */
771
+ private _pendingSubscriptions;
772
+ /** Timer that emits an error if _connect() is never called with pending work. */
749
773
  private _disconnectedWarnTimer;
750
774
  constructor(config?: WorkspaceClientConfig);
751
775
  /** @internal Called by WindowManagerProvider after mount. */
@@ -754,11 +778,9 @@ declare class WorkspaceClient {
754
778
  _disconnect(): void;
755
779
  /** True while the provider is mounted and React state is accessible. */
756
780
  get isConnected(): boolean;
757
- /**
758
- * Dispatches a void action immediately if connected, or queues it for replay.
759
- * In development, warns if the client is still not connected after 1 second.
760
- */
781
+ private _startWarnTimer;
761
782
  private _dispatch;
783
+ private _subscribeRaw;
762
784
  openPanel(...args: Parameters<WindowActions['openPanel']>): void;
763
785
  closePanel(id: string): void;
764
786
  minimizePanel(id: string): void;
@@ -777,12 +799,37 @@ declare class WorkspaceClient {
777
799
  /** Returns the IDs of all currently open panels. */
778
800
  getOpenPanelIds(): string[];
779
801
  saveLayout(): string;
780
- loadLayout(json: string): void;
802
+ loadLayout(json: string): boolean;
781
803
  setDirection(dir: 'ltr' | 'rtl'): void;
782
- publish(event: string, data: unknown): void;
783
- subscribe(event: string, callback: (data: unknown) => void): () => void;
804
+ publish<K extends keyof (TUserEvents & BuiltInPanelEvents)>(event: K, data: (TUserEvents & BuiltInPanelEvents)[K]): void;
805
+ subscribe<K extends keyof (TUserEvents & BuiltInPanelEvents)>(event: K, callback: (data: (TUserEvents & BuiltInPanelEvents)[K]) => void): () => void;
806
+ /** Subscribe to panel open events. Fires only for newly created panels. */
807
+ onPanelOpen(callback: (id: string, component: string) => void): () => void;
808
+ /** Subscribe to panel close events. */
809
+ onPanelClose(callback: (id: string) => void): () => void;
810
+ /** Subscribe to panel minimize events. */
811
+ onPanelMinimize(callback: (id: string) => void): () => void;
812
+ /** Subscribe to panel restore events. */
813
+ onPanelRestore(callback: (id: string) => void): () => void;
784
814
  }
785
815
 
816
+ /**
817
+ * Composite provider that wraps both `WindowManagerProvider` and `PanelProvider`
818
+ * in the correct order. Drop-in replacement for manually nesting both providers.
819
+ *
820
+ * `WindowManagerProvider` and `PanelProvider` remain independently exported
821
+ * for cases that require custom nesting or separate configuration.
822
+ *
823
+ * @example
824
+ * ```tsx
825
+ * <DockableDesktopProvider client={workspace}>
826
+ * <WindowManager />
827
+ * <ModalStackRenderer />
828
+ * </DockableDesktopProvider>
829
+ * ```
830
+ */
831
+ declare const DockableDesktopProvider: React$1.FC<WindowManagerProviderProps>;
832
+
786
833
  /**
787
834
  * Options used when requesting to close a container.
788
835
  */
@@ -827,8 +874,8 @@ interface FormContainerContract {
827
874
  /**
828
875
  * Context that supplies the {@link FormContainerContract} to panels inside the Window Manager.
829
876
  */
830
- declare const FormContainerContext: React$1.Context<FormContainerContract>;
831
- declare const FormContainerProvider: React$1.Provider<FormContainerContract>;
877
+ declare const FormContainerContext: Context<FormContainerContract>;
878
+ declare const FormContainerProvider: Provider<FormContainerContract>;
832
879
  /**
833
880
  * React hook to retrieve the current {@link FormContainerContract} from context.
834
881
  * Enables sub-forms to trigger close requests, mark themselves dirty, rename their tabs, or listen to resize events.
@@ -855,7 +902,7 @@ interface SidePanelOptions {
855
902
  /** Display title for the side-panel header. */
856
903
  title?: PanelTitle;
857
904
  /** Icon displayed next to the panel title. */
858
- icon?: React__default.ReactNode;
905
+ icon?: React$1.ReactNode;
859
906
  /** Specific CSS width (e.g. 300, '40%') for the panel container. */
860
907
  width?: number | string;
861
908
  }
@@ -864,7 +911,7 @@ interface ModalOptions {
864
911
  /** Display title for the modal header. */
865
912
  title?: PanelTitle;
866
913
  /** Icon displayed in the modal title bar. */
867
- icon?: React__default.ReactNode;
914
+ icon?: React$1.ReactNode;
868
915
  /** Size modifier affecting CSS max-width rules. */
869
916
  size?: 'small' | 'medium' | 'large' | 'fullscreen' | 'auto';
870
917
  /** If false, hides the modal backdrop exit click and header close button. */
@@ -927,7 +974,7 @@ interface PanelActions {
927
974
  * PanelProvider component manages the state and action handlers
928
975
  * for drawers (left/right) and active stacked modal overlays.
929
976
  */
930
- declare const PanelProvider: React__default.FC<{
977
+ declare const PanelProvider: React$1.FC<{
931
978
  children: ReactNode;
932
979
  }>;
933
980
  /**
@@ -945,7 +992,7 @@ declare const usePanelActions: () => PanelActions;
945
992
  * ModalStackRenderer component acts as the global container rendering
946
993
  * all active stacked modal windows in the workspace.
947
994
  */
948
- declare const ModalStackRenderer: React__default.FC;
995
+ declare const ModalStackRenderer: React$1.FC;
949
996
 
950
997
  interface SidePanelRendererProps {
951
998
  /**
@@ -959,15 +1006,15 @@ interface SidePanelRendererProps {
959
1006
  * SidePanelRenderer component acts as the global container rendering both
960
1007
  * left and right side drawers if they are currently active.
961
1008
  */
962
- declare const SidePanelRenderer: React__default.FC<SidePanelRendererProps>;
1009
+ declare const SidePanelRenderer: React$1.FC<SidePanelRendererProps>;
963
1010
  /**
964
1011
  * LeftPanelRenderer component renders ONLY the left side drawer if it is currently active.
965
1012
  */
966
- declare const LeftPanelRenderer: React__default.FC<SidePanelRendererProps>;
1013
+ declare const LeftPanelRenderer: React$1.FC<SidePanelRendererProps>;
967
1014
  /**
968
1015
  * RightPanelRenderer component renders ONLY the right side drawer if it is currently active.
969
1016
  */
970
- declare const RightPanelRenderer: React__default.FC<SidePanelRendererProps>;
1017
+ declare const RightPanelRenderer: React$1.FC<SidePanelRendererProps>;
971
1018
 
972
1019
  /**
973
1020
  * Props for the {@link ConfirmationForm} component.
@@ -1000,7 +1047,7 @@ interface ConfirmationFormProps {
1000
1047
  * ConfirmationForm component renders a standard dialog content layout,
1001
1048
  * allowing users to confirm actions or abort them. Exposes action callbacks.
1002
1049
  */
1003
- declare const ConfirmationForm: React__default.FC<ConfirmationFormProps>;
1050
+ declare const ConfirmationForm: React$1.FC<ConfirmationFormProps>;
1004
1051
 
1005
1052
  /**
1006
1053
  * @file Sidebar.tsx
@@ -1014,7 +1061,7 @@ declare const ConfirmationForm: React__default.FC<ConfirmationFormProps>;
1014
1061
  interface SidebarTab {
1015
1062
  id: string;
1016
1063
  label: string;
1017
- icon: React__default.ReactNode;
1064
+ icon: React$1.ReactNode;
1018
1065
  /**
1019
1066
  * Mount immediately when the Sidebar first renders, not on first user click.
1020
1067
  * Implies `preserveState: true`.
@@ -1038,7 +1085,7 @@ interface SidebarTab {
1038
1085
  * @param onOpen - call to expand the drawer and select this tab programmatically
1039
1086
  * (useful when the panel itself detects it has new data to show)
1040
1087
  */
1041
- renderContent: (tabId: string, onClose: () => void, onOpen: () => void) => React__default.ReactNode;
1088
+ renderContent: (tabId: string, onClose: () => void, onOpen: () => void) => React$1.ReactNode;
1042
1089
  }
1043
1090
  interface SidebarProps {
1044
1091
  /** Which side the tab strip and drawer appear on. Default: 'right' */
@@ -1051,7 +1098,7 @@ interface SidebarProps {
1051
1098
  /** Called when the active tab changes in uncontrolled mode. */
1052
1099
  onActiveTabChange?: (tabId: string | null) => void;
1053
1100
  /** Main workspace content, rendered between the strip and drawer (or around them). */
1054
- children?: React__default.ReactNode;
1101
+ children?: React$1.ReactNode;
1055
1102
  }
1056
1103
  /**
1057
1104
  * Imperative handle exposed by `<Sidebar ref={...}>` via forwardRef.
@@ -1070,6 +1117,6 @@ interface SidebarHandle {
1070
1117
  * Sidebar component rendering a tab strip and a collapsible content drawer.
1071
1118
  * Supports imperative method bindings like openTab and closeDrawer via forwardRef.
1072
1119
  */
1073
- declare const Sidebar: React__default.ForwardRefExoticComponent<SidebarProps & React__default.RefAttributes<SidebarHandle>>;
1120
+ declare const Sidebar: React$1.ForwardRefExoticComponent<SidebarProps & React$1.RefAttributes<SidebarHandle>>;
1074
1121
 
1075
- export { type CloseOptions, ConfirmationForm, type ConfirmationFormProps, type ContextMenuPredefinedMessage, type FloatingWindow, FormContainerContext, type FormContainerContract, FormContainerProvider, type LayoutGridNode, type LayoutLeafNode, type LayoutNode, LeftPanelRenderer, type MessageFormatter, type ModalOptions, ModalStackRenderer, type PanelActions, type PanelDefinition, type PanelInfo, type PanelInstance, type PanelInstanceId, PanelProvider, PanelRegistry, PanelRegistryClass, type PanelRegistryEntry, type PanelState, type PanelTitle, type PredefinedMessageKey, RightPanelRenderer, type SidePanelOptions, SidePanelRenderer, type SidePanelRendererProps, Sidebar, type SidebarHandle, type SidebarProps, type SidebarTab, type SplitOrientation, type StyleClasses, type WindowActions, WindowManager, WindowManagerProvider, type WindowState, WorkspaceClient, type WorkspaceClientConfig, defaultPredefinedMessages, formatLabel, useFormContainer, useFormatMessage, usePanelActions, usePanelContext, usePanelState, usePredefinedMessages, useRegistry, useStyleClasses, useWindowManagerActions, useWindowManagerState };
1122
+ export { type BuiltInPanelEvents, type CloseOptions, ConfirmationForm, type ConfirmationFormProps, type ContextMenuPredefinedMessage, DockableDesktopProvider, type DropPosition, type DropTarget, type FloatingWindow, FormContainerContext, type FormContainerContract, FormContainerProvider, type LayoutGridNode, type LayoutLeafNode, type LayoutNode, LeftPanelRenderer, type MessageFormatter, type ModalOptions, ModalStackRenderer, type PanelActions, type PanelDefinition, type PanelInfo, type PanelInstance, type PanelInstanceId, PanelProvider, PanelRegistry, PanelRegistryClass, type PanelRegistryEntry, type PanelState, type PanelTitle, type PredefinedMessageKey, RightPanelRenderer, type SidePanelOptions, SidePanelRenderer, type SidePanelRendererProps, Sidebar, type SidebarHandle, type SidebarProps, type SidebarTab, type SplitDirection, type SplitOrientation, type StyleClasses, type WindowActions, WindowManager, WindowManagerProvider, type WindowState, WorkspaceClient, type WorkspaceClientConfig, defaultPredefinedMessages, formatLabel, useFormContainer, useFormatMessage, usePanelActions, usePanelContext, usePanelId, usePanelState, usePredefinedMessages, useRegistry, useStyleClasses, useWindowManagerActions, useWindowManagerState };