@forgeax/app-shell 0.41.0 → 0.43.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/react.d.ts +32 -1
- package/dist/react.js +210 -9
- package/package.json +1 -1
package/dist/react.d.ts
CHANGED
|
@@ -41,6 +41,37 @@ interface ResizeHandleProps {
|
|
|
41
41
|
ariaLabel?: string;
|
|
42
42
|
title?: string;
|
|
43
43
|
}
|
|
44
|
+
type PointerDragFinishReason = 'pointerup' | 'pointercancel' | 'lostpointercapture' | 'dispose' | 'error';
|
|
45
|
+
interface PointerDragSessionOptions<Session> {
|
|
46
|
+
readonly element: HTMLElement;
|
|
47
|
+
readonly begin: (event: globalThis.PointerEvent) => Session | null;
|
|
48
|
+
readonly move: (session: Session, event: globalThis.PointerEvent) => void;
|
|
49
|
+
readonly end?: (session: Session, reason: PointerDragFinishReason) => void;
|
|
50
|
+
readonly preventDefault?: boolean;
|
|
51
|
+
readonly stopPropagation?: boolean;
|
|
52
|
+
readonly draggingClassName?: string;
|
|
53
|
+
}
|
|
54
|
+
type ThresholdPointerDragFinishReason = 'pointerup' | 'pointercancel' | 'cancel' | 'dispose' | 'error';
|
|
55
|
+
interface ThresholdPointerDragSessionOptions<Session> {
|
|
56
|
+
readonly target: Window;
|
|
57
|
+
readonly pointerId: number;
|
|
58
|
+
readonly startX: number;
|
|
59
|
+
readonly startY: number;
|
|
60
|
+
readonly threshold: number;
|
|
61
|
+
readonly begin: (event: globalThis.PointerEvent) => Session | null;
|
|
62
|
+
readonly move: (session: Session, event: globalThis.PointerEvent) => void;
|
|
63
|
+
readonly end?: (session: Session, reason: ThresholdPointerDragFinishReason) => void;
|
|
64
|
+
readonly onSettled?: (reason: ThresholdPointerDragFinishReason, started: boolean) => void;
|
|
65
|
+
readonly registerCancel?: (cancel: () => void) => void | (() => void);
|
|
66
|
+
}
|
|
67
|
+
interface ThresholdPointerDragSession {
|
|
68
|
+
cancel(): void;
|
|
69
|
+
dispose(): void;
|
|
70
|
+
}
|
|
71
|
+
/** Own one post-pointerdown threshold arm and its global listener lifecycle. */
|
|
72
|
+
declare function installThresholdPointerDragSession<Session>(options: ThresholdPointerDragSessionOptions<Session>): ThresholdPointerDragSession;
|
|
73
|
+
/** Own one imperative pointer-capture drag session and its balanced teardown. */
|
|
74
|
+
declare function installPointerDragSession<Session>(options: PointerDragSessionOptions<Session>): () => void;
|
|
44
75
|
type AnchoredResizeDirection = 'subtract' | 'add';
|
|
45
76
|
interface AnchoredResizeSession {
|
|
46
77
|
readonly startSize: number;
|
|
@@ -202,4 +233,4 @@ interface ShellSlotProps extends HTMLAttributes<HTMLElement> {
|
|
|
202
233
|
/** Structural shell marker that preserves the caller's semantic element. */
|
|
203
234
|
declare function ShellSlot({ as, name, ...props }: ShellSlotProps): ReactElement;
|
|
204
235
|
|
|
205
|
-
export { type AnchoredResizeDirection, AnchoredResizeHandle, type AnchoredResizeHandleProps, type AnchoredResizeSession, DetachedPanelBoundary, type DetachedPanelBoundaryProps, DetachedSurfaceFrame, type DetachedSurfaceFrameProps, DetachedSurfaceStatus, type DetachedSurfaceStatusProps, type DetachedSurfaceStatusTone, type DockLayoutControlBinding, type DockLayoutControlBindingOptions, DockLayoutMenu, type DockLayoutMenuPanel, type DockLayoutMenuProps, FloatingMenu, type FloatingMenuAnchor, type FloatingMenuPoint, type FloatingMenuProps, type PanelContentPadding, type PanelContentPolicy, type PanelContentScroll, type PanelContentTone, PanelEmptyState, type PanelEmptyStateProps, PanelSurface, type PanelSurfaceProps, type PersistentSizeStorage, type PersistentSizeStore, type PersistentSizeStoreOptions, type PersistentSizeUpdate, ResizeHandle, type ResizeHandleProps, ShellSlot, type ShellSlotElement, type ShellSlotProps, SlotDebugOverlay, SurfacePlaceholder, type SurfacePlaceholderProps, SurfaceRegion, type SurfaceRegionProps, applyAnchoredResizeDelta, beginAnchoredResize, createPersistentSizeStore, hashSlotHue, isSlotDebugEnabled, useDockLayoutControlBinding, useLocalSize, usePersistentSizeStore };
|
|
236
|
+
export { type AnchoredResizeDirection, AnchoredResizeHandle, type AnchoredResizeHandleProps, type AnchoredResizeSession, DetachedPanelBoundary, type DetachedPanelBoundaryProps, DetachedSurfaceFrame, type DetachedSurfaceFrameProps, DetachedSurfaceStatus, type DetachedSurfaceStatusProps, type DetachedSurfaceStatusTone, type DockLayoutControlBinding, type DockLayoutControlBindingOptions, DockLayoutMenu, type DockLayoutMenuPanel, type DockLayoutMenuProps, FloatingMenu, type FloatingMenuAnchor, type FloatingMenuPoint, type FloatingMenuProps, type PanelContentPadding, type PanelContentPolicy, type PanelContentScroll, type PanelContentTone, PanelEmptyState, type PanelEmptyStateProps, PanelSurface, type PanelSurfaceProps, type PersistentSizeStorage, type PersistentSizeStore, type PersistentSizeStoreOptions, type PersistentSizeUpdate, type PointerDragFinishReason, type PointerDragSessionOptions, ResizeHandle, type ResizeHandleProps, ShellSlot, type ShellSlotElement, type ShellSlotProps, SlotDebugOverlay, SurfacePlaceholder, type SurfacePlaceholderProps, SurfaceRegion, type SurfaceRegionProps, type ThresholdPointerDragFinishReason, type ThresholdPointerDragSession, type ThresholdPointerDragSessionOptions, applyAnchoredResizeDelta, beginAnchoredResize, createPersistentSizeStore, hashSlotHue, installPointerDragSession, installThresholdPointerDragSession, isSlotDebugEnabled, useDockLayoutControlBinding, useLocalSize, usePersistentSizeStore };
|
package/dist/react.js
CHANGED
|
@@ -690,13 +690,13 @@ function useLocalSize(key, initial, min, max) {
|
|
|
690
690
|
};
|
|
691
691
|
return [value, setValue];
|
|
692
692
|
}
|
|
693
|
-
var
|
|
694
|
-
function
|
|
693
|
+
var elementClassLeases = /* @__PURE__ */ new WeakMap();
|
|
694
|
+
function acquireElementClassLease(element, tokens) {
|
|
695
695
|
const uniqueTokens = [...new Set(tokens)];
|
|
696
|
-
let records =
|
|
696
|
+
let records = elementClassLeases.get(element);
|
|
697
697
|
if (!records) {
|
|
698
698
|
records = /* @__PURE__ */ new Map();
|
|
699
|
-
|
|
699
|
+
elementClassLeases.set(element, records);
|
|
700
700
|
}
|
|
701
701
|
for (const token of uniqueTokens) {
|
|
702
702
|
const existing = records.get(token);
|
|
@@ -704,8 +704,8 @@ function acquireBodyClassLease(body, tokens) {
|
|
|
704
704
|
existing.count += 1;
|
|
705
705
|
continue;
|
|
706
706
|
}
|
|
707
|
-
const owned = !
|
|
708
|
-
if (owned)
|
|
707
|
+
const owned = !element.classList.contains(token);
|
|
708
|
+
if (owned) element.classList.add(token);
|
|
709
709
|
records.set(token, { count: 1, owned });
|
|
710
710
|
}
|
|
711
711
|
let active = true;
|
|
@@ -718,9 +718,208 @@ function acquireBodyClassLease(body, tokens) {
|
|
|
718
718
|
record.count -= 1;
|
|
719
719
|
if (record.count > 0) continue;
|
|
720
720
|
records?.delete(token);
|
|
721
|
-
if (record.owned)
|
|
721
|
+
if (record.owned) element.classList.remove(token);
|
|
722
722
|
}
|
|
723
|
-
if (records?.size === 0)
|
|
723
|
+
if (records?.size === 0) elementClassLeases.delete(element);
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function installThresholdPointerDragSession(options) {
|
|
727
|
+
const threshold = Number.isFinite(options.threshold) ? Math.max(0, options.threshold) : 0;
|
|
728
|
+
let disposed = false;
|
|
729
|
+
let settled = false;
|
|
730
|
+
let settledReason = null;
|
|
731
|
+
let starting = false;
|
|
732
|
+
let active = null;
|
|
733
|
+
let unregisterCancel = null;
|
|
734
|
+
const removeListeners = () => {
|
|
735
|
+
options.target.removeEventListener("pointermove", onPointerMove, true);
|
|
736
|
+
options.target.removeEventListener("pointerup", onPointerFinish, true);
|
|
737
|
+
options.target.removeEventListener("pointercancel", onPointerFinish, true);
|
|
738
|
+
};
|
|
739
|
+
const releaseCancelRegistration = () => {
|
|
740
|
+
const unregister = unregisterCancel;
|
|
741
|
+
unregisterCancel = null;
|
|
742
|
+
try {
|
|
743
|
+
unregister?.();
|
|
744
|
+
} catch {
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
const settle = (reason) => {
|
|
748
|
+
if (settled) return;
|
|
749
|
+
settled = true;
|
|
750
|
+
settledReason = reason;
|
|
751
|
+
removeListeners();
|
|
752
|
+
releaseCancelRegistration();
|
|
753
|
+
const current = active;
|
|
754
|
+
active = null;
|
|
755
|
+
if (current !== null) {
|
|
756
|
+
try {
|
|
757
|
+
options.end?.(current, reason);
|
|
758
|
+
} catch {
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
try {
|
|
762
|
+
options.onSettled?.(reason, current !== null);
|
|
763
|
+
} catch {
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
function onPointerMove(event) {
|
|
767
|
+
if (settled || event.pointerId !== options.pointerId) return;
|
|
768
|
+
if (active === null) {
|
|
769
|
+
if (starting) return;
|
|
770
|
+
if (Math.hypot(event.clientX - options.startX, event.clientY - options.startY) < threshold) return;
|
|
771
|
+
starting = true;
|
|
772
|
+
let candidate;
|
|
773
|
+
try {
|
|
774
|
+
candidate = options.begin(event);
|
|
775
|
+
} catch {
|
|
776
|
+
starting = false;
|
|
777
|
+
settle("error");
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
starting = false;
|
|
781
|
+
if (candidate === null) {
|
|
782
|
+
settle("cancel");
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
if (settled) {
|
|
786
|
+
try {
|
|
787
|
+
options.end?.(candidate, settledReason ?? "dispose");
|
|
788
|
+
} catch {
|
|
789
|
+
}
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
active = candidate;
|
|
793
|
+
}
|
|
794
|
+
const current = active;
|
|
795
|
+
if (current === null) return;
|
|
796
|
+
try {
|
|
797
|
+
options.move(current, event);
|
|
798
|
+
} catch {
|
|
799
|
+
settle("error");
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
function onPointerFinish(event) {
|
|
803
|
+
if (settled || event.pointerId !== options.pointerId) return;
|
|
804
|
+
settle(event.type === "pointercancel" ? "pointercancel" : "pointerup");
|
|
805
|
+
}
|
|
806
|
+
options.target.addEventListener("pointermove", onPointerMove, true);
|
|
807
|
+
options.target.addEventListener("pointerup", onPointerFinish, true);
|
|
808
|
+
options.target.addEventListener("pointercancel", onPointerFinish, true);
|
|
809
|
+
if (options.registerCancel) {
|
|
810
|
+
let registered;
|
|
811
|
+
try {
|
|
812
|
+
registered = options.registerCancel(() => settle("cancel"));
|
|
813
|
+
} catch {
|
|
814
|
+
settle("error");
|
|
815
|
+
registered = void 0;
|
|
816
|
+
}
|
|
817
|
+
if (registered) {
|
|
818
|
+
if (settled) {
|
|
819
|
+
try {
|
|
820
|
+
registered();
|
|
821
|
+
} catch {
|
|
822
|
+
}
|
|
823
|
+
} else {
|
|
824
|
+
unregisterCancel = registered;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return {
|
|
829
|
+
cancel: () => settle("cancel"),
|
|
830
|
+
dispose: () => {
|
|
831
|
+
if (disposed) return;
|
|
832
|
+
disposed = true;
|
|
833
|
+
settle("dispose");
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
function installPointerDragSession(options) {
|
|
838
|
+
const { element } = options;
|
|
839
|
+
let disposed = false;
|
|
840
|
+
let starting = false;
|
|
841
|
+
let active = null;
|
|
842
|
+
const removeSessionListeners = () => {
|
|
843
|
+
element.removeEventListener("pointermove", onPointerMove);
|
|
844
|
+
element.removeEventListener("pointerup", onPointerFinish);
|
|
845
|
+
element.removeEventListener("pointercancel", onPointerFinish);
|
|
846
|
+
element.removeEventListener("lostpointercapture", onPointerFinish);
|
|
847
|
+
};
|
|
848
|
+
const finish = (reason) => {
|
|
849
|
+
const current = active;
|
|
850
|
+
if (!current) return;
|
|
851
|
+
active = null;
|
|
852
|
+
removeSessionListeners();
|
|
853
|
+
try {
|
|
854
|
+
element.releasePointerCapture(current.pointerId);
|
|
855
|
+
} catch {
|
|
856
|
+
}
|
|
857
|
+
try {
|
|
858
|
+
current.releaseClass();
|
|
859
|
+
} catch {
|
|
860
|
+
}
|
|
861
|
+
try {
|
|
862
|
+
options.end?.(current.session, reason);
|
|
863
|
+
} catch {
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
function onPointerMove(event) {
|
|
867
|
+
const current = active;
|
|
868
|
+
if (!current || current.pointerId !== event.pointerId) return;
|
|
869
|
+
try {
|
|
870
|
+
options.move(current.session, event);
|
|
871
|
+
} catch {
|
|
872
|
+
finish("error");
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
function onPointerFinish(event) {
|
|
876
|
+
if (!active || active.pointerId !== event.pointerId) return;
|
|
877
|
+
const reason = event.type === "pointercancel" ? "pointercancel" : event.type === "lostpointercapture" ? "lostpointercapture" : "pointerup";
|
|
878
|
+
finish(reason);
|
|
879
|
+
}
|
|
880
|
+
const onPointerDown = (event) => {
|
|
881
|
+
if (disposed || active || starting) return;
|
|
882
|
+
starting = true;
|
|
883
|
+
let session;
|
|
884
|
+
try {
|
|
885
|
+
session = options.begin(event);
|
|
886
|
+
} catch {
|
|
887
|
+
starting = false;
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
starting = false;
|
|
891
|
+
if (session === null) return;
|
|
892
|
+
if (disposed) {
|
|
893
|
+
try {
|
|
894
|
+
options.end?.(session, "dispose");
|
|
895
|
+
} catch {
|
|
896
|
+
}
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (options.preventDefault) event.preventDefault();
|
|
900
|
+
if (options.stopPropagation) event.stopPropagation();
|
|
901
|
+
const classTokens = options.draggingClassName?.trim().split(/\s+/).filter(Boolean) ?? [];
|
|
902
|
+
active = {
|
|
903
|
+
pointerId: event.pointerId,
|
|
904
|
+
session,
|
|
905
|
+
releaseClass: acquireElementClassLease(element, classTokens)
|
|
906
|
+
};
|
|
907
|
+
element.addEventListener("pointermove", onPointerMove);
|
|
908
|
+
element.addEventListener("pointerup", onPointerFinish);
|
|
909
|
+
element.addEventListener("pointercancel", onPointerFinish);
|
|
910
|
+
element.addEventListener("lostpointercapture", onPointerFinish);
|
|
911
|
+
try {
|
|
912
|
+
element.setPointerCapture(event.pointerId);
|
|
913
|
+
} catch {
|
|
914
|
+
finish("error");
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
element.addEventListener("pointerdown", onPointerDown);
|
|
918
|
+
return () => {
|
|
919
|
+
if (disposed) return;
|
|
920
|
+
disposed = true;
|
|
921
|
+
element.removeEventListener("pointerdown", onPointerDown);
|
|
922
|
+
finish("dispose");
|
|
724
923
|
};
|
|
725
924
|
}
|
|
726
925
|
function beginAnchoredResize(startSize, direction = "subtract") {
|
|
@@ -845,7 +1044,7 @@ function AnchoredResizeHandle({
|
|
|
845
1044
|
finishSession();
|
|
846
1045
|
const bodyClassTokens = bodyClassNameRef.current?.trim().split(/\s+/).filter(Boolean) ?? [];
|
|
847
1046
|
const resize = beginAnchoredResize(readSizeRef.current(), directionRef.current);
|
|
848
|
-
const releaseBodyClass = typeof document !== "undefined" && bodyClassTokens.length > 0 ?
|
|
1047
|
+
const releaseBodyClass = typeof document !== "undefined" && bodyClassTokens.length > 0 ? acquireElementClassLease(document.body, bodyClassTokens) : () => {
|
|
849
1048
|
};
|
|
850
1049
|
sessionRef.current = {
|
|
851
1050
|
resize,
|
|
@@ -1235,6 +1434,8 @@ export {
|
|
|
1235
1434
|
beginAnchoredResize,
|
|
1236
1435
|
createPersistentSizeStore,
|
|
1237
1436
|
hashSlotHue,
|
|
1437
|
+
installPointerDragSession,
|
|
1438
|
+
installThresholdPointerDragSession,
|
|
1238
1439
|
isSlotDebugEnabled,
|
|
1239
1440
|
useDockLayoutControlBinding,
|
|
1240
1441
|
useLocalSize,
|