@moneyforward/mfui-components 3.11.0 → 3.12.1

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.
Files changed (46) hide show
  1. package/dist/src/Breadcrumbs/Breadcrumbs.d.ts +9 -0
  2. package/dist/src/Breadcrumbs/Breadcrumbs.js +150 -0
  3. package/dist/src/Breadcrumbs/Breadcrumbs.types.d.ts +31 -0
  4. package/dist/src/Breadcrumbs/Breadcrumbs.types.js +1 -0
  5. package/dist/src/Breadcrumbs/index.d.ts +2 -0
  6. package/dist/src/Breadcrumbs/index.js +1 -0
  7. package/dist/src/Button/Button.d.ts +1 -1
  8. package/dist/src/CheckboxGroup/CheckboxGroup.d.ts +1 -1
  9. package/dist/src/DateTimeSelection/DateRangePicker/DateRangePickerProvider/DateRangePickerProvider.d.ts +2 -2
  10. package/dist/src/DateTimeSelection/shared/BaseRangePicker/BaseRangePickerProvider/BaseRangePickerProvider.d.ts +2 -2
  11. package/dist/src/IconButton/IconButton.d.ts +2 -2
  12. package/dist/src/MultipleSelectBox/MultipleSelectBox.d.ts +1 -1
  13. package/dist/src/MultipleSelectBox/MultipleSelectBox.js +5 -2
  14. package/dist/src/MultipleSelectBox/MultipleSelectBox.types.d.ts +9 -0
  15. package/dist/src/Popover/Popover.js +29 -0
  16. package/dist/src/RadioButton/RadioButton.d.ts +1 -1
  17. package/dist/src/RadioGroup/RadioGroup.d.ts +1 -1
  18. package/dist/src/SplitView/SplitView.d.ts +7 -16
  19. package/dist/src/SplitView/SplitView.js +110 -70
  20. package/dist/src/SplitView/SplitView.types.d.ts +84 -56
  21. package/dist/src/SplitView/hooks/useSplitViewAnimation.d.ts +6 -6
  22. package/dist/src/SplitView/hooks/useSplitViewAnimation.js +46 -48
  23. package/dist/src/SplitView/hooks/useSplitViewDrag.d.ts +5 -4
  24. package/dist/src/SplitView/hooks/useSplitViewDrag.js +22 -12
  25. package/dist/src/SplitView/hooks/useSplitViewKeyboard.d.ts +7 -6
  26. package/dist/src/SplitView/hooks/useSplitViewKeyboard.js +22 -16
  27. package/dist/src/SplitView/hooks/useSplitViewPanelVisibility.d.ts +3 -3
  28. package/dist/src/SplitView/hooks/useSplitViewPanelVisibility.js +9 -9
  29. package/dist/src/SplitView/hooks/useSplitViewResize.d.ts +6 -6
  30. package/dist/src/SplitView/hooks/useSplitViewResize.js +16 -16
  31. package/dist/src/SplitView/utils/calculatePanelSize.d.ts +11 -11
  32. package/dist/src/SplitView/utils/calculatePanelSize.js +13 -13
  33. package/dist/src/SplitView/utils/styles.d.ts +21 -5
  34. package/dist/src/SplitView/utils/styles.js +47 -21
  35. package/dist/src/Tooltip/Tooltip.d.ts +2 -1
  36. package/dist/src/Tooltip/Tooltip.js +4 -2
  37. package/dist/src/Tooltip/Tooltip.types.d.ts +11 -0
  38. package/dist/src/index.d.ts +1 -0
  39. package/dist/src/index.js +1 -0
  40. package/dist/styled-system/recipes/breadcrumbs-slot-recipe.d.ts +33 -0
  41. package/dist/styled-system/recipes/breadcrumbs-slot-recipe.js +63 -0
  42. package/dist/styled-system/recipes/index.d.ts +1 -0
  43. package/dist/styled-system/recipes/index.js +1 -0
  44. package/dist/styles.css +88 -7
  45. package/dist/tsconfig.build.tsbuildinfo +1 -1
  46. package/package.json +3 -3
@@ -8,13 +8,13 @@ import { useSplitViewDrag } from './hooks/useSplitViewDrag';
8
8
  import { useSplitViewKeyboard } from './hooks/useSplitViewKeyboard';
9
9
  import { useSplitViewPanelVisibility } from './hooks/useSplitViewPanelVisibility';
10
10
  import { useSplitViewResize } from './hooks/useSplitViewResize';
11
- import { calculateDividerStyle, calculateRightPanelStyleUnified } from './utils/styles';
11
+ import { calculateControlledPanelStyle, calculateDividerStyle } from './utils/styles';
12
12
  import { parseSizeToNumber } from './utils/parseSize';
13
13
  /**
14
14
  * A resizable split layout component with two panels.
15
15
  *
16
16
  * Users can adjust panel sizes by dragging the divider between panels.
17
- * The right panel can be shown or hidden using the `isOpen` prop.
17
+ * The controlled panel (determined by `targetPanel`) can be shown or hidden using the `isOpen` prop.
18
18
  *
19
19
  * @example
20
20
  * ```tsx
@@ -24,99 +24,130 @@ import { parseSizeToNumber } from './utils/parseSize';
24
24
  * leftPanelSlot={<div>Left Panel</div>}
25
25
  * rightPanelSlot={<div>Right Panel</div>}
26
26
  * isOpen={isOpen}
27
- * initialRightPanelSize={300}
28
- * minRightPanelSize={200}
29
- * maxRightPanelSize={500}
27
+ * targetPanel="right"
28
+ * initialPanelSize={300}
29
+ * minPanelSize={200}
30
+ * maxPanelSize={500}
30
31
  * style={{ minWidth: '600px' }}
31
32
  * />
32
33
  * ```
33
34
  */
34
- export const SplitView = forwardRef(({ className, leftPanelSlot, rightPanelSlot, isOpen, initialRightPanelSize, minRightPanelSize, maxRightPanelSize, leftPanelProps, rightPanelProps, dividerProps, enableAutoUnmount = true, ...props }, ref) => {
35
+ export const SplitView = forwardRef(({ className, leftPanelSlot, rightPanelSlot, isOpen, initialPanelSize, minPanelSize, maxPanelSize, targetPanel, initialRightPanelSize, minRightPanelSize, maxRightPanelSize, leftPanelProps, rightPanelProps, dividerProps, enableAutoUnmount = true, ...props }, ref) => {
36
+ // Normalize legacy props to the new API
37
+ const resolvedTargetPanel = targetPanel ?? 'right';
38
+ const resolvedInitialPanelSize = initialPanelSize ?? initialRightPanelSize;
39
+ const resolvedMinPanelSize = minPanelSize ?? minRightPanelSize;
40
+ const resolvedMaxPanelSize = maxPanelSize ?? maxRightPanelSize;
35
41
  // Convert CSS width values to numbers for internal calculations
36
- const initialRightPanelSizeNumber = parseSizeToNumber(initialRightPanelSize, 'initialRightPanelSize');
37
- const minRightPanelSizeNumber = parseSizeToNumber(minRightPanelSize, 'minRightPanelSize');
38
- const maxRightPanelSizeNumber = parseSizeToNumber(maxRightPanelSize, 'maxRightPanelSize');
39
- // Prop validation
42
+ const initialPanelSizeNumber = parseSizeToNumber(resolvedInitialPanelSize, 'initialPanelSize');
43
+ const minPanelSizeNumber = parseSizeToNumber(resolvedMinPanelSize, 'minPanelSize');
44
+ const maxPanelSizeNumber = parseSizeToNumber(resolvedMaxPanelSize, 'maxPanelSize');
45
+ // Warn when legacy and new API props are mixed.
46
+ // These checks are intentionally guarded at runtime for JavaScript callers who bypass TypeScript's
47
+ // discriminated union constraints (e.g., via `as any` or plain JS usage).
40
48
  useEffect(() => {
41
- if (minRightPanelSizeNumber < 0) {
42
- console.error(`SplitView: minRightPanelSize must be non-negative, but got ${String(minRightPanelSize)}.`);
49
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
50
+ if (initialPanelSize !== undefined && initialRightPanelSize !== undefined) {
51
+ console.warn('SplitView: initialPanelSize and initialRightPanelSize cannot be used together. ' +
52
+ 'initialPanelSize takes precedence. Remove initialRightPanelSize.');
43
53
  }
44
- if (maxRightPanelSizeNumber < 0) {
45
- console.error(`SplitView: maxRightPanelSize must be non-negative, but got ${String(maxRightPanelSize)}.`);
54
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
55
+ if (minPanelSize !== undefined && minRightPanelSize !== undefined) {
56
+ console.warn('SplitView: minPanelSize and minRightPanelSize cannot be used together. ' +
57
+ 'minPanelSize takes precedence. Remove minRightPanelSize.');
46
58
  }
47
- if (initialRightPanelSizeNumber < 0) {
48
- console.error(`SplitView: initialRightPanelSize must be non-negative, but got ${String(initialRightPanelSize)}.`);
59
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
60
+ if (maxPanelSize !== undefined && maxRightPanelSize !== undefined) {
61
+ console.warn('SplitView: maxPanelSize and maxRightPanelSize cannot be used together. ' +
62
+ 'maxPanelSize takes precedence. Remove maxRightPanelSize.');
49
63
  }
50
- if (minRightPanelSizeNumber > maxRightPanelSizeNumber) {
51
- console.error(`SplitView: minRightPanelSize (${String(minRightPanelSize)}) must be less than or equal to maxRightPanelSize (${String(maxRightPanelSize)}).`);
64
+ }, [initialPanelSize, initialRightPanelSize, minPanelSize, minRightPanelSize, maxPanelSize, maxRightPanelSize]);
65
+ // Validate resolved prop values
66
+ useEffect(() => {
67
+ if (minPanelSizeNumber < 0) {
68
+ console.error(`SplitView: minPanelSize must be non-negative, but got ${String(resolvedMinPanelSize)}.`);
69
+ }
70
+ if (maxPanelSizeNumber < 0) {
71
+ console.error(`SplitView: maxPanelSize must be non-negative, but got ${String(resolvedMaxPanelSize)}.`);
72
+ }
73
+ if (initialPanelSizeNumber < 0) {
74
+ console.error(`SplitView: initialPanelSize must be non-negative, but got ${String(resolvedInitialPanelSize)}.`);
75
+ }
76
+ if (minPanelSizeNumber > maxPanelSizeNumber) {
77
+ console.error(`SplitView: minPanelSize (${String(resolvedMinPanelSize)}) must be less than or equal to maxPanelSize (${String(resolvedMaxPanelSize)}).`);
52
78
  }
53
- if (initialRightPanelSizeNumber < minRightPanelSizeNumber) {
54
- console.error(`SplitView: initialRightPanelSize (${String(initialRightPanelSize)}) must be greater than or equal to minRightPanelSize (${String(minRightPanelSize)}).`);
79
+ if (initialPanelSizeNumber < minPanelSizeNumber) {
80
+ console.error(`SplitView: initialPanelSize (${String(resolvedInitialPanelSize)}) must be greater than or equal to minPanelSize (${String(resolvedMinPanelSize)}).`);
55
81
  }
56
- if (initialRightPanelSizeNumber > maxRightPanelSizeNumber) {
57
- console.error(`SplitView: initialRightPanelSize (${String(initialRightPanelSize)}) must be less than or equal to maxRightPanelSize (${String(maxRightPanelSize)}).`);
82
+ if (initialPanelSizeNumber > maxPanelSizeNumber) {
83
+ console.error(`SplitView: initialPanelSize (${String(resolvedInitialPanelSize)}) must be less than or equal to maxPanelSize (${String(resolvedMaxPanelSize)}).`);
58
84
  }
59
85
  }, [
60
- initialRightPanelSize,
61
- minRightPanelSize,
62
- maxRightPanelSize,
63
- initialRightPanelSizeNumber,
64
- minRightPanelSizeNumber,
65
- maxRightPanelSizeNumber,
86
+ resolvedInitialPanelSize,
87
+ resolvedMinPanelSize,
88
+ resolvedMaxPanelSize,
89
+ initialPanelSizeNumber,
90
+ minPanelSizeNumber,
91
+ maxPanelSizeNumber,
66
92
  ]);
67
93
  const classes = splitViewSlotRecipe();
68
94
  const containerRef = useRef(null);
69
- const [rightPanelSize, setRightPanelSize] = useState();
95
+ // Size of the controlled panel (the panel specified by targetPanel)
96
+ const [controlledPanelSize, setControlledPanelSize] = useState();
70
97
  const [isAnimating, setIsAnimating] = useState(false);
71
- const [animatedRightPanelSize, setAnimatedRightPanelSize] = useState();
98
+ const [animatedPanelSize, setAnimatedPanelSize] = useState();
72
99
  const [isSlideOutAnimating, setIsSlideOutAnimating] = useState(false);
73
- // Store last known right panel size for slide-out animation
74
- const lastRightPanelSizeRef = useRef(undefined);
75
- // Memoized callback to update last right panel size
76
- const setLastRightPanelSize = useCallback((size) => {
77
- lastRightPanelSizeRef.current = size;
100
+ // Store last known controlled panel size for slide-out animation
101
+ const lastControlledPanelSizeRef = useRef(undefined);
102
+ // Memoized callback to update last controlled panel size
103
+ const setLastControlledPanelSize = useCallback((size) => {
104
+ lastControlledPanelSizeRef.current = size;
78
105
  }, []);
106
+ // The slot of the controlled panel (varies by targetPanel)
107
+ const controlledPanelSlot = resolvedTargetPanel === 'left' ? leftPanelSlot : rightPanelSlot;
79
108
  // Panel visibility management
80
- const { isRightPanelVisible, isInitialMountRef, wasRightPanelVisibleOnMountRef, hasRightPanelBeenVisible, setHasRightPanelBeenVisible, previousIsRightPanelVisibleRef, lastRightPanelRef, } = useSplitViewPanelVisibility(isOpen, rightPanelSlot);
81
- // Determine if right panel should be rendered based on enableAutoUnmount
82
- const shouldRenderRightPanel = enableAutoUnmount ? isRightPanelVisible : true;
109
+ const { isRightPanelVisible, isInitialMountRef, wasRightPanelVisibleOnMountRef, hasRightPanelBeenVisible, setHasRightPanelBeenVisible, previousIsRightPanelVisibleRef, lastRightPanelRef, } = useSplitViewPanelVisibility(isOpen, controlledPanelSlot);
110
+ // Determine if the controlled panel should be rendered based on enableAutoUnmount
111
+ const shouldRenderControlledPanel = enableAutoUnmount ? isRightPanelVisible : true;
83
112
  // Animation management
84
113
  useSplitViewAnimation({
85
114
  isRightPanelVisible,
86
115
  containerRef,
87
- initialRightPanelSize: initialRightPanelSizeNumber,
88
- minRightPanelSize: minRightPanelSizeNumber,
116
+ initialPanelSize: initialPanelSizeNumber,
117
+ minPanelSize: minPanelSizeNumber,
89
118
  isInitialMountRef,
90
119
  wasRightPanelVisibleOnMountRef,
91
120
  previousIsRightPanelVisibleRef,
92
121
  hasRightPanelBeenVisible,
93
122
  isAnimating,
94
- rightPanelSize,
95
- lastRightPanelSizeRef,
123
+ controlledPanelSize,
124
+ lastControlledPanelSizeRef,
96
125
  lastRightPanelRef,
97
- setRightPanelSize,
126
+ setControlledPanelSize,
98
127
  setIsAnimating,
99
- setAnimatedRightPanelSize,
128
+ setAnimatedPanelSize,
100
129
  setHasRightPanelBeenVisible,
101
130
  setIsSlideOutAnimating,
102
131
  });
103
132
  // Drag management
104
133
  const { isDragging, handleMouseDown } = useSplitViewDrag({
105
134
  containerRef,
106
- minRightPanelSize: minRightPanelSizeNumber,
107
- maxRightPanelSize: maxRightPanelSizeNumber,
108
- setRightPanelSize,
109
- setLastRightPanelSize,
135
+ targetPanel: resolvedTargetPanel,
136
+ minPanelSize: minPanelSizeNumber,
137
+ maxPanelSize: maxPanelSizeNumber,
138
+ setControlledPanelSize,
139
+ setLastControlledPanelSize,
110
140
  });
111
141
  // Keyboard navigation
112
142
  const { handleKeyDown } = useSplitViewKeyboard({
113
143
  containerRef,
114
- rightPanelSize,
115
- initialRightPanelSize: initialRightPanelSizeNumber,
116
- minRightPanelSize: minRightPanelSizeNumber,
117
- maxRightPanelSize: maxRightPanelSizeNumber,
118
- setRightPanelSize,
119
- setLastRightPanelSize,
144
+ targetPanel: resolvedTargetPanel,
145
+ controlledPanelSize,
146
+ initialPanelSize: initialPanelSizeNumber,
147
+ minPanelSize: minPanelSizeNumber,
148
+ maxPanelSize: maxPanelSizeNumber,
149
+ setControlledPanelSize,
150
+ setLastControlledPanelSize,
120
151
  });
121
152
  // Resize management
122
153
  useSplitViewResize({
@@ -124,32 +155,37 @@ export const SplitView = forwardRef(({ className, leftPanelSlot, rightPanelSlot,
124
155
  containerRef,
125
156
  isAnimating,
126
157
  isDragging,
127
- rightPanelSize,
128
- minRightPanelSize: minRightPanelSizeNumber,
129
- maxRightPanelSize: maxRightPanelSizeNumber,
130
- setRightPanelSize,
131
- setLastRightPanelSize,
158
+ controlledPanelSize,
159
+ minPanelSize: minPanelSizeNumber,
160
+ maxPanelSize: maxPanelSizeNumber,
161
+ setControlledPanelSize,
162
+ setLastControlledPanelSize,
132
163
  });
133
- // Calculate current right panel size based on animation and visibility state
134
- let currentRightPanelSize;
164
+ // Calculate current controlled panel size based on animation and visibility state
165
+ let currentControlledPanelSize;
135
166
  if (isAnimating) {
136
- currentRightPanelSize = animatedRightPanelSize;
167
+ currentControlledPanelSize = animatedPanelSize;
137
168
  }
138
169
  else if (isRightPanelVisible) {
139
- // Use rightPanelSize if set, otherwise fallback to initialRightPanelSize directly
140
- currentRightPanelSize = rightPanelSize ?? initialRightPanelSizeNumber;
170
+ currentControlledPanelSize = controlledPanelSize ?? initialPanelSizeNumber;
141
171
  }
142
172
  else {
143
- currentRightPanelSize = undefined;
173
+ currentControlledPanelSize = undefined;
144
174
  }
145
- const rightPanelStyle = calculateRightPanelStyleUnified({
146
- currentSize: currentRightPanelSize,
175
+ // The full open size of the controlled panel: used to fix the inner wrapper width during animation
176
+ // so that the panel content never reflows as the outer div width shrinks.
177
+ const fullControlledPanelSize = lastControlledPanelSizeRef.current ?? controlledPanelSize ?? initialPanelSizeNumber;
178
+ // Calculate styles for the controlled panel (applied to left or right panel based on targetPanel)
179
+ const { outer: controlledPanelOuterStyle, inner: controlledPanelInnerStyle } = calculateControlledPanelStyle({
180
+ currentSize: currentControlledPanelSize,
181
+ fullPanelSize: fullControlledPanelSize,
182
+ targetPanel: resolvedTargetPanel,
147
183
  enableAutoUnmount,
148
184
  isRightPanelVisible,
149
185
  isSlideOutAnimating,
150
186
  hasRightPanelBeenVisible,
151
187
  isAnimating,
152
- rightPanelPropsStyle: rightPanelProps?.style,
188
+ panelPropsStyle: resolvedTargetPanel === 'left' ? leftPanelProps?.style : rightPanelProps?.style,
153
189
  });
154
190
  const dividerStyle = calculateDividerStyle({
155
191
  hasRightPanelBeenVisible,
@@ -157,6 +193,10 @@ export const SplitView = forwardRef(({ className, leftPanelSlot, rightPanelSlot,
157
193
  isDragging,
158
194
  dividerPropsStyle: dividerProps?.style,
159
195
  });
196
+ // Apply controlled panel style to the correct panel based on targetPanel.
197
+ // When a panel is the main panel (not controlled), flex: 1 ensures it fills remaining space.
198
+ const computedLeftPanelStyle = resolvedTargetPanel === 'left' ? controlledPanelOuterStyle : leftPanelProps?.style;
199
+ const computedRightPanelStyle = resolvedTargetPanel === 'right' ? controlledPanelOuterStyle : { flex: 1, ...rightPanelProps?.style };
160
200
  return (_jsxs("div", { ref: (node) => {
161
201
  // Handle both refs
162
202
  if (typeof ref === 'function') {
@@ -167,7 +207,7 @@ export const SplitView = forwardRef(({ className, leftPanelSlot, rightPanelSlot,
167
207
  ref.current = node;
168
208
  }
169
209
  containerRef.current = node;
170
- }, className: cx(classes.root, 'mfui-SplitView__root', className), ...props, children: [_jsx("div", { ...leftPanelProps, className: cx(classes.leftPanel, 'mfui-SplitView__leftPanel', leftPanelProps?.className), children: leftPanelSlot }), isRightPanelVisible || isSlideOutAnimating ? (_jsx("div", { ...dividerProps, className: cx(classes.divider, 'mfui-SplitView__divider', dividerProps?.className), role: "separator", "aria-orientation": "vertical", "aria-label": dividerProps?.['aria-label'] ?? '左右のパネルを調整',
210
+ }, className: cx(classes.root, 'mfui-SplitView__root', className), ...props, children: [resolvedTargetPanel === 'left' ? (shouldRenderControlledPanel || isSlideOutAnimating ? (_jsx("div", { ...leftPanelProps, className: cx(classes.leftPanel, 'mfui-SplitView__leftPanel', leftPanelProps?.className), style: computedLeftPanelStyle, children: _jsx("div", { style: controlledPanelInnerStyle, children: enableAutoUnmount ? (leftPanelSlot ?? lastRightPanelRef.current) : leftPanelSlot }) })) : null) : (_jsx("div", { ...leftPanelProps, className: cx(classes.leftPanel, 'mfui-SplitView__leftPanel', leftPanelProps?.className), style: computedLeftPanelStyle, children: leftPanelSlot })), isRightPanelVisible || isSlideOutAnimating ? (_jsx("div", { ...dividerProps, className: cx(classes.divider, 'mfui-SplitView__divider', dividerProps?.className), role: "separator", "aria-orientation": "vertical", "aria-label": dividerProps?.['aria-label'] ?? '左右のパネルを調整',
171
211
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
172
- tabIndex: 0, style: dividerStyle, onPointerDown: handleMouseDown, onKeyDown: handleKeyDown })) : null, shouldRenderRightPanel || isSlideOutAnimating ? (_jsx("div", { ...rightPanelProps, className: cx(classes.rightPanel, 'mfui-SplitView__rightPanel', rightPanelProps?.className), style: rightPanelStyle, children: enableAutoUnmount ? (rightPanelSlot ?? lastRightPanelRef.current) : rightPanelSlot })) : null] }));
212
+ tabIndex: 0, style: dividerStyle, onPointerDown: handleMouseDown, onKeyDown: handleKeyDown })) : null, resolvedTargetPanel === 'right' ? (shouldRenderControlledPanel || isSlideOutAnimating ? (_jsx("div", { ...rightPanelProps, className: cx(classes.rightPanel, 'mfui-SplitView__rightPanel', rightPanelProps?.className), style: computedRightPanelStyle, children: _jsx("div", { style: controlledPanelInnerStyle, children: enableAutoUnmount ? (rightPanelSlot ?? lastRightPanelRef.current) : rightPanelSlot }) })) : null) : (_jsx("div", { ...rightPanelProps, className: cx(classes.rightPanel, 'mfui-SplitView__rightPanel', rightPanelProps?.className), style: computedRightPanelStyle, children: rightPanelSlot }))] }));
173
213
  });
@@ -1,10 +1,10 @@
1
1
  import { type ComponentPropsWithoutRef, type CSSProperties, type ReactNode } from 'react';
2
2
  /**
3
- * Props for the SplitView component
3
+ * Base props shared by both the legacy and new panel size APIs.
4
4
  */
5
- export type SplitViewProps = {
5
+ type SplitViewBaseProps = {
6
6
  /**
7
- * The content to display in the left panel
7
+ * The content to display in the left panel.
8
8
  */
9
9
  leftPanelSlot: ReactNode;
10
10
  /**
@@ -12,89 +12,117 @@ export type SplitViewProps = {
12
12
  */
13
13
  rightPanelSlot: ReactNode;
14
14
  /**
15
- * Controls the visibility of the right panel.
15
+ * Controls which panel is visible.
16
16
  *
17
- * When `true`, the right panel is shown with slide-in animation.
18
- * When `false`, the right panel is hidden with slide-out animation.
19
- * When `undefined`, the right panel is visible by default.
17
+ * When `true`, the controlled panel (determined by `targetPanel`) is shown with a slide-in animation.
18
+ * When `false`, the controlled panel is hidden with a slide-out animation.
19
+ * When `undefined`, the controlled panel is visible by default.
20
20
  *
21
21
  * The behavior when hidden depends on the `enableAutoUnmount` prop:
22
- * - `enableAutoUnmount=true` (default): The right panel content will be unmounted when hidden
23
- * - `enableAutoUnmount=false`: The right panel content stays mounted but is hidden via CSS
22
+ * - `enableAutoUnmount=true` (default): The controlled panel content will be unmounted when hidden
23
+ * - `enableAutoUnmount=false`: The controlled panel content stays mounted but is hidden via CSS
24
24
  *
25
- * @default undefined (right panel is visible by default)
25
+ * @default undefined (controlled panel is visible by default)
26
26
  *
27
27
  * @example
28
28
  * ```tsx
29
- * // Default: Memory-efficient (enableAutoUnmount=true)
29
+ * // New API: control left panel size
30
30
  * <SplitView
31
31
  * leftPanelSlot={<LeftPanel />}
32
32
  * rightPanelSlot={<RightPanel />}
33
33
  * isOpen={isOpen}
34
- * initialRightPanelSize={300}
35
- * minRightPanelSize={200}
36
- * maxRightPanelSize={500}
37
- * style={{ minWidth: '600px' }}
38
- * />
39
- *
40
- * // Advanced: State preservation (enableAutoUnmount=false)
41
- * <SplitView
42
- * leftPanelSlot={<LeftPanel />}
43
- * rightPanelSlot={<ExpensiveFormWithState />}
44
- * isOpen={isOpen}
45
- * initialRightPanelSize={300}
46
- * minRightPanelSize={200}
47
- * maxRightPanelSize={500}
48
- * enableAutoUnmount={false}
34
+ * targetPanel="left"
35
+ * initialPanelSize={300}
36
+ * minPanelSize={200}
37
+ * maxPanelSize={500}
49
38
  * style={{ minWidth: '600px' }}
50
39
  * />
51
40
  * ```
52
41
  */
53
42
  isOpen?: boolean;
54
43
  /**
55
- * The initial size of the second panel.
44
+ * Props for the left panel container.
45
+ */
46
+ leftPanelProps?: ComponentPropsWithoutRef<'div'>;
47
+ /**
48
+ * Props for the right panel container.
49
+ */
50
+ rightPanelProps?: ComponentPropsWithoutRef<'div'>;
51
+ /**
52
+ * Props for the divider element.
53
+ */
54
+ dividerProps?: ComponentPropsWithoutRef<'div'>;
55
+ /**
56
+ * Enable auto unmounting of the controlled panel content when it is not displayed.
57
+ * When true, the controlled panel content will return null instead of hiding via CSS.
56
58
  *
57
- * This prop is required and must be specified when using SplitView.
58
- * The right panel will be displayed at this size initially.
59
+ * @default true
60
+ */
61
+ enableAutoUnmount?: boolean;
62
+ } & ComponentPropsWithoutRef<'div'>;
63
+ /**
64
+ * Legacy panel size props (right-panel-specific).
65
+ *
66
+ * This type will be deprecated in v4.0.0.
67
+ * Use `TargetPanelSizeProps` (`initialPanelSize`, `minPanelSize`, `maxPanelSize`, `targetPanel`) instead.
68
+ */
69
+ type LegacyPanelSizeProps = {
70
+ /**
71
+ * The initial size of the right panel.
59
72
  *
60
- * @example
61
- * ```tsx
62
- * <SplitView
63
- * leftPanelSlot={<LeftPanel />}
64
- * rightPanelSlot={<RightPanel />}
65
- * initialRightPanelSize={300}
66
- * minRightPanelSize={200}
67
- * maxRightPanelSize={500}
68
- * style={{ minWidth: '600px' }}
69
- * />
70
- * ```
73
+ * This prop will be deprecated in v4.0.0. Use `initialPanelSize` with `targetPanel="right"` instead.
71
74
  */
72
- initialRightPanelSize: CSSProperties['width'];
75
+ initialRightPanelSize: NonNullable<CSSProperties['width']>;
73
76
  /**
74
- * The minimum size of the second panel
77
+ * The minimum size of the right panel.
78
+ *
79
+ * This prop will be deprecated in v4.0.0. Use `minPanelSize` with `targetPanel="right"` instead.
75
80
  */
76
- minRightPanelSize: CSSProperties['minWidth'];
81
+ minRightPanelSize: NonNullable<CSSProperties['minWidth']>;
77
82
  /**
78
- * The maximum size of the second panel
83
+ * The maximum size of the right panel.
84
+ *
85
+ * This prop will be deprecated in v4.0.0. Use `maxPanelSize` with `targetPanel="right"` instead.
79
86
  */
80
- maxRightPanelSize: CSSProperties['maxWidth'];
87
+ maxRightPanelSize: NonNullable<CSSProperties['maxWidth']>;
88
+ initialPanelSize?: never;
89
+ minPanelSize?: never;
90
+ maxPanelSize?: never;
91
+ targetPanel?: never;
92
+ };
93
+ /**
94
+ * Panel size props for the new API. Supports controlling either the left or right panel.
95
+ */
96
+ type TargetPanelSizeProps = {
81
97
  /**
82
- * Props for the left panel container
98
+ * The initial size of the panel specified by `targetPanel`.
83
99
  */
84
- leftPanelProps?: ComponentPropsWithoutRef<'div'>;
100
+ initialPanelSize: NonNullable<CSSProperties['width']>;
85
101
  /**
86
- * Props for the right panel container
102
+ * The minimum size of the panel specified by `targetPanel`.
87
103
  */
88
- rightPanelProps?: ComponentPropsWithoutRef<'div'>;
104
+ minPanelSize: NonNullable<CSSProperties['minWidth']>;
89
105
  /**
90
- * Props for the divider element
106
+ * The maximum size of the panel specified by `targetPanel`.
91
107
  */
92
- dividerProps?: ComponentPropsWithoutRef<'div'>;
108
+ maxPanelSize: NonNullable<CSSProperties['maxWidth']>;
93
109
  /**
94
- * Enable auto unmounting of the right panel content when it's not displayed.
95
- * When true, the right panel content will return null instead of hiding via CSS.
110
+ * Specifies which panel's size is controlled by `initialPanelSize`, `minPanelSize`, and `maxPanelSize`.
111
+ * Also determines which panel is shown or hidden by the `isOpen` prop.
96
112
  *
97
- * @default true
113
+ * - `"right"`: The right panel has a fixed size; the left panel expands to fill remaining space.
114
+ * - `"left"`: The left panel has a fixed size; the right panel expands to fill remaining space.
98
115
  */
99
- enableAutoUnmount?: boolean;
100
- } & ComponentPropsWithoutRef<'div'>;
116
+ targetPanel: 'left' | 'right';
117
+ /** Disallowed when using the new API. Use `initialPanelSize` instead. */
118
+ initialRightPanelSize?: never;
119
+ /** Disallowed when using the new API. Use `minPanelSize` instead. */
120
+ minRightPanelSize?: never;
121
+ /** Disallowed when using the new API. Use `maxPanelSize` instead. */
122
+ maxRightPanelSize?: never;
123
+ };
124
+ /**
125
+ * Props for the SplitView component.
126
+ */
127
+ export type SplitViewProps = SplitViewBaseProps & (LegacyPanelSizeProps | TargetPanelSizeProps);
128
+ export {};
@@ -7,8 +7,8 @@ import { type ReactNode } from 'react';
7
7
  export declare function useSplitViewAnimation(options: {
8
8
  isRightPanelVisible: boolean;
9
9
  containerRef: React.RefObject<HTMLDivElement | null>;
10
- initialRightPanelSize: number;
11
- minRightPanelSize: number;
10
+ initialPanelSize: number;
11
+ minPanelSize: number;
12
12
  isInitialMountRef: {
13
13
  current: boolean;
14
14
  };
@@ -20,16 +20,16 @@ export declare function useSplitViewAnimation(options: {
20
20
  };
21
21
  hasRightPanelBeenVisible: boolean;
22
22
  isAnimating: boolean;
23
- rightPanelSize: number | undefined;
24
- lastRightPanelSizeRef: {
23
+ controlledPanelSize: number | undefined;
24
+ lastControlledPanelSizeRef: {
25
25
  current: number | undefined;
26
26
  };
27
27
  lastRightPanelRef: {
28
28
  current: ReactNode;
29
29
  };
30
- setRightPanelSize: (size: number | undefined) => void;
30
+ setControlledPanelSize: (size: number | undefined) => void;
31
31
  setIsAnimating: (animating: boolean) => void;
32
- setAnimatedRightPanelSize: (size: number | undefined) => void;
32
+ setAnimatedPanelSize: (size: number | undefined) => void;
33
33
  setHasRightPanelBeenVisible: (visible: boolean) => void;
34
34
  setIsSlideOutAnimating: (animating: boolean) => void;
35
35
  }): void;