kempo-ui 0.0.73 → 0.0.74
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.
- package/dist/components/Split.js +42 -12
- package/docs/components/split.html +37 -16
- package/docs/src/components/Split.js +42 -12
- package/package.json +1 -1
- package/src/components/Split.js +54 -21
- package/tests/components/Split.browser-test.js +119 -35
package/dist/components/Split.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import drag from"../utils/drag.js";export default class Split extends ShadowComponent{static properties={resizing:{type:Boolean,reflect:!0},stacked:{type:Boolean,reflect:!0},stackWidth:{type:Number,attribute:"stack-width"}};constructor(){super(),this.resizing=!1,this.stacked=!1,this.stackWidth=0,this.
|
|
1
|
+
import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import drag from"../utils/drag.js";export default class Split extends ShadowComponent{static properties={resizing:{type:Boolean,reflect:!0},stacked:{type:Boolean,reflect:!0},stackWidth:{type:Number,attribute:"stack-width"},direction:{type:String,reflect:!0}};constructor(){super(),this.resizing=!1,this.stacked=!1,this.stackWidth=0,this.direction="horizontal",this.dragStartSize=0,this.dragCleanup=()=>{},this.resizeObserver=null}firstUpdated(){super.firstUpdated(),this.setupDragHandler(),this.setupResizeObserver()}disconnectedCallback(){super.disconnectedCallback(),this.dragCleanup(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null)}handleDragStart=()=>{this.resizing=!0,this.dragStartSize=Math.round(this.shadowRoot.getElementById("pane-1").getBoundingClientRect()["vertical"===this.direction?"height":"width"]),this.dispatchEvent(new CustomEvent("resizestart",{detail:{startSize:this.dragStartSize},bubbles:!0}))};handleDrag=({x:e,y:t})=>{const i="vertical"===this.direction?t:e,s=`${this.dragStartSize+i}px`;this.setSize(s),this.dispatchEvent(new CustomEvent("resize",{detail:{size:s},bubbles:!0}))};handleDragEnd=({x:e,y:t})=>{this.resizing=!1;const i="vertical"===this.direction?t:e,s=`${this.dragStartSize+i}px`;this.setSize(s),this.dispatchEvent(new CustomEvent("resizeend",{detail:{size:s},bubbles:!0}))};setSize(e){this.style.setProperty("--pane_1_size",e)}setupDragHandler(){const e=this.shadowRoot.getElementById("divider-handle");e&&(this.dragCleanup=drag({element:e,callback:this.handleDrag,startCallback:this.handleDragStart,endCallback:this.handleDragEnd}))}setupResizeObserver(){this.resizeObserver=new ResizeObserver(e=>{for(const t of e){const e=t.contentRect.width;this.stacked=e<=this.stackWidth}}),this.resizeObserver.observe(this)}static styles=css`
|
|
2
2
|
:host {
|
|
3
|
-
--
|
|
3
|
+
--pane_1_size: calc((100% - var(--handle_width)) / 2);
|
|
4
4
|
--handle_width: 0.5rem;
|
|
5
|
-
--
|
|
5
|
+
--min_pane_size: 6rem;
|
|
6
6
|
|
|
7
7
|
height: 100%;
|
|
8
8
|
display: flex;
|
|
@@ -16,14 +16,14 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.pane {
|
|
19
|
-
min-width: var(--
|
|
20
|
-
max-width: calc(100% - var(--
|
|
19
|
+
min-width: var(--min_pane_size);
|
|
20
|
+
max-width: calc(100% - var(--min_pane_size));
|
|
21
21
|
max-height: 100%;
|
|
22
22
|
overflow: hidden;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
flex: 0 0 var(--
|
|
25
|
+
#pane-1 {
|
|
26
|
+
flex: 0 0 var(--pane_1_size);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
#divider-handle {
|
|
@@ -48,12 +48,12 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
|
|
|
48
48
|
border-left: 1px solid var(--c_border);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
#
|
|
51
|
+
#pane-2 {
|
|
52
52
|
flex: 1 1;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
:host([stacked]) #
|
|
56
|
-
:host([stacked]) #
|
|
55
|
+
:host([stacked]) #pane-1,
|
|
56
|
+
:host([stacked]) #pane-2 {
|
|
57
57
|
display: block;
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -71,14 +71,44 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
|
|
|
71
71
|
:host([stacked]) {
|
|
72
72
|
display: block;
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
:host([direction="vertical"]) {
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
:host([direction="vertical"]) .pane {
|
|
80
|
+
min-width: 0;
|
|
81
|
+
max-width: 100%;
|
|
82
|
+
min-height: var(--min_pane_size);
|
|
83
|
+
max-height: calc(100% - var(--min_pane_size));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:host([direction="vertical"]) #pane-1 {
|
|
87
|
+
flex: 0 0 var(--pane_1_size);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
:host([direction="vertical"]) #divider-handle {
|
|
91
|
+
width: 100%;
|
|
92
|
+
height: var(--handle_width);
|
|
93
|
+
cursor: ns-resize;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: initial;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
:host([direction="vertical"]) #divider-border {
|
|
99
|
+
width: 100%;
|
|
100
|
+
height: 1px;
|
|
101
|
+
border-left: none;
|
|
102
|
+
border-top: 1px solid var(--c_border);
|
|
103
|
+
}
|
|
74
104
|
`;render(){return html`
|
|
75
|
-
<div id="
|
|
105
|
+
<div id="pane-1" class="pane">
|
|
76
106
|
<slot></slot>
|
|
77
107
|
</div>
|
|
78
108
|
<div id="divider-handle">
|
|
79
109
|
<div id="divider-border"></div>
|
|
80
110
|
</div>
|
|
81
|
-
<div id="
|
|
111
|
+
<div id="pane-2" class="pane">
|
|
82
112
|
<slot name="right"></slot>
|
|
83
113
|
</div>
|
|
84
114
|
`}}customElements.define("k-split",Split);
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
<h6>Examples</h6>
|
|
24
24
|
<a href="#basicUsage">Basic Usage</a><br />
|
|
25
25
|
<a href="#resizing">Resizing</a><br />
|
|
26
|
+
<a href="#verticalSplit">Vertical Split</a><br />
|
|
26
27
|
|
|
27
28
|
<h6 class="mt"><a href="#jsRef" class="no-link">JavaScript Reference</a></h6>
|
|
28
29
|
<a href="#constructor">Constructor</a><br />
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
</k-accordion>
|
|
37
38
|
|
|
38
39
|
<h3 id="basicUsage"><a href="#basicUsage" class="no-link">Basic Usage</a></h3>
|
|
39
|
-
<p>Create a split view using the <code>k-split</code> component. Add content to the
|
|
40
|
+
<p>Create a split view using the <code>k-split</code> component. Add content to the first pane by placing it inside the component, and add content to the second pane by using the <code>slot="right"</code> attribute.</p>
|
|
40
41
|
<div class="row -mx mb">
|
|
41
42
|
<div class="col d-span-6 m-span-12 px">
|
|
42
43
|
<k-card label="HTML">
|
|
@@ -54,16 +55,16 @@
|
|
|
54
55
|
</div>
|
|
55
56
|
|
|
56
57
|
<h3 id="resizing"><a href="#resizing" class="no-link">Resizing</a></h3>
|
|
57
|
-
<p>The split view can be resized by dragging the divider handle. The initial
|
|
58
|
+
<p>The split view can be resized by dragging the divider handle. The initial size of the first pane can be set using the <code>--pane_1_size</code> CSS custom property.</p>
|
|
58
59
|
<div class="row -mx mb">
|
|
59
60
|
<div class="col d-span-6 m-span-12 px">
|
|
60
61
|
<k-card label="HTML">
|
|
61
|
-
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-split</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"--
|
|
62
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-split</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"--pane_1_size: 30%; height: 10rem"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"b"</span>></span><br /> <span class="hljs-tag"><<span class="hljs-name">div</span>></span>Left Pane Content<span class="hljs-tag"></<span class="hljs-name">div</span>></span><br /> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"right"</span>></span>Right Pane Content<span class="hljs-tag"></<span class="hljs-name">div</span>></span><br /><span class="hljs-tag"></<span class="hljs-name">k-split</span>></span></code></pre>
|
|
62
63
|
</k-card>
|
|
63
64
|
</div>
|
|
64
65
|
<div class="col d-span-6 m-span-12 px">
|
|
65
66
|
<k-card label="Results">
|
|
66
|
-
<k-split style="--
|
|
67
|
+
<k-split style="--pane_1_size: 30%; height: 10rem" class="b">
|
|
67
68
|
<div>Left Pane Content</div>
|
|
68
69
|
<div slot="right">Right Pane Content</div>
|
|
69
70
|
</k-split>
|
|
@@ -72,21 +73,21 @@
|
|
|
72
73
|
</div>
|
|
73
74
|
|
|
74
75
|
<h3>Sizes</h3>
|
|
75
|
-
<p>Set the CSS Custom Property <code>--
|
|
76
|
-
<p>Set the CSS Custom Property <code>--
|
|
77
|
-
<p>Set the CSS Custom Property <code>--handle_width</code> to set the size of the handle (the draggable region between the
|
|
76
|
+
<p>Set the CSS Custom Property <code>--pane_1_size</code> to set the initial size of the first pane.</p>
|
|
77
|
+
<p>Set the CSS Custom Property <code>--min_pane_size</code> to set the minimum size each pane can be.</p>
|
|
78
|
+
<p>Set the CSS Custom Property <code>--handle_width</code> to set the size of the handle (the draggable region between the panes).</p>
|
|
78
79
|
<div class="row -mx">
|
|
79
80
|
<div class="col m-span-12 px">
|
|
80
81
|
<k-card label="HTML">
|
|
81
|
-
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-split</span><br /> <span class="hljs-attr">style</span>=<span class="hljs-string">"<br /> --
|
|
82
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-split</span><br /> <span class="hljs-attr">style</span>=<span class="hljs-string">"<br /> --pane_1_size: 100px;<br /> --min_pane_size: 100px;<br /> --handle_width: 20px;<br /> height: 10rem<br /> "</span><br /> <span class="hljs-attr">class</span>=<span class="hljs-string">"b"</span><br />></span><br /> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>left<span class="hljs-tag"></<span class="hljs-name">p</span>></span><br /> <span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"right"</span>></span>right<span class="hljs-tag"></<span class="hljs-name">p</span>></span><br /><span class="hljs-tag"></<span class="hljs-name">k-split</span>></span></code></pre>
|
|
82
83
|
</k-card>
|
|
83
84
|
</div>
|
|
84
85
|
<div class="col m-span-12 px">
|
|
85
86
|
<k-card label="Output">
|
|
86
87
|
<k-split
|
|
87
88
|
style="
|
|
88
|
-
--
|
|
89
|
-
--
|
|
89
|
+
--pane_1_size: 100px;
|
|
90
|
+
--min_pane_size: 100px;
|
|
90
91
|
--handle_width: 20px;
|
|
91
92
|
height: 10rem
|
|
92
93
|
"
|
|
@@ -99,6 +100,24 @@
|
|
|
99
100
|
</div>
|
|
100
101
|
</div>
|
|
101
102
|
|
|
103
|
+
<h3 id="verticalSplit"><a href="#verticalSplit" class="no-link">Vertical Split</a></h3>
|
|
104
|
+
<p>Use the <code>direction="vertical"</code> attribute to create a vertical split where the top and bottom panes are divided by a horizontal handle. Set an explicit height on the component for predictable sizing. The default slot provides the top pane content; use <code>slot="right"</code> for the bottom pane content.</p>
|
|
105
|
+
<div class="row -mx mb">
|
|
106
|
+
<div class="col d-span-6 m-span-12 px">
|
|
107
|
+
<k-card label="HTML">
|
|
108
|
+
<pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">k-split</span> <span class="hljs-attr">direction</span>=<span class="hljs-string">"vertical"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"height: 16rem"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"b"</span>></span><br /> <span class="hljs-tag"><<span class="hljs-name">div</span>></span>Top Pane Content<span class="hljs-tag"></<span class="hljs-name">div</span>></span><br /> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"right"</span>></span>Bottom Pane Content<span class="hljs-tag"></<span class="hljs-name">div</span>></span><br /><span class="hljs-tag"></<span class="hljs-name">k-split</span>></span></code></pre>
|
|
109
|
+
</k-card>
|
|
110
|
+
</div>
|
|
111
|
+
<div class="col d-span-6 m-span-12 px">
|
|
112
|
+
<k-card label="Results">
|
|
113
|
+
<k-split direction="vertical" style="height: 16rem" class="b">
|
|
114
|
+
<div>Top Pane Content</div>
|
|
115
|
+
<div slot="right">Bottom Pane Content</div>
|
|
116
|
+
</k-split>
|
|
117
|
+
</k-card>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
102
121
|
<h3 id="stacking"><a href="#stacking" class="no-link">Stacking</a></h3>
|
|
103
122
|
<p>When the screen size is small (mobile) a split panel may not make sense, rather than changing the markup set the <code>stack-width</code> attribute to stack the contents (disable split view) when the component's size is less than the provided size.</p>
|
|
104
123
|
<div class="row -mx">
|
|
@@ -140,18 +159,20 @@
|
|
|
140
159
|
<p>Whether the split view is in stacked mode. Syncs to <code>stacked</code> attribute.</p>
|
|
141
160
|
<h5><code>stackWidth<i>: number</i></code></h5>
|
|
142
161
|
<p>The window width threshold for stacking behavior. Syncs to <code>stack-width</code> attribute.</p>
|
|
162
|
+
<h5><code>direction<i>: string</i></code></h5>
|
|
163
|
+
<p>The direction of the split. Can be <code>"horizontal"</code> (default) or <code>"vertical"</code>. Syncs to <code>direction</code> attribute.</p>
|
|
143
164
|
|
|
144
165
|
<h3 id="cssCustomProperties"><a href="#cssCustomProperties" class="no-link">CSS Custom Properties</a></h3>
|
|
145
|
-
<h5><code>--
|
|
146
|
-
<p>The
|
|
166
|
+
<h5><code>--pane_1_size</code></h5>
|
|
167
|
+
<p>The size of pane 1 (width in horizontal mode, height in vertical mode). Default is <code>calc((100% - var(--handle_width)) / 2)</code>.</p>
|
|
147
168
|
<h5><code>--handle_width</code></h5>
|
|
148
|
-
<p>The width of the draggable divider handle. Default is <code>0.5rem</code>.</p>
|
|
149
|
-
<h5><code>--
|
|
150
|
-
<p>The minimum
|
|
169
|
+
<p>The width/height of the draggable divider handle. Default is <code>0.5rem</code>.</p>
|
|
170
|
+
<h5><code>--min_pane_size</code></h5>
|
|
171
|
+
<p>The minimum size each pane can be resized to. Default is <code>6rem</code>.</p>
|
|
151
172
|
|
|
152
173
|
<h3 id="methods"><a href="#methods" class="no-link">Methods</a></h3>
|
|
153
174
|
<h5><code>setSize(size)<i>: void</i></code></h5>
|
|
154
|
-
<p>Sets the
|
|
175
|
+
<p>Sets the size of pane 1 via <code>--pane_1_size</code>. Controls width in horizontal mode and height in vertical mode.</p>
|
|
155
176
|
|
|
156
177
|
<h3 id="events"><a href="#events" class="no-link">Events</a></h3>
|
|
157
178
|
<h5><code>resizestart</code></h5>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import drag from"../utils/drag.js";export default class Split extends ShadowComponent{static properties={resizing:{type:Boolean,reflect:!0},stacked:{type:Boolean,reflect:!0},stackWidth:{type:Number,attribute:"stack-width"}};constructor(){super(),this.resizing=!1,this.stacked=!1,this.stackWidth=0,this.
|
|
1
|
+
import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import drag from"../utils/drag.js";export default class Split extends ShadowComponent{static properties={resizing:{type:Boolean,reflect:!0},stacked:{type:Boolean,reflect:!0},stackWidth:{type:Number,attribute:"stack-width"},direction:{type:String,reflect:!0}};constructor(){super(),this.resizing=!1,this.stacked=!1,this.stackWidth=0,this.direction="horizontal",this.dragStartSize=0,this.dragCleanup=()=>{},this.resizeObserver=null}firstUpdated(){super.firstUpdated(),this.setupDragHandler(),this.setupResizeObserver()}disconnectedCallback(){super.disconnectedCallback(),this.dragCleanup(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null)}handleDragStart=()=>{this.resizing=!0,this.dragStartSize=Math.round(this.shadowRoot.getElementById("pane-1").getBoundingClientRect()["vertical"===this.direction?"height":"width"]),this.dispatchEvent(new CustomEvent("resizestart",{detail:{startSize:this.dragStartSize},bubbles:!0}))};handleDrag=({x:e,y:t})=>{const i="vertical"===this.direction?t:e,s=`${this.dragStartSize+i}px`;this.setSize(s),this.dispatchEvent(new CustomEvent("resize",{detail:{size:s},bubbles:!0}))};handleDragEnd=({x:e,y:t})=>{this.resizing=!1;const i="vertical"===this.direction?t:e,s=`${this.dragStartSize+i}px`;this.setSize(s),this.dispatchEvent(new CustomEvent("resizeend",{detail:{size:s},bubbles:!0}))};setSize(e){this.style.setProperty("--pane_1_size",e)}setupDragHandler(){const e=this.shadowRoot.getElementById("divider-handle");e&&(this.dragCleanup=drag({element:e,callback:this.handleDrag,startCallback:this.handleDragStart,endCallback:this.handleDragEnd}))}setupResizeObserver(){this.resizeObserver=new ResizeObserver(e=>{for(const t of e){const e=t.contentRect.width;this.stacked=e<=this.stackWidth}}),this.resizeObserver.observe(this)}static styles=css`
|
|
2
2
|
:host {
|
|
3
|
-
--
|
|
3
|
+
--pane_1_size: calc((100% - var(--handle_width)) / 2);
|
|
4
4
|
--handle_width: 0.5rem;
|
|
5
|
-
--
|
|
5
|
+
--min_pane_size: 6rem;
|
|
6
6
|
|
|
7
7
|
height: 100%;
|
|
8
8
|
display: flex;
|
|
@@ -16,14 +16,14 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.pane {
|
|
19
|
-
min-width: var(--
|
|
20
|
-
max-width: calc(100% - var(--
|
|
19
|
+
min-width: var(--min_pane_size);
|
|
20
|
+
max-width: calc(100% - var(--min_pane_size));
|
|
21
21
|
max-height: 100%;
|
|
22
22
|
overflow: hidden;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
flex: 0 0 var(--
|
|
25
|
+
#pane-1 {
|
|
26
|
+
flex: 0 0 var(--pane_1_size);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
#divider-handle {
|
|
@@ -48,12 +48,12 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
|
|
|
48
48
|
border-left: 1px solid var(--c_border);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
#
|
|
51
|
+
#pane-2 {
|
|
52
52
|
flex: 1 1;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
:host([stacked]) #
|
|
56
|
-
:host([stacked]) #
|
|
55
|
+
:host([stacked]) #pane-1,
|
|
56
|
+
:host([stacked]) #pane-2 {
|
|
57
57
|
display: block;
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -71,14 +71,44 @@ import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComp
|
|
|
71
71
|
:host([stacked]) {
|
|
72
72
|
display: block;
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
:host([direction="vertical"]) {
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
:host([direction="vertical"]) .pane {
|
|
80
|
+
min-width: 0;
|
|
81
|
+
max-width: 100%;
|
|
82
|
+
min-height: var(--min_pane_size);
|
|
83
|
+
max-height: calc(100% - var(--min_pane_size));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:host([direction="vertical"]) #pane-1 {
|
|
87
|
+
flex: 0 0 var(--pane_1_size);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
:host([direction="vertical"]) #divider-handle {
|
|
91
|
+
width: 100%;
|
|
92
|
+
height: var(--handle_width);
|
|
93
|
+
cursor: ns-resize;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: initial;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
:host([direction="vertical"]) #divider-border {
|
|
99
|
+
width: 100%;
|
|
100
|
+
height: 1px;
|
|
101
|
+
border-left: none;
|
|
102
|
+
border-top: 1px solid var(--c_border);
|
|
103
|
+
}
|
|
74
104
|
`;render(){return html`
|
|
75
|
-
<div id="
|
|
105
|
+
<div id="pane-1" class="pane">
|
|
76
106
|
<slot></slot>
|
|
77
107
|
</div>
|
|
78
108
|
<div id="divider-handle">
|
|
79
109
|
<div id="divider-border"></div>
|
|
80
110
|
</div>
|
|
81
|
-
<div id="
|
|
111
|
+
<div id="pane-2" class="pane">
|
|
82
112
|
<slot name="right"></slot>
|
|
83
113
|
</div>
|
|
84
114
|
`}}customElements.define("k-split",Split);
|
package/package.json
CHANGED
package/src/components/Split.js
CHANGED
|
@@ -6,7 +6,8 @@ export default class Split extends ShadowComponent {
|
|
|
6
6
|
static properties = {
|
|
7
7
|
resizing: { type: Boolean, reflect: true },
|
|
8
8
|
stacked: { type: Boolean, reflect: true },
|
|
9
|
-
stackWidth: { type: Number, attribute: 'stack-width' }
|
|
9
|
+
stackWidth: { type: Number, attribute: 'stack-width' },
|
|
10
|
+
direction: { type: String, reflect: true }
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
constructor() {
|
|
@@ -15,9 +16,10 @@ export default class Split extends ShadowComponent {
|
|
|
15
16
|
this.resizing = false;
|
|
16
17
|
this.stacked = false;
|
|
17
18
|
this.stackWidth = 0;
|
|
19
|
+
this.direction = 'horizontal';
|
|
18
20
|
|
|
19
21
|
// Private state
|
|
20
|
-
this.
|
|
22
|
+
this.dragStartSize = 0;
|
|
21
23
|
this.dragCleanup = () => {};
|
|
22
24
|
this.resizeObserver = null;
|
|
23
25
|
}
|
|
@@ -45,15 +47,16 @@ export default class Split extends ShadowComponent {
|
|
|
45
47
|
*/
|
|
46
48
|
handleDragStart = () => {
|
|
47
49
|
this.resizing = true;
|
|
48
|
-
this.
|
|
50
|
+
this.dragStartSize = Math.round(this.shadowRoot.getElementById('pane-1').getBoundingClientRect()[this.direction === 'vertical' ? 'height' : 'width']);
|
|
49
51
|
this.dispatchEvent(new CustomEvent('resizestart', {
|
|
50
|
-
detail: { startSize: this.
|
|
52
|
+
detail: { startSize: this.dragStartSize },
|
|
51
53
|
bubbles: true
|
|
52
54
|
}));
|
|
53
55
|
};
|
|
54
56
|
|
|
55
|
-
handleDrag = ({ x }) => {
|
|
56
|
-
const
|
|
57
|
+
handleDrag = ({ x, y }) => {
|
|
58
|
+
const delta = this.direction === 'vertical' ? y : x;
|
|
59
|
+
const size = `${this.dragStartSize + delta}px`;
|
|
57
60
|
this.setSize(size);
|
|
58
61
|
this.dispatchEvent(new CustomEvent('resize', {
|
|
59
62
|
detail: { size },
|
|
@@ -61,10 +64,10 @@ export default class Split extends ShadowComponent {
|
|
|
61
64
|
}));
|
|
62
65
|
};
|
|
63
66
|
|
|
64
|
-
handleDragEnd = ({ x }) => {
|
|
67
|
+
handleDragEnd = ({ x, y }) => {
|
|
65
68
|
this.resizing = false;
|
|
66
|
-
const
|
|
67
|
-
const size = `${
|
|
69
|
+
const delta = this.direction === 'vertical' ? y : x;
|
|
70
|
+
const size = `${this.dragStartSize + delta}px`;
|
|
68
71
|
this.setSize(size);
|
|
69
72
|
this.dispatchEvent(new CustomEvent('resizeend', {
|
|
70
73
|
detail: { size },
|
|
@@ -76,7 +79,7 @@ export default class Split extends ShadowComponent {
|
|
|
76
79
|
Public Methods
|
|
77
80
|
*/
|
|
78
81
|
setSize(size) {
|
|
79
|
-
this.style.setProperty('--
|
|
82
|
+
this.style.setProperty('--pane_1_size', size);
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
setupDragHandler() {
|
|
@@ -106,9 +109,9 @@ export default class Split extends ShadowComponent {
|
|
|
106
109
|
*/
|
|
107
110
|
static styles = css`
|
|
108
111
|
:host {
|
|
109
|
-
--
|
|
112
|
+
--pane_1_size: calc((100% - var(--handle_width)) / 2);
|
|
110
113
|
--handle_width: 0.5rem;
|
|
111
|
-
--
|
|
114
|
+
--min_pane_size: 6rem;
|
|
112
115
|
|
|
113
116
|
height: 100%;
|
|
114
117
|
display: flex;
|
|
@@ -122,14 +125,14 @@ export default class Split extends ShadowComponent {
|
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
.pane {
|
|
125
|
-
min-width: var(--
|
|
126
|
-
max-width: calc(100% - var(--
|
|
128
|
+
min-width: var(--min_pane_size);
|
|
129
|
+
max-width: calc(100% - var(--min_pane_size));
|
|
127
130
|
max-height: 100%;
|
|
128
131
|
overflow: hidden;
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
#
|
|
132
|
-
flex: 0 0 var(--
|
|
134
|
+
#pane-1 {
|
|
135
|
+
flex: 0 0 var(--pane_1_size);
|
|
133
136
|
}
|
|
134
137
|
|
|
135
138
|
#divider-handle {
|
|
@@ -154,12 +157,12 @@ export default class Split extends ShadowComponent {
|
|
|
154
157
|
border-left: 1px solid var(--c_border);
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
#
|
|
160
|
+
#pane-2 {
|
|
158
161
|
flex: 1 1;
|
|
159
162
|
}
|
|
160
163
|
|
|
161
|
-
:host([stacked]) #
|
|
162
|
-
:host([stacked]) #
|
|
164
|
+
:host([stacked]) #pane-1,
|
|
165
|
+
:host([stacked]) #pane-2 {
|
|
163
166
|
display: block;
|
|
164
167
|
}
|
|
165
168
|
|
|
@@ -177,6 +180,36 @@ export default class Split extends ShadowComponent {
|
|
|
177
180
|
:host([stacked]) {
|
|
178
181
|
display: block;
|
|
179
182
|
}
|
|
183
|
+
|
|
184
|
+
:host([direction="vertical"]) {
|
|
185
|
+
flex-direction: column;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
:host([direction="vertical"]) .pane {
|
|
189
|
+
min-width: 0;
|
|
190
|
+
max-width: 100%;
|
|
191
|
+
min-height: var(--min_pane_size);
|
|
192
|
+
max-height: calc(100% - var(--min_pane_size));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
:host([direction="vertical"]) #pane-1 {
|
|
196
|
+
flex: 0 0 var(--pane_1_size);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
:host([direction="vertical"]) #divider-handle {
|
|
200
|
+
width: 100%;
|
|
201
|
+
height: var(--handle_width);
|
|
202
|
+
cursor: ns-resize;
|
|
203
|
+
align-items: center;
|
|
204
|
+
justify-content: initial;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
:host([direction="vertical"]) #divider-border {
|
|
208
|
+
width: 100%;
|
|
209
|
+
height: 1px;
|
|
210
|
+
border-left: none;
|
|
211
|
+
border-top: 1px solid var(--c_border);
|
|
212
|
+
}
|
|
180
213
|
`;
|
|
181
214
|
|
|
182
215
|
/*
|
|
@@ -184,13 +217,13 @@ export default class Split extends ShadowComponent {
|
|
|
184
217
|
*/
|
|
185
218
|
render() {
|
|
186
219
|
return html`
|
|
187
|
-
<div id="
|
|
220
|
+
<div id="pane-1" class="pane">
|
|
188
221
|
<slot></slot>
|
|
189
222
|
</div>
|
|
190
223
|
<div id="divider-handle">
|
|
191
224
|
<div id="divider-border"></div>
|
|
192
225
|
</div>
|
|
193
|
-
<div id="
|
|
226
|
+
<div id="pane-2" class="pane">
|
|
194
227
|
<slot name="right"></slot>
|
|
195
228
|
</div>
|
|
196
229
|
`;
|
|
@@ -5,7 +5,7 @@ const createSplit = async (options = {}) => {
|
|
|
5
5
|
container.style.width = '800px';
|
|
6
6
|
container.style.height = '400px';
|
|
7
7
|
container.innerHTML = `
|
|
8
|
-
<k-split ${options.stacked ? 'stacked' : ''} ${options.stackWidth ? `stack-width="${options.stackWidth}"` : ''}>
|
|
8
|
+
<k-split ${options.stacked ? 'stacked' : ''} ${options.stackWidth ? `stack-width="${options.stackWidth}"` : ''} ${options.direction ? `direction="${options.direction}"` : ''}>
|
|
9
9
|
<div id="left-content">Left Pane Content</div>
|
|
10
10
|
<div slot="right" id="right-content">Right Pane Content</div>
|
|
11
11
|
</k-split>
|
|
@@ -102,41 +102,41 @@ export default {
|
|
|
102
102
|
'should render left pane': async ({pass, fail}) => {
|
|
103
103
|
const { container, split } = await createSplit();
|
|
104
104
|
|
|
105
|
-
const
|
|
106
|
-
if(!
|
|
105
|
+
const pane1 = split.shadowRoot.getElementById('pane-1');
|
|
106
|
+
if(!pane1){
|
|
107
107
|
cleanup(container);
|
|
108
|
-
fail('Split should render
|
|
108
|
+
fail('Split should render pane-1');
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
if(!
|
|
112
|
+
if(!pane1.classList.contains('pane')){
|
|
113
113
|
cleanup(container);
|
|
114
|
-
fail('
|
|
114
|
+
fail('pane-1 should have pane class');
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
cleanup(container);
|
|
119
|
-
pass('Split renders
|
|
119
|
+
pass('Split renders pane-1');
|
|
120
120
|
},
|
|
121
121
|
|
|
122
122
|
'should render right pane': async ({pass, fail}) => {
|
|
123
123
|
const { container, split } = await createSplit();
|
|
124
124
|
|
|
125
|
-
const
|
|
126
|
-
if(!
|
|
125
|
+
const pane2 = split.shadowRoot.getElementById('pane-2');
|
|
126
|
+
if(!pane2){
|
|
127
127
|
cleanup(container);
|
|
128
|
-
fail('Split should render
|
|
128
|
+
fail('Split should render pane-2');
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
if(!
|
|
132
|
+
if(!pane2.classList.contains('pane')){
|
|
133
133
|
cleanup(container);
|
|
134
|
-
fail('
|
|
134
|
+
fail('pane-2 should have pane class');
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
cleanup(container);
|
|
139
|
-
pass('Split renders
|
|
139
|
+
pass('Split renders pane-2');
|
|
140
140
|
},
|
|
141
141
|
|
|
142
142
|
'should render divider handle': async ({pass, fail}) => {
|
|
@@ -170,31 +170,31 @@ export default {
|
|
|
170
170
|
'should render default slot for left content': async ({pass, fail}) => {
|
|
171
171
|
const { container, split } = await createSplit();
|
|
172
172
|
|
|
173
|
-
const
|
|
174
|
-
const slot =
|
|
173
|
+
const pane1 = split.shadowRoot.getElementById('pane-1');
|
|
174
|
+
const slot = pane1.querySelector('slot:not([name])');
|
|
175
175
|
if(!slot){
|
|
176
176
|
cleanup(container);
|
|
177
|
-
fail('
|
|
177
|
+
fail('pane-1 should have default slot');
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
cleanup(container);
|
|
182
|
-
pass('Split renders default slot for
|
|
182
|
+
pass('Split renders default slot for pane-1 content');
|
|
183
183
|
},
|
|
184
184
|
|
|
185
185
|
'should render named slot for right content': async ({pass, fail}) => {
|
|
186
186
|
const { container, split } = await createSplit();
|
|
187
187
|
|
|
188
|
-
const
|
|
189
|
-
const slot =
|
|
188
|
+
const pane2 = split.shadowRoot.getElementById('pane-2');
|
|
189
|
+
const slot = pane2.querySelector('slot[name="right"]');
|
|
190
190
|
if(!slot){
|
|
191
191
|
cleanup(container);
|
|
192
|
-
fail('
|
|
192
|
+
fail('pane-2 should have named right slot');
|
|
193
193
|
return;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
cleanup(container);
|
|
197
|
-
pass('Split renders named slot for
|
|
197
|
+
pass('Split renders named slot for pane-2 content');
|
|
198
198
|
},
|
|
199
199
|
|
|
200
200
|
'should slot left content correctly': async ({pass, fail}) => {
|
|
@@ -250,20 +250,20 @@ export default {
|
|
|
250
250
|
pass('Split has setSize method');
|
|
251
251
|
},
|
|
252
252
|
|
|
253
|
-
'setSize should set --
|
|
253
|
+
'setSize should set --pane_1_size CSS property': async ({pass, fail}) => {
|
|
254
254
|
const { container, split } = await createSplit();
|
|
255
255
|
|
|
256
256
|
split.setSize('300px');
|
|
257
|
-
const
|
|
257
|
+
const pane1Size = split.style.getPropertyValue('--pane_1_size');
|
|
258
258
|
|
|
259
|
-
if(
|
|
259
|
+
if(pane1Size !== '300px'){
|
|
260
260
|
cleanup(container);
|
|
261
|
-
fail(`Expected --
|
|
261
|
+
fail(`Expected --pane_1_size to be 300px, got ${pane1Size}`);
|
|
262
262
|
return;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
cleanup(container);
|
|
266
|
-
pass('setSize sets --
|
|
266
|
+
pass('setSize sets --pane_1_size property');
|
|
267
267
|
},
|
|
268
268
|
|
|
269
269
|
'should have ew-resize cursor on divider handle': async ({pass, fail}) => {
|
|
@@ -521,8 +521,8 @@ export default {
|
|
|
521
521
|
split.resizing = true;
|
|
522
522
|
await split.updateComplete;
|
|
523
523
|
|
|
524
|
-
const
|
|
525
|
-
const pointerEvents = getComputedStyle(
|
|
524
|
+
const pane1 = split.shadowRoot.getElementById('pane-1');
|
|
525
|
+
const pointerEvents = getComputedStyle(pane1).pointerEvents;
|
|
526
526
|
|
|
527
527
|
if(pointerEvents !== 'none'){
|
|
528
528
|
cleanup(container);
|
|
@@ -540,8 +540,8 @@ export default {
|
|
|
540
540
|
split.resizing = true;
|
|
541
541
|
await split.updateComplete;
|
|
542
542
|
|
|
543
|
-
const
|
|
544
|
-
const userSelect = getComputedStyle(
|
|
543
|
+
const pane1 = split.shadowRoot.getElementById('pane-1');
|
|
544
|
+
const userSelect = getComputedStyle(pane1).userSelect;
|
|
545
545
|
|
|
546
546
|
if(userSelect !== 'none'){
|
|
547
547
|
cleanup(container);
|
|
@@ -611,19 +611,103 @@ export default {
|
|
|
611
611
|
const { container, split } = await createSplit();
|
|
612
612
|
|
|
613
613
|
split.handleDragStart();
|
|
614
|
-
const
|
|
614
|
+
const startSize = split.dragStartSize;
|
|
615
615
|
split.handleDrag({ x: 100, y: 0 });
|
|
616
616
|
|
|
617
|
-
const
|
|
618
|
-
const
|
|
617
|
+
const pane1Size = split.style.getPropertyValue('--pane_1_size');
|
|
618
|
+
const expectedSize = `${startSize + 100}px`;
|
|
619
619
|
|
|
620
|
-
if(
|
|
620
|
+
if(pane1Size !== expectedSize){
|
|
621
621
|
cleanup(container);
|
|
622
|
-
fail(`Expected --
|
|
622
|
+
fail(`Expected --pane_1_size ${expectedSize}, got ${pane1Size}`);
|
|
623
623
|
return;
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
cleanup(container);
|
|
627
627
|
pass('Size updates during drag');
|
|
628
|
+
},
|
|
629
|
+
|
|
630
|
+
'should have default direction as horizontal': async ({pass, fail}) => {
|
|
631
|
+
const { container, split } = await createSplit();
|
|
632
|
+
|
|
633
|
+
if(split.direction !== 'horizontal'){
|
|
634
|
+
cleanup(container);
|
|
635
|
+
fail(`Expected direction to be horizontal, got ${split.direction}`);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
cleanup(container);
|
|
640
|
+
pass('Default direction is horizontal');
|
|
641
|
+
},
|
|
642
|
+
|
|
643
|
+
'should accept direction="vertical" attribute': async ({pass, fail}) => {
|
|
644
|
+
const { container, split } = await createSplit({ direction: 'vertical' });
|
|
645
|
+
|
|
646
|
+
if(split.direction !== 'vertical'){
|
|
647
|
+
cleanup(container);
|
|
648
|
+
fail(`Expected direction to be vertical, got ${split.direction}`);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if(!split.hasAttribute('direction') || split.getAttribute('direction') !== 'vertical'){
|
|
653
|
+
cleanup(container);
|
|
654
|
+
fail('direction attribute should be reflected as vertical');
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
cleanup(container);
|
|
659
|
+
pass('direction="vertical" attribute accepted and reflected');
|
|
660
|
+
},
|
|
661
|
+
|
|
662
|
+
'should have ns-resize cursor on divider handle when vertical': async ({pass, fail}) => {
|
|
663
|
+
const { container, split } = await createSplit({ direction: 'vertical' });
|
|
664
|
+
|
|
665
|
+
const handle = split.shadowRoot.getElementById('divider-handle');
|
|
666
|
+
const cursor = getComputedStyle(handle).cursor;
|
|
667
|
+
|
|
668
|
+
if(cursor !== 'ns-resize'){
|
|
669
|
+
cleanup(container);
|
|
670
|
+
fail(`Expected cursor ns-resize for vertical split, got ${cursor}`);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
cleanup(container);
|
|
675
|
+
pass('Divider handle has ns-resize cursor in vertical mode');
|
|
676
|
+
},
|
|
677
|
+
|
|
678
|
+
'setSize should set --pane_1_size CSS property in vertical mode': async ({pass, fail}) => {
|
|
679
|
+
const { container, split } = await createSplit({ direction: 'vertical' });
|
|
680
|
+
|
|
681
|
+
split.setSize('200px');
|
|
682
|
+
const pane1Size = split.style.getPropertyValue('--pane_1_size');
|
|
683
|
+
|
|
684
|
+
if(pane1Size !== '200px'){
|
|
685
|
+
cleanup(container);
|
|
686
|
+
fail(`Expected --pane_1_size to be 200px, got ${pane1Size}`);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
cleanup(container);
|
|
691
|
+
pass('setSize sets --pane_1_size property in vertical mode');
|
|
692
|
+
},
|
|
693
|
+
|
|
694
|
+
'should update size during vertical drag': async ({pass, fail}) => {
|
|
695
|
+
const { container, split } = await createSplit({ direction: 'vertical' });
|
|
696
|
+
|
|
697
|
+
split.handleDragStart();
|
|
698
|
+
const startSize = split.dragStartSize;
|
|
699
|
+
split.handleDrag({ x: 0, y: 80 });
|
|
700
|
+
|
|
701
|
+
const pane1Size = split.style.getPropertyValue('--pane_1_size');
|
|
702
|
+
const expectedSize = `${startSize + 80}px`;
|
|
703
|
+
|
|
704
|
+
if(pane1Size !== expectedSize){
|
|
705
|
+
cleanup(container);
|
|
706
|
+
fail(`Expected --pane_1_size ${expectedSize}, got ${pane1Size}`);
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
cleanup(container);
|
|
711
|
+
pass('Size updates during vertical drag');
|
|
628
712
|
}
|
|
629
713
|
};
|