panel-splitjs 0.2.1__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.1'
32
- __version_tuple__ = version_tuple = (0, 2, 1)
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
@@ -33,12 +33,15 @@ class Size(param.Parameter):
33
33
  return
34
34
  if self.length is not None and isinstance(val, tuple) and len(val) != self.length:
35
35
  raise ValueError(f"Size parameter {self.name!r} must have length {self.length}")
36
- 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))):
37
37
  raise ValueError(f"Size parameter {self.name!r} only takes int or float values")
38
38
 
39
39
 
40
40
  class SplitBase(JSComponent, ListLike):
41
41
 
42
+ gutter_size = param.Integer(default=8, doc="""
43
+ Width of the gutter element.""")
44
+
42
45
  max_size = Size(default=None, doc="""
43
46
  The maximum sizes of the panels (in pixels) either as a single value or a tuple.""")
44
47
 
@@ -109,7 +112,7 @@ class Split(SplitBase):
109
112
  The component to place in the left panel.
110
113
  When invert=True, this will appear on the right side.""")
111
114
 
112
- show_buttons = param.Boolean(default=True, doc="""
115
+ show_buttons = param.Boolean(default=False, doc="""
113
116
  Whether to show the toggle buttons on the divider.
114
117
  When False, the buttons are hidden and panels can only be resized by dragging.""")
115
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panel-splitjs
3
- Version: 0.2.1
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
@@ -81,16 +81,18 @@ pn.extension()
81
81
 
82
82
  # Create a simple split layout
83
83
  split = Split(
84
- pn.pane.Markdown("## Left Panel\nContent here"),
85
- 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),
86
86
  sizes=(50, 50), # Equal sizing initially
87
- min_size=100, # Minimum 100px for each panel
88
- show_buttons=True
87
+ min_size=150, # Minimum 150px for each panel
88
+ sizing_mode="stretch_both",
89
89
  )
90
90
 
91
91
  split.servable()
92
92
  ```
93
93
 
94
+ ![Quick Start Example](docs/assets/images/quick-start.gif)
95
+
94
96
  ## Usage Examples
95
97
 
96
98
  ### Basic Horizontal Split
@@ -99,30 +101,35 @@ split.servable()
99
101
  import panel as pn
100
102
  from panel_splitjs import HSplit
101
103
 
102
- pn.extension()
104
+ pn.extension(sizing_mode="stretch_width")
103
105
 
104
106
  left_panel = pn.Column(
105
107
  "# Main Content",
106
108
  pn.widgets.TextInput(name="Input"),
107
- 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
108
111
  )
109
112
 
110
113
  right_panel = pn.Column(
111
114
  "# Sidebar",
112
115
  pn.widgets.Select(name="Options", options=["A", "B", "C"]),
116
+ margin=25, # To separate toggle button and column
113
117
  )
114
118
 
115
119
  split = HSplit(
116
120
  left_panel,
117
121
  right_panel,
118
122
  sizes=(70, 30), # 70% left, 30% right
119
- min_size=200, # Minimum 200px for each panel
120
- show_buttons=True
123
+ min_size=300, # Minimum 300px for each panel
124
+ sizing_mode="stretch_width",
125
+ height=250,
121
126
  )
122
127
 
123
128
  split.servable()
124
129
  ```
125
130
 
131
+ ![Basic Horizontal Split Example](docs/assets/images/basic-horizontal-split.png)
132
+
126
133
  ### Vertical Split
127
134
 
128
135
  ```python
@@ -137,13 +144,40 @@ bottom_panel = pn.pane.Markdown("## Bottom Section\nFooter content")
137
144
  split = VSplit(
138
145
  top_panel,
139
146
  bottom_panel,
140
- sizes=(60, 40),
141
- 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",
142
174
  )
143
175
 
144
176
  split.servable()
145
177
  ```
146
178
 
179
+ ![Show Buttons Example](docs/assets/images/show-buttons.png)
180
+
147
181
  ### Collapsible Sidebar
148
182
 
149
183
  ```python
@@ -153,24 +187,27 @@ from panel_splitjs import Split
153
187
  pn.extension()
154
188
 
155
189
  # Start with right panel collapsed
190
+ button = pn.widgets.Button(name="Toggle Sidebar")
191
+
156
192
  split = Split(
157
- pn.pane.Markdown("## Main Content"),
158
- 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)),
159
195
  collapsed=1, # 0 for first panel, 1 for second panel, None for not collapsed
160
- expanded_sizes=(65, 35), # When expanded, 65% main, 35% sidebar
161
- show_buttons=True,
162
- 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",
163
198
  )
164
199
 
165
200
  # Toggle collapse programmatically
166
- button = pn.widgets.Button(name="Toggle Sidebar")
201
+
167
202
  def toggle(event):
168
203
  split.collapsed = None if split.collapsed == 1 else 1
169
204
  button.on_click(toggle)
170
205
 
171
- pn.Column(button, split).servable()
206
+ split.servable()
172
207
  ```
173
208
 
209
+ ![Collapsible Sidebar Example](docs/assets/images/collapsable-sidebar.gif)
210
+
174
211
  ### Multi-Panel Split
175
212
 
176
213
  ```python
@@ -186,12 +223,15 @@ multi = MultiSplit(
186
223
  pn.pane.Markdown("## Panel 3"),
187
224
  sizes=(30, 40, 30), # Three panels with custom sizing
188
225
  min_size=100, # Minimum 100px for each panel
189
- orientation="horizontal"
226
+ orientation="horizontal",
227
+ sizing_mode="stretch_both",
190
228
  )
191
229
 
192
230
  multi.servable()
193
231
  ```
194
232
 
233
+ ![MultiSplit Example](docs/assets/images/multisplit.png)
234
+
195
235
  ## API Reference
196
236
 
197
237
  ### Split
@@ -206,7 +246,7 @@ The main split panel component for creating two-panel layouts with collapsible f
206
246
  - `max_size` (int | tuple, default=None): Maximum sizes in pixels - single value applies to both panels, tuple for individual sizes
207
247
  - `min_size` (int | tuple, default=0): Minimum sizes in pixels - single value applies to both panels, tuple for individual sizes
208
248
  - `orientation` (str, default="horizontal"): Either `"horizontal"` or `"vertical"`
209
- - `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
210
250
  - `sizes` (tuple, default=(50, 50)): Initial percentage sizes of the panels
211
251
  - `snap_size` (int, default=30): Snap to minimum size at this offset in pixels
212
252
  - `step_size` (int, default=1): Step size in pixels at which panel sizes can be changed
@@ -247,21 +287,24 @@ from panel_splitjs import Split
247
287
 
248
288
  pn.extension()
249
289
 
250
- chat = pn.chat.ChatInterface()
251
- 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")
252
293
 
253
294
  split = Split(
254
295
  chat,
255
296
  output,
256
297
  collapsed=None, # Both panels visible
257
298
  expanded_sizes=(50, 50),
258
- show_buttons=True,
259
- 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",
260
301
  )
261
302
 
262
303
  split.servable()
263
304
  ```
264
305
 
306
+ ![Chat Example](docs/assets/images/chat-example.png)
307
+
265
308
  ### Dashboard with Collapsible Controls
266
309
 
267
310
  ```python
@@ -270,26 +313,30 @@ from panel_splitjs import Split
270
313
 
271
314
  pn.extension()
272
315
 
273
- controls = pn.Column(
274
- pn.widgets.Select(name="Dataset", options=["A", "B", "C"]),
275
- pn.widgets.IntSlider(name="Threshold", start=0, end=100),
276
- pn.widgets.Button(name="Update")
277
- )
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
+ )
278
323
 
279
- visualization = pn.pane.Markdown("## Main Visualization Area")
324
+ visualization = pn.pane.Markdown("## Main Visualization Area")
280
325
 
281
326
  split = Split(
282
327
  controls,
283
328
  visualization,
284
- collapsed=0, # Start with controls collapsed
285
- expanded_sizes=(25, 75),
329
+ sizes=(20, 80),
330
+ min_size=(300, 0),
286
331
  show_buttons=True,
287
- min_size=(250, 400) # Minimum sizes for each panel
332
+ sizing_mode="stretch_both",
288
333
  )
289
334
 
290
335
  split.servable()
291
336
  ```
292
337
 
338
+ ![Dashboard with Collapsible Controls](docs/assets/images/dashboard-with-collapsable-controls.png)
339
+
293
340
  ### Responsive Layout with Size Constraints
294
341
 
295
342
  ```python
@@ -299,18 +346,21 @@ from panel_splitjs import Split
299
346
  pn.extension()
300
347
 
301
348
  split = Split(
302
- pn.pane.Markdown("## Panel 1\nResponsive content"),
303
- 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)),
304
351
  sizes=(50, 50),
305
352
  min_size=200, # Minimum 200px per panel
306
353
  max_size=800, # Maximum 800px per panel
307
354
  snap_size=50, # Snap to min size when within 50px
308
- show_buttons=True
355
+ show_buttons=True,
356
+ sizing_mode="stretch_both",
309
357
  )
310
358
 
311
359
  split.servable()
312
360
  ```
313
361
 
362
+ ![Responsive Layout with Size Constraints](docs/assets/images/responsive-layout-with-size-constraints.png)
363
+
314
364
  ### Complex Multi-Panel Layout
315
365
 
316
366
  ```python
@@ -320,10 +370,11 @@ from panel_splitjs import MultiSplit
320
370
  pn.extension()
321
371
 
322
372
  # Create a four-panel layout
323
- sidebar = pn.Column("## Sidebar", pn.widgets.Select(options=["A", "B", "C"]))
324
- main = pn.pane.Markdown("## Main Content Area")
325
- detail = pn.pane.Markdown("## Detail Panel")
326
- 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")
327
378
 
328
379
  multi = MultiSplit(
329
380
  sidebar,
@@ -332,12 +383,15 @@ multi = MultiSplit(
332
383
  console,
333
384
  sizes=(15, 40, 25, 20), # Custom sizing for each panel
334
385
  min_size=(150, 300, 200, 150), # Individual minimums
335
- orientation="horizontal"
386
+ orientation="horizontal",
387
+ sizing_mode="stretch_both",
336
388
  )
337
389
 
338
390
  multi.servable()
339
391
  ```
340
392
 
393
+ ![Complex Multi-Panel Layout](docs/assets/images/complex-multi-panel-layout.png)
394
+
341
395
  ### Nested Splits
342
396
 
343
397
  ```python
@@ -350,21 +404,25 @@ pn.extension()
350
404
  left = pn.pane.Markdown("## Left Panel")
351
405
 
352
406
  # Right side has a vertical split
353
- top_right = pn.pane.Markdown("## Top Right")
354
- bottom_right = pn.pane.Markdown("## Bottom Right")
355
- right = VSplit(top_right, bottom_right, sizes=(60, 40))
356
-
357
- # Main horizontal split
358
- layout = HSplit(
359
- left,
360
- right,
361
- sizes=(30, 70),
362
- min_size=200
363
- )
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
+ )
364
420
 
365
421
  layout.servable()
366
422
  ```
367
423
 
424
+ ![Nested Splits](docs/assets/images/nested-splits.png)
425
+
368
426
  ## Development
369
427
 
370
428
  This project is managed by [pixi](https://pixi.sh).
@@ -392,6 +450,15 @@ pixi run build
392
450
  pixi run test
393
451
  ```
394
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
+
395
462
  ## Contributing
396
463
 
397
464
  Contributions are welcome! Please feel free to submit a Pull Request.
@@ -1,18 +1,18 @@
1
1
  panel_splitjs/__init__.py,sha256=BKEeHeKAv90kV3GybL6FH8RCwFZM4B6gffr7T8242Qk,150
2
2
  panel_splitjs/__version.py,sha256=rpIYpR7RLjD5NBNasrT3f60C0qTL-nnHBifOofA_qyo,1778
3
- panel_splitjs/_version.py,sha256=vYqoJTG51NOUmYyL0xt8asRK8vUT4lGAdal_EZ59mvw,704
4
- panel_splitjs/base.py,sha256=sN7X38U6eWl_r1wX0w_BN7g1zU62nXXbUsY9wN40yK4,6373
5
- panel_splitjs/dist/panel-splitjs.bundle.js,sha256=wi-s9nn8rpnVVlzopD6WWvEvPN3tqxdnfYzkuOGhLf0,10167
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
6
  panel_splitjs/dist/css/arrow_down.svg,sha256=pPSAQIH-UkJf1HbWJhAapaT-rROqn6JVPQldOT3Al0I,214
7
7
  panel_splitjs/dist/css/arrow_left.svg,sha256=XZ1Qf7CzKTij-Fa4Up51Gbu_WnBcScK7Qx-tOprvEzE,215
8
8
  panel_splitjs/dist/css/arrow_right.svg,sha256=_-3m5dLhPwH9caIEk8XLp3Z8-xQHHvTBny6AcyFVRb4,214
9
9
  panel_splitjs/dist/css/arrow_up.svg,sha256=FoVQYz0kh1SAf7EJAs2ZI-ZuuQjcPzR3uM4uViZ87Qs,215
10
10
  panel_splitjs/dist/css/handle.svg,sha256=tEQAE3lNBVzPigcp9Z0SQZCW0bSzfECYIvpl19NOd0E,899
11
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.1.dist-info/METADATA,sha256=bcWnzoBlyEPgAw4TItibAhnu13tWEiCcw8CzTBNTPb0,10903
16
- panel_splitjs-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
- panel_splitjs-0.2.1.dist-info/licenses/LICENSE.txt,sha256=q8G87qfLzElD9n5Nxl1sOuzafC0z7H_nPgUcGWKzCTw,1515
18
- panel_splitjs-0.2.1.dist-info/RECORD,,
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,,