panel-splitjs 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.
panel_splitjs/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.0'
32
- __version_tuple__ = version_tuple = (0, 2, 0)
31
+ __version__ = version = '0.3.0'
32
+ __version_tuple__ = version_tuple = (0, 3, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
panel_splitjs/base.py CHANGED
@@ -3,12 +3,20 @@ from pathlib import Path
3
3
  import param
4
4
  from bokeh.embed.bundle import extension_dirs
5
5
  from panel.custom import Children, JSComponent
6
+ from panel.io.resources import EXTENSION_CDN
6
7
  from panel.layout.base import ListLike
8
+ from panel.util import base_version
7
9
 
10
+ from .__version import __version__ # noqa
11
+
12
+ IS_RELEASE = __version__ == base_version(__version__)
8
13
  BASE_PATH = Path(__file__).parent
9
14
  DIST_PATH = BASE_PATH / 'dist'
15
+ CDN_BASE = f"https://cdn.holoviz.org/panel-splitjs/v{base_version(__version__)}"
16
+ CDN_DIST = f"{CDN_BASE}/panel-material-ui.bundle.js"
10
17
 
11
18
  extension_dirs['panel-splitjs'] = DIST_PATH
19
+ EXTENSION_CDN[DIST_PATH] = CDN_BASE
12
20
 
13
21
 
14
22
  class Size(param.Parameter):
@@ -25,12 +33,15 @@ class Size(param.Parameter):
25
33
  return
26
34
  if self.length is not None and isinstance(val, tuple) and len(val) != self.length:
27
35
  raise ValueError(f"Size parameter {self.name!r} must have length {self.length}")
28
- if not (isinstance(val, (int, float)) or (isinstance(val, tuple) and all(isinstance(v, (int, float)) for v in val))):
36
+ if not (isinstance(val, (int, float)) or (isinstance(val, tuple) and all(isinstance(v, (int, float)) or v is None for v in val))):
29
37
  raise ValueError(f"Size parameter {self.name!r} only takes int or float values")
30
38
 
31
39
 
32
40
  class SplitBase(JSComponent, ListLike):
33
41
 
42
+ gutter_size = param.Integer(default=8, doc="""
43
+ Width of the gutter element.""")
44
+
34
45
  max_size = Size(default=None, doc="""
35
46
  The maximum sizes of the panels (in pixels) either as a single value or a tuple.""")
36
47
 
@@ -101,7 +112,7 @@ class Split(SplitBase):
101
112
  The component to place in the left panel.
102
113
  When invert=True, this will appear on the right side.""")
103
114
 
104
- show_buttons = param.Boolean(default=True, doc="""
115
+ show_buttons = param.Boolean(default=False, doc="""
105
116
  Whether to show the toggle buttons on the divider.
106
117
  When False, the buttons are hidden and panels can only be resized by dragging.""")
107
118
 
@@ -13,42 +13,27 @@
13
13
  flex-direction: column;
14
14
  }
15
15
 
16
+ /* Padding for panel edges unless collapsed */
17
+ .single-split.horizontal.expand-buttons > div:nth-child(1) { padding-right: 15px; }
18
+ .single-split.horizontal > div:nth-child(1):has(.collapsed-content) { padding-right: 0; }
19
+ .single-split.horizontal.expand-buttons > div:nth-child(3) { padding-left: 15px; }
20
+ .single-split.horizontal > div:nth-child(3):has(.collapsed-content) { padding-left: 0; }
21
+
22
+ .single-split.vertical.expand-buttons > div:nth-child(1) { padding-bottom: 15px; }
23
+ .single-split.vertical > div:nth-child(1):has(.collapsed-content) { padding-bottom: 0; }
24
+ .single-split.vertical.expand-buttons > div:nth-child(3) { padding-top: 15px; }
25
+ .single-split.vertical > div:nth-child(3):has(.collapsed-content) { padding-top: 0; }
26
+
16
27
  /* Style for initial load to prevent FOUC */
17
28
  .loading {
18
29
  visibility: hidden;
19
30
  }
20
31
 
21
- /* Max width for comfortable reading */
22
- .left-panel-content {
23
- max-width: clamp(450px, 95vw, 1200px);
24
- margin: 0px auto;
25
- }
26
-
27
- /* Split panel styles */
32
+ /* Split panel styles (combine .split > div rules) */
28
33
  .split > div {
29
34
  position: relative;
30
35
  }
31
36
 
32
- .split.single-split > div:nth-child(1) {
33
- overflow: clip;
34
- }
35
-
36
- .split.single-split > div:nth-child(2) {
37
- overflow: visible;
38
- position: relative;
39
- width: 100%;
40
- }
41
-
42
- /* Ensure buttons stay visible even when panels are collapsed */
43
- .split.single-split > div:first-child {
44
- min-width: 0 !important; /* Override any minimum width */
45
- }
46
-
47
- .split.single-split > div:nth-child(2) {
48
- overflow: visible !important; /* Ensure buttons remain visible */
49
- position: relative !important;
50
- }
51
-
52
37
  /* Content wrapper styles */
53
38
  .content-wrapper {
54
39
  width: 100%;
@@ -58,7 +43,7 @@
58
43
  padding-inline: 0.5rem;
59
44
  }
60
45
 
61
- /* Toggle button basic styles */
46
+ /* Toggle button base styles (deduplicated, combine base and arrow masks) */
62
47
  .toggle-button-left, .toggle-button-right, .toggle-button-up, .toggle-button-down {
63
48
  position: absolute;
64
49
  width: 24px;
@@ -72,34 +57,47 @@
72
57
  transition: opacity 0.2s;
73
58
  border-radius: 4px;
74
59
  padding: 2px;
60
+
61
+ background-color: var(--panel-on-background-color);
62
+ -webkit-mask-repeat: no-repeat;
63
+ mask-repeat: no-repeat;
64
+ -webkit-mask-position: center;
65
+ mask-position: center;
66
+ -webkit-mask-size: 16px;
67
+ mask-size: 16px;
75
68
  }
76
69
 
77
- /* Left button (<) - positioned on left side of divider */
78
70
  .toggle-button-left {
79
- left: -34px; /* 24px width + 10px spacing from divider */
71
+ left: -28px;
80
72
  top: 50%;
81
73
  transform: translateY(-50%);
74
+ -webkit-mask-image: url("arrow_left.svg");
75
+ mask-image: url("arrow_left.svg");
82
76
  }
83
-
84
- /* Right button (>) - positioned on right side of divider */
85
77
  .toggle-button-right {
86
- left: 2px;
78
+ left: -4px;
87
79
  top: 50%;
88
80
  transform: translateY(-50%);
81
+ -webkit-mask-image: url("arrow_right.svg");
82
+ mask-image: url("arrow_right.svg");
89
83
  }
90
-
91
- /* Up button (^) - positioned above divider */
92
84
  .toggle-button-up {
93
- top: -34px; /* 24px height + 10px spacing from divider */
85
+ top: -28px;
94
86
  left: 50%;
95
87
  transform: translateX(-50%);
88
+ -webkit-mask-image: url("arrow_up.svg");
89
+ mask-image: url("arrow_up.svg");
96
90
  }
97
-
98
- /* Down button (v) - positioned below divider */
99
91
  .toggle-button-down {
100
- top: 2px;
92
+ top: -4px;
101
93
  left: 50%;
102
94
  transform: translateX(-50%);
95
+ -webkit-mask-image: url("arrow_down.svg");
96
+ mask-image: url("arrow_down.svg");
97
+ }
98
+
99
+ .toggle-button-left:hover, .toggle-button-right:hover, .toggle-button-up:hover, .toggle-button-down:hover {
100
+ opacity: 1;
103
101
  }
104
102
 
105
103
  /* Collapsed state */
@@ -113,23 +111,19 @@
113
111
  background-repeat: no-repeat;
114
112
  background-position: 50%;
115
113
  transition: background-color 0.2s;
114
+ z-index: 999;
116
115
  }
117
-
118
116
  .gutter:hover {
119
117
  background-color: var(--panel-surface-color);
120
118
  }
121
-
122
119
  .gutter.gutter-horizontal {
123
120
  cursor: col-resize;
124
121
  position: relative;
125
122
  width: 10px;
126
- z-index: 1;
127
123
  }
128
-
129
124
  .gutter.gutter-vertical {
130
125
  cursor: row-resize;
131
126
  }
132
-
133
127
  .gutter::after {
134
128
  content: "";
135
129
  position: absolute;
@@ -142,13 +136,11 @@
142
136
  mask-repeat: no-repeat;
143
137
  background-color: var(--panel-border-color);
144
138
  }
145
-
146
139
  .gutter.gutter-horizontal::after {
147
140
  width: 10px;
148
141
  height: 24px;
149
142
  cursor: col-resize;
150
143
  }
151
-
152
144
  .gutter.gutter-vertical::after {
153
145
  width: 24px;
154
146
  height: 10px;
@@ -156,16 +148,14 @@
156
148
  mask-image: url("handle_vertical.svg");
157
149
  cursor: row-resize;
158
150
  }
159
-
160
151
  .gutter > .divider {
161
152
  --gap: 40px;
162
153
  --thickness: 1px;
163
- --color: var(--border-color);
154
+ --color: var(--panel-border-color);
164
155
  background: var(--color);
165
156
  position: absolute;
166
157
  }
167
-
168
- /* Horizontal variant */
158
+ /* Horizontal variant for divider */
169
159
  .gutter-vertical > .divider {
170
160
  top: 50%;
171
161
  width: 100%;
@@ -179,8 +169,7 @@
179
169
  var(--color) calc(50% + var(--gap) / 2),
180
170
  var(--color) 100%);
181
171
  }
182
-
183
- /* Vertical variant */
172
+ /* Vertical variant for divider */
184
173
  .gutter-horizontal > .divider {
185
174
  left: 50%;
186
175
  height: 100%;
@@ -195,73 +184,25 @@
195
184
  var(--color) 100%);
196
185
  }
197
186
 
198
- /* Toggle button base styles */
199
- .toggle-button-left,
200
- .toggle-button-right,
201
- .toggle-button-up,
202
- .toggle-button-down {
203
- width: 24px;
204
- height: 24px;
205
- background-color: var(--panel-on-background-color);
206
- -webkit-mask-repeat: no-repeat;
207
- mask-repeat: no-repeat;
208
- -webkit-mask-position: center;
209
- mask-position: center;
210
- -webkit-mask-size: 16px;
211
- mask-size: 16px;
212
- opacity: 0.5;
213
- }
214
-
215
- .toggle-button-left:hover, .toggle-button-right:hover, .toggle-button-up:hover, .toggle-button-down:hover {
216
- opacity: 1;
217
- }
218
-
219
- /* Left arrow button */
220
- .toggle-button-left {
221
- -webkit-mask-image: url("arrow_left.svg");
222
- mask-image: url("arrow_left.svg");
223
- }
224
-
225
- /* Right arrow button */
226
- .toggle-button-right {
227
- -webkit-mask-image: url("arrow_right.svg");
228
- mask-image: url("arrow_right.svg");
229
- }
230
-
231
- /* Up arrow button */
232
- .toggle-button-up {
233
- -webkit-mask-image: url("arrow_up.svg");
234
- mask-image: url("arrow_up.svg");
235
- }
236
-
237
- /* Down arrow button */
238
- .toggle-button-down {
239
- -webkit-mask-image: url("arrow_down.svg");
240
- mask-image: url("arrow_down.svg");
241
- }
242
-
243
- /* Animation for toggle icon */
187
+ /* Toggle button animation */
244
188
  @keyframes jumpLeftRight {
245
189
  0%, 100% { transform: translateY(-50%); }
246
190
  25% { transform: translate(-4px, -50%); }
247
191
  50% { transform: translateY(-50%); }
248
192
  75% { transform: translate(4px, -50%); }
249
193
  }
250
-
251
194
  @keyframes jumpUpDown {
252
195
  0%, 100% { transform: translateX(-50%); }
253
196
  25% { transform: translate(-50%, -4px); }
254
197
  50% { transform: translateX(-50%); }
255
198
  75% { transform: translate(-50%, 4px); }
256
199
  }
257
-
258
200
  .toggle-button-left.animated, .toggle-button-right.animated {
259
201
  animation-name: jumpLeftRight;
260
202
  animation-duration: 0.5s;
261
203
  animation-timing-function: ease;
262
204
  animation-iteration-count: 3;
263
205
  }
264
-
265
206
  .toggle-button-up.animated, .toggle-button-down.animated {
266
207
  animation-name: jumpUpDown;
267
208
  animation-duration: 0.5s;
@@ -1 +1 @@
1
- var ye=Object.defineProperty;var ce=(t,s)=>{for(var a in s)ye(t,a,{get:s[a],enumerable:!0})};var U={};ce(U,{render:()=>Ne});var E=typeof window<"u"?window:null,ee=E===null,q=ee?void 0:E.document,x="addEventListener",N="removeEventListener",T="getBoundingClientRect",H="_a",O="_b",k="_c",Y="horizontal",L=function(){return!1},_e=ee?"calc":["","-webkit-","-moz-","-o-"].filter(function(t){var s=q.createElement("div");return s.style.cssText="width:"+t+"calc(9px)",!!s.style.length}).shift()+"calc",ue=function(t){return typeof t=="string"||t instanceof String},oe=function(t){if(ue(t)){var s=q.querySelector(t);if(!s)throw new Error("Selector "+t+" did not match a DOM element");return s}return t},z=function(t,s,a){var c=t[s];return c!==void 0?c:a},J=function(t,s,a,c){if(s){if(c==="end")return 0;if(c==="center")return t/2}else if(a){if(c==="start")return 0;if(c==="center")return t/2}return t},be=function(t,s){var a=q.createElement("div");return a.className="gutter gutter-"+s,a},we=function(t,s,a){var c={};return ue(s)?c[t]=s:c[t]=_e+"("+s+"% - "+a+"px)",c},Ee=function(t,s){var a;return a={},a[t]=s+"px",a},xe=function(t,s){if(s===void 0&&(s={}),ee)return{};var a=t,c,b,S,y,d,l;Array.from&&(a=Array.from(a));var h=oe(a[0]),f=h.parentNode,w=getComputedStyle?getComputedStyle(f):null,u=w?w.flexDirection:null,p=z(s,"sizes")||a.map(function(){return 100/a.length}),P=z(s,"minSize",100),B=Array.isArray(P)?P:a.map(function(){return P}),j=z(s,"maxSize",1/0),Z=Array.isArray(j)?j:a.map(function(){return j}),o=z(s,"expandToMin",!1),g=z(s,"gutterSize",10),D=z(s,"gutterAlign","center"),C=z(s,"snapOffset",30),A=Array.isArray(C)?C:a.map(function(){return C}),M=z(s,"dragInterval",1),G=z(s,"direction",Y),Q=z(s,"cursor",G===Y?"col-resize":"row-resize"),fe=z(s,"gutter",be),ne=z(s,"elementStyle",we),de=z(s,"gutterStyle",Ee);G===Y?(c="width",b="clientX",S="left",y="right",d="clientWidth"):G==="vertical"&&(c="height",b="clientY",S="top",y="bottom",d="clientHeight");function R(r,e,n,i){var m=ne(c,e,n,i);Object.keys(m).forEach(function(v){r.style[v]=m[v]})}function ve(r,e,n){var i=de(c,e,n);Object.keys(i).forEach(function(m){r.style[m]=i[m]})}function V(){return l.map(function(r){return r.size})}function re(r){return"touches"in r?r.touches[0][b]:r[b]}function ie(r){var e=l[this.a],n=l[this.b],i=e.size+n.size;e.size=r/this.size*i,n.size=i-r/this.size*i,R(e.element,e.size,this[O],e.i),R(n.element,n.size,this[k],n.i)}function pe(r){var e,n=l[this.a],i=l[this.b];this.dragging&&(e=re(r)-this.start+(this[O]-this.dragOffset),M>1&&(e=Math.round(e/M)*M),e<=n.minSize+n.snapOffset+this[O]?e=n.minSize+this[O]:e>=this.size-(i.minSize+i.snapOffset+this[k])&&(e=this.size-(i.minSize+this[k])),e>=n.maxSize-n.snapOffset+this[O]?e=n.maxSize+this[O]:e<=this.size-(i.maxSize-i.snapOffset+this[k])&&(e=this.size-(i.maxSize+this[k])),ie.call(this,e),z(s,"onDrag",L)(V()))}function se(){var r=l[this.a].element,e=l[this.b].element,n=r[T](),i=e[T]();this.size=n[c]+i[c]+this[O]+this[k],this.start=n[S],this.end=n[y]}function ge(r){if(!getComputedStyle)return null;var e=getComputedStyle(r);if(!e)return null;var n=r[d];return n===0?null:(G===Y?n-=parseFloat(e.paddingLeft)+parseFloat(e.paddingRight):n-=parseFloat(e.paddingTop)+parseFloat(e.paddingBottom),n)}function ae(r){var e=ge(f);if(e===null||B.reduce(function(v,_){return v+_},0)>e)return r;var n=0,i=[],m=r.map(function(v,_){var F=e*v/100,W=J(g,_===0,_===r.length-1,D),X=B[_]+W;return F<X?(n+=X-F,i.push(0),X):(i.push(F-X),F)});return n===0?r:m.map(function(v,_){var F=v;if(n>0&&i[_]-n>0){var W=Math.min(n,i[_]-n);n-=W,F=v-W}return F/e*100})}function me(){var r=this,e=l[r.a].element,n=l[r.b].element;r.dragging&&z(s,"onDragEnd",L)(V()),r.dragging=!1,E[N]("mouseup",r.stop),E[N]("touchend",r.stop),E[N]("touchcancel",r.stop),E[N]("mousemove",r.move),E[N]("touchmove",r.move),r.stop=null,r.move=null,e[N]("selectstart",L),e[N]("dragstart",L),n[N]("selectstart",L),n[N]("dragstart",L),e.style.userSelect="",e.style.webkitUserSelect="",e.style.MozUserSelect="",e.style.pointerEvents="",n.style.userSelect="",n.style.webkitUserSelect="",n.style.MozUserSelect="",n.style.pointerEvents="",r.gutter.style.cursor="",r.parent.style.cursor="",q.body.style.cursor=""}function he(r){if(!("button"in r&&r.button!==0)){var e=this,n=l[e.a].element,i=l[e.b].element;e.dragging||z(s,"onDragStart",L)(V()),r.preventDefault(),e.dragging=!0,e.move=pe.bind(e),e.stop=me.bind(e),E[x]("mouseup",e.stop),E[x]("touchend",e.stop),E[x]("touchcancel",e.stop),E[x]("mousemove",e.move),E[x]("touchmove",e.move),n[x]("selectstart",L),n[x]("dragstart",L),i[x]("selectstart",L),i[x]("dragstart",L),n.style.userSelect="none",n.style.webkitUserSelect="none",n.style.MozUserSelect="none",n.style.pointerEvents="none",i.style.userSelect="none",i.style.webkitUserSelect="none",i.style.MozUserSelect="none",i.style.pointerEvents="none",e.gutter.style.cursor=Q,e.parent.style.cursor=Q,q.body.style.cursor=Q,se.call(e),e.dragOffset=re(r)-e.end}}p=ae(p);var I=[];l=a.map(function(r,e){var n={element:oe(r),size:p[e],minSize:B[e],maxSize:Z[e],snapOffset:A[e],i:e},i;if(e>0&&(i={a:e-1,b:e,dragging:!1,direction:G,parent:f},i[O]=J(g,e-1===0,!1,D),i[k]=J(g,!1,e===a.length-1,D),u==="row-reverse"||u==="column-reverse")){var m=i.a;i.a=i.b,i.b=m}if(e>0){var v=fe(e,G,n.element);ve(v,g,e),i[H]=he.bind(i),v[x]("mousedown",i[H]),v[x]("touchstart",i[H]),f.insertBefore(v,n.element),i.gutter=v}return R(n.element,n.size,J(g,e===0,e===a.length-1,D),e),e>0&&I.push(i),n});function le(r){var e=r.i===I.length,n=e?I[r.i-1]:I[r.i];se.call(n);var i=e?n.size-r.minSize-n[k]:r.minSize+n[O];ie.call(n,i)}l.forEach(function(r){var e=r.element[T]()[c];e<r.minSize&&(o?le(r):r.minSize=e)});function ze(r){var e=ae(r);e.forEach(function(n,i){if(i>0){var m=I[i-1],v=l[m.a],_=l[m.b];v.size=e[i-1],_.size=n,R(v.element,v.size,m[O],v.i),R(_.element,_.size,m[k],_.i)}})}function Se(r,e){I.forEach(function(n){if(e!==!0?n.parent.removeChild(n.gutter):(n.gutter[N]("mousedown",n[H]),n.gutter[N]("touchstart",n[H])),r!==!0){var i=ne(c,n.a.size,n[O]);Object.keys(i).forEach(function(m){l[n.a].element.style[m]="",l[n.b].element.style[m]=""})}})}return{setSizes:ze,getSizes:V,collapse:function(e){le(l[e])},destroy:Se,parent:f,pairs:I}},K=xe;var $=5;function Ne({model:t,el:s}){let a=document.createElement("div");a.className=`split single-split ${t.orientation}`,a.classList.add("loading");let c=document.createElement("div");c.className="split-panel";let b=document.createElement("div");b.className="split-panel",a.append(c,b);let S=document.createElement("div"),y=document.createElement("div");if(S.className=t.collapsed===0?"collapsed-content":"content-wrapper",y.className=t.collapsed===1?"collapsed-content":"content-wrapper",t.objects!=null&&t.objects.length==2){let[o,g]=t.get_child("objects");S.append(o),y.append(g)}c.append(S),b.append(y),t.on("objects",()=>{let[o,g]=t.get_child("objects");S.replaceChildren(o),y.replaceChildren(g)});let d,l,h=0,f=0;function w(){h=f=0}t.show_buttons&&(d=document.createElement("div"),l=document.createElement("div"),t.orientation==="horizontal"?(d.className="toggle-button-left",l.className="toggle-button-right"):(d.className="toggle-button-up",l.className="toggle-button-down"),b.append(d,l),d.addEventListener("click",()=>{h++,f=0;let o;h===1&&t.sizes[1]<t.expanded_sizes[1]?(o=t.expanded_sizes,u=null):(u=0,o=[0,100],h=0),t.collapsed=u,j(o,!0)}),l.addEventListener("click",()=>{f++,h=0;let o;f===1&&t.sizes[0]<t.expanded_sizes[0]?(o=t.expanded_sizes,u=null):(u=1,o=[100,0],f=0),t.collapsed=u,j(o,!0)})),s.append(a);let u=t.collapsed,p=t.sizes,P=u?[100,0]:t.sizes,B=K([c,b],{sizes:P,minSize:t.min_size,maxSize:t.max_size||+"Infinity",dragInterval:t.step_size,snapOffset:t.snap_size,gutterSize:8,gutter:(o,g)=>{let D=document.createElement("div");D.className=`gutter gutter-${g}`;let C=document.createElement("div");return C.className="divider",D.append(C),D},direction:t.orientation,onDrag:o=>{let g=o[0]<=$?0:o[1]<=$?1:null;u!==g&&(u=g,j(o))},onDragEnd:o=>{u=o[0]<=$?0:o[1]<=$?1:null,t.collapsed=u,j(o,!0),w()}});function j(o=null,g=!1){let D=o?o[0]<=$:!1,C=o?o[1]<=$:!1,[A,M]=o;C?(y.className="collapsed-content",[A,M]=[100,0]):y.className="content-wrapper",D?(S.className="collapsed-content",[A,M]=[0,100]):S.className="content-wrapper",g&&(B.setSizes([A,M]),o=[A,M],t.sizes=[A,M],window.dispatchEvent(new Event("resize")))}t.on("sizes",()=>{p!==t.sizes&&(p=t.sizes,j(p,!0))}),t.on("collapsed",()=>{if(u===t.collapsed)return;u=t.collapsed;let o=u===0?[0,100]:u===1?[100,0]:t.expanded_sizes;j(o,!0)});let Z=!1;t.on("after_layout",()=>{Z||(Z=!0,t.show_buttons&&(d.classList.add("animated"),l.classList.add("animated"),setTimeout(()=>{d.classList.remove("animated"),l.classList.remove("animated")},1500)),window.dispatchEvent(new Event("resize")),a.classList.remove("loading"))}),t.on("remove",()=>B.destroy())}var te={};ce(te,{render:()=>Oe});function Oe({model:t,el:s}){let a=document.createElement("div");a.className=`split multi-split ${t.orientation}`,a.classList.add("loading");let c=null;function b(d,l){for(let h=0;h<l.length;h++){let f=l[h],w=d.children[h];w?.id!==f.id&&(w?d.insertBefore(f,w):d.append(f))}for(;d.children.length>l.length;)d.removeChild(d.lastElementChild)}let S=()=>{c!=null&&(c.destroy(),c=null);let d=t.objects?t.get_child("objects"):[],l=[];for(let f=0;f<d.length;f++){let w=d[f],u=`split-panel-${t.objects[f].id}`,p=s.querySelector(`#${u}`);p==null&&(p=document.createElement("div"),p.className="split-panel",p.id=u,p.replaceChildren(w)),l.push(p)}b(a,l);let h=t.sizes;c=K(l,{sizes:h,minSize:t.min_size||0,maxSize:t.max_size||+"Infinity",dragInterval:t.step_size||1,snapOffset:t.snap_size||30,gutterSize:8,gutter:(f,w)=>{let u=document.createElement("div");u.className=`gutter gutter-${w}`;let p=document.createElement("div");return p.className="divider",u.append(p),u},direction:t.orientation,onDragEnd:f=>{h=f,this.model.sizes=h}})};S(),s.append(a),t.on("objects",S),t.on("sizes",()=>{sizes!==t.sizes&&(sizes=t.sizes,c.setSizes(sizes))});let y=!1;t.on("after_layout",()=>{y||(y=!0,a.classList.remove("loading"))}),t.on("remove",()=>c.destroy())}var ke={HSplit:U,MultiSplit:te,Split:U,VSplit:U};export{ke as default};
1
+ var ye=Object.defineProperty;var ce=(e,a)=>{for(var r in a)ye(e,r,{get:a[r],enumerable:!0})};var H={};ce(H,{render:()=>Ne});var E=typeof window<"u"?window:null,ee=E===null,Z=ee?void 0:E.document,O="addEventListener",L="removeEventListener",T="getBoundingClientRect",q="_a",j="_b",A="_c",J="horizontal",D=function(){return!1},_e=ee?"calc":["","-webkit-","-moz-","-o-"].filter(function(e){var a=Z.createElement("div");return a.style.cssText="width:"+e+"calc(9px)",!!a.style.length}).shift()+"calc",ue=function(e){return typeof e=="string"||e instanceof String},oe=function(e){if(ue(e)){var a=Z.querySelector(e);if(!a)throw new Error("Selector "+e+" did not match a DOM element");return a}return e},z=function(e,a,r){var l=e[a];return l!==void 0?l:r},K=function(e,a,r,l){if(a){if(l==="end")return 0;if(l==="center")return e/2}else if(r){if(l==="start")return 0;if(l==="center")return e/2}return e},be=function(e,a){var r=Z.createElement("div");return r.className="gutter gutter-"+a,r},we=function(e,a,r){var l={};return ue(a)?l[e]=a:l[e]=_e+"("+a+"% - "+r+"px)",l},xe=function(e,a){var r;return r={},r[e]=a+"px",r},Ee=function(e,a){if(a===void 0&&(a={}),ee)return{};var r=e,l,b,w,_,f,o;Array.from&&(r=Array.from(r));var v=oe(r[0]),u=v.parentNode,h=getComputedStyle?getComputedStyle(u):null,m=h?h.flexDirection:null,S=z(a,"sizes")||r.map(function(){return 100/r.length}),p=z(a,"minSize",100),M=Array.isArray(p)?p:r.map(function(){return p}),P=z(a,"maxSize",1/0),R=Array.isArray(P)?P:r.map(function(){return P}),k=z(a,"expandToMin",!1),C=z(a,"gutterSize",10),c=z(a,"gutterAlign","center"),y=z(a,"snapOffset",30),U=Array.isArray(y)?y:r.map(function(){return y}),$=z(a,"dragInterval",1),N=z(a,"direction",J),F=z(a,"cursor",N===J?"col-resize":"row-resize"),fe=z(a,"gutter",be),ne=z(a,"elementStyle",we),de=z(a,"gutterStyle",xe);N===J?(l="width",b="clientX",w="left",_="right",f="clientWidth"):N==="vertical"&&(l="height",b="clientY",w="top",_="bottom",f="clientHeight");function W(i,t,n,s){var g=ne(l,t,n,s);Object.keys(g).forEach(function(d){i.style[d]=g[d]})}function ve(i,t,n){var s=de(l,t,n);Object.keys(s).forEach(function(g){i.style[g]=s[g]})}function V(){return o.map(function(i){return i.size})}function ie(i){return"touches"in i?i.touches[0][b]:i[b]}function se(i){var t=o[this.a],n=o[this.b],s=t.size+n.size;t.size=i/this.size*s,n.size=s-i/this.size*s,W(t.element,t.size,this[j],t.i),W(n.element,n.size,this[A],n.i)}function pe(i){var t,n=o[this.a],s=o[this.b];this.dragging&&(t=ie(i)-this.start+(this[j]-this.dragOffset),$>1&&(t=Math.round(t/$)*$),t<=n.minSize+n.snapOffset+this[j]?t=n.minSize+this[j]:t>=this.size-(s.minSize+s.snapOffset+this[A])&&(t=this.size-(s.minSize+this[A])),t>=n.maxSize-n.snapOffset+this[j]?t=n.maxSize+this[j]:t<=this.size-(s.maxSize-s.snapOffset+this[A])&&(t=this.size-(s.maxSize+this[A])),se.call(this,t),z(a,"onDrag",D)(V()))}function re(){var i=o[this.a].element,t=o[this.b].element,n=i[T](),s=t[T]();this.size=n[l]+s[l]+this[j]+this[A],this.start=n[w],this.end=n[_]}function ge(i){if(!getComputedStyle)return null;var t=getComputedStyle(i);if(!t)return null;var n=i[f];return n===0?null:(N===J?n-=parseFloat(t.paddingLeft)+parseFloat(t.paddingRight):n-=parseFloat(t.paddingTop)+parseFloat(t.paddingBottom),n)}function ae(i){var t=ge(u);if(t===null||M.reduce(function(d,x){return d+x},0)>t)return i;var n=0,s=[],g=i.map(function(d,x){var G=t*d/100,X=K(C,x===0,x===i.length-1,c),Y=M[x]+X;return G<Y?(n+=Y-G,s.push(0),Y):(s.push(G-Y),G)});return n===0?i:g.map(function(d,x){var G=d;if(n>0&&s[x]-n>0){var X=Math.min(n,s[x]-n);n-=X,G=d-X}return G/t*100})}function he(){var i=this,t=o[i.a].element,n=o[i.b].element;i.dragging&&z(a,"onDragEnd",D)(V()),i.dragging=!1,E[L]("mouseup",i.stop),E[L]("touchend",i.stop),E[L]("touchcancel",i.stop),E[L]("mousemove",i.move),E[L]("touchmove",i.move),i.stop=null,i.move=null,t[L]("selectstart",D),t[L]("dragstart",D),n[L]("selectstart",D),n[L]("dragstart",D),t.style.userSelect="",t.style.webkitUserSelect="",t.style.MozUserSelect="",t.style.pointerEvents="",n.style.userSelect="",n.style.webkitUserSelect="",n.style.MozUserSelect="",n.style.pointerEvents="",i.gutter.style.cursor="",i.parent.style.cursor="",Z.body.style.cursor=""}function ze(i){if(!("button"in i&&i.button!==0)){var t=this,n=o[t.a].element,s=o[t.b].element;t.dragging||z(a,"onDragStart",D)(V()),i.preventDefault(),t.dragging=!0,t.move=pe.bind(t),t.stop=he.bind(t),E[O]("mouseup",t.stop),E[O]("touchend",t.stop),E[O]("touchcancel",t.stop),E[O]("mousemove",t.move),E[O]("touchmove",t.move),n[O]("selectstart",D),n[O]("dragstart",D),s[O]("selectstart",D),s[O]("dragstart",D),n.style.userSelect="none",n.style.webkitUserSelect="none",n.style.MozUserSelect="none",n.style.pointerEvents="none",s.style.userSelect="none",s.style.webkitUserSelect="none",s.style.MozUserSelect="none",s.style.pointerEvents="none",t.gutter.style.cursor=F,t.parent.style.cursor=F,Z.body.style.cursor=F,re.call(t),t.dragOffset=ie(i)-t.end}}S=ae(S);var B=[];o=r.map(function(i,t){var n={element:oe(i),size:S[t],minSize:M[t],maxSize:R[t],snapOffset:U[t],i:t},s;if(t>0&&(s={a:t-1,b:t,dragging:!1,direction:N,parent:u},s[j]=K(C,t-1===0,!1,c),s[A]=K(C,!1,t===r.length-1,c),m==="row-reverse"||m==="column-reverse")){var g=s.a;s.a=s.b,s.b=g}if(t>0){var d=fe(t,N,n.element);ve(d,C,t),s[q]=ze.bind(s),d[O]("mousedown",s[q]),d[O]("touchstart",s[q]),u.insertBefore(d,n.element),s.gutter=d}return W(n.element,n.size,K(C,t===0,t===r.length-1,c),t),t>0&&B.push(s),n});function le(i){var t=i.i===B.length,n=t?B[i.i-1]:B[i.i];re.call(n);var s=t?n.size-i.minSize-n[A]:i.minSize+n[j];se.call(n,s)}o.forEach(function(i){var t=i.element[T]()[l];t<i.minSize&&(k?le(i):i.minSize=t)});function me(i){var t=ae(i);t.forEach(function(n,s){if(s>0){var g=B[s-1],d=o[g.a],x=o[g.b];d.size=t[s-1],x.size=n,W(d.element,d.size,g[j],d.i),W(x.element,x.size,g[A],x.i)}})}function Se(i,t){B.forEach(function(n){if(t!==!0?n.parent.removeChild(n.gutter):(n.gutter[L]("mousedown",n[q]),n.gutter[L]("touchstart",n[q])),i!==!0){var s=ne(l,n.a.size,n[j]);Object.keys(s).forEach(function(g){o[n.a].element.style[g]="",o[n.b].element.style[g]=""})}})}return{setSizes:me,getSizes:V,collapse:function(t){le(o[t])},destroy:Se,parent:u,pairs:B}},Q=Ee;var I=5;function Ne({model:e,el:a}){let r=document.createElement("div");r.className=`split single-split ${e.orientation} `,r.style.visibility="hidden",r.classList.add("loading"),e.show_buttons&&r.classList.add("expand-buttons");let[l,b]=Array.isArray(e.min_size)?e.min_size:[e.min_size,e.min_size];e.orientation==="horizontal"?r.style.minWidth=`${l+b+e.gutter_size}px`:r.style.minHeight=`${l+b+e.gutter_size}px`;let w=document.createElement("div");w.className="split-panel",l&&(e.orientation==="horizontal"?w.style.minWidth=`${l}px`:w.style.minHeight=`${l}px`);let _=document.createElement("div");_.className="split-panel",b&&(e.orientation==="horizontal"?_.style.minWidth=`${b}px`:_.style.minHeight=`${b}px`),r.append(w,_);let f=document.createElement("div"),o=document.createElement("div");if(f.className=e.collapsed===0?"collapsed-content":"content-wrapper",o.className=e.collapsed===1?"collapsed-content":"content-wrapper",e.objects!=null&&e.objects.length==2){let[c,y]=e.get_child("objects");f.append(c),o.append(y)}w.append(f),_.append(o),e.on("objects",()=>{let[c,y]=e.get_child("objects");f.replaceChildren(c),o.replaceChildren(y)});let v,u,h=0,m=0;function S(){h=m=0}e.show_buttons&&(v=document.createElement("div"),u=document.createElement("div"),e.orientation==="horizontal"?(v.className="toggle-button-left",u.className="toggle-button-right"):(v.className="toggle-button-up",u.className="toggle-button-down"),_.append(v,u),v.addEventListener("click",()=>{h++,m=0;let c;h===1&&e.sizes[1]<e.expanded_sizes[1]?(c=e.expanded_sizes,p=null):(p=0,c=[0,100],h=0),k(c,!0)}),u.addEventListener("click",()=>{m++,h=0;let c;m===1&&e.sizes[0]<e.expanded_sizes[0]?(c=e.expanded_sizes,p=null):(p=1,c=[100,0],m=0),k(c,!0)})),a.append(r);let p=e.collapsed,M=e.sizes,P=p?[100,0]:e.sizes,R=Q([w,_],{sizes:P,minSize:e.min_size,maxSize:e.max_size||+"Infinity",dragInterval:e.step_size,snapOffset:e.snap_size,gutterSize:e.gutter_size,gutter:(c,y)=>{let U=document.createElement("div");U.className=`gutter gutter-${y}`;let $=document.createElement("div");return $.className="divider",U.append($),U},direction:e.orientation,onDrag:c=>{let y=c[0]<=I?0:c[1]<=I?1:null;p!==y&&(p=y,k(c))},onDragEnd:c=>{p=c[0]<=I?0:c[1]<=I?1:null,e.collapsed=p,k(c,!0),S()}});function k(c=null,y=!1){let U=c?c[0]<=I&&l<I:!1,$=c?c[1]<=I&&b<I:!1,[N,F]=c;$?(o.className="collapsed-content",[N,F]=[100,0]):o.className="content-wrapper",U?(f.className="collapsed-content",[N,F]=[0,100]):f.className="content-wrapper",y&&(R.setSizes([N,F]),c=[N,F],window.dispatchEvent(new Event("resize")),requestAnimationFrame(()=>{e.sizes=R.getSizes()}))}e.on("sizes",()=>{M!==e.sizes&&(M=e.sizes,e.collapsed=1-M[0]>=0?0:1-M[1]>=0?1:null,k(M,!0))}),e.on("collapsed",()=>{if(p===e.collapsed)return;p=e.collapsed;let c=p===0?[0,100]:p===1?[100,0]:e.expanded_sizes;k(c,!0)});let C=!1;e.on("after_layout",()=>{C||(C=!0,e.show_buttons&&(v.classList.add("animated"),u.classList.add("animated"),setTimeout(()=>{v.classList.remove("animated"),u.classList.remove("animated")},1500)),window.dispatchEvent(new Event("resize")),r.style.visibility="",r.classList.remove("loading"))}),e.on("remove",()=>R.destroy())}var te={};ce(te,{render:()=>Oe});function Oe({model:e,el:a}){let r=document.createElement("div");r.className=`split multi-split ${e.orientation}`,r.style.visibility="hidden",r.classList.add("loading");let l=null;function b(f,o){for(let v=0;v<o.length;v++){let u=o[v],h=f.children[v];h?.id!==u.id&&(h?f.insertBefore(u,h):f.append(u))}for(;f.children.length>o.length;)f.removeChild(f.lastElementChild)}let w=()=>{l!=null&&(l.destroy(),l=null);let f=e.objects?e.get_child("objects"):[],o=[];for(let u=0;u<f.length;u++){let h=f[u],m=`split-panel-${e.objects[u].id}`,S=a.querySelector(`#${m}`);S==null&&(S=document.createElement("div"),S.className="split-panel",S.id=m,S.replaceChildren(h)),o.push(S)}b(r,o);let v=e.sizes;l=Q(o,{sizes:v,minSize:e.min_size||0,maxSize:e.max_size||+"Infinity",dragInterval:e.step_size||1,snapOffset:e.snap_size||30,gutterSize:e.gutter_size,gutter:(u,h)=>{let m=document.createElement("div");m.className=`gutter gutter-${h}`;let S=document.createElement("div");return S.className="divider",m.append(S),m},direction:e.orientation,onDragEnd:u=>{v=u,this.model.sizes=v}})};w(),a.append(r),e.on("objects",w),e.on("sizes",()=>{sizes!==e.sizes&&(sizes=e.sizes,l.setSizes(sizes))});let _=!1;e.on("after_layout",()=>{_||(_=!0,r.style.visibility="",r.classList.remove("loading"))}),e.on("remove",()=>l.destroy())}var Ae={HSplit:H,MultiSplit:te,Split:H,VSplit:H};export{Ae as default};
@@ -3,6 +3,7 @@ import Split from "https://esm.sh/split.js@1.6.5"
3
3
  export function render({ model, el }) {
4
4
  const split_div = document.createElement("div")
5
5
  split_div.className = `split multi-split ${model.orientation}`
6
+ split_div.style.visibility = "hidden"
6
7
  split_div.classList.add("loading")
7
8
 
8
9
  let split = null
@@ -61,7 +62,7 @@ export function render({ model, el }) {
61
62
  maxSize: model.max_size || Number("Infinity"),
62
63
  dragInterval: model.step_size || 1,
63
64
  snapOffset: model.snap_size || 30,
64
- gutterSize: 8,
65
+ gutterSize: model.gutter_size,
65
66
  gutter: (index, direction) => {
66
67
  const gutter = document.createElement('div')
67
68
  gutter.className = `gutter gutter-${direction}`
@@ -94,6 +95,7 @@ export function render({ model, el }) {
94
95
  model.on("after_layout", () => {
95
96
  if (!initialized) {
96
97
  initialized = true
98
+ split_div.style.visibility = ""
97
99
  split_div.classList.remove("loading")
98
100
  }
99
101
  })
@@ -4,13 +4,39 @@ const COLLAPSED_SIZE = 5
4
4
 
5
5
  export function render({ model, el }) {
6
6
  const split_div = document.createElement("div")
7
- split_div.className = `split single-split ${model.orientation}`
7
+ split_div.className = `split single-split ${model.orientation} `
8
+ split_div.style.visibility = "hidden"
8
9
  split_div.classList.add("loading")
10
+ if (model.show_buttons) {
11
+ split_div.classList.add("expand-buttons")
12
+ }
13
+
14
+ const [left_min, right_min] = Array.isArray(model.min_size) ? model.min_size : [model.min_size, model.min_size]
15
+
16
+ if (model.orientation === "horizontal") {
17
+ split_div.style.minWidth = `${left_min + right_min + model.gutter_size}px`
18
+ } else {
19
+ split_div.style.minHeight = `${left_min + right_min + model.gutter_size}px`
20
+ }
9
21
 
10
22
  const split0 = document.createElement("div")
11
23
  split0.className = "split-panel"
24
+ if (left_min) {
25
+ if (model.orientation === "horizontal") {
26
+ split0.style.minWidth = `${left_min}px`
27
+ } else {
28
+ split0.style.minHeight = `${left_min}px`
29
+ }
30
+ }
12
31
  const split1 = document.createElement("div")
13
32
  split1.className = "split-panel"
33
+ if (right_min) {
34
+ if (model.orientation === "horizontal") {
35
+ split1.style.minWidth = `${right_min}px`
36
+ } else {
37
+ split1.style.minHeight = `${right_min}px`
38
+ }
39
+ }
14
40
  split_div.append(split0, split1)
15
41
 
16
42
  const left_content_wrapper = document.createElement("div")
@@ -63,7 +89,6 @@ export function render({ model, el }) {
63
89
  new_sizes = [0, 100]
64
90
  left_click_count = 0
65
91
  }
66
- model.collapsed = is_collapsed
67
92
  sync_ui(new_sizes, true)
68
93
  })
69
94
 
@@ -80,7 +105,6 @@ export function render({ model, el }) {
80
105
  new_sizes = [100, 0]
81
106
  right_click_count = 0
82
107
  }
83
- model.collapsed = is_collapsed
84
108
  sync_ui(new_sizes, true)
85
109
  })
86
110
  }
@@ -96,7 +120,7 @@ export function render({ model, el }) {
96
120
  maxSize: model.max_size || Number("Infinity"),
97
121
  dragInterval: model.step_size,
98
122
  snapOffset: model.snap_size,
99
- gutterSize: 8,
123
+ gutterSize: model.gutter_size,
100
124
  gutter: (index, direction) => {
101
125
  const gutter = document.createElement('div')
102
126
  gutter.className = `gutter gutter-${direction}`
@@ -123,8 +147,8 @@ export function render({ model, el }) {
123
147
  })
124
148
 
125
149
  function sync_ui(sizes = null, resize = false) {
126
- const left_panel_hidden = sizes ? sizes[0] <= COLLAPSED_SIZE : false
127
- const right_panel_hidden = sizes ? sizes[1] <= COLLAPSED_SIZE : false
150
+ const left_panel_hidden = sizes ? ((sizes[0] <= COLLAPSED_SIZE) && (left_min < COLLAPSED_SIZE)) : false
151
+ const right_panel_hidden = sizes ? ((sizes[1] <= COLLAPSED_SIZE) && (right_min < COLLAPSED_SIZE)) : false
128
152
 
129
153
  let [ls, rs] = sizes
130
154
  if (right_panel_hidden) {
@@ -143,8 +167,8 @@ export function render({ model, el }) {
143
167
  if (resize) {
144
168
  split_instance.setSizes([ls, rs])
145
169
  sizes = [ls, rs]
146
- model.sizes = [ls, rs]
147
170
  window.dispatchEvent(new Event('resize'))
171
+ requestAnimationFrame(() => { model.sizes = split_instance.getSizes() })
148
172
  }
149
173
  }
150
174
 
@@ -153,6 +177,7 @@ export function render({ model, el }) {
153
177
  return
154
178
  }
155
179
  sizes = model.sizes
180
+ model.collapsed = (1-sizes[0]) >= 0 ? 0 : (1-sizes[1]) >= 0 ? 1 : null
156
181
  sync_ui(sizes, true)
157
182
  })
158
183
 
@@ -183,6 +208,7 @@ export function render({ model, el }) {
183
208
  }, 1500)
184
209
  }
185
210
  window.dispatchEvent(new Event('resize'))
211
+ split_div.style.visibility = ""
186
212
  split_div.classList.remove("loading")
187
213
  })
188
214
 
@@ -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.
@@ -0,0 +1,18 @@
1
+ panel_splitjs/__init__.py,sha256=BKEeHeKAv90kV3GybL6FH8RCwFZM4B6gffr7T8242Qk,150
2
+ panel_splitjs/__version.py,sha256=rpIYpR7RLjD5NBNasrT3f60C0qTL-nnHBifOofA_qyo,1778
3
+ panel_splitjs/_version.py,sha256=5zTqm8rgXsWYBpB2M3Zw_K1D-aV8wP7NsBLrmMKkrAQ,704
4
+ panel_splitjs/base.py,sha256=QglUWw4lvtPr0UseVeI0JDYVO_bsPB6CN2Wyv3Katps,6480
5
+ panel_splitjs/dist/panel-splitjs.bundle.js,sha256=ROM8240wfpavN1bJxKolvZ2j1ohpbbJruZq89t0qzZo,10759
6
+ panel_splitjs/dist/css/arrow_down.svg,sha256=pPSAQIH-UkJf1HbWJhAapaT-rROqn6JVPQldOT3Al0I,214
7
+ panel_splitjs/dist/css/arrow_left.svg,sha256=XZ1Qf7CzKTij-Fa4Up51Gbu_WnBcScK7Qx-tOprvEzE,215
8
+ panel_splitjs/dist/css/arrow_right.svg,sha256=_-3m5dLhPwH9caIEk8XLp3Z8-xQHHvTBny6AcyFVRb4,214
9
+ panel_splitjs/dist/css/arrow_up.svg,sha256=FoVQYz0kh1SAf7EJAs2ZI-ZuuQjcPzR3uM4uViZ87Qs,215
10
+ panel_splitjs/dist/css/handle.svg,sha256=tEQAE3lNBVzPigcp9Z0SQZCW0bSzfECYIvpl19NOd0E,899
11
+ panel_splitjs/dist/css/handle_vertical.svg,sha256=2QZdZzNiLaJp93Ot4tJBhfGjF07EiMfN-Hq3Uf5Z_BI,801
12
+ panel_splitjs/dist/css/splitjs.css,sha256=cWv_xwUFFl0rMaQh4CUhBKfOoS0mWu7qhlV439paruA,5555
13
+ panel_splitjs/models/multi_split.js,sha256=8Q5CpkoF4Lt14HZeJyvMjMAnPOOiG64m6RuEILG0nPc,2880
14
+ panel_splitjs/models/split.js,sha256=vruTcf632VbsVLma-oRlzpXVOMt97z02xyhSMwCz68U,6937
15
+ panel_splitjs-0.3.0.dist-info/METADATA,sha256=xCZKv7h977YdiWc68DelFUH62E_J9LaLTWrkffrLZME,13068
16
+ panel_splitjs-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
+ panel_splitjs-0.3.0.dist-info/licenses/LICENSE.txt,sha256=q8G87qfLzElD9n5Nxl1sOuzafC0z7H_nPgUcGWKzCTw,1515
18
+ panel_splitjs-0.3.0.dist-info/RECORD,,
@@ -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,17 +0,0 @@
1
- panel_splitjs/__init__.py,sha256=BKEeHeKAv90kV3GybL6FH8RCwFZM4B6gffr7T8242Qk,150
2
- panel_splitjs/__version.py,sha256=rpIYpR7RLjD5NBNasrT3f60C0qTL-nnHBifOofA_qyo,1778
3
- panel_splitjs/_version.py,sha256=Dg8AmJomLVpjKL6prJylOONZAPRtB86LOce7dorQS_A,704
4
- panel_splitjs/base.py,sha256=4KXVGom_-ZAOsIXAStcwN0ckyU6wuphCMLV4hadSS-M,6024
5
- panel_splitjs/dist/panel-splitjs.bundle.js,sha256=wi-s9nn8rpnVVlzopD6WWvEvPN3tqxdnfYzkuOGhLf0,10167
6
- panel_splitjs/dist/css/arrow_down.svg,sha256=pPSAQIH-UkJf1HbWJhAapaT-rROqn6JVPQldOT3Al0I,214
7
- panel_splitjs/dist/css/arrow_left.svg,sha256=XZ1Qf7CzKTij-Fa4Up51Gbu_WnBcScK7Qx-tOprvEzE,215
8
- panel_splitjs/dist/css/arrow_right.svg,sha256=_-3m5dLhPwH9caIEk8XLp3Z8-xQHHvTBny6AcyFVRb4,214
9
- panel_splitjs/dist/css/arrow_up.svg,sha256=FoVQYz0kh1SAf7EJAs2ZI-ZuuQjcPzR3uM4uViZ87Qs,215
10
- panel_splitjs/dist/css/handle.svg,sha256=tEQAE3lNBVzPigcp9Z0SQZCW0bSzfECYIvpl19NOd0E,899
11
- panel_splitjs/dist/css/handle_vertical.svg,sha256=2QZdZzNiLaJp93Ot4tJBhfGjF07EiMfN-Hq3Uf5Z_BI,801
12
- panel_splitjs/dist/css/splitjs.css,sha256=6Foh_0tA2IhjMzgRAQzKBbzXo_FRx2N8znDSwhpF8_k,6001
13
- panel_splitjs/models/multi_split.js,sha256=fWDy7SIAk1BZaFGxTIjQRdb98EnwVWVQsOUFmyukUKA,2786
14
- panel_splitjs/models/split.js,sha256=-vHOddI0fY4FWrlJ3QLtwrrfvOGHmek3vZYHYVbznIY,5940
15
- panel_splitjs-0.2.0.dist-info/METADATA,sha256=9kp_cUB98iaPyD8gN-r3Un-vh1Bx_68LotqWuOIaOWk,10877
16
- panel_splitjs-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
- panel_splitjs-0.2.0.dist-info/RECORD,,