react-resizable-panels 1.0.4 → 1.0.6

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 (36) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/README.md +202 -15
  3. package/dist/declarations/src/index.d.ts +10 -1
  4. package/dist/declarations/src/utils/dom/calculateAvailablePanelSizeInPixels.d.ts +1 -0
  5. package/dist/declarations/src/utils/dom/getAvailableGroupSizePixels.d.ts +1 -0
  6. package/dist/declarations/src/utils/dom/getPanelElement.d.ts +1 -0
  7. package/dist/declarations/src/utils/dom/getPanelElementsForGroup.d.ts +1 -0
  8. package/dist/declarations/src/utils/dom/getPanelGroupElement.d.ts +1 -0
  9. package/dist/declarations/src/utils/dom/getResizeHandleElement.d.ts +1 -0
  10. package/dist/declarations/src/utils/dom/getResizeHandleElementIndex.d.ts +1 -0
  11. package/dist/declarations/src/utils/dom/getResizeHandleElementsForGroup.d.ts +1 -0
  12. package/dist/declarations/src/utils/dom/getResizeHandlePanelIds.d.ts +2 -0
  13. package/dist/react-resizable-panels.browser.cjs.js +66 -5
  14. package/dist/react-resizable-panels.browser.cjs.mjs +10 -1
  15. package/dist/react-resizable-panels.browser.development.cjs.js +66 -5
  16. package/dist/react-resizable-panels.browser.development.cjs.mjs +10 -1
  17. package/dist/react-resizable-panels.browser.development.esm.js +58 -6
  18. package/dist/react-resizable-panels.browser.esm.js +58 -6
  19. package/dist/react-resizable-panels.cjs.js +66 -5
  20. package/dist/react-resizable-panels.cjs.mjs +10 -1
  21. package/dist/react-resizable-panels.development.cjs.js +66 -5
  22. package/dist/react-resizable-panels.development.cjs.mjs +10 -1
  23. package/dist/react-resizable-panels.development.esm.js +58 -6
  24. package/dist/react-resizable-panels.development.node.cjs.js +66 -5
  25. package/dist/react-resizable-panels.development.node.cjs.mjs +10 -1
  26. package/dist/react-resizable-panels.development.node.esm.js +58 -6
  27. package/dist/react-resizable-panels.esm.js +58 -6
  28. package/dist/react-resizable-panels.node.cjs.js +66 -5
  29. package/dist/react-resizable-panels.node.cjs.mjs +10 -1
  30. package/dist/react-resizable-panels.node.esm.js +58 -6
  31. package/package.json +1 -1
  32. package/src/Panel.ts +1 -1
  33. package/src/PanelGroup.ts +2 -1
  34. package/src/PanelGroupContext.ts +4 -1
  35. package/src/index.ts +23 -3
  36. package/src/utils/computePanelFlexBoxStyle.ts +7 -3
package/CHANGELOG.md CHANGED
@@ -1,8 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.6
4
+
5
+ - Export internal DOM helper methods.
6
+
7
+ ## 1.0.5
8
+
9
+ - Fix server rendering regression (#240); Panels will now render with their `defaultSize` during initial mount (if one is specified). This allows server-rendered components to store the most recent size in a cookie and use that value as the default for subsequent page visits.
10
+
3
11
  ## 1.0.4
4
12
 
5
- - Edge case bug fix for `isCollapsed` panel method
13
+ - Edge case bug fix for `isCollapsed` panel method; previously an uninitialized `collapsedSize` value was not being initialized to `0`, which caused `isCollapsed` to incorrectly report `false` in some cases.
6
14
 
7
15
  ## 1.0.3
8
16
 
package/README.md CHANGED
@@ -26,26 +26,23 @@ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
26
26
 
27
27
  ### `PanelGroup`
28
28
 
29
- | prop | type | description |
30
- | :--------------------------------- | :--------------------------- | :---------------------------------------------------------------- |
31
- | `autoSaveId` | `?string` | Unique id used to auto-save group arrangement via `localStorage` |
32
- | `children` | `ReactNode` | Arbitrary React element(s) |
33
- | `className` | `?string` | Class name to attach to root element |
34
- | `direction` | `"horizontal" \| "vertical"` | Group orientation |
35
- | `disablePointerEventsDuringResize` | `?boolean = false` | Disable pointer events inside `Panel`s during resize <sup>2</sup> |
36
- | `id` | `?string` | Group id; falls back to `useId` when not provided |
37
- | `onLayout` | `?(sizes: number[]) => void` | Called when group layout changes |
38
- | `storage` | `?PanelGroupStorage` | Custom storage API; defaults to `localStorage` <sup>1</sup> |
39
- | `style` | `?CSSProperties` | CSS style to attach to root element |
40
- | `tagName` | `?string = "div"` | HTML element tag name for root element |
29
+ | prop | type | description |
30
+ | :----------- | :--------------------------- | :--------------------------------------------------------------- |
31
+ | `autoSaveId` | `?string` | Unique id used to auto-save group arrangement via `localStorage` |
32
+ | `children` | `ReactNode` | Arbitrary React element(s) |
33
+ | `className` | `?string` | Class name to attach to root element |
34
+ | `direction` | `"horizontal" \| "vertical"` | Group orientation |
35
+ | `id` | `?string` | Group id; falls back to `useId` when not provided |
36
+ | `onLayout` | `?(sizes: number[]) => void` | Called when group layout changes |
37
+ | `storage` | `?PanelGroupStorage` | Custom storage API; defaults to `localStorage` <sup>1</sup> |
38
+ | `style` | `?CSSProperties` | CSS style to attach to root element |
39
+ | `tagName` | `?string = "div"` | HTML element tag name for root element |
41
40
 
42
41
  <sup>1</sup>: Storage API must define the following _synchronous_ methods:
43
42
 
44
43
  - `getItem: (name:string) => string`
45
44
  - `setItem: (name: string, value: string) => void`
46
45
 
47
- <sup>2</sup>: This behavior is disabled by default because it can interfere with scrollbar styles, but it can be useful in the edge case where a `Panel` contains an `<iframe>`
48
-
49
46
  `PanelGroup` components also expose an imperative API for manual resizing:
50
47
  | method | description
51
48
  | :-------------------------------- | :---
@@ -94,4 +91,194 @@ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
94
91
 
95
92
  ---
96
93
 
97
- #### If you like this project, [buy me a coffee](http://givebrian.coffee/).
94
+ ## FAQ
95
+
96
+ ### Can panel sizes be specified in pixels?
97
+
98
+ No. Pixel-based constraints [added significant complexity](https://github.com/bvaughn/react-resizable-panels/pull/176) to the initialization and validation logic and so I've decided not to support them. You may be able to implement a version of this yourself following [a pattern like this](https://github.com/bvaughn/react-resizable-panels/issues/46#issuecomment-1368108416) but it is not officially supported by this library.
99
+
100
+ ### How can I fix layout/sizing problems with conditionally rendered panels?
101
+
102
+ The `Panel` API doesn't _require_ `id` and `order` props because they aren't necessary for static layouts. When panels are conditionally rendered though, it's best to supply these values.
103
+
104
+ ```tsx
105
+ <PanelGroup direction="horizontal">
106
+ {renderSideBar && (
107
+ <>
108
+ <Panel id="sidebar" minSize={25} order={1}>
109
+ <Sidebar />
110
+ </Panel>
111
+ <PanelResizeHandle />
112
+ </>
113
+ )}
114
+ <Panel minSize={25} order={2}>
115
+ <Main />
116
+ </Panel>
117
+ </PanelGroup>
118
+ ```
119
+
120
+ ### How can I use persistent layouts with SSR?
121
+
122
+ By default, this library uses `localStorage` to persist layouts. With server rendering, this can cause a flicker when the default layout (rendered on the server) is replaced with the persisted layout (in `localStorage`). The way to avoid this flicker is to also persist the layout with a cookie like so:
123
+
124
+ ##### Server component
125
+
126
+ ```tsx
127
+ import ResizablePanels from "@/app/ResizablePanels";
128
+ import { cookies } from "next/headers";
129
+
130
+ export function ServerComponent() {
131
+ const layout = cookies().get("react-resizable-panels:layout");
132
+
133
+ let defaultLayout;
134
+ if (layout) {
135
+ defaultLayout = JSON.parse(layout.value);
136
+ }
137
+
138
+ return <ClientComponent defaultLayout={defaultLayout} />;
139
+ }
140
+ ```
141
+
142
+ ##### Client component
143
+
144
+ ```tsx
145
+ "use client";
146
+
147
+ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
148
+
149
+ export function ClientComponent({
150
+ defaultLayout = [33, 67],
151
+ }: {
152
+ defaultLayout: number[] | undefined;
153
+ }) {
154
+ const onLayout = (sizes: number[]) => {
155
+ document.cookie = `react-resizable-panels:layout=${JSON.stringify(sizes)}`;
156
+ };
157
+
158
+ return (
159
+ <PanelGroup direction="horizontal" onLayout={onLayout}>
160
+ <Panel defaultSize={defaultLayout[0]}>{/* ... */}</Panel>
161
+ <PanelResizeHandle className="w-2 bg-blue-800" />
162
+ <Panel defaultSize={defaultLayout[1]}>{/* ... */}</Panel>
163
+ </PanelGroup>
164
+ );
165
+ }
166
+ ```
167
+
168
+ ---
169
+
170
+ ## FAQ
171
+
172
+ ### Can panel sizes be specified in pixels?
173
+
174
+ No. Pixel-based constraints [added significant complexity](https://github.com/bvaughn/react-resizable-panels/pull/176) to the initialization and validation logic and so I've decided not to support them. You may be able to implement a version of this yourself following [a pattern like this](https://github.com/bvaughn/react-resizable-panels/issues/46#issuecomment-1368108416) but it is not officially supported by this library.
175
+
176
+ ### Can a attach a ref to the DOM elements?
177
+
178
+ No. I think exposing two refs (one for the component's imperative API and one for a DOM element) would be awkward. This library does export several utility methods for accessing the underlying DOM elements though. For example:
179
+
180
+ ```tsx
181
+ export function Example() {
182
+ const refs = useRef();
183
+
184
+ useEffect(() => {
185
+ const groupElement = getPanelGroupElement("group");
186
+ const leftPanelElement = getPanelElement("left-panel");
187
+ const rightPanelElement = getPanelElement("right-panel");
188
+
189
+ // If you want to, you can store them in a ref to pass around
190
+ refs.current = {
191
+ groupElement,
192
+ leftPanelElement,
193
+ rightPanelElement,
194
+ };
195
+ }, []);
196
+
197
+ return (
198
+ <PanelGroup direction="horizontal" id="group">
199
+ <Panel id="left-panel">{/* ... */}</Panel>
200
+ <PanelResizeHandle />
201
+ <Panel id="right-panel">{/* ... */}</Panel>
202
+ </PanelGroup>
203
+ );
204
+ }
205
+ ```
206
+
207
+ ### Why don't I see any resize UI?
208
+
209
+ This likely means that you haven't applied any CSS to style the resize handles. By default, a resize handle is just an empty DOM element. To add styling, use the `className` or `style` props:
210
+
211
+ ```tsx
212
+ // Tailwind example
213
+ <PanelResizeHandle className="w-2 bg-blue-800" />
214
+ ```
215
+
216
+ ### How can I fix layout/sizing problems with conditionally rendered panels?
217
+
218
+ The `Panel` API doesn't _require_ `id` and `order` props because they aren't necessary for static layouts. When panels are conditionally rendered though, it's best to supply these values.
219
+
220
+ ```tsx
221
+ <PanelGroup direction="horizontal">
222
+ {renderSideBar && (
223
+ <>
224
+ <Panel id="sidebar" minSize={25} order={1}>
225
+ <Sidebar />
226
+ </Panel>
227
+ <PanelResizeHandle />
228
+ </>
229
+ )}
230
+ <Panel minSize={25} order={2}>
231
+ <Main />
232
+ </Panel>
233
+ </PanelGroup>
234
+ ```
235
+
236
+ ### How can I use persistent layouts with SSR?
237
+
238
+ By default, this library uses `localStorage` to persist layouts. With server rendering, this can cause a flicker when the default layout (rendered on the server) is replaced with the persisted layout (in `localStorage`). The way to avoid this flicker is to also persist the layout with a cookie like so:
239
+
240
+ ##### Server component
241
+
242
+ ```tsx
243
+ import ResizablePanels from "@/app/ResizablePanels";
244
+ import { cookies } from "next/headers";
245
+
246
+ export function ServerComponent() {
247
+ const layout = cookies().get("react-resizable-panels:layout");
248
+
249
+ let defaultLayout;
250
+ if (layout) {
251
+ defaultLayout = JSON.parse(layout.value);
252
+ }
253
+
254
+ return <ClientComponent defaultLayout={defaultLayout} />;
255
+ }
256
+ ```
257
+
258
+ ##### Client component
259
+
260
+ ```tsx
261
+ "use client";
262
+
263
+ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
264
+
265
+ export function ClientComponent({
266
+ defaultLayout = [33, 67],
267
+ }: {
268
+ defaultLayout: number[] | undefined;
269
+ }) {
270
+ const onLayout = (sizes: number[]) => {
271
+ document.cookie = `react-resizable-panels:layout=${JSON.stringify(sizes)}`;
272
+ };
273
+
274
+ return (
275
+ <PanelGroup direction="horizontal" onLayout={onLayout}>
276
+ <Panel defaultSize={defaultLayout[0]}>{/* ... */}</Panel>
277
+ <PanelResizeHandle className="w-2 bg-blue-800" />
278
+ <Panel defaultSize={defaultLayout[1]}>{/* ... */}</Panel>
279
+ </PanelGroup>
280
+ );
281
+ }
282
+ ```
283
+
284
+ A demo of this is available [here](https://github.com/bvaughn/react-resizable-panels-demo-ssr).
@@ -2,7 +2,16 @@ import { Panel } from "./Panel.js";
2
2
  import { PanelGroup } from "./PanelGroup.js";
3
3
  import { PanelResizeHandle } from "./PanelResizeHandle.js";
4
4
  import { assert } from "./utils/assert.js";
5
+ import { calculateAvailablePanelSizeInPixels } from "./utils/dom/calculateAvailablePanelSizeInPixels.js";
6
+ import { getAvailableGroupSizePixels } from "./utils/dom/getAvailableGroupSizePixels.js";
7
+ import { getPanelElement } from "./utils/dom/getPanelElement.js";
8
+ import { getPanelElementsForGroup } from "./utils/dom/getPanelElementsForGroup.js";
9
+ import { getPanelGroupElement } from "./utils/dom/getPanelGroupElement.js";
10
+ import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement.js";
11
+ import { getResizeHandleElementIndex } from "./utils/dom/getResizeHandleElementIndex.js";
12
+ import { getResizeHandleElementsForGroup } from "./utils/dom/getResizeHandleElementsForGroup.js";
13
+ import { getResizeHandlePanelIds } from "./utils/dom/getResizeHandlePanelIds.js";
5
14
  import type { ImperativePanelHandle, PanelOnCollapse, PanelOnExpand, PanelOnResize, PanelProps } from "./Panel.js";
6
15
  import type { ImperativePanelGroupHandle, PanelGroupOnLayout, PanelGroupProps, PanelGroupStorage } from "./PanelGroup.js";
7
16
  import type { PanelResizeHandleOnDragging, PanelResizeHandleProps } from "./PanelResizeHandle.js";
8
- export { ImperativePanelGroupHandle, ImperativePanelHandle, PanelGroupOnLayout, PanelGroupProps, PanelGroupStorage, PanelOnCollapse, PanelOnExpand, PanelOnResize, PanelProps, PanelResizeHandleOnDragging, PanelResizeHandleProps, assert, Panel, PanelGroup, PanelResizeHandle, };
17
+ export { ImperativePanelGroupHandle, ImperativePanelHandle, PanelGroupOnLayout, PanelGroupProps, PanelGroupStorage, PanelOnCollapse, PanelOnExpand, PanelOnResize, PanelProps, PanelResizeHandleOnDragging, PanelResizeHandleProps, Panel, PanelGroup, PanelResizeHandle, assert, calculateAvailablePanelSizeInPixels, getAvailableGroupSizePixels, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds, };
@@ -0,0 +1 @@
1
+ export declare function calculateAvailablePanelSizeInPixels(groupId: string): number;
@@ -0,0 +1 @@
1
+ export declare function getAvailableGroupSizePixels(groupId: string): number;
@@ -0,0 +1 @@
1
+ export declare function getPanelElement(id: string): HTMLDivElement | null;
@@ -0,0 +1 @@
1
+ export declare function getPanelElementsForGroup(groupId: string): HTMLDivElement[];
@@ -0,0 +1 @@
1
+ export declare function getPanelGroupElement(id: string): HTMLDivElement | null;
@@ -0,0 +1 @@
1
+ export declare function getResizeHandleElement(id: string): HTMLDivElement | null;
@@ -0,0 +1 @@
1
+ export declare function getResizeHandleElementIndex(groupId: string, id: string): number | null;
@@ -0,0 +1 @@
1
+ export declare function getResizeHandleElementsForGroup(groupId: string): HTMLDivElement[];
@@ -0,0 +1,2 @@
1
+ import { PanelData } from "../../Panel.js";
2
+ export declare function getResizeHandlePanelIds(groupId: string, handleId: string, panelsArray: PanelData[]): [idBefore: string | null, idAfter: string | null];
@@ -163,7 +163,7 @@ function PanelWithForwardedRef({
163
163
  resizePanel(panelDataRef.current, size);
164
164
  }
165
165
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
166
- const style = getPanelStyle(panelDataRef.current);
166
+ const style = getPanelStyle(panelDataRef.current, defaultSize);
167
167
  return createElement(Type, {
168
168
  ...rest,
169
169
  children,
@@ -858,6 +858,7 @@ function compareLayouts(a, b) {
858
858
 
859
859
  // the % of the group's overall space this panel should occupy.
860
860
  function computePanelFlexBoxStyle({
861
+ defaultSize,
861
862
  dragState,
862
863
  layout,
863
864
  panelData,
@@ -866,10 +867,12 @@ function computePanelFlexBoxStyle({
866
867
  }) {
867
868
  const size = layout[panelIndex];
868
869
  let flexGrow;
869
- if (panelData.length === 1) {
870
- flexGrow = "1";
871
- } else if (size == null) {
870
+ if (size == null) {
872
871
  // Initial render (before panels have registered themselves)
872
+ // In order to support server rendering, fall back to default size if provided
873
+ flexGrow = defaultSize !== null && defaultSize !== void 0 ? defaultSize : "1";
874
+ } else if (panelData.length === 1) {
875
+ // Special case: Single panel group should always fill full width/height
873
876
  flexGrow = "1";
874
877
  } else {
875
878
  flexGrow = size.toPrecision(precision);
@@ -1306,12 +1309,13 @@ function PanelGroupWithForwardedRef({
1306
1309
  }, []);
1307
1310
 
1308
1311
  // This API should never read from committedValuesRef
1309
- const getPanelStyle = useCallback(panelData => {
1312
+ const getPanelStyle = useCallback((panelData, defaultSize) => {
1310
1313
  const {
1311
1314
  panelDataArray
1312
1315
  } = eagerValuesRef.current;
1313
1316
  const panelIndex = findPanelDataIndex(panelDataArray, panelData);
1314
1317
  return computePanelFlexBoxStyle({
1318
+ defaultSize,
1315
1319
  dragState,
1316
1320
  layout,
1317
1321
  panelData: panelDataArray,
@@ -1819,7 +1823,64 @@ function PanelResizeHandle({
1819
1823
  }
1820
1824
  PanelResizeHandle.displayName = "PanelResizeHandle";
1821
1825
 
1826
+ function calculateAvailablePanelSizeInPixels(groupId) {
1827
+ const panelGroupElement = getPanelGroupElement(groupId);
1828
+ if (panelGroupElement == null) {
1829
+ return NaN;
1830
+ }
1831
+ const direction = panelGroupElement.getAttribute("data-panel-group-direction");
1832
+ const resizeHandles = getResizeHandleElementsForGroup(groupId);
1833
+ if (direction === "horizontal") {
1834
+ return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
1835
+ return accumulated + handle.offsetWidth;
1836
+ }, 0);
1837
+ } else {
1838
+ return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
1839
+ return accumulated + handle.offsetHeight;
1840
+ }, 0);
1841
+ }
1842
+ }
1843
+
1844
+ function getAvailableGroupSizePixels(groupId) {
1845
+ const panelGroupElement = getPanelGroupElement(groupId);
1846
+ if (panelGroupElement == null) {
1847
+ return NaN;
1848
+ }
1849
+ const direction = panelGroupElement.getAttribute("data-panel-group-direction");
1850
+ const resizeHandles = getResizeHandleElementsForGroup(groupId);
1851
+ if (direction === "horizontal") {
1852
+ return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
1853
+ return accumulated + handle.offsetWidth;
1854
+ }, 0);
1855
+ } else {
1856
+ return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
1857
+ return accumulated + handle.offsetHeight;
1858
+ }, 0);
1859
+ }
1860
+ }
1861
+
1862
+ function getPanelElement(id) {
1863
+ const element = document.querySelector(`[data-panel-id="${id}"]`);
1864
+ if (element) {
1865
+ return element;
1866
+ }
1867
+ return null;
1868
+ }
1869
+
1870
+ function getPanelElementsForGroup(groupId) {
1871
+ return Array.from(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
1872
+ }
1873
+
1822
1874
  exports.Panel = Panel;
1823
1875
  exports.PanelGroup = PanelGroup;
1824
1876
  exports.PanelResizeHandle = PanelResizeHandle;
1825
1877
  exports.assert = assert;
1878
+ exports.calculateAvailablePanelSizeInPixels = calculateAvailablePanelSizeInPixels;
1879
+ exports.getAvailableGroupSizePixels = getAvailableGroupSizePixels;
1880
+ exports.getPanelElement = getPanelElement;
1881
+ exports.getPanelElementsForGroup = getPanelElementsForGroup;
1882
+ exports.getPanelGroupElement = getPanelGroupElement;
1883
+ exports.getResizeHandleElement = getResizeHandleElement;
1884
+ exports.getResizeHandleElementIndex = getResizeHandleElementIndex;
1885
+ exports.getResizeHandleElementsForGroup = getResizeHandleElementsForGroup;
1886
+ exports.getResizeHandlePanelIds = getResizeHandlePanelIds;
@@ -2,5 +2,14 @@ export {
2
2
  Panel,
3
3
  PanelGroup,
4
4
  PanelResizeHandle,
5
- assert
5
+ assert,
6
+ calculateAvailablePanelSizeInPixels,
7
+ getAvailableGroupSizePixels,
8
+ getPanelElement,
9
+ getPanelElementsForGroup,
10
+ getPanelGroupElement,
11
+ getResizeHandleElement,
12
+ getResizeHandleElementIndex,
13
+ getResizeHandleElementsForGroup,
14
+ getResizeHandlePanelIds
6
15
  } from "./react-resizable-panels.browser.cjs.js";
@@ -169,7 +169,7 @@ function PanelWithForwardedRef({
169
169
  resizePanel(panelDataRef.current, size);
170
170
  }
171
171
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
172
- const style = getPanelStyle(panelDataRef.current);
172
+ const style = getPanelStyle(panelDataRef.current, defaultSize);
173
173
  return createElement(Type, {
174
174
  ...rest,
175
175
  children,
@@ -874,6 +874,7 @@ function compareLayouts(a, b) {
874
874
 
875
875
  // the % of the group's overall space this panel should occupy.
876
876
  function computePanelFlexBoxStyle({
877
+ defaultSize,
877
878
  dragState,
878
879
  layout,
879
880
  panelData,
@@ -882,10 +883,12 @@ function computePanelFlexBoxStyle({
882
883
  }) {
883
884
  const size = layout[panelIndex];
884
885
  let flexGrow;
885
- if (panelData.length === 1) {
886
- flexGrow = "1";
887
- } else if (size == null) {
886
+ if (size == null) {
888
887
  // Initial render (before panels have registered themselves)
888
+ // In order to support server rendering, fall back to default size if provided
889
+ flexGrow = defaultSize !== null && defaultSize !== void 0 ? defaultSize : "1";
890
+ } else if (panelData.length === 1) {
891
+ // Special case: Single panel group should always fill full width/height
889
892
  flexGrow = "1";
890
893
  } else {
891
894
  flexGrow = size.toPrecision(precision);
@@ -1411,12 +1414,13 @@ function PanelGroupWithForwardedRef({
1411
1414
  }, []);
1412
1415
 
1413
1416
  // This API should never read from committedValuesRef
1414
- const getPanelStyle = useCallback(panelData => {
1417
+ const getPanelStyle = useCallback((panelData, defaultSize) => {
1415
1418
  const {
1416
1419
  panelDataArray
1417
1420
  } = eagerValuesRef.current;
1418
1421
  const panelIndex = findPanelDataIndex(panelDataArray, panelData);
1419
1422
  return computePanelFlexBoxStyle({
1423
+ defaultSize,
1420
1424
  dragState,
1421
1425
  layout,
1422
1426
  panelData: panelDataArray,
@@ -1924,7 +1928,64 @@ function PanelResizeHandle({
1924
1928
  }
1925
1929
  PanelResizeHandle.displayName = "PanelResizeHandle";
1926
1930
 
1931
+ function calculateAvailablePanelSizeInPixels(groupId) {
1932
+ const panelGroupElement = getPanelGroupElement(groupId);
1933
+ if (panelGroupElement == null) {
1934
+ return NaN;
1935
+ }
1936
+ const direction = panelGroupElement.getAttribute("data-panel-group-direction");
1937
+ const resizeHandles = getResizeHandleElementsForGroup(groupId);
1938
+ if (direction === "horizontal") {
1939
+ return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
1940
+ return accumulated + handle.offsetWidth;
1941
+ }, 0);
1942
+ } else {
1943
+ return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
1944
+ return accumulated + handle.offsetHeight;
1945
+ }, 0);
1946
+ }
1947
+ }
1948
+
1949
+ function getAvailableGroupSizePixels(groupId) {
1950
+ const panelGroupElement = getPanelGroupElement(groupId);
1951
+ if (panelGroupElement == null) {
1952
+ return NaN;
1953
+ }
1954
+ const direction = panelGroupElement.getAttribute("data-panel-group-direction");
1955
+ const resizeHandles = getResizeHandleElementsForGroup(groupId);
1956
+ if (direction === "horizontal") {
1957
+ return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
1958
+ return accumulated + handle.offsetWidth;
1959
+ }, 0);
1960
+ } else {
1961
+ return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
1962
+ return accumulated + handle.offsetHeight;
1963
+ }, 0);
1964
+ }
1965
+ }
1966
+
1967
+ function getPanelElement(id) {
1968
+ const element = document.querySelector(`[data-panel-id="${id}"]`);
1969
+ if (element) {
1970
+ return element;
1971
+ }
1972
+ return null;
1973
+ }
1974
+
1975
+ function getPanelElementsForGroup(groupId) {
1976
+ return Array.from(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
1977
+ }
1978
+
1927
1979
  exports.Panel = Panel;
1928
1980
  exports.PanelGroup = PanelGroup;
1929
1981
  exports.PanelResizeHandle = PanelResizeHandle;
1930
1982
  exports.assert = assert;
1983
+ exports.calculateAvailablePanelSizeInPixels = calculateAvailablePanelSizeInPixels;
1984
+ exports.getAvailableGroupSizePixels = getAvailableGroupSizePixels;
1985
+ exports.getPanelElement = getPanelElement;
1986
+ exports.getPanelElementsForGroup = getPanelElementsForGroup;
1987
+ exports.getPanelGroupElement = getPanelGroupElement;
1988
+ exports.getResizeHandleElement = getResizeHandleElement;
1989
+ exports.getResizeHandleElementIndex = getResizeHandleElementIndex;
1990
+ exports.getResizeHandleElementsForGroup = getResizeHandleElementsForGroup;
1991
+ exports.getResizeHandlePanelIds = getResizeHandlePanelIds;
@@ -2,5 +2,14 @@ export {
2
2
  Panel,
3
3
  PanelGroup,
4
4
  PanelResizeHandle,
5
- assert
5
+ assert,
6
+ calculateAvailablePanelSizeInPixels,
7
+ getAvailableGroupSizePixels,
8
+ getPanelElement,
9
+ getPanelElementsForGroup,
10
+ getPanelGroupElement,
11
+ getResizeHandleElement,
12
+ getResizeHandleElementIndex,
13
+ getResizeHandleElementsForGroup,
14
+ getResizeHandlePanelIds
6
15
  } from "./react-resizable-panels.browser.development.cjs.js";
@@ -145,7 +145,7 @@ function PanelWithForwardedRef({
145
145
  resizePanel(panelDataRef.current, size);
146
146
  }
147
147
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
148
- const style = getPanelStyle(panelDataRef.current);
148
+ const style = getPanelStyle(panelDataRef.current, defaultSize);
149
149
  return createElement(Type, {
150
150
  ...rest,
151
151
  children,
@@ -850,6 +850,7 @@ function compareLayouts(a, b) {
850
850
 
851
851
  // the % of the group's overall space this panel should occupy.
852
852
  function computePanelFlexBoxStyle({
853
+ defaultSize,
853
854
  dragState,
854
855
  layout,
855
856
  panelData,
@@ -858,10 +859,12 @@ function computePanelFlexBoxStyle({
858
859
  }) {
859
860
  const size = layout[panelIndex];
860
861
  let flexGrow;
861
- if (panelData.length === 1) {
862
- flexGrow = "1";
863
- } else if (size == null) {
862
+ if (size == null) {
864
863
  // Initial render (before panels have registered themselves)
864
+ // In order to support server rendering, fall back to default size if provided
865
+ flexGrow = defaultSize !== null && defaultSize !== void 0 ? defaultSize : "1";
866
+ } else if (panelData.length === 1) {
867
+ // Special case: Single panel group should always fill full width/height
865
868
  flexGrow = "1";
866
869
  } else {
867
870
  flexGrow = size.toPrecision(precision);
@@ -1387,12 +1390,13 @@ function PanelGroupWithForwardedRef({
1387
1390
  }, []);
1388
1391
 
1389
1392
  // This API should never read from committedValuesRef
1390
- const getPanelStyle = useCallback(panelData => {
1393
+ const getPanelStyle = useCallback((panelData, defaultSize) => {
1391
1394
  const {
1392
1395
  panelDataArray
1393
1396
  } = eagerValuesRef.current;
1394
1397
  const panelIndex = findPanelDataIndex(panelDataArray, panelData);
1395
1398
  return computePanelFlexBoxStyle({
1399
+ defaultSize,
1396
1400
  dragState,
1397
1401
  layout,
1398
1402
  panelData: panelDataArray,
@@ -1900,4 +1904,52 @@ function PanelResizeHandle({
1900
1904
  }
1901
1905
  PanelResizeHandle.displayName = "PanelResizeHandle";
1902
1906
 
1903
- export { Panel, PanelGroup, PanelResizeHandle, assert };
1907
+ function calculateAvailablePanelSizeInPixels(groupId) {
1908
+ const panelGroupElement = getPanelGroupElement(groupId);
1909
+ if (panelGroupElement == null) {
1910
+ return NaN;
1911
+ }
1912
+ const direction = panelGroupElement.getAttribute("data-panel-group-direction");
1913
+ const resizeHandles = getResizeHandleElementsForGroup(groupId);
1914
+ if (direction === "horizontal") {
1915
+ return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
1916
+ return accumulated + handle.offsetWidth;
1917
+ }, 0);
1918
+ } else {
1919
+ return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
1920
+ return accumulated + handle.offsetHeight;
1921
+ }, 0);
1922
+ }
1923
+ }
1924
+
1925
+ function getAvailableGroupSizePixels(groupId) {
1926
+ const panelGroupElement = getPanelGroupElement(groupId);
1927
+ if (panelGroupElement == null) {
1928
+ return NaN;
1929
+ }
1930
+ const direction = panelGroupElement.getAttribute("data-panel-group-direction");
1931
+ const resizeHandles = getResizeHandleElementsForGroup(groupId);
1932
+ if (direction === "horizontal") {
1933
+ return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
1934
+ return accumulated + handle.offsetWidth;
1935
+ }, 0);
1936
+ } else {
1937
+ return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
1938
+ return accumulated + handle.offsetHeight;
1939
+ }, 0);
1940
+ }
1941
+ }
1942
+
1943
+ function getPanelElement(id) {
1944
+ const element = document.querySelector(`[data-panel-id="${id}"]`);
1945
+ if (element) {
1946
+ return element;
1947
+ }
1948
+ return null;
1949
+ }
1950
+
1951
+ function getPanelElementsForGroup(groupId) {
1952
+ return Array.from(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
1953
+ }
1954
+
1955
+ export { Panel, PanelGroup, PanelResizeHandle, assert, calculateAvailablePanelSizeInPixels, getAvailableGroupSizePixels, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds };