panel-splitjs 0.2.0__tar.gz → 0.3.0__tar.gz

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 (53) hide show
  1. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.github/workflows/build.yml +5 -5
  2. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.github/workflows/test.yml +2 -2
  3. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.github/workflows/update-lockfiles.yml +1 -1
  4. panel_splitjs-0.3.0/LICENSE.txt +30 -0
  5. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/PKG-INFO +120 -52
  6. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/README.md +118 -51
  7. panel_splitjs-0.3.0/docs/assets/images/basic-horizontal-split.png +0 -0
  8. panel_splitjs-0.3.0/docs/assets/images/basic-vertical-split.png +0 -0
  9. panel_splitjs-0.3.0/docs/assets/images/chat-example.png +0 -0
  10. panel_splitjs-0.3.0/docs/assets/images/collapsable-sidebar.gif +0 -0
  11. panel_splitjs-0.3.0/docs/assets/images/complex-multi-panel-layout.png +0 -0
  12. panel_splitjs-0.3.0/docs/assets/images/dashboard-with-collapsable-controls.png +0 -0
  13. panel_splitjs-0.3.0/docs/assets/images/multisplit.png +0 -0
  14. panel_splitjs-0.3.0/docs/assets/images/nested-splits.png +0 -0
  15. panel_splitjs-0.3.0/docs/assets/images/quick-start.gif +0 -0
  16. panel_splitjs-0.3.0/docs/assets/images/responsive-layout-with-size-constraints.png +0 -0
  17. panel_splitjs-0.3.0/docs/assets/images/show-buttons.png +0 -0
  18. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/pixi.lock +1627 -1517
  19. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/_version.py +2 -2
  20. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/base.py +13 -2
  21. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/dist/css/splitjs.css +42 -101
  22. panel_splitjs-0.3.0/src/panel_splitjs/dist/panel-splitjs.bundle.js +1 -0
  23. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/models/multi_split.js +3 -1
  24. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/models/split.js +33 -7
  25. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/tests/test_ui.py +105 -5
  26. panel_splitjs-0.2.0/src/panel_splitjs/dist/panel-splitjs.bundle.js +0 -1
  27. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.copier-answers.yml +0 -0
  28. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.gitattributes +0 -0
  29. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.github/CODEOWNERS +0 -0
  30. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.github/dependabot.yml +0 -0
  31. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.gitignore +0 -0
  32. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.pre-commit-config.yaml +0 -0
  33. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/.prettierrc +0 -0
  34. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/MANIFEST.in +0 -0
  35. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/docs/assets/logo.svg +0 -0
  36. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/docs/index.md +0 -0
  37. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/docs/reference/panel_splitjs.md +0 -0
  38. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/examples/apps/multi.py +0 -0
  39. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/examples/apps/simple.py +0 -0
  40. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/hatch_build.py +0 -0
  41. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/mkdocs.yml +0 -0
  42. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/pixi.toml +0 -0
  43. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/pyproject.toml +0 -0
  44. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/__init__.py +0 -0
  45. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/__version.py +0 -0
  46. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/dist/css/arrow_down.svg +0 -0
  47. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/dist/css/arrow_left.svg +0 -0
  48. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/dist/css/arrow_right.svg +0 -0
  49. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/dist/css/arrow_up.svg +0 -0
  50. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/dist/css/handle.svg +0 -0
  51. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/src/panel_splitjs/dist/css/handle_vertical.svg +0 -0
  52. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/tests/conftest.py +0 -0
  53. {panel_splitjs-0.2.0 → panel_splitjs-0.3.0}/tests/test_base.py +0 -0
@@ -18,7 +18,7 @@ jobs:
18
18
  with:
19
19
  fetch-depth: 0
20
20
  - name: Set up pixi
21
- uses: prefix-dev/setup-pixi@194d461b21b6c5717c722ffc597fa91ed2ff29fa # v0.9.1
21
+ uses: prefix-dev/setup-pixi@28eb668aafebd9dede9d97c4ba1cd9989a4d0004 # v0.9.2
22
22
  with:
23
23
  environments: build
24
24
  - name: Build project
@@ -26,12 +26,12 @@ jobs:
26
26
  - name: Check package
27
27
  run: pixi run -e build check-wheel
28
28
  - name: Upload package
29
- uses: actions/upload-artifact@v4
29
+ uses: actions/upload-artifact@v5
30
30
  with:
31
31
  name: pip
32
32
  path: dist/*
33
33
  - name: Upload bundle
34
- uses: actions/upload-artifact@v4
34
+ uses: actions/upload-artifact@v5
35
35
  with:
36
36
  name: cdn
37
37
  path: src/panel_splitjs/dist/
@@ -44,7 +44,7 @@ jobs:
44
44
  id-token: write
45
45
  environment: pypi
46
46
  steps:
47
- - uses: actions/download-artifact@v5
47
+ - uses: actions/download-artifact@v6
48
48
  with:
49
49
  name: pip
50
50
  path: dist/
@@ -56,7 +56,7 @@ jobs:
56
56
  needs: [build]
57
57
  runs-on: ubuntu-latest
58
58
  steps:
59
- - uses: actions/download-artifact@v5
59
+ - uses: actions/download-artifact@v6
60
60
  with:
61
61
  name: cdn
62
62
  path: dist/
@@ -44,7 +44,7 @@ jobs:
44
44
  steps:
45
45
  - uses: actions/checkout@v5.0.0
46
46
  - name: Set up pixi
47
- uses: prefix-dev/setup-pixi@v0.9.1
47
+ uses: prefix-dev/setup-pixi@v0.9.2
48
48
  - uses: holoviz-dev/holoviz_tasks/pre-commit@v0
49
49
  - uses: pre-commit/action@v3.0.1
50
50
  if: needs.setup.outputs.img_change == 'true'
@@ -169,7 +169,7 @@ jobs:
169
169
  FAIL="--screenshot only-on-failure --full-page-screenshot --output ui_screenshots --tracing retain-on-failure"
170
170
  pixi run -e ${{ matrix.environment }} test-ui $COV --cov-config=.uicoveragerc $FAIL
171
171
  - name: Upload UI Screenshots
172
- uses: actions/upload-artifact@v4
172
+ uses: actions/upload-artifact@v5
173
173
  if: always()
174
174
  with:
175
175
  name: ui_screenshots_${{ runner.os }}
@@ -14,7 +14,7 @@ jobs:
14
14
  steps:
15
15
  - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
16
16
  - name: Set up pixi
17
- uses: prefix-dev/setup-pixi@194d461b21b6c5717c722ffc597fa91ed2ff29fa # v0.9.1
17
+ uses: prefix-dev/setup-pixi@28eb668aafebd9dede9d97c4ba1cd9989a4d0004 # v0.9.2
18
18
  with:
19
19
  run-install: false
20
20
  - name: Update lockfiles
@@ -0,0 +1,30 @@
1
+ Copyright (c) 2025, HoloViz team (holoviz.org).
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are
6
+ met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the
14
+ distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of any
17
+ contributors may be used to endorse or promote products derived
18
+ from this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panel-splitjs
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Provides split.js components for Panel.
5
5
  Project-URL: Homepage, https://github.com/panel-extensions/panel-splitjs
6
6
  Project-URL: Source, https://github.com/panel-extensions/panel-splitjs
7
7
  Author-email: Philipp Rudiger <philipp.jfr@gmail.com>
8
8
  Maintainer-email: Philipp Rudiger <philipp.jfr@gmail.com>
9
9
  License: BSD
10
+ License-File: LICENSE.txt
10
11
  Classifier: Development Status :: 5 - Production/Stable
11
12
  Classifier: Intended Audience :: Developers
12
13
  Classifier: Intended Audience :: Science/Research
@@ -80,16 +81,18 @@ pn.extension()
80
81
 
81
82
  # Create a simple split layout
82
83
  split = Split(
83
- pn.pane.Markdown("## Left Panel\nContent here"),
84
- pn.pane.Markdown("## Right Panel\nMore content"),
84
+ pn.pane.Markdown("## Left Panel\nContent here", width=150),
85
+ pn.pane.Markdown("## Right Panel\nMore content", width=150),
85
86
  sizes=(50, 50), # Equal sizing initially
86
- min_size=100, # Minimum 100px for each panel
87
- show_buttons=True
87
+ min_size=150, # Minimum 150px for each panel
88
+ sizing_mode="stretch_both",
88
89
  )
89
90
 
90
91
  split.servable()
91
92
  ```
92
93
 
94
+ ![Quick Start Example](docs/assets/images/quick-start.gif)
95
+
93
96
  ## Usage Examples
94
97
 
95
98
  ### Basic Horizontal Split
@@ -98,30 +101,35 @@ split.servable()
98
101
  import panel as pn
99
102
  from panel_splitjs import HSplit
100
103
 
101
- pn.extension()
104
+ pn.extension(sizing_mode="stretch_width")
102
105
 
103
106
  left_panel = pn.Column(
104
107
  "# Main Content",
105
108
  pn.widgets.TextInput(name="Input"),
106
- pn.pane.Markdown("This is the main content area.")
109
+ pn.pane.Markdown("This is the main content area."),
110
+ margin=25, # To separate toggle button and column
107
111
  )
108
112
 
109
113
  right_panel = pn.Column(
110
114
  "# Sidebar",
111
115
  pn.widgets.Select(name="Options", options=["A", "B", "C"]),
116
+ margin=25, # To separate toggle button and column
112
117
  )
113
118
 
114
119
  split = HSplit(
115
120
  left_panel,
116
121
  right_panel,
117
122
  sizes=(70, 30), # 70% left, 30% right
118
- min_size=200, # Minimum 200px for each panel
119
- show_buttons=True
123
+ min_size=300, # Minimum 300px for each panel
124
+ sizing_mode="stretch_width",
125
+ height=250,
120
126
  )
121
127
 
122
128
  split.servable()
123
129
  ```
124
130
 
131
+ ![Basic Horizontal Split Example](docs/assets/images/basic-horizontal-split.png)
132
+
125
133
  ### Vertical Split
126
134
 
127
135
  ```python
@@ -136,13 +144,40 @@ bottom_panel = pn.pane.Markdown("## Bottom Section\nFooter content")
136
144
  split = VSplit(
137
145
  top_panel,
138
146
  bottom_panel,
139
- sizes=(60, 40),
140
- min_size=150
147
+ sizes=(70, 30),
148
+ min_size=200,
149
+ height=600,
150
+ sizing_mode="stretch_width"
151
+ )
152
+
153
+ split.servable()
154
+ ```
155
+
156
+ ![Basic Vertical Split Example](docs/assets/images/basic-vertical-split.png)
157
+
158
+ ### Show Buttons
159
+
160
+ ```python
161
+ import panel as pn
162
+ from panel_splitjs import Split
163
+
164
+ pn.extension()
165
+
166
+ # Create a simple split layout
167
+ split = Split(
168
+ pn.pane.Markdown("## Left Panel\nContent here", width=150),
169
+ pn.pane.Markdown("## Right Panel\nMore content", width=150),
170
+ sizes=(50, 50), # Equal sizing initially
171
+ min_size=150, # Minimum 150px for each panel
172
+ show_buttons=True,
173
+ sizing_mode="stretch_both",
141
174
  )
142
175
 
143
176
  split.servable()
144
177
  ```
145
178
 
179
+ ![Show Buttons Example](docs/assets/images/show-buttons.png)
180
+
146
181
  ### Collapsible Sidebar
147
182
 
148
183
  ```python
@@ -152,24 +187,27 @@ from panel_splitjs import Split
152
187
  pn.extension()
153
188
 
154
189
  # Start with right panel collapsed
190
+ button = pn.widgets.Button(name="Toggle Sidebar")
191
+
155
192
  split = Split(
156
- pn.pane.Markdown("## Main Content"),
157
- pn.pane.Markdown("## Collapsible Sidebar"),
193
+ pn.Column(pn.pane.Markdown("## Main Content"), button),
194
+ pn.pane.Markdown("## Collapsible Sidebar", margin=(10,10,10,25)),
158
195
  collapsed=1, # 0 for first panel, 1 for second panel, None for not collapsed
159
- expanded_sizes=(65, 35), # When expanded, 65% main, 35% sidebar
160
- show_buttons=True,
161
- min_size=(200, 200) # Minimum 200px for each panel
196
+ expanded_sizes=(80, 20), # When expanded, 80% main, 20% sidebar
197
+ sizing_mode="stretch_both",
162
198
  )
163
199
 
164
200
  # Toggle collapse programmatically
165
- button = pn.widgets.Button(name="Toggle Sidebar")
201
+
166
202
  def toggle(event):
167
203
  split.collapsed = None if split.collapsed == 1 else 1
168
204
  button.on_click(toggle)
169
205
 
170
- pn.Column(button, split).servable()
206
+ split.servable()
171
207
  ```
172
208
 
209
+ ![Collapsible Sidebar Example](docs/assets/images/collapsable-sidebar.gif)
210
+
173
211
  ### Multi-Panel Split
174
212
 
175
213
  ```python
@@ -185,12 +223,15 @@ multi = MultiSplit(
185
223
  pn.pane.Markdown("## Panel 3"),
186
224
  sizes=(30, 40, 30), # Three panels with custom sizing
187
225
  min_size=100, # Minimum 100px for each panel
188
- orientation="horizontal"
226
+ orientation="horizontal",
227
+ sizing_mode="stretch_both",
189
228
  )
190
229
 
191
230
  multi.servable()
192
231
  ```
193
232
 
233
+ ![MultiSplit Example](docs/assets/images/multisplit.png)
234
+
194
235
  ## API Reference
195
236
 
196
237
  ### Split
@@ -205,7 +246,7 @@ The main split panel component for creating two-panel layouts with collapsible f
205
246
  - `max_size` (int | tuple, default=None): Maximum sizes in pixels - single value applies to both panels, tuple for individual sizes
206
247
  - `min_size` (int | tuple, default=0): Minimum sizes in pixels - single value applies to both panels, tuple for individual sizes
207
248
  - `orientation` (str, default="horizontal"): Either `"horizontal"` or `"vertical"`
208
- - `show_buttons` (bool, default=True): Show collapse/expand toggle buttons on the divider
249
+ - `show_buttons` (bool, default=False): Show collapse/expand toggle buttons on the divider
209
250
  - `sizes` (tuple, default=(50, 50)): Initial percentage sizes of the panels
210
251
  - `snap_size` (int, default=30): Snap to minimum size at this offset in pixels
211
252
  - `step_size` (int, default=1): Step size in pixels at which panel sizes can be changed
@@ -246,21 +287,24 @@ from panel_splitjs import Split
246
287
 
247
288
  pn.extension()
248
289
 
249
- chat = pn.chat.ChatInterface()
250
- output = pn.Column("# Output Area")
290
+ with pn.config.set(sizing_mode="stretch_width"):
291
+ chat = pn.chat.ChatInterface(margin=(5,25,5,5))
292
+ output = pn.Column("# Output Area")
251
293
 
252
294
  split = Split(
253
295
  chat,
254
296
  output,
255
297
  collapsed=None, # Both panels visible
256
298
  expanded_sizes=(50, 50),
257
- show_buttons=True,
258
- min_size=(300, 300) # Minimum 300px for each panel
299
+ min_size=(600, 300), # Minimum 600px for the first panel, 300px for the second panel
300
+ sizing_mode="stretch_both",
259
301
  )
260
302
 
261
303
  split.servable()
262
304
  ```
263
305
 
306
+ ![Chat Example](docs/assets/images/chat-example.png)
307
+
264
308
  ### Dashboard with Collapsible Controls
265
309
 
266
310
  ```python
@@ -269,26 +313,30 @@ from panel_splitjs import Split
269
313
 
270
314
  pn.extension()
271
315
 
272
- controls = pn.Column(
273
- pn.widgets.Select(name="Dataset", options=["A", "B", "C"]),
274
- pn.widgets.IntSlider(name="Threshold", start=0, end=100),
275
- pn.widgets.Button(name="Update")
276
- )
316
+ with pn.config.set(sizing_mode="stretch_width"):
317
+ controls = pn.Column(
318
+ pn.widgets.Select(name="Dataset", options=["A", "B", "C"]),
319
+ pn.widgets.IntSlider(name="Threshold", start=0, end=100),
320
+ pn.widgets.Button(name="Update"),
321
+ margin=(5,20,5,5),
322
+ )
277
323
 
278
- visualization = pn.pane.Markdown("## Main Visualization Area")
324
+ visualization = pn.pane.Markdown("## Main Visualization Area")
279
325
 
280
326
  split = Split(
281
327
  controls,
282
328
  visualization,
283
- collapsed=0, # Start with controls collapsed
284
- expanded_sizes=(25, 75),
329
+ sizes=(20, 80),
330
+ min_size=(300, 0),
285
331
  show_buttons=True,
286
- min_size=(250, 400) # Minimum sizes for each panel
332
+ sizing_mode="stretch_both",
287
333
  )
288
334
 
289
335
  split.servable()
290
336
  ```
291
337
 
338
+ ![Dashboard with Collapsible Controls](docs/assets/images/dashboard-with-collapsable-controls.png)
339
+
292
340
  ### Responsive Layout with Size Constraints
293
341
 
294
342
  ```python
@@ -298,18 +346,21 @@ from panel_splitjs import Split
298
346
  pn.extension()
299
347
 
300
348
  split = Split(
301
- pn.pane.Markdown("## Panel 1\nResponsive content"),
302
- pn.pane.Markdown("## Panel 2\nMore responsive content"),
349
+ pn.pane.Markdown("## Panel 1\nResponsive content", sizing_mode="stretch_width", margin=(5,25,5,5)),
350
+ pn.pane.Markdown("## Panel 2\nMore responsive content", sizing_mode="stretch_width", margin=(5,5,5,25)),
303
351
  sizes=(50, 50),
304
352
  min_size=200, # Minimum 200px per panel
305
353
  max_size=800, # Maximum 800px per panel
306
354
  snap_size=50, # Snap to min size when within 50px
307
- show_buttons=True
355
+ show_buttons=True,
356
+ sizing_mode="stretch_both",
308
357
  )
309
358
 
310
359
  split.servable()
311
360
  ```
312
361
 
362
+ ![Responsive Layout with Size Constraints](docs/assets/images/responsive-layout-with-size-constraints.png)
363
+
313
364
  ### Complex Multi-Panel Layout
314
365
 
315
366
  ```python
@@ -319,10 +370,11 @@ from panel_splitjs import MultiSplit
319
370
  pn.extension()
320
371
 
321
372
  # Create a four-panel layout
322
- sidebar = pn.Column("## Sidebar", pn.widgets.Select(options=["A", "B", "C"]))
323
- main = pn.pane.Markdown("## Main Content Area")
324
- detail = pn.pane.Markdown("## Detail Panel")
325
- console = pn.pane.Markdown("## Console Output")
373
+ with pn.config.set(sizing_mode="stretch_width"):
374
+ sidebar = pn.Column("## Sidebar", pn.widgets.Select(options=["A", "B", "C"]))
375
+ main = pn.pane.Markdown("## Main Content Area")
376
+ detail = pn.pane.Markdown("## Detail Panel")
377
+ console = pn.pane.Markdown("## Console Output")
326
378
 
327
379
  multi = MultiSplit(
328
380
  sidebar,
@@ -331,12 +383,15 @@ multi = MultiSplit(
331
383
  console,
332
384
  sizes=(15, 40, 25, 20), # Custom sizing for each panel
333
385
  min_size=(150, 300, 200, 150), # Individual minimums
334
- orientation="horizontal"
386
+ orientation="horizontal",
387
+ sizing_mode="stretch_both",
335
388
  )
336
389
 
337
390
  multi.servable()
338
391
  ```
339
392
 
393
+ ![Complex Multi-Panel Layout](docs/assets/images/complex-multi-panel-layout.png)
394
+
340
395
  ### Nested Splits
341
396
 
342
397
  ```python
@@ -349,21 +404,25 @@ pn.extension()
349
404
  left = pn.pane.Markdown("## Left Panel")
350
405
 
351
406
  # Right side has a vertical split
352
- top_right = pn.pane.Markdown("## Top Right")
353
- bottom_right = pn.pane.Markdown("## Bottom Right")
354
- right = VSplit(top_right, bottom_right, sizes=(60, 40))
355
-
356
- # Main horizontal split
357
- layout = HSplit(
358
- left,
359
- right,
360
- sizes=(30, 70),
361
- min_size=200
362
- )
407
+ with pn.config.set(sizing_mode="stretch_both"):
408
+ top_right = pn.pane.Markdown("## Top Right")
409
+ bottom_right = pn.pane.Markdown("## Bottom Right")
410
+ right = VSplit(top_right, bottom_right, sizes=(60, 40))
411
+
412
+ # Main horizontal split
413
+ layout = HSplit(
414
+ left,
415
+ right,
416
+ sizes=(30, 70),
417
+ min_size=200,
418
+ sizing_mode="stretch_both",
419
+ )
363
420
 
364
421
  layout.servable()
365
422
  ```
366
423
 
424
+ ![Nested Splits](docs/assets/images/nested-splits.png)
425
+
367
426
  ## Development
368
427
 
369
428
  This project is managed by [pixi](https://pixi.sh).
@@ -391,6 +450,15 @@ pixi run build
391
450
  pixi run test
392
451
  ```
393
452
 
453
+ ### Pre-commit
454
+
455
+ Before committing the first time please install `pre-commit`:
456
+
457
+ ```bash
458
+ pip install pre-commit
459
+ pre-commit install
460
+ ```
461
+
394
462
  ## Contributing
395
463
 
396
464
  Contributions are welcome! Please feel free to submit a Pull Request.