@forgeax/app-shell 0.40.0 → 0.42.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 +34 -1
- package/dist/react.js +170 -13
- package/package.json +1 -1
package/dist/react.d.ts
CHANGED
|
@@ -10,6 +10,27 @@ declare function isSlotDebugEnabled(search?: string): boolean;
|
|
|
10
10
|
/** Dev-time visualization derived only from live `data-fx-slot` markers. */
|
|
11
11
|
declare function SlotDebugOverlay(): ReactElement;
|
|
12
12
|
|
|
13
|
+
interface PersistentSizeStorage {
|
|
14
|
+
getItem(key: string): string | null;
|
|
15
|
+
setItem(key: string, value: string): void;
|
|
16
|
+
}
|
|
17
|
+
interface PersistentSizeStoreOptions {
|
|
18
|
+
storageKey: string;
|
|
19
|
+
defaultSize: number;
|
|
20
|
+
minSize: number;
|
|
21
|
+
maxSize: number;
|
|
22
|
+
storage?: PersistentSizeStorage | null;
|
|
23
|
+
}
|
|
24
|
+
type PersistentSizeUpdate = number | ((previous: number) => number);
|
|
25
|
+
interface PersistentSizeStore {
|
|
26
|
+
getSnapshot(): number;
|
|
27
|
+
subscribe(listener: () => void): () => void;
|
|
28
|
+
setSize(next: PersistentSizeUpdate): void;
|
|
29
|
+
reload(): void;
|
|
30
|
+
}
|
|
31
|
+
/** Product-neutral persistent numeric state for resizable shell regions. */
|
|
32
|
+
declare function createPersistentSizeStore(options: PersistentSizeStoreOptions): PersistentSizeStore;
|
|
33
|
+
declare function usePersistentSizeStore(store: PersistentSizeStore): number;
|
|
13
34
|
declare function useLocalSize(key: string, initial: number, min: number, max: number): readonly [number, (next: number | ((previous: number) => number)) => void];
|
|
14
35
|
interface ResizeHandleProps {
|
|
15
36
|
orientation: 'col' | 'row';
|
|
@@ -20,6 +41,18 @@ interface ResizeHandleProps {
|
|
|
20
41
|
ariaLabel?: string;
|
|
21
42
|
title?: string;
|
|
22
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
|
+
/** Own one imperative pointer-capture drag session and its balanced teardown. */
|
|
55
|
+
declare function installPointerDragSession<Session>(options: PointerDragSessionOptions<Session>): () => void;
|
|
23
56
|
type AnchoredResizeDirection = 'subtract' | 'add';
|
|
24
57
|
interface AnchoredResizeSession {
|
|
25
58
|
readonly startSize: number;
|
|
@@ -181,4 +214,4 @@ interface ShellSlotProps extends HTMLAttributes<HTMLElement> {
|
|
|
181
214
|
/** Structural shell marker that preserves the caller's semantic element. */
|
|
182
215
|
declare function ShellSlot({ as, name, ...props }: ShellSlotProps): ReactElement;
|
|
183
216
|
|
|
184
|
-
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, ResizeHandle, type ResizeHandleProps, ShellSlot, type ShellSlotElement, type ShellSlotProps, SlotDebugOverlay, SurfacePlaceholder, type SurfacePlaceholderProps, SurfaceRegion, type SurfaceRegionProps, applyAnchoredResizeDelta, beginAnchoredResize, hashSlotHue, isSlotDebugEnabled, useDockLayoutControlBinding, useLocalSize };
|
|
217
|
+
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, applyAnchoredResizeDelta, beginAnchoredResize, createPersistentSizeStore, hashSlotHue, installPointerDragSession, isSlotDebugEnabled, useDockLayoutControlBinding, useLocalSize, usePersistentSizeStore };
|
package/dist/react.js
CHANGED
|
@@ -595,8 +595,74 @@ function SlotDebugOverlay() {
|
|
|
595
595
|
}
|
|
596
596
|
|
|
597
597
|
// src/resize.tsx
|
|
598
|
-
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
598
|
+
import { useEffect as useEffect2, useRef, useState as useState2, useSyncExternalStore } from "react";
|
|
599
599
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
600
|
+
function browserPersistentSizeStorage() {
|
|
601
|
+
if (typeof window === "undefined") return null;
|
|
602
|
+
try {
|
|
603
|
+
return window.localStorage;
|
|
604
|
+
} catch {
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function createPersistentSizeStore(options) {
|
|
609
|
+
const minSize = Math.min(options.minSize, options.maxSize);
|
|
610
|
+
const maxSize = Math.max(options.minSize, options.maxSize);
|
|
611
|
+
const normalize = (value2, fallback) => {
|
|
612
|
+
if (!Number.isFinite(value2)) return fallback;
|
|
613
|
+
return Math.min(maxSize, Math.max(minSize, Math.round(value2)));
|
|
614
|
+
};
|
|
615
|
+
const defaultSize = normalize(options.defaultSize, minSize);
|
|
616
|
+
const storage = options.storage === void 0 ? browserPersistentSizeStorage() : options.storage;
|
|
617
|
+
const read = () => {
|
|
618
|
+
try {
|
|
619
|
+
const raw = storage?.getItem(options.storageKey);
|
|
620
|
+
if (!raw) return defaultSize;
|
|
621
|
+
const parsed = Number.parseInt(raw, 10);
|
|
622
|
+
return normalize(parsed, defaultSize);
|
|
623
|
+
} catch {
|
|
624
|
+
return defaultSize;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
let value = read();
|
|
628
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
629
|
+
const commit = (next) => {
|
|
630
|
+
if (Object.is(value, next)) return;
|
|
631
|
+
value = next;
|
|
632
|
+
for (const listener of [...listeners]) {
|
|
633
|
+
try {
|
|
634
|
+
listener();
|
|
635
|
+
} catch {
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
return {
|
|
640
|
+
getSnapshot: () => value,
|
|
641
|
+
subscribe: (listener) => {
|
|
642
|
+
listeners.add(listener);
|
|
643
|
+
let active = true;
|
|
644
|
+
return () => {
|
|
645
|
+
if (!active) return;
|
|
646
|
+
active = false;
|
|
647
|
+
listeners.delete(listener);
|
|
648
|
+
};
|
|
649
|
+
},
|
|
650
|
+
setSize: (next) => {
|
|
651
|
+
const candidate = typeof next === "function" ? next(value) : next;
|
|
652
|
+
const normalized = normalize(candidate, value);
|
|
653
|
+
if (Object.is(value, normalized)) return;
|
|
654
|
+
try {
|
|
655
|
+
storage?.setItem(options.storageKey, String(normalized));
|
|
656
|
+
} catch {
|
|
657
|
+
}
|
|
658
|
+
commit(normalized);
|
|
659
|
+
},
|
|
660
|
+
reload: () => commit(read())
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function usePersistentSizeStore(store) {
|
|
664
|
+
return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
665
|
+
}
|
|
600
666
|
function useLocalSize(key, initial, min, max) {
|
|
601
667
|
const clamp = (value2) => Math.min(max, Math.max(min, value2));
|
|
602
668
|
const [value, setValueRaw] = useState2(() => {
|
|
@@ -624,13 +690,13 @@ function useLocalSize(key, initial, min, max) {
|
|
|
624
690
|
};
|
|
625
691
|
return [value, setValue];
|
|
626
692
|
}
|
|
627
|
-
var
|
|
628
|
-
function
|
|
693
|
+
var elementClassLeases = /* @__PURE__ */ new WeakMap();
|
|
694
|
+
function acquireElementClassLease(element, tokens) {
|
|
629
695
|
const uniqueTokens = [...new Set(tokens)];
|
|
630
|
-
let records =
|
|
696
|
+
let records = elementClassLeases.get(element);
|
|
631
697
|
if (!records) {
|
|
632
698
|
records = /* @__PURE__ */ new Map();
|
|
633
|
-
|
|
699
|
+
elementClassLeases.set(element, records);
|
|
634
700
|
}
|
|
635
701
|
for (const token of uniqueTokens) {
|
|
636
702
|
const existing = records.get(token);
|
|
@@ -638,8 +704,8 @@ function acquireBodyClassLease(body, tokens) {
|
|
|
638
704
|
existing.count += 1;
|
|
639
705
|
continue;
|
|
640
706
|
}
|
|
641
|
-
const owned = !
|
|
642
|
-
if (owned)
|
|
707
|
+
const owned = !element.classList.contains(token);
|
|
708
|
+
if (owned) element.classList.add(token);
|
|
643
709
|
records.set(token, { count: 1, owned });
|
|
644
710
|
}
|
|
645
711
|
let active = true;
|
|
@@ -652,9 +718,97 @@ function acquireBodyClassLease(body, tokens) {
|
|
|
652
718
|
record.count -= 1;
|
|
653
719
|
if (record.count > 0) continue;
|
|
654
720
|
records?.delete(token);
|
|
655
|
-
if (record.owned)
|
|
721
|
+
if (record.owned) element.classList.remove(token);
|
|
656
722
|
}
|
|
657
|
-
if (records?.size === 0)
|
|
723
|
+
if (records?.size === 0) elementClassLeases.delete(element);
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function installPointerDragSession(options) {
|
|
727
|
+
const { element } = options;
|
|
728
|
+
let disposed = false;
|
|
729
|
+
let starting = false;
|
|
730
|
+
let active = null;
|
|
731
|
+
const removeSessionListeners = () => {
|
|
732
|
+
element.removeEventListener("pointermove", onPointerMove);
|
|
733
|
+
element.removeEventListener("pointerup", onPointerFinish);
|
|
734
|
+
element.removeEventListener("pointercancel", onPointerFinish);
|
|
735
|
+
element.removeEventListener("lostpointercapture", onPointerFinish);
|
|
736
|
+
};
|
|
737
|
+
const finish = (reason) => {
|
|
738
|
+
const current = active;
|
|
739
|
+
if (!current) return;
|
|
740
|
+
active = null;
|
|
741
|
+
removeSessionListeners();
|
|
742
|
+
try {
|
|
743
|
+
element.releasePointerCapture(current.pointerId);
|
|
744
|
+
} catch {
|
|
745
|
+
}
|
|
746
|
+
try {
|
|
747
|
+
current.releaseClass();
|
|
748
|
+
} catch {
|
|
749
|
+
}
|
|
750
|
+
try {
|
|
751
|
+
options.end?.(current.session, reason);
|
|
752
|
+
} catch {
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
function onPointerMove(event) {
|
|
756
|
+
const current = active;
|
|
757
|
+
if (!current || current.pointerId !== event.pointerId) return;
|
|
758
|
+
try {
|
|
759
|
+
options.move(current.session, event);
|
|
760
|
+
} catch {
|
|
761
|
+
finish("error");
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
function onPointerFinish(event) {
|
|
765
|
+
if (!active || active.pointerId !== event.pointerId) return;
|
|
766
|
+
const reason = event.type === "pointercancel" ? "pointercancel" : event.type === "lostpointercapture" ? "lostpointercapture" : "pointerup";
|
|
767
|
+
finish(reason);
|
|
768
|
+
}
|
|
769
|
+
const onPointerDown = (event) => {
|
|
770
|
+
if (disposed || active || starting) return;
|
|
771
|
+
starting = true;
|
|
772
|
+
let session;
|
|
773
|
+
try {
|
|
774
|
+
session = options.begin(event);
|
|
775
|
+
} catch {
|
|
776
|
+
starting = false;
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
starting = false;
|
|
780
|
+
if (session === null) return;
|
|
781
|
+
if (disposed) {
|
|
782
|
+
try {
|
|
783
|
+
options.end?.(session, "dispose");
|
|
784
|
+
} catch {
|
|
785
|
+
}
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
if (options.preventDefault) event.preventDefault();
|
|
789
|
+
if (options.stopPropagation) event.stopPropagation();
|
|
790
|
+
const classTokens = options.draggingClassName?.trim().split(/\s+/).filter(Boolean) ?? [];
|
|
791
|
+
active = {
|
|
792
|
+
pointerId: event.pointerId,
|
|
793
|
+
session,
|
|
794
|
+
releaseClass: acquireElementClassLease(element, classTokens)
|
|
795
|
+
};
|
|
796
|
+
element.addEventListener("pointermove", onPointerMove);
|
|
797
|
+
element.addEventListener("pointerup", onPointerFinish);
|
|
798
|
+
element.addEventListener("pointercancel", onPointerFinish);
|
|
799
|
+
element.addEventListener("lostpointercapture", onPointerFinish);
|
|
800
|
+
try {
|
|
801
|
+
element.setPointerCapture(event.pointerId);
|
|
802
|
+
} catch {
|
|
803
|
+
finish("error");
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
element.addEventListener("pointerdown", onPointerDown);
|
|
807
|
+
return () => {
|
|
808
|
+
if (disposed) return;
|
|
809
|
+
disposed = true;
|
|
810
|
+
element.removeEventListener("pointerdown", onPointerDown);
|
|
811
|
+
finish("dispose");
|
|
658
812
|
};
|
|
659
813
|
}
|
|
660
814
|
function beginAnchoredResize(startSize, direction = "subtract") {
|
|
@@ -779,7 +933,7 @@ function AnchoredResizeHandle({
|
|
|
779
933
|
finishSession();
|
|
780
934
|
const bodyClassTokens = bodyClassNameRef.current?.trim().split(/\s+/).filter(Boolean) ?? [];
|
|
781
935
|
const resize = beginAnchoredResize(readSizeRef.current(), directionRef.current);
|
|
782
|
-
const releaseBodyClass = typeof document !== "undefined" && bodyClassTokens.length > 0 ?
|
|
936
|
+
const releaseBodyClass = typeof document !== "undefined" && bodyClassTokens.length > 0 ? acquireElementClassLease(document.body, bodyClassTokens) : () => {
|
|
783
937
|
};
|
|
784
938
|
sessionRef.current = {
|
|
785
939
|
resize,
|
|
@@ -944,7 +1098,7 @@ var SurfaceRegion = forwardRef(
|
|
|
944
1098
|
);
|
|
945
1099
|
|
|
946
1100
|
// src/dock-layout-control.ts
|
|
947
|
-
import { useEffect as useEffect3, useMemo, useSyncExternalStore } from "react";
|
|
1101
|
+
import { useEffect as useEffect3, useMemo, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
948
1102
|
function useDockLayoutControlBinding({
|
|
949
1103
|
state,
|
|
950
1104
|
onToggle,
|
|
@@ -952,7 +1106,7 @@ function useDockLayoutControlBinding({
|
|
|
952
1106
|
closePanel,
|
|
953
1107
|
reopenPanel
|
|
954
1108
|
}) {
|
|
955
|
-
const snapshot =
|
|
1109
|
+
const snapshot = useSyncExternalStore2(
|
|
956
1110
|
state.subscribe,
|
|
957
1111
|
state.getSnapshot,
|
|
958
1112
|
state.getSnapshot
|
|
@@ -1167,10 +1321,13 @@ export {
|
|
|
1167
1321
|
SurfaceRegion,
|
|
1168
1322
|
applyAnchoredResizeDelta,
|
|
1169
1323
|
beginAnchoredResize,
|
|
1324
|
+
createPersistentSizeStore,
|
|
1170
1325
|
hashSlotHue,
|
|
1326
|
+
installPointerDragSession,
|
|
1171
1327
|
isSlotDebugEnabled,
|
|
1172
1328
|
useDockLayoutControlBinding,
|
|
1173
|
-
useLocalSize
|
|
1329
|
+
useLocalSize,
|
|
1330
|
+
usePersistentSizeStore
|
|
1174
1331
|
};
|
|
1175
1332
|
/*! Bundled license information:
|
|
1176
1333
|
|