@operato/layout 0.3.21 → 0.3.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/src/actions/layout.d.ts +89 -0
  3. package/dist/src/actions/layout.js +140 -0
  4. package/dist/src/actions/layout.js.map +1 -0
  5. package/dist/src/actions/snackbar.d.ts +22 -0
  6. package/dist/src/actions/snackbar.js +24 -0
  7. package/dist/src/actions/snackbar.js.map +1 -0
  8. package/dist/src/components/ox-floating-overlay.d.ts +2 -0
  9. package/dist/src/components/ox-floating-overlay.js +331 -0
  10. package/dist/src/components/ox-floating-overlay.js.map +1 -0
  11. package/dist/src/components/ox-resize-splitter.d.ts +13 -0
  12. package/dist/src/components/ox-resize-splitter.js +108 -0
  13. package/dist/src/components/ox-resize-splitter.js.map +1 -0
  14. package/dist/src/index.d.ts +8 -1
  15. package/dist/src/index.js +8 -1
  16. package/dist/src/index.js.map +1 -1
  17. package/dist/src/initializer.d.ts +2 -0
  18. package/dist/src/initializer.js +91 -0
  19. package/dist/src/initializer.js.map +1 -0
  20. package/dist/src/layouts/ox-aside-bar.d.ts +2 -0
  21. package/dist/src/layouts/ox-aside-bar.js +105 -0
  22. package/dist/src/layouts/ox-aside-bar.js.map +1 -0
  23. package/dist/src/layouts/ox-footer-bar.d.ts +2 -0
  24. package/dist/src/layouts/ox-footer-bar.js +106 -0
  25. package/dist/src/layouts/ox-footer-bar.js.map +1 -0
  26. package/dist/src/layouts/ox-header-bar.d.ts +2 -0
  27. package/dist/src/layouts/ox-header-bar.js +103 -0
  28. package/dist/src/layouts/ox-header-bar.js.map +1 -0
  29. package/dist/src/layouts/ox-nav-bar.d.ts +2 -0
  30. package/dist/src/layouts/ox-nav-bar.js +107 -0
  31. package/dist/src/layouts/ox-nav-bar.js.map +1 -0
  32. package/dist/src/layouts/ox-snack-bar.d.ts +2 -0
  33. package/dist/src/layouts/ox-snack-bar.js +119 -0
  34. package/dist/src/layouts/ox-snack-bar.js.map +1 -0
  35. package/dist/src/reducers/layout.d.ts +13 -0
  36. package/dist/src/reducers/layout.js +62 -0
  37. package/dist/src/reducers/layout.js.map +1 -0
  38. package/dist/src/reducers/snackbar.d.ts +18 -0
  39. package/dist/src/reducers/snackbar.js +30 -0
  40. package/dist/src/reducers/snackbar.js.map +1 -0
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +14 -6
  43. package/src/actions/layout.ts +233 -0
  44. package/src/actions/snackbar.ts +60 -0
  45. package/src/components/ox-floating-overlay.ts +317 -0
  46. package/src/components/ox-resize-splitter.ts +126 -0
  47. package/src/index.ts +10 -1
  48. package/src/initializer.ts +113 -0
  49. package/src/layouts/ox-aside-bar.ts +106 -0
  50. package/src/layouts/ox-footer-bar.ts +106 -0
  51. package/src/layouts/ox-header-bar.ts +103 -0
  52. package/src/layouts/ox-nav-bar.ts +108 -0
  53. package/src/layouts/ox-snack-bar.ts +108 -0
  54. package/src/reducers/layout.ts +72 -0
  55. package/src/reducers/snackbar.ts +32 -0
  56. package/dist/src/ox-layout.d.ts +0 -45
  57. package/dist/src/ox-layout.js +0 -148
  58. package/dist/src/ox-layout.js.map +0 -1
  59. package/dist/src/ox-toolbar-style.d.ts +0 -4
  60. package/dist/src/ox-toolbar-style.js +0 -207
  61. package/dist/src/ox-toolbar-style.js.map +0 -1
  62. package/dist/src/ox-toolbar.d.ts +0 -4
  63. package/dist/src/ox-toolbar.js +0 -123
  64. package/dist/src/ox-toolbar.js.map +0 -1
  65. package/dist/stories/index.stories.d.ts +0 -33
  66. package/dist/stories/index.stories.js +0 -33
  67. package/dist/stories/index.stories.js.map +0 -1
  68. package/dist/test/ox-layout.test.d.ts +0 -1
  69. package/dist/test/ox-layout.test.js +0 -24
  70. package/dist/test/ox-layout.test.js.map +0 -1
  71. package/src/ox-layout.ts +0 -191
  72. package/src/ox-toolbar-style.ts +0 -208
  73. package/src/ox-toolbar.ts +0 -135
  74. package/stories/index.stories.ts +0 -52
  75. package/test/ox-layout.test.ts +0 -35
@@ -0,0 +1,317 @@
1
+ import '@things-factory/help'
2
+ import '@material/mwc-icon'
3
+
4
+ import { css, html, LitElement, PropertyValues } from 'lit'
5
+ import { customElement, property } from 'lit/decorators.js'
6
+
7
+ import { ScrollbarStyles } from '@operato/styles'
8
+
9
+ @customElement('ox-floating-overlay')
10
+ class FloatingOverlay extends LitElement {
11
+ static styles = [
12
+ ScrollbarStyles,
13
+ css`
14
+ /* for layout style */
15
+ :host {
16
+ position: relative;
17
+ z-index: 1;
18
+ }
19
+
20
+ :host([hovering='edge']) {
21
+ /* edge hovering 인 경우에는 상위 relative position 크기와 위치를 반영한다. */
22
+ position: initial;
23
+ }
24
+
25
+ #backdrop {
26
+ position: fixed;
27
+ left: 0;
28
+ top: 0;
29
+
30
+ width: 100vw;
31
+ height: 100vh;
32
+
33
+ background-color: var(--overlay-background-color);
34
+ }
35
+
36
+ [overlayed] {
37
+ position: absolute;
38
+
39
+ display: flex;
40
+ flex-direction: column;
41
+ overflow: hidden;
42
+ background: transparent;
43
+ pointer-events: none;
44
+ }
45
+
46
+ [overlayed][hovering='center'] {
47
+ position: fixed;
48
+
49
+ left: 50%;
50
+ top: 50%;
51
+ transform: translate(-50%, -50%);
52
+
53
+ opacity: 0;
54
+ }
55
+
56
+ [overlayed][hovering='center'][opened] {
57
+ opacity: 1;
58
+ transition: opacity 0.3s ease-in;
59
+ }
60
+
61
+ [hovering='center'] {
62
+ width: var(--overlay-center-normal-width, 60%);
63
+ height: var(--overlay-center-normal-height, 60%);
64
+ }
65
+
66
+ [hovering='center'][size='small'] {
67
+ width: var(--overlay-center-small-width, 40%);
68
+ height: var(--overlay-center-small-height, 40%);
69
+ }
70
+
71
+ [hovering='center'][size='large'] {
72
+ width: var(--overlay-center-large-width, 100%);
73
+ height: var(--overlay-center-large-height, 100%);
74
+ }
75
+
76
+ [header] {
77
+ --help-icon-color: #fff;
78
+ --help-icon-hover-color: #fff;
79
+
80
+ pointer-events: initial;
81
+ }
82
+
83
+ [content] {
84
+ flex: 1;
85
+
86
+ overflow: hidden;
87
+ }
88
+
89
+ ::slotted(*) {
90
+ box-sizing: border-box;
91
+ pointer-events: initial;
92
+ }
93
+
94
+ [hovering='center'] [content] ::slotted(*) {
95
+ width: 100%;
96
+ height: 100%;
97
+ }
98
+ [direction='up'],
99
+ [direction='down'] {
100
+ width: 100%;
101
+
102
+ max-height: 0;
103
+ transition: max-height 0.7s ease-in;
104
+ }
105
+ [direction='up'] {
106
+ bottom: 0;
107
+ }
108
+ [direction='down'] {
109
+ top: 0;
110
+ }
111
+
112
+ [direction='up'][opened],
113
+ [direction='down'][opened] {
114
+ max-height: 100vh;
115
+ }
116
+
117
+ [settled][direction='down'] [content],
118
+ [settled][direction='up'] [content] {
119
+ overflow-y: auto;
120
+ }
121
+
122
+ [direction='left'],
123
+ [direction='right'] {
124
+ height: 100%;
125
+
126
+ max-width: 0;
127
+ transition: max-width 0.5s ease-in;
128
+ }
129
+ [direction='left'] {
130
+ right: 0;
131
+ }
132
+ [direction='right'] {
133
+ left: 0;
134
+ }
135
+
136
+ [direction='left'][opened],
137
+ [direction='right'][opened] {
138
+ max-width: 100vw;
139
+ }
140
+
141
+ [settled][direction='left'] [content],
142
+ [settled][direction='right'] [content] {
143
+ overflow-x: auto;
144
+ }
145
+
146
+ @media screen and (max-width: 460px) {
147
+ [direction='up'],
148
+ [direction='down'] {
149
+ max-height: 100vh;
150
+ }
151
+
152
+ [direction='left'],
153
+ [direction='right'] {
154
+ max-width: 100vw;
155
+ }
156
+ }
157
+ `,
158
+ css`
159
+ /* for header style */
160
+ [header] {
161
+ display: flex;
162
+ flex-direction: row;
163
+ align-items: center;
164
+
165
+ background-color: var(--overlay-header-background-color);
166
+ color: var(--overlay-header-color);
167
+ }
168
+
169
+ slot[name='header'] {
170
+ flex: 1;
171
+
172
+ display: flex;
173
+ flex-direction: row;
174
+ align-items: center;
175
+ justify-content: center;
176
+ }
177
+
178
+ [name='header']::slotted(*) {
179
+ margin: 0 auto;
180
+ }
181
+
182
+ [name='header'] > h1 {
183
+ text-transform: capitalize;
184
+ font: var(--overlay-header-font);
185
+ }
186
+
187
+ [historyback] {
188
+ margin-left: 10px;
189
+ margin-right: auto;
190
+ }
191
+
192
+ [close] {
193
+ margin-left: auto;
194
+ margin-right: 10px;
195
+ }
196
+
197
+ [historyback],
198
+ [close] {
199
+ display: none;
200
+ }
201
+
202
+ [closable][close] {
203
+ display: block;
204
+ }
205
+
206
+ @media screen and (max-width: 460px) {
207
+ [closable][historyback] {
208
+ display: block;
209
+ }
210
+
211
+ [closable][close] {
212
+ display: none;
213
+ }
214
+ }
215
+ `
216
+ ]
217
+
218
+ @property({ type: Boolean }) backdrop: boolean = false
219
+ @property({ type: String }) direction?: 'up' | 'down' | 'left' | 'right'
220
+ @property({ type: String, reflect: true }) hovering?: 'center' | 'edge'
221
+ @property({ type: String }) size?: 'small' | 'normal' | 'large'
222
+ @property({ type: String }) name?: string
223
+ @property({ type: String }) title: string = ''
224
+ @property({ type: Boolean }) closable: boolean = false
225
+ @property({ type: Object }) templateProperties: any
226
+ @property({ type: Object }) help: any
227
+
228
+ render() {
229
+ var direction = this.hovering == 'center' ? false : this.direction
230
+
231
+ return html`
232
+ ${Boolean(this.backdrop)
233
+ ? html` <div id="backdrop" ?hidden=${!this.backdrop} @click=${() => this.onClose(true)}></div> `
234
+ : html``}
235
+
236
+ <div
237
+ overlayed
238
+ hovering=${this.hovering || 'center'}
239
+ direction=${direction}
240
+ size=${this.size || 'normal'}
241
+ @close-overlay=${() => this.onClose()}
242
+ @transitionstart=${(e: Event) => {
243
+ /* to hide scrollbar during transition */
244
+ ;(e.target as HTMLElement).removeAttribute('settled')
245
+ }}
246
+ @transitionend=${(e: Event) => {
247
+ ;(e.target as HTMLElement).setAttribute('settled', '')
248
+ }}
249
+ >
250
+ <div header>
251
+ <mwc-icon @click=${() => this.onClose()} ?closable=${this.closable} historyback>arrow_back</mwc-icon>
252
+ <slot name="header">
253
+ ${this.title || this.closable
254
+ ? html`
255
+ <h1>
256
+ ${this.title || ''}&nbsp;${this.help ? html` <help-icon .topic=${this.help}></help-icon>` : html``}
257
+ </h1>
258
+ `
259
+ : html``}</slot
260
+ >
261
+ <mwc-icon @click=${() => this.onClose()} ?closable=${this.closable} close>close</mwc-icon>
262
+ </div>
263
+
264
+ <div content>
265
+ <slot> </slot>
266
+ </div>
267
+ </div>
268
+ `
269
+ }
270
+
271
+ updated(changes: PropertyValues<this>) {
272
+ if (changes.has('templateProperties') && this.templateProperties) {
273
+ var template = this.firstElementChild
274
+ if (template) {
275
+ for (let prop in this.templateProperties) {
276
+ //@ts-ignore
277
+ template[prop] = this.templateProperties[prop]
278
+ }
279
+ }
280
+ }
281
+ }
282
+
283
+ firstUpdated() {
284
+ requestAnimationFrame(() => {
285
+ /* transition(animation) 효과를 위해 'opened' 속성을 변화시킨다. */
286
+ this.renderRoot.querySelector('[overlayed]')?.setAttribute('opened', 'true')
287
+ })
288
+ }
289
+
290
+ disconnectedCallback() {
291
+ document.dispatchEvent(
292
+ new CustomEvent('overlay-closed', {
293
+ detail: this.name
294
+ })
295
+ )
296
+
297
+ super.disconnectedCallback()
298
+ }
299
+
300
+ onClose(escape?: boolean) {
301
+ /* 현재 overlay state를 확인해서, 자신이 포함하고 있는 템플릿인 경우에 history.back() 한다. */
302
+
303
+ var state = history.state
304
+ var overlay = (state || {}).overlay
305
+
306
+ if (!overlay || overlay.name !== this.name) {
307
+ return
308
+ }
309
+
310
+ /* Backdrop click 경우는 escape 시도라고 정의한다. overlay 속성이 escapable이 아닌 경우에는 동작하지 않는다. */
311
+ if (escape && !overlay.escapable) {
312
+ return true
313
+ }
314
+
315
+ history.back()
316
+ }
317
+ }
@@ -0,0 +1,126 @@
1
+ import { css, html, LitElement } from 'lit'
2
+ import { customElement } from 'lit/decorators.js'
3
+
4
+ @customElement('ox-resize-splitter')
5
+ export class ResizeSplitter extends LitElement {
6
+ static _dragImage: HTMLImageElement
7
+
8
+ static get dragImage() {
9
+ if (!ResizeSplitter._dragImage) {
10
+ ResizeSplitter._dragImage = new Image()
11
+ ResizeSplitter._dragImage.src =
12
+ 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
13
+ }
14
+ return ResizeSplitter._dragImage
15
+ }
16
+
17
+ static styles = css`
18
+ :host {
19
+ position: relative;
20
+ opacity: 0.7;
21
+ background-color: var(--splitter-background-color);
22
+ }
23
+
24
+ :host(:hover) {
25
+ background-color: var(--splitter-hover-background-color);
26
+ }
27
+
28
+ div {
29
+ position: absolute;
30
+ width: 100%;
31
+ height: 100%;
32
+ }
33
+ `
34
+
35
+ private dragstart?: { x: number; y: number }
36
+
37
+ connectedCallback() {
38
+ super.connectedCallback()
39
+
40
+ if (this.hasAttribute('vertical')) {
41
+ this.style.width = '3px'
42
+ this.style.height = '100%'
43
+ this.style.cursor = 'col-resize'
44
+ } else {
45
+ this.style.width = '100%'
46
+ this.style.height = '3px'
47
+ this.style.cursor = 'row-resize'
48
+ }
49
+ }
50
+
51
+ render() {
52
+ return html`
53
+ <div
54
+ draggable="true"
55
+ @dragstart=${(e: DragEvent) => this._onDragStart(e)}
56
+ @drag=${this._throttled(100, this._onDrag.bind(this))}
57
+ @dragend=${(e: DragEvent) => this._onDragEnd(e)}
58
+ ></div>
59
+ `
60
+ }
61
+
62
+ // TODO onDrag 이벤트가 계속 발생하므로 처리하는 성능 저하됨. 그래서 throttling 하도록 함
63
+ _throttled(delay: number, fn: (...args: any) => void) {
64
+ let lastCall = 0
65
+ return function (...args: any) {
66
+ const now = new Date().getTime()
67
+ if (now - lastCall < delay) {
68
+ return
69
+ }
70
+ lastCall = now
71
+ return fn(...args)
72
+ }
73
+ }
74
+
75
+ _onDragStart(e: DragEvent) {
76
+ e.dataTransfer!.setDragImage(ResizeSplitter.dragImage, 0, 0)
77
+
78
+ this.dragstart = {
79
+ x: e.clientX,
80
+ y: e.clientY
81
+ }
82
+
83
+ this.dispatchEvent(
84
+ new CustomEvent('splitter-dragstart', {
85
+ bubbles: true,
86
+ composed: true
87
+ })
88
+ )
89
+
90
+ e.stopPropagation()
91
+ }
92
+
93
+ _onDrag(e: DragEvent) {
94
+ if (e.clientX == 0) {
95
+ return
96
+ }
97
+
98
+ this.dispatchEvent(
99
+ new CustomEvent('splitter-drag', {
100
+ bubbles: true,
101
+ composed: true,
102
+ detail: {
103
+ x: e.clientX - this.dragstart!.x,
104
+ y: e.clientY - this.dragstart!.y
105
+ }
106
+ })
107
+ )
108
+
109
+ e.stopPropagation()
110
+ }
111
+
112
+ _onDragEnd(e: DragEvent) {
113
+ this.dispatchEvent(
114
+ new CustomEvent('splitter-dragend', {
115
+ bubbles: true,
116
+ composed: true,
117
+ detail: {
118
+ x: e.clientX - this.dragstart!.x,
119
+ y: e.clientY - this.dragstart!.y
120
+ }
121
+ })
122
+ )
123
+
124
+ e.stopPropagation()
125
+ }
126
+ }
package/src/index.ts CHANGED
@@ -1 +1,10 @@
1
- export * from './ox-layout'
1
+ import './initializer'
2
+
3
+ export * from './layouts/ox-snack-bar.js'
4
+ export * from './layouts/ox-header-bar.js'
5
+ export * from './layouts/ox-nav-bar.js'
6
+ export * from './layouts/ox-aside-bar.js'
7
+ export * from './layouts/ox-footer-bar.js'
8
+
9
+ export * from './actions/layout'
10
+ export * from './actions/snackbar'
@@ -0,0 +1,113 @@
1
+ import { REGISTER_NAVIGATION_CALLBACK, store } from '@operato/shell'
2
+
3
+ import { closeOverlay, openOverlay, openPopup, toggleOverlay, UPDATE_VIEWPART } from './actions/layout'
4
+ import { showSnackbar } from './actions/snackbar'
5
+ import layout from './reducers/layout'
6
+ import snackbar from './reducers/snackbar'
7
+
8
+ store.addReducers({
9
+ layout,
10
+ snackbar
11
+ })
12
+
13
+ document.addEventListener('open-overlay', event => {
14
+ const { name, options } = (event as CustomEvent).detail
15
+ openOverlay(name, options)
16
+ })
17
+
18
+ document.addEventListener('close-overlay', event => {
19
+ const { name } = (event as CustomEvent).detail
20
+ closeOverlay(name)
21
+ })
22
+
23
+ document.addEventListener('toggle-overlay', event => {
24
+ const { name, options } = (event as CustomEvent).detail
25
+ toggleOverlay(name, options)
26
+ })
27
+
28
+ document.addEventListener('open-popup', event => {
29
+ const { template, options, callback } = (event as CustomEvent).detail
30
+ var popup = openPopup(template, options)
31
+ if (popup && callback) callback(popup)
32
+ })
33
+
34
+ document.addEventListener('notify', event => {
35
+ let { message, level, ex = '', option = {} } = (event as CustomEvent).detail
36
+
37
+ switch (level) {
38
+ case 'error':
39
+ console.error(message, ex)
40
+ break
41
+ case 'warn':
42
+ console.warn(message, ex)
43
+ break
44
+ case 'info':
45
+ console.info(message)
46
+ break
47
+ default:
48
+ break
49
+ }
50
+
51
+ store.dispatch(
52
+ showSnackbar(level, {
53
+ message,
54
+ ...(option as {
55
+ action?: any
56
+ timer?: number
57
+ })
58
+ }) as any
59
+ )
60
+ })
61
+
62
+ /* overlay handling */
63
+ var overlayStack: any[] = []
64
+ function getLastSequence() {
65
+ return overlayStack.length > 0 ? overlayStack[overlayStack.length - 1].overlay.sequence : -1
66
+ }
67
+
68
+ document.addEventListener('keydown', event => {
69
+ if (overlayStack.length > 0 && event.keyCode == 27 /* KEY_ESC */) {
70
+ history.state?.overlay?.escapable && history.back()
71
+ }
72
+ })
73
+
74
+ const historyHandler = (location: string, event: Event) => {
75
+ var navigated = event instanceof PopStateEvent
76
+
77
+ var state = history.state
78
+ var overlay = state?.overlay
79
+ var sequence = overlay?.sequence || -1
80
+
81
+ var lastSequence = getLastSequence()
82
+
83
+ if (overlayStack.length > 0 && sequence < lastSequence) {
84
+ /* overlay 관련 history가 아닌 경우. */
85
+ do {
86
+ let { overlay } = overlayStack.pop()
87
+ store.dispatch({
88
+ type: UPDATE_VIEWPART,
89
+ name: overlay.name,
90
+ override: { show: false }
91
+ })
92
+
93
+ lastSequence = getLastSequence()
94
+ } while (sequence < lastSequence)
95
+ }
96
+
97
+ if (!navigated && overlay) {
98
+ overlayStack.push({ ...state })
99
+
100
+ store.dispatch({
101
+ type: UPDATE_VIEWPART,
102
+ name: overlay.name,
103
+ override: { show: true }
104
+ })
105
+ }
106
+ }
107
+
108
+ store.dispatch({
109
+ type: REGISTER_NAVIGATION_CALLBACK,
110
+ callback: historyHandler
111
+ })
112
+
113
+ export default store
@@ -0,0 +1,106 @@
1
+ import '../components/ox-floating-overlay.js'
2
+ import '../components/ox-resize-splitter.js'
3
+
4
+ import { css, html, LitElement } from 'lit'
5
+ import { customElement, property, state } from 'lit/decorators.js'
6
+ import { connect } from 'pwa-helpers/connect-mixin.js'
7
+
8
+ import { ScrollbarStyles } from '@operato/styles'
9
+
10
+ import { Viewpart, VIEWPART_LEVEL } from '../actions/layout.js'
11
+ import store from '../initializer.js'
12
+
13
+ @customElement('ox-aside-bar')
14
+ class AsideBar extends connect(store)(LitElement) {
15
+ static styles = [
16
+ ScrollbarStyles,
17
+ css`
18
+ :host {
19
+ display: flex;
20
+ flex-flow: row-reverse nowrap;
21
+ align-items: stretch;
22
+
23
+ position: relative;
24
+ }
25
+
26
+ *[asidebar] {
27
+ display: block;
28
+ overflow-y: auto;
29
+ }
30
+ `
31
+ ]
32
+
33
+ @property({ type: Boolean, attribute: 'fullbleed' }) fullbleed: boolean = false
34
+
35
+ @state() viewparts: { [name: string]: Viewpart } = {}
36
+
37
+ private _startWidth: number = 0
38
+
39
+ render() {
40
+ var viewparts = this.viewparts
41
+ var asidebars = Object.keys(viewparts)
42
+ .map(name => {
43
+ return {
44
+ name,
45
+ ...viewparts[name]
46
+ }
47
+ })
48
+ .filter(viewpart => viewpart.position == 'asidebar' && (!this.fullbleed || viewpart.hovering))
49
+
50
+ asidebars = [
51
+ ...asidebars.filter(viewpart => viewpart.level == VIEWPART_LEVEL.TOPMOST),
52
+ ...asidebars.filter(viewpart => viewpart.level !== VIEWPART_LEVEL.TOPMOST)
53
+ ]
54
+
55
+ return html`
56
+ ${asidebars.map(asidebar =>
57
+ !asidebar.show
58
+ ? html``
59
+ : asidebar.hovering
60
+ ? html`
61
+ <ox-floating-overlay
62
+ .backdrop=${asidebar.backdrop}
63
+ direction="left"
64
+ .hovering=${asidebar.hovering}
65
+ .name=${asidebar.name}
66
+ .size=${asidebar.size}
67
+ .title=${asidebar.title}
68
+ .help=${asidebar.help}
69
+ .closable=${asidebar.closable}
70
+ .templateProperties=${asidebar.templateProperties}
71
+ >${asidebar.template}</ox-floating-overlay
72
+ >
73
+ `
74
+ : html`
75
+ <div asidebar>${asidebar.template}</div>
76
+ ${asidebar.resizable
77
+ ? html`
78
+ <ox-resize-splitter
79
+ @splitter-dragstart=${(e: CustomEvent) => this.resizeStart(e)}
80
+ @splitter-drag=${(e: CustomEvent) => this.resizeDrag(e)}
81
+ vertical
82
+ ></ox-resize-splitter>
83
+ `
84
+ : html``}
85
+ `
86
+ )}
87
+ `
88
+ }
89
+
90
+ resizeStart(e: CustomEvent) {
91
+ this._startWidth = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement)?.offsetWidth
92
+ }
93
+
94
+ resizeDrag(e: CustomEvent) {
95
+ var delta = e.detail
96
+
97
+ var x = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement)?.querySelectorAll('*')
98
+ Array.from(x).forEach(ele => {
99
+ ;(ele as HTMLElement).style.width = `${this._startWidth - delta.x}px`
100
+ })
101
+ }
102
+
103
+ stateChanged(state: any) {
104
+ this.viewparts = state.layout.viewparts || {}
105
+ }
106
+ }