@moneyforward/mfui-components 3.11.0 → 3.12.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/src/Breadcrumbs/Breadcrumbs.d.ts +9 -0
- package/dist/src/Breadcrumbs/Breadcrumbs.js +150 -0
- package/dist/src/Breadcrumbs/Breadcrumbs.types.d.ts +31 -0
- package/dist/src/Breadcrumbs/Breadcrumbs.types.js +1 -0
- package/dist/src/Breadcrumbs/index.d.ts +2 -0
- package/dist/src/Breadcrumbs/index.js +1 -0
- package/dist/src/Button/Button.d.ts +1 -1
- package/dist/src/CheckboxGroup/CheckboxGroup.d.ts +1 -1
- package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerProvider/DateRangePickerProvider.d.ts +2 -2
- package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerProvider/BaseRangePickerProvider.d.ts +2 -2
- package/dist/src/IconButton/IconButton.d.ts +2 -2
- package/dist/src/MultipleSelectBox/MultipleSelectBox.d.ts +1 -1
- package/dist/src/MultipleSelectBox/MultipleSelectBox.js +5 -2
- package/dist/src/MultipleSelectBox/MultipleSelectBox.types.d.ts +9 -0
- package/dist/src/RadioButton/RadioButton.d.ts +1 -1
- package/dist/src/RadioGroup/RadioGroup.d.ts +1 -1
- package/dist/src/SplitView/SplitView.d.ts +7 -16
- package/dist/src/SplitView/SplitView.js +110 -70
- package/dist/src/SplitView/SplitView.types.d.ts +84 -56
- package/dist/src/SplitView/hooks/useSplitViewAnimation.d.ts +6 -6
- package/dist/src/SplitView/hooks/useSplitViewAnimation.js +46 -48
- package/dist/src/SplitView/hooks/useSplitViewDrag.d.ts +5 -4
- package/dist/src/SplitView/hooks/useSplitViewDrag.js +22 -12
- package/dist/src/SplitView/hooks/useSplitViewKeyboard.d.ts +7 -6
- package/dist/src/SplitView/hooks/useSplitViewKeyboard.js +22 -16
- package/dist/src/SplitView/hooks/useSplitViewPanelVisibility.d.ts +3 -3
- package/dist/src/SplitView/hooks/useSplitViewPanelVisibility.js +9 -9
- package/dist/src/SplitView/hooks/useSplitViewResize.d.ts +6 -6
- package/dist/src/SplitView/hooks/useSplitViewResize.js +16 -16
- package/dist/src/SplitView/utils/calculatePanelSize.d.ts +11 -11
- package/dist/src/SplitView/utils/calculatePanelSize.js +13 -13
- package/dist/src/SplitView/utils/styles.d.ts +21 -5
- package/dist/src/SplitView/utils/styles.js +47 -21
- package/dist/src/Tooltip/Tooltip.d.ts +2 -1
- package/dist/src/Tooltip/Tooltip.js +4 -2
- package/dist/src/Tooltip/Tooltip.types.d.ts +11 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/styled-system/recipes/breadcrumbs-slot-recipe.d.ts +33 -0
- package/dist/styled-system/recipes/breadcrumbs-slot-recipe.js +63 -0
- package/dist/styled-system/recipes/index.d.ts +1 -0
- package/dist/styled-system/recipes/index.js +1 -0
- package/dist/styles.css +88 -7
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useLayoutEffect } from 'react';
|
|
2
2
|
import { ANIMATION_SIZE_THRESHOLD_PX } from '../constants';
|
|
3
|
-
import {
|
|
3
|
+
import { calculateInitialPanelSize } from '../utils/calculatePanelSize';
|
|
4
4
|
import { createSlideInAnimation, createSlideOutAnimation } from '../utils/animation';
|
|
5
5
|
/**
|
|
6
6
|
* Hook to handle slide-in and slide-out animations for the split view.
|
|
@@ -8,20 +8,20 @@ import { createSlideInAnimation, createSlideOutAnimation } from '../utils/animat
|
|
|
8
8
|
* @param options - Animation hook options
|
|
9
9
|
*/
|
|
10
10
|
export function useSplitViewAnimation(options) {
|
|
11
|
-
const { isRightPanelVisible, containerRef,
|
|
12
|
-
// Track when
|
|
11
|
+
const { isRightPanelVisible, containerRef, initialPanelSize, isInitialMountRef, wasRightPanelVisibleOnMountRef, previousIsRightPanelVisibleRef, hasRightPanelBeenVisible, isAnimating, controlledPanelSize, lastControlledPanelSizeRef, lastRightPanelRef, setControlledPanelSize, setIsAnimating, setAnimatedPanelSize, setHasRightPanelBeenVisible, setIsSlideOutAnimating, } = options;
|
|
12
|
+
// Track when the controlled panel becomes visible to trigger animation
|
|
13
|
+
// (only when opened by a user action, not on initial mount)
|
|
13
14
|
useLayoutEffect(() => {
|
|
14
15
|
const isInitialMount = isInitialMountRef.current;
|
|
15
16
|
const previousIsRightPanelVisible = previousIsRightPanelVisibleRef.current;
|
|
16
17
|
// Update previous visibility state at the start of layout effect
|
|
17
18
|
previousIsRightPanelVisibleRef.current = isRightPanelVisible;
|
|
18
|
-
// Handle initial mount: if
|
|
19
|
+
// Handle initial mount: if panel is already visible, set size without animation
|
|
19
20
|
if (isInitialMount && isRightPanelVisible && wasRightPanelVisibleOnMountRef.current) {
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
lastRightPanelSizeRef.current = targetRightPanelSize;
|
|
21
|
+
const savedPanelSize = lastControlledPanelSizeRef.current;
|
|
22
|
+
const targetPanelSize = calculateInitialPanelSize(initialPanelSize, savedPanelSize);
|
|
23
|
+
setControlledPanelSize(targetPanelSize);
|
|
24
|
+
lastControlledPanelSizeRef.current = targetPanelSize;
|
|
25
25
|
// hasRightPanelBeenVisible is already true from initial state, no need to set it
|
|
26
26
|
isInitialMountRef.current = false;
|
|
27
27
|
return;
|
|
@@ -30,63 +30,64 @@ export function useSplitViewAnimation(options) {
|
|
|
30
30
|
if (isInitialMount) {
|
|
31
31
|
isInitialMountRef.current = false;
|
|
32
32
|
}
|
|
33
|
-
// Animate slide-in only when
|
|
34
|
-
//
|
|
33
|
+
// Animate slide-in only when the controlled panel becomes visible after initial mount
|
|
34
|
+
// (i.e., triggered by a user action, not on first render)
|
|
35
35
|
const justBecameVisible = isRightPanelVisible && !previousIsRightPanelVisible && !hasRightPanelBeenVisible;
|
|
36
36
|
if (justBecameVisible && !isAnimating && !isInitialMount) {
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
// Start animation from 0px (right panel hidden)
|
|
37
|
+
const savedPanelSize = lastControlledPanelSizeRef.current;
|
|
38
|
+
const targetPanelSize = calculateInitialPanelSize(initialPanelSize, savedPanelSize);
|
|
39
|
+
// Start animation from 0 (panel hidden)
|
|
41
40
|
const startSize = 0;
|
|
42
|
-
//
|
|
43
|
-
if (Math.abs(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
lastRightPanelSizeRef.current = targetRightPanelSize;
|
|
41
|
+
// Skip animation if the size difference is negligible
|
|
42
|
+
if (Math.abs(targetPanelSize - startSize) < ANIMATION_SIZE_THRESHOLD_PX) {
|
|
43
|
+
setControlledPanelSize(targetPanelSize);
|
|
44
|
+
lastControlledPanelSizeRef.current = targetPanelSize;
|
|
47
45
|
setHasRightPanelBeenVisible(true);
|
|
48
46
|
return;
|
|
49
47
|
}
|
|
50
|
-
//
|
|
51
|
-
|
|
48
|
+
// Store the target size before animation so the inner wrapper can maintain
|
|
49
|
+
// the correct fixed width from the very first frame.
|
|
50
|
+
lastControlledPanelSizeRef.current = targetPanelSize;
|
|
51
|
+
// Immediately set the panel size to avoid layout shift flash
|
|
52
|
+
setControlledPanelSize(startSize);
|
|
52
53
|
setIsAnimating(true);
|
|
53
|
-
|
|
54
|
+
setAnimatedPanelSize(startSize);
|
|
54
55
|
setHasRightPanelBeenVisible(true);
|
|
55
56
|
createSlideInAnimation({
|
|
56
57
|
startSize,
|
|
57
|
-
targetSize:
|
|
58
|
+
targetSize: targetPanelSize,
|
|
58
59
|
onUpdate: (size) => {
|
|
59
|
-
|
|
60
|
+
setAnimatedPanelSize(size);
|
|
60
61
|
},
|
|
61
62
|
onComplete: () => {
|
|
62
63
|
setIsAnimating(false);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
setAnimatedPanelSize(undefined);
|
|
65
|
+
setControlledPanelSize(targetPanelSize);
|
|
66
|
+
lastControlledPanelSizeRef.current = targetPanelSize;
|
|
66
67
|
},
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
|
-
// Slide-out animation:
|
|
70
|
+
// Slide-out animation: controlled panel becomes hidden
|
|
70
71
|
if (!isRightPanelVisible && hasRightPanelBeenVisible) {
|
|
71
72
|
if (containerRef.current && !isAnimating) {
|
|
72
|
-
// Start from current
|
|
73
|
-
const startSize =
|
|
74
|
-
// Animate to
|
|
73
|
+
// Start from current controlled panel size
|
|
74
|
+
const startSize = lastControlledPanelSizeRef.current ?? controlledPanelSize ?? 0;
|
|
75
|
+
// Animate to 0 (panel hidden)
|
|
75
76
|
const targetSize = 0;
|
|
76
77
|
setIsAnimating(true);
|
|
77
78
|
setIsSlideOutAnimating(true);
|
|
78
|
-
|
|
79
|
+
setAnimatedPanelSize(startSize);
|
|
79
80
|
createSlideOutAnimation({
|
|
80
81
|
startSize,
|
|
81
82
|
targetSize,
|
|
82
83
|
onUpdate: (size) => {
|
|
83
|
-
|
|
84
|
+
setAnimatedPanelSize(size);
|
|
84
85
|
},
|
|
85
86
|
onComplete: () => {
|
|
86
87
|
setIsAnimating(false);
|
|
87
88
|
setIsSlideOutAnimating(false);
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
setAnimatedPanelSize(undefined);
|
|
90
|
+
setControlledPanelSize(undefined);
|
|
90
91
|
setHasRightPanelBeenVisible(false);
|
|
91
92
|
// Clear stored content after animation completes
|
|
92
93
|
lastRightPanelRef.current = null;
|
|
@@ -94,32 +95,29 @@ export function useSplitViewAnimation(options) {
|
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
else {
|
|
97
|
-
// No animation
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
lastRightPanelSizeRef.current = rightPanelSize;
|
|
98
|
+
// No animation — immediately reset
|
|
99
|
+
if (controlledPanelSize !== undefined) {
|
|
100
|
+
lastControlledPanelSizeRef.current = controlledPanelSize;
|
|
101
101
|
}
|
|
102
102
|
setHasRightPanelBeenVisible(false);
|
|
103
|
-
|
|
104
|
-
setRightPanelSize(undefined);
|
|
103
|
+
setControlledPanelSize(undefined);
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
106
|
}, [
|
|
108
107
|
isRightPanelVisible,
|
|
109
108
|
containerRef,
|
|
110
|
-
|
|
111
|
-
minRightPanelSize,
|
|
109
|
+
initialPanelSize,
|
|
112
110
|
isInitialMountRef,
|
|
113
111
|
wasRightPanelVisibleOnMountRef,
|
|
114
112
|
previousIsRightPanelVisibleRef,
|
|
115
113
|
hasRightPanelBeenVisible,
|
|
116
114
|
isAnimating,
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
controlledPanelSize,
|
|
116
|
+
lastControlledPanelSizeRef,
|
|
119
117
|
lastRightPanelRef,
|
|
120
|
-
|
|
118
|
+
setControlledPanelSize,
|
|
121
119
|
setIsAnimating,
|
|
122
|
-
|
|
120
|
+
setAnimatedPanelSize,
|
|
123
121
|
setHasRightPanelBeenVisible,
|
|
124
122
|
setIsSlideOutAnimating,
|
|
125
123
|
]);
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export declare function useSplitViewDrag(options: {
|
|
7
7
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
targetPanel: 'left' | 'right';
|
|
9
|
+
minPanelSize: number;
|
|
10
|
+
maxPanelSize: number;
|
|
11
|
+
setControlledPanelSize: (size: number | undefined) => void;
|
|
12
|
+
setLastControlledPanelSize: (size: number | undefined) => void;
|
|
12
13
|
}): {
|
|
13
14
|
isDragging: boolean;
|
|
14
15
|
handleMouseDown: (event: React.PointerEvent<HTMLDivElement>) => void;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { calculateConstrainedPanelSize } from '../utils/calculatePanelSize';
|
|
3
3
|
/**
|
|
4
4
|
* Hook to handle drag interactions for resizing the split view.
|
|
5
5
|
*
|
|
6
6
|
* @param options - Drag hook options
|
|
7
7
|
*/
|
|
8
8
|
export function useSplitViewDrag(options) {
|
|
9
|
-
const { containerRef,
|
|
9
|
+
const { containerRef, targetPanel, minPanelSize, maxPanelSize, setControlledPanelSize, setLastControlledPanelSize } = options;
|
|
10
10
|
const [isDragging, setIsDragging] = useState(false);
|
|
11
11
|
const pointerIdRef = useRef(null);
|
|
12
12
|
/**
|
|
13
|
-
* Handle pointer down on the divider
|
|
13
|
+
* Handle pointer down on the divider.
|
|
14
14
|
*/
|
|
15
15
|
const handlePointerDown = useCallback((event) => {
|
|
16
16
|
event.preventDefault();
|
|
@@ -20,7 +20,7 @@ export function useSplitViewDrag(options) {
|
|
|
20
20
|
setIsDragging(true);
|
|
21
21
|
}, []);
|
|
22
22
|
/**
|
|
23
|
-
* Handle pointer move during drag
|
|
23
|
+
* Handle pointer move during drag.
|
|
24
24
|
*/
|
|
25
25
|
const handlePointerMove = useCallback((event) => {
|
|
26
26
|
if (!isDragging || pointerIdRef.current !== event.pointerId)
|
|
@@ -29,14 +29,24 @@ export function useSplitViewDrag(options) {
|
|
|
29
29
|
return;
|
|
30
30
|
const containerRect = containerRef.current.getBoundingClientRect();
|
|
31
31
|
const containerSize = containerRect.width;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
// Compute raw controlled panel size based on which panel is being controlled
|
|
33
|
+
const rawControlledPanelSize = targetPanel === 'left'
|
|
34
|
+
? event.clientX - containerRect.left // left panel size = pointer X from container left
|
|
35
|
+
: containerSize - (event.clientX - containerRect.left); // right panel size (legacy behavior)
|
|
36
|
+
const constrainedSize = calculateConstrainedPanelSize(rawControlledPanelSize, minPanelSize, maxPanelSize);
|
|
37
|
+
setControlledPanelSize(constrainedSize);
|
|
38
|
+
setLastControlledPanelSize(constrainedSize);
|
|
39
|
+
}, [
|
|
40
|
+
isDragging,
|
|
41
|
+
containerRef,
|
|
42
|
+
targetPanel,
|
|
43
|
+
minPanelSize,
|
|
44
|
+
maxPanelSize,
|
|
45
|
+
setControlledPanelSize,
|
|
46
|
+
setLastControlledPanelSize,
|
|
47
|
+
]);
|
|
38
48
|
/**
|
|
39
|
-
* Handle pointer up to stop dragging
|
|
49
|
+
* Handle pointer up to stop dragging.
|
|
40
50
|
*/
|
|
41
51
|
const handlePointerUp = useCallback((event) => {
|
|
42
52
|
if (pointerIdRef.current === event.pointerId) {
|
|
@@ -45,7 +55,7 @@ export function useSplitViewDrag(options) {
|
|
|
45
55
|
}
|
|
46
56
|
}, []);
|
|
47
57
|
/**
|
|
48
|
-
* Set up pointer event listeners
|
|
58
|
+
* Set up pointer event listeners.
|
|
49
59
|
*/
|
|
50
60
|
useEffect(() => {
|
|
51
61
|
if (!isDragging)
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export declare function useSplitViewKeyboard(options: {
|
|
7
7
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
targetPanel: 'left' | 'right';
|
|
9
|
+
controlledPanelSize: number | undefined;
|
|
10
|
+
initialPanelSize: number;
|
|
11
|
+
minPanelSize: number;
|
|
12
|
+
maxPanelSize: number;
|
|
13
|
+
setControlledPanelSize: (size: number | undefined) => void;
|
|
14
|
+
setLastControlledPanelSize: (size: number | undefined) => void;
|
|
14
15
|
}): {
|
|
15
16
|
handleKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
16
17
|
};
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
import { KEYBOARD_STEP_PX } from '../constants';
|
|
3
|
-
import {
|
|
3
|
+
import { calculateConstrainedPanelSize } from '../utils/calculatePanelSize';
|
|
4
4
|
/**
|
|
5
5
|
* Hook to handle keyboard navigation for resizing the split view.
|
|
6
6
|
*
|
|
7
7
|
* @param options - Keyboard hook options
|
|
8
8
|
*/
|
|
9
9
|
export function useSplitViewKeyboard(options) {
|
|
10
|
-
const { containerRef,
|
|
10
|
+
const { containerRef, targetPanel, controlledPanelSize, initialPanelSize, minPanelSize, maxPanelSize, setControlledPanelSize, setLastControlledPanelSize, } = options;
|
|
11
11
|
/**
|
|
12
|
-
* Handle keyboard navigation for the divider
|
|
12
|
+
* Handle keyboard navigation for the divider.
|
|
13
|
+
*
|
|
14
|
+
* Key directions depend on targetPanel:
|
|
15
|
+
* - targetPanel="right": ArrowLeft expands the right panel, ArrowRight shrinks it
|
|
16
|
+
* - targetPanel="left": ArrowRight expands the left panel, ArrowLeft shrinks it
|
|
13
17
|
*/
|
|
14
18
|
const handleKeyDown = useCallback((event) => {
|
|
15
19
|
if (!containerRef.current)
|
|
16
20
|
return;
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
// Key-to-action mapping varies by targetPanel to keep UX intuitive:
|
|
22
|
+
// the divider always moves in the direction of the pressed arrow key.
|
|
23
|
+
const increaseKeys = targetPanel === 'left' ? ['ArrowRight'] : ['ArrowLeft'];
|
|
24
|
+
const decreaseKeys = targetPanel === 'left' ? ['ArrowLeft'] : ['ArrowRight'];
|
|
19
25
|
if (![...increaseKeys, ...decreaseKeys].includes(event.key))
|
|
20
26
|
return;
|
|
21
27
|
event.preventDefault();
|
|
22
|
-
const currentSize =
|
|
28
|
+
const currentSize = controlledPanelSize ?? initialPanelSize;
|
|
23
29
|
let newSize = currentSize;
|
|
24
30
|
if (increaseKeys.includes(event.key)) {
|
|
25
31
|
newSize = currentSize + KEYBOARD_STEP_PX;
|
|
@@ -27,18 +33,18 @@ export function useSplitViewKeyboard(options) {
|
|
|
27
33
|
else if (decreaseKeys.includes(event.key)) {
|
|
28
34
|
newSize = currentSize - KEYBOARD_STEP_PX;
|
|
29
35
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
setLastRightPanelSize(constrainedSize);
|
|
36
|
+
const constrainedSize = calculateConstrainedPanelSize(newSize, minPanelSize, maxPanelSize);
|
|
37
|
+
setControlledPanelSize(constrainedSize);
|
|
38
|
+
setLastControlledPanelSize(constrainedSize);
|
|
34
39
|
}, [
|
|
35
40
|
containerRef,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
targetPanel,
|
|
42
|
+
controlledPanelSize,
|
|
43
|
+
initialPanelSize,
|
|
44
|
+
minPanelSize,
|
|
45
|
+
maxPanelSize,
|
|
46
|
+
setControlledPanelSize,
|
|
47
|
+
setLastControlledPanelSize,
|
|
42
48
|
]);
|
|
43
49
|
return { handleKeyDown };
|
|
44
50
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
/**
|
|
3
|
-
* Hook to manage the visibility state of the
|
|
3
|
+
* Hook to manage the visibility state of the controlled panel.
|
|
4
4
|
*
|
|
5
5
|
* @param isOpen - Controlled visibility state (optional)
|
|
6
6
|
*
|
|
7
|
-
* @param
|
|
7
|
+
* @param controlledPanelSlot - The content of the controlled panel (left or right depending on targetPanel)
|
|
8
8
|
*
|
|
9
9
|
* @returns Object containing visibility state and related refs
|
|
10
10
|
*/
|
|
11
|
-
export declare function useSplitViewPanelVisibility(isOpen: boolean | undefined,
|
|
11
|
+
export declare function useSplitViewPanelVisibility(isOpen: boolean | undefined, controlledPanelSlot: ReactNode): {
|
|
12
12
|
isRightPanelVisible: boolean;
|
|
13
13
|
isInitialMountRef: import("react").RefObject<boolean>;
|
|
14
14
|
wasRightPanelVisibleOnMountRef: import("react").RefObject<boolean | null>;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
2
|
/**
|
|
3
|
-
* Hook to manage the visibility state of the
|
|
3
|
+
* Hook to manage the visibility state of the controlled panel.
|
|
4
4
|
*
|
|
5
5
|
* @param isOpen - Controlled visibility state (optional)
|
|
6
6
|
*
|
|
7
|
-
* @param
|
|
7
|
+
* @param controlledPanelSlot - The content of the controlled panel (left or right depending on targetPanel)
|
|
8
8
|
*
|
|
9
9
|
* @returns Object containing visibility state and related refs
|
|
10
10
|
*/
|
|
11
|
-
export function useSplitViewPanelVisibility(isOpen,
|
|
12
|
-
// Determine if
|
|
11
|
+
export function useSplitViewPanelVisibility(isOpen, controlledPanelSlot) {
|
|
12
|
+
// Determine if the controlled panel should be visible (controlled by isOpen prop only)
|
|
13
13
|
const isRightPanelVisible = isOpen ?? true;
|
|
14
14
|
// Track if this is the initial mount
|
|
15
15
|
const isInitialMountRef = useRef(true);
|
|
16
|
-
// Track if
|
|
16
|
+
// Track if the controlled panel was visible on initial mount
|
|
17
17
|
const wasRightPanelVisibleOnMountRef = useRef(null);
|
|
18
18
|
// Initialize wasRightPanelVisibleOnMountRef on first render only
|
|
19
19
|
if (wasRightPanelVisibleOnMountRef.current === null) {
|
|
@@ -24,14 +24,14 @@ export function useSplitViewPanelVisibility(isOpen, rightPanelSlot) {
|
|
|
24
24
|
// Track previous visibility state
|
|
25
25
|
// Note: This ref is updated in useSplitViewAnimation hook to ensure correct timing
|
|
26
26
|
const previousIsRightPanelVisibleRef = useRef(isRightPanelVisible);
|
|
27
|
-
// Store last seen
|
|
27
|
+
// Store last seen controlled panel slot for slide-out animation
|
|
28
28
|
const lastRightPanelRef = useRef(null);
|
|
29
|
-
// Store
|
|
29
|
+
// Store controlled panel slot when visible for use during slide-out animation
|
|
30
30
|
useEffect(() => {
|
|
31
31
|
if (isRightPanelVisible) {
|
|
32
|
-
lastRightPanelRef.current =
|
|
32
|
+
lastRightPanelRef.current = controlledPanelSlot;
|
|
33
33
|
}
|
|
34
|
-
}, [
|
|
34
|
+
}, [controlledPanelSlot, isRightPanelVisible]);
|
|
35
35
|
return {
|
|
36
36
|
isRightPanelVisible,
|
|
37
37
|
isInitialMountRef,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Hook to handle container resize: maintain
|
|
2
|
+
* Hook to handle container resize: maintain controlled panel size and apply constraints.
|
|
3
3
|
*
|
|
4
4
|
* @param options - Resize hook options
|
|
5
5
|
*/
|
|
@@ -8,9 +8,9 @@ export declare function useSplitViewResize(options: {
|
|
|
8
8
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
9
9
|
isAnimating: boolean;
|
|
10
10
|
isDragging: boolean;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
controlledPanelSize: number | undefined;
|
|
12
|
+
minPanelSize: number;
|
|
13
|
+
maxPanelSize: number;
|
|
14
|
+
setControlledPanelSize: (size: number | undefined) => void;
|
|
15
|
+
setLastControlledPanelSize: (size: number | undefined) => void;
|
|
16
16
|
}): void;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { calculateConstrainedPanelSize } from '../utils/calculatePanelSize';
|
|
3
3
|
/**
|
|
4
|
-
* Hook to handle container resize: maintain
|
|
4
|
+
* Hook to handle container resize: maintain controlled panel size and apply constraints.
|
|
5
5
|
*
|
|
6
6
|
* @param options - Resize hook options
|
|
7
7
|
*/
|
|
8
8
|
export function useSplitViewResize(options) {
|
|
9
|
-
const { isRightPanelVisible, containerRef, isAnimating, isDragging,
|
|
9
|
+
const { isRightPanelVisible, containerRef, isAnimating, isDragging, controlledPanelSize, minPanelSize, maxPanelSize, setControlledPanelSize, setLastControlledPanelSize, } = options;
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
if (!isRightPanelVisible || !containerRef.current || isAnimating || isDragging)
|
|
12
12
|
return;
|
|
@@ -14,15 +14,15 @@ export function useSplitViewResize(options) {
|
|
|
14
14
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
15
15
|
for (const entry of entries) {
|
|
16
16
|
const containerSize = entry.contentRect.width;
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
//
|
|
20
|
-
const maxAllowedSize = Math.min(
|
|
21
|
-
const
|
|
17
|
+
const currentControlledPanelSize = controlledPanelSize;
|
|
18
|
+
if (currentControlledPanelSize !== undefined) {
|
|
19
|
+
// Controlled panel size must not exceed container size
|
|
20
|
+
const maxAllowedSize = Math.min(maxPanelSize, containerSize);
|
|
21
|
+
const constrainedSize = calculateConstrainedPanelSize(currentControlledPanelSize, minPanelSize, maxAllowedSize);
|
|
22
22
|
// Only update if constraints were applied
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
if (constrainedSize !== currentControlledPanelSize) {
|
|
24
|
+
setControlledPanelSize(constrainedSize);
|
|
25
|
+
setLastControlledPanelSize(constrainedSize);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -36,10 +36,10 @@ export function useSplitViewResize(options) {
|
|
|
36
36
|
containerRef,
|
|
37
37
|
isAnimating,
|
|
38
38
|
isDragging,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
controlledPanelSize,
|
|
40
|
+
minPanelSize,
|
|
41
|
+
maxPanelSize,
|
|
42
|
+
setControlledPanelSize,
|
|
43
|
+
setLastControlledPanelSize,
|
|
44
44
|
]);
|
|
45
45
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Calculate the
|
|
2
|
+
* Calculate the panel size with min/max constraints applied.
|
|
3
3
|
*
|
|
4
|
-
* @param
|
|
4
|
+
* @param panelSize - The desired panel size
|
|
5
5
|
*
|
|
6
|
-
* @param
|
|
6
|
+
* @param minPanelSize - The minimum size of the panel
|
|
7
7
|
*
|
|
8
|
-
* @param
|
|
8
|
+
* @param maxPanelSize - The maximum size of the panel
|
|
9
9
|
*
|
|
10
|
-
* @returns The constrained
|
|
10
|
+
* @returns The constrained panel size
|
|
11
11
|
*/
|
|
12
|
-
export declare function
|
|
12
|
+
export declare function calculateConstrainedPanelSize(panelSize: number, minPanelSize: number, maxPanelSize: number): number;
|
|
13
13
|
/**
|
|
14
|
-
* Calculate the initial
|
|
14
|
+
* Calculate the initial controlled panel size based on props and saved state.
|
|
15
15
|
*
|
|
16
|
-
* @param
|
|
16
|
+
* @param initialPanelSize - The initial panel size prop
|
|
17
17
|
*
|
|
18
|
-
* @param
|
|
18
|
+
* @param savedPanelSize - The saved panel size from previous state (optional)
|
|
19
19
|
*
|
|
20
|
-
* @returns The calculated
|
|
20
|
+
* @returns The calculated panel size
|
|
21
21
|
*/
|
|
22
|
-
export declare function
|
|
22
|
+
export declare function calculateInitialPanelSize(initialPanelSize: number, savedPanelSize?: number): number;
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Calculate the
|
|
2
|
+
* Calculate the panel size with min/max constraints applied.
|
|
3
3
|
*
|
|
4
|
-
* @param
|
|
4
|
+
* @param panelSize - The desired panel size
|
|
5
5
|
*
|
|
6
|
-
* @param
|
|
6
|
+
* @param minPanelSize - The minimum size of the panel
|
|
7
7
|
*
|
|
8
|
-
* @param
|
|
8
|
+
* @param maxPanelSize - The maximum size of the panel
|
|
9
9
|
*
|
|
10
|
-
* @returns The constrained
|
|
10
|
+
* @returns The constrained panel size
|
|
11
11
|
*/
|
|
12
|
-
export function
|
|
13
|
-
return Math.max(
|
|
12
|
+
export function calculateConstrainedPanelSize(panelSize, minPanelSize, maxPanelSize) {
|
|
13
|
+
return Math.max(minPanelSize, Math.min(panelSize, maxPanelSize));
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Calculate the initial
|
|
16
|
+
* Calculate the initial controlled panel size based on props and saved state.
|
|
17
17
|
*
|
|
18
|
-
* @param
|
|
18
|
+
* @param initialPanelSize - The initial panel size prop
|
|
19
19
|
*
|
|
20
|
-
* @param
|
|
20
|
+
* @param savedPanelSize - The saved panel size from previous state (optional)
|
|
21
21
|
*
|
|
22
|
-
* @returns The calculated
|
|
22
|
+
* @returns The calculated panel size
|
|
23
23
|
*/
|
|
24
|
-
export function
|
|
25
|
-
return
|
|
24
|
+
export function calculateInitialPanelSize(initialPanelSize, savedPanelSize) {
|
|
25
|
+
return savedPanelSize ?? initialPanelSize;
|
|
26
26
|
}
|
|
@@ -13,18 +13,34 @@ export declare function calculateDividerStyle(options: {
|
|
|
13
13
|
dividerPropsStyle?: CSSProperties;
|
|
14
14
|
}): CSSProperties;
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Styles returned for the controlled panel: the outer div handles layout and animation,
|
|
17
|
+
* the inner div maintains a fixed width during animation to prevent content reflow.
|
|
18
|
+
*/
|
|
19
|
+
export type ControlledPanelStyles = {
|
|
20
|
+
/** Applied to the panel div (the flex item). */
|
|
21
|
+
outer: CSSProperties;
|
|
22
|
+
/**
|
|
23
|
+
* Applied to an inner wrapper div that wraps the panel's slot content.
|
|
24
|
+
* Maintains a fixed width during animation so the content never reflows.
|
|
25
|
+
*/
|
|
26
|
+
inner: CSSProperties;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Calculate the controlled panel style based on the current size state, visibility, and animation state.
|
|
17
30
|
*
|
|
18
31
|
* @param options - Style calculation options
|
|
19
32
|
*
|
|
20
|
-
* @returns
|
|
33
|
+
* @returns Styles for the outer panel div and the inner content wrapper div.
|
|
21
34
|
*/
|
|
22
|
-
export declare function
|
|
35
|
+
export declare function calculateControlledPanelStyle(options: {
|
|
23
36
|
currentSize: number | undefined;
|
|
37
|
+
/** The full open size of the panel, used to fix the inner wrapper width during animation. */
|
|
38
|
+
fullPanelSize: number;
|
|
39
|
+
targetPanel: 'left' | 'right';
|
|
24
40
|
enableAutoUnmount: boolean;
|
|
25
41
|
isRightPanelVisible: boolean;
|
|
26
42
|
isSlideOutAnimating: boolean;
|
|
27
43
|
hasRightPanelBeenVisible: boolean;
|
|
28
44
|
isAnimating: boolean;
|
|
29
|
-
|
|
30
|
-
}):
|
|
45
|
+
panelPropsStyle?: CSSProperties;
|
|
46
|
+
}): ControlledPanelStyles;
|