@forgeax/app-shell 0.39.1 → 0.41.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 +40 -1
- package/dist/react.js +194 -8
- 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,7 +41,25 @@ interface ResizeHandleProps {
|
|
|
20
41
|
ariaLabel?: string;
|
|
21
42
|
title?: string;
|
|
22
43
|
}
|
|
44
|
+
type AnchoredResizeDirection = 'subtract' | 'add';
|
|
45
|
+
interface AnchoredResizeSession {
|
|
46
|
+
readonly startSize: number;
|
|
47
|
+
readonly direction: AnchoredResizeDirection;
|
|
48
|
+
totalDelta: number;
|
|
49
|
+
}
|
|
50
|
+
/** Capture one unclamped drag origin so overshoot stays pinned until the pointer returns. */
|
|
51
|
+
declare function beginAnchoredResize(startSize: number, direction?: AnchoredResizeDirection): AnchoredResizeSession;
|
|
52
|
+
/** Project incremental pointer travel from the stable drag origin. */
|
|
53
|
+
declare function applyAnchoredResizeDelta(session: AnchoredResizeSession, delta: number): number;
|
|
23
54
|
declare function ResizeHandle({ orientation, onDrag, onDragStart, onDragEnd, className, ariaLabel, title, }: ResizeHandleProps): react.JSX.Element;
|
|
55
|
+
interface AnchoredResizeHandleProps extends Omit<ResizeHandleProps, 'onDrag' | 'onDragStart' | 'onDragEnd'> {
|
|
56
|
+
readSize: () => number;
|
|
57
|
+
writeSize: (next: number) => void;
|
|
58
|
+
direction?: AnchoredResizeDirection;
|
|
59
|
+
resizingBodyClassName?: string;
|
|
60
|
+
}
|
|
61
|
+
/** Product-neutral anchored resize session over the public pointer carrier. */
|
|
62
|
+
declare function AnchoredResizeHandle({ readSize, writeSize, direction, resizingBodyClassName, ...handleProps }: AnchoredResizeHandleProps): react.JSX.Element;
|
|
24
63
|
|
|
25
64
|
type PanelContentPadding = 'none' | 'sm' | 'md';
|
|
26
65
|
type PanelContentScroll = 'none' | 'auto';
|
|
@@ -163,4 +202,4 @@ interface ShellSlotProps extends HTMLAttributes<HTMLElement> {
|
|
|
163
202
|
/** Structural shell marker that preserves the caller's semantic element. */
|
|
164
203
|
declare function ShellSlot({ as, name, ...props }: ShellSlotProps): ReactElement;
|
|
165
204
|
|
|
166
|
-
export { 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, hashSlotHue, isSlotDebugEnabled, useDockLayoutControlBinding, useLocalSize };
|
|
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 };
|
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,6 +690,46 @@ function useLocalSize(key, initial, min, max) {
|
|
|
624
690
|
};
|
|
625
691
|
return [value, setValue];
|
|
626
692
|
}
|
|
693
|
+
var bodyClassLeases = /* @__PURE__ */ new WeakMap();
|
|
694
|
+
function acquireBodyClassLease(body, tokens) {
|
|
695
|
+
const uniqueTokens = [...new Set(tokens)];
|
|
696
|
+
let records = bodyClassLeases.get(body);
|
|
697
|
+
if (!records) {
|
|
698
|
+
records = /* @__PURE__ */ new Map();
|
|
699
|
+
bodyClassLeases.set(body, records);
|
|
700
|
+
}
|
|
701
|
+
for (const token of uniqueTokens) {
|
|
702
|
+
const existing = records.get(token);
|
|
703
|
+
if (existing) {
|
|
704
|
+
existing.count += 1;
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
const owned = !body.classList.contains(token);
|
|
708
|
+
if (owned) body.classList.add(token);
|
|
709
|
+
records.set(token, { count: 1, owned });
|
|
710
|
+
}
|
|
711
|
+
let active = true;
|
|
712
|
+
return () => {
|
|
713
|
+
if (!active) return;
|
|
714
|
+
active = false;
|
|
715
|
+
for (const token of uniqueTokens) {
|
|
716
|
+
const record = records?.get(token);
|
|
717
|
+
if (!record) continue;
|
|
718
|
+
record.count -= 1;
|
|
719
|
+
if (record.count > 0) continue;
|
|
720
|
+
records?.delete(token);
|
|
721
|
+
if (record.owned) body.classList.remove(token);
|
|
722
|
+
}
|
|
723
|
+
if (records?.size === 0) bodyClassLeases.delete(body);
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function beginAnchoredResize(startSize, direction = "subtract") {
|
|
727
|
+
return { startSize, direction, totalDelta: 0 };
|
|
728
|
+
}
|
|
729
|
+
function applyAnchoredResizeDelta(session, delta) {
|
|
730
|
+
session.totalDelta += delta;
|
|
731
|
+
return session.startSize + (session.direction === "subtract" ? -session.totalDelta : session.totalDelta);
|
|
732
|
+
}
|
|
627
733
|
function ResizeHandle({
|
|
628
734
|
orientation,
|
|
629
735
|
onDrag,
|
|
@@ -644,24 +750,47 @@ function ResizeHandle({
|
|
|
644
750
|
if (!startRef.current) return;
|
|
645
751
|
startRef.current = null;
|
|
646
752
|
resetGlobalDragStyles();
|
|
647
|
-
|
|
753
|
+
try {
|
|
754
|
+
onDragEndRef.current?.();
|
|
755
|
+
} catch {
|
|
756
|
+
}
|
|
648
757
|
};
|
|
649
758
|
useEffect2(() => finishDrag, []);
|
|
650
759
|
const onPointerDown = (event) => {
|
|
651
760
|
if (startRef.current) return;
|
|
652
761
|
event.preventDefault();
|
|
653
|
-
|
|
762
|
+
try {
|
|
763
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
764
|
+
} catch {
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
654
767
|
startRef.current = { pointerId: event.pointerId, x: event.clientX, y: event.clientY };
|
|
655
768
|
document.body.style.cursor = orientation === "col" ? "col-resize" : "row-resize";
|
|
656
769
|
document.body.style.userSelect = "none";
|
|
657
|
-
|
|
770
|
+
try {
|
|
771
|
+
onDragStart?.();
|
|
772
|
+
} catch {
|
|
773
|
+
try {
|
|
774
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
775
|
+
} catch {
|
|
776
|
+
}
|
|
777
|
+
finishDrag();
|
|
778
|
+
}
|
|
658
779
|
};
|
|
659
780
|
const onPointerMove = (event) => {
|
|
660
781
|
if (!startRef.current || startRef.current.pointerId !== event.pointerId) return;
|
|
661
782
|
const deltaX = event.clientX - startRef.current.x;
|
|
662
783
|
const deltaY = event.clientY - startRef.current.y;
|
|
663
784
|
startRef.current = { pointerId: event.pointerId, x: event.clientX, y: event.clientY };
|
|
664
|
-
|
|
785
|
+
try {
|
|
786
|
+
onDrag(orientation === "col" ? deltaX : deltaY);
|
|
787
|
+
} catch {
|
|
788
|
+
try {
|
|
789
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
790
|
+
} catch {
|
|
791
|
+
}
|
|
792
|
+
finishDrag();
|
|
793
|
+
}
|
|
665
794
|
};
|
|
666
795
|
const finish = (event) => {
|
|
667
796
|
if (!startRef.current || startRef.current.pointerId !== event.pointerId) return;
|
|
@@ -686,6 +815,58 @@ function ResizeHandle({
|
|
|
686
815
|
}
|
|
687
816
|
);
|
|
688
817
|
}
|
|
818
|
+
function AnchoredResizeHandle({
|
|
819
|
+
readSize,
|
|
820
|
+
writeSize,
|
|
821
|
+
direction = "subtract",
|
|
822
|
+
resizingBodyClassName,
|
|
823
|
+
...handleProps
|
|
824
|
+
}) {
|
|
825
|
+
const readSizeRef = useRef(readSize);
|
|
826
|
+
const writeSizeRef = useRef(writeSize);
|
|
827
|
+
const directionRef = useRef(direction);
|
|
828
|
+
const bodyClassNameRef = useRef(resizingBodyClassName);
|
|
829
|
+
readSizeRef.current = readSize;
|
|
830
|
+
writeSizeRef.current = writeSize;
|
|
831
|
+
directionRef.current = direction;
|
|
832
|
+
bodyClassNameRef.current = resizingBodyClassName;
|
|
833
|
+
const sessionRef = useRef(null);
|
|
834
|
+
const finishSession = () => {
|
|
835
|
+
const active = sessionRef.current;
|
|
836
|
+
if (!active) return;
|
|
837
|
+
sessionRef.current = null;
|
|
838
|
+
try {
|
|
839
|
+
active.releaseBodyClass();
|
|
840
|
+
} catch {
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
useEffect2(() => finishSession, []);
|
|
844
|
+
const startSession = () => {
|
|
845
|
+
finishSession();
|
|
846
|
+
const bodyClassTokens = bodyClassNameRef.current?.trim().split(/\s+/).filter(Boolean) ?? [];
|
|
847
|
+
const resize = beginAnchoredResize(readSizeRef.current(), directionRef.current);
|
|
848
|
+
const releaseBodyClass = typeof document !== "undefined" && bodyClassTokens.length > 0 ? acquireBodyClassLease(document.body, bodyClassTokens) : () => {
|
|
849
|
+
};
|
|
850
|
+
sessionRef.current = {
|
|
851
|
+
resize,
|
|
852
|
+
releaseBodyClass
|
|
853
|
+
};
|
|
854
|
+
};
|
|
855
|
+
const applyDelta = (delta) => {
|
|
856
|
+
const active = sessionRef.current;
|
|
857
|
+
if (!active) return;
|
|
858
|
+
writeSizeRef.current(applyAnchoredResizeDelta(active.resize, delta));
|
|
859
|
+
};
|
|
860
|
+
return /* @__PURE__ */ jsx2(
|
|
861
|
+
ResizeHandle,
|
|
862
|
+
{
|
|
863
|
+
...handleProps,
|
|
864
|
+
onDrag: applyDelta,
|
|
865
|
+
onDragStart: startSession,
|
|
866
|
+
onDragEnd: finishSession
|
|
867
|
+
}
|
|
868
|
+
);
|
|
869
|
+
}
|
|
689
870
|
|
|
690
871
|
// src/panel.tsx
|
|
691
872
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
@@ -829,7 +1010,7 @@ var SurfaceRegion = forwardRef(
|
|
|
829
1010
|
);
|
|
830
1011
|
|
|
831
1012
|
// src/dock-layout-control.ts
|
|
832
|
-
import { useEffect as useEffect3, useMemo, useSyncExternalStore } from "react";
|
|
1013
|
+
import { useEffect as useEffect3, useMemo, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
833
1014
|
function useDockLayoutControlBinding({
|
|
834
1015
|
state,
|
|
835
1016
|
onToggle,
|
|
@@ -837,7 +1018,7 @@ function useDockLayoutControlBinding({
|
|
|
837
1018
|
closePanel,
|
|
838
1019
|
reopenPanel
|
|
839
1020
|
}) {
|
|
840
|
-
const snapshot =
|
|
1021
|
+
const snapshot = useSyncExternalStore2(
|
|
841
1022
|
state.subscribe,
|
|
842
1023
|
state.getSnapshot,
|
|
843
1024
|
state.getSnapshot
|
|
@@ -1037,6 +1218,7 @@ function ShellSlot({
|
|
|
1037
1218
|
return createElement(as, { ...props, "data-fx-slot": name });
|
|
1038
1219
|
}
|
|
1039
1220
|
export {
|
|
1221
|
+
AnchoredResizeHandle,
|
|
1040
1222
|
DetachedPanelBoundary,
|
|
1041
1223
|
DetachedSurfaceFrame,
|
|
1042
1224
|
DetachedSurfaceStatus,
|
|
@@ -1049,10 +1231,14 @@ export {
|
|
|
1049
1231
|
SlotDebugOverlay,
|
|
1050
1232
|
SurfacePlaceholder,
|
|
1051
1233
|
SurfaceRegion,
|
|
1234
|
+
applyAnchoredResizeDelta,
|
|
1235
|
+
beginAnchoredResize,
|
|
1236
|
+
createPersistentSizeStore,
|
|
1052
1237
|
hashSlotHue,
|
|
1053
1238
|
isSlotDebugEnabled,
|
|
1054
1239
|
useDockLayoutControlBinding,
|
|
1055
|
-
useLocalSize
|
|
1240
|
+
useLocalSize,
|
|
1241
|
+
usePersistentSizeStore
|
|
1056
1242
|
};
|
|
1057
1243
|
/*! Bundled license information:
|
|
1058
1244
|
|