@operato/layout 8.0.0-beta.0 β 8.0.0-beta.1
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/CHANGELOG.md +9 -0
- package/package.json +6 -6
- package/.editorconfig +0 -29
- package/.storybook/main.js +0 -3
- package/.storybook/preview.js +0 -52
- package/.storybook/server.mjs +0 -8
- package/src/actions/layout.ts +0 -222
- package/src/actions/snackbar.ts +0 -60
- package/src/components/ox-resize-splitter.ts +0 -137
- package/src/components/ox-split-pane.ts +0 -113
- package/src/index.ts +0 -16
- package/src/initializer.ts +0 -113
- package/src/layouts/ox-aside-bar.ts +0 -111
- package/src/layouts/ox-footer-bar.ts +0 -112
- package/src/layouts/ox-header-bar.ts +0 -108
- package/src/layouts/ox-nav-bar.ts +0 -113
- package/src/layouts/ox-page-footer-bar.ts +0 -112
- package/src/layouts/ox-page-header-bar.ts +0 -106
- package/src/layouts/ox-snack-bar.ts +0 -109
- package/src/reducers/layout.ts +0 -72
- package/src/reducers/snackbar.ts +0 -32
- package/tsconfig.json +0 -24
- package/web-dev-server.config.mjs +0 -27
- package/web-test-runner.config.mjs +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [8.0.0-beta.1](https://github.com/hatiolab/operato/compare/v8.0.0-beta.0...v8.0.0-beta.1) (2025-01-08)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :bug: Bug Fix
|
|
10
|
+
|
|
11
|
+
* missing .npmignore ([be05985](https://github.com/hatiolab/operato/commit/be05985abfae4af53501f718dd52932099f7fbcb))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
## [8.0.0-beta.0](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.56...v8.0.0-beta.0) (2025-01-07)
|
|
7
16
|
|
|
8
17
|
**Note:** Version bump only for package @operato/layout
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@operato/layout",
|
|
3
3
|
"description": "Webcomponent layout following open-wc recommendations",
|
|
4
4
|
"author": "heartyoh",
|
|
5
|
-
"version": "8.0.0-beta.
|
|
5
|
+
"version": "8.0.0-beta.1",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
7
7
|
"module": "dist/src/index.js",
|
|
8
8
|
"exports": {
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@material/web": "^2.0.0",
|
|
65
|
-
"@operato/popup": "^8.0.0-beta.
|
|
66
|
-
"@operato/shell": "^8.0.0-beta.
|
|
67
|
-
"@operato/styles": "^8.0.0-beta.
|
|
68
|
-
"@operato/utils": "^8.0.0-beta.
|
|
65
|
+
"@operato/popup": "^8.0.0-beta.1",
|
|
66
|
+
"@operato/shell": "^8.0.0-beta.1",
|
|
67
|
+
"@operato/styles": "^8.0.0-beta.1",
|
|
68
|
+
"@operato/utils": "^8.0.0-beta.1",
|
|
69
69
|
"lit": "^3.1.2",
|
|
70
70
|
"pwa-helpers": "^0.9.1"
|
|
71
71
|
},
|
|
@@ -101,5 +101,5 @@
|
|
|
101
101
|
"prettier --write"
|
|
102
102
|
]
|
|
103
103
|
},
|
|
104
|
-
"gitHead": "
|
|
104
|
+
"gitHead": "d5b28a2e9deb632c0dc80132f6a7196dd6fe4220"
|
|
105
105
|
}
|
package/.editorconfig
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# EditorConfig helps developers define and maintain consistent
|
|
2
|
-
# coding styles between different editors and IDEs
|
|
3
|
-
# editorconfig.org
|
|
4
|
-
|
|
5
|
-
root = true
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
[*]
|
|
9
|
-
|
|
10
|
-
# Change these settings to your own preference
|
|
11
|
-
indent_style = space
|
|
12
|
-
indent_size = 2
|
|
13
|
-
|
|
14
|
-
# We recommend you to keep these unchanged
|
|
15
|
-
end_of_line = lf
|
|
16
|
-
charset = utf-8
|
|
17
|
-
trim_trailing_whitespace = true
|
|
18
|
-
insert_final_newline = true
|
|
19
|
-
|
|
20
|
-
[*.md]
|
|
21
|
-
trim_trailing_whitespace = false
|
|
22
|
-
|
|
23
|
-
[*.json]
|
|
24
|
-
indent_size = 2
|
|
25
|
-
|
|
26
|
-
[*.{html,js,md}]
|
|
27
|
-
block_comment_start = /**
|
|
28
|
-
block_comment = *
|
|
29
|
-
block_comment_end = */
|
package/.storybook/main.js
DELETED
package/.storybook/preview.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { i18next } from '@operato/i18n'
|
|
2
|
-
|
|
3
|
-
export const globalTypes = {
|
|
4
|
-
locale: {
|
|
5
|
-
name: 'Locale',
|
|
6
|
-
description: 'Internationalization locale',
|
|
7
|
-
toolbar: {
|
|
8
|
-
icon: 'globe',
|
|
9
|
-
items: [
|
|
10
|
-
{ value: 'en', right: 'πΊπΈ', title: 'English' },
|
|
11
|
-
{ value: 'ko', right: 'π°π·', title: 'νκ΅μ΄' },
|
|
12
|
-
{ value: 'zh', right: 'π¨π³', title: 'δΈζ' },
|
|
13
|
-
{ value: 'ja', right: 'π―π΅', title: 'ζ₯ζ¬θͺ' },
|
|
14
|
-
{ value: 'ms', right: 'π²πΎ', title: 'Bahasa Melayu' }
|
|
15
|
-
],
|
|
16
|
-
showName: true
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
theme: {
|
|
20
|
-
name: 'Theme',
|
|
21
|
-
description: 'Global theme for components',
|
|
22
|
-
toolbar: {
|
|
23
|
-
icon: 'paintbrush',
|
|
24
|
-
items: [
|
|
25
|
-
{ value: 'light', title: 'Light' },
|
|
26
|
-
{ value: 'dark', title: 'Dark' }
|
|
27
|
-
],
|
|
28
|
-
showName: true
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const decorators = [
|
|
34
|
-
(Story, context) => {
|
|
35
|
-
const { locale, theme } = context.globals
|
|
36
|
-
|
|
37
|
-
if (locale) {
|
|
38
|
-
i18next.changeLanguage(locale)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Set the theme class for the document
|
|
42
|
-
if (theme === 'dark') {
|
|
43
|
-
document.documentElement.classList.add('dark')
|
|
44
|
-
document.documentElement.classList.remove('light')
|
|
45
|
-
} else {
|
|
46
|
-
document.documentElement.classList.add('light')
|
|
47
|
-
document.documentElement.classList.remove('dark')
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return Story()
|
|
51
|
-
}
|
|
52
|
-
]
|
package/.storybook/server.mjs
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { storybookPlugin } from '@web/dev-server-storybook';
|
|
2
|
-
import baseConfig from '../web-dev-server.config.mjs';
|
|
3
|
-
|
|
4
|
-
export default /** @type {import('@web/dev-server').DevServerConfig} */ ({
|
|
5
|
-
...baseConfig,
|
|
6
|
-
open: '/',
|
|
7
|
-
plugins: [storybookPlugin({ type: 'web-components' }), ...baseConfig.plugins],
|
|
8
|
-
});
|
package/src/actions/layout.ts
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import { TemplateResult } from 'lit'
|
|
2
|
-
|
|
3
|
-
import { PopupHandle, PopupOptions, setOpenPopupImplementation } from '@operato/popup'
|
|
4
|
-
import { store } from '@operato/shell'
|
|
5
|
-
|
|
6
|
-
export type Viewpart = {
|
|
7
|
-
hovering?: 'center' | 'edge' | 'next'
|
|
8
|
-
show?: boolean
|
|
9
|
-
size?: string
|
|
10
|
-
title?: string
|
|
11
|
-
help?: string
|
|
12
|
-
level?: VIEWPART_LEVEL
|
|
13
|
-
closable?: boolean
|
|
14
|
-
search?: {
|
|
15
|
-
value?: string
|
|
16
|
-
handler?: (closure: any, value: string) => void
|
|
17
|
-
placeholder?: string
|
|
18
|
-
}
|
|
19
|
-
filter?: {
|
|
20
|
-
handler?: (closure: any) => void
|
|
21
|
-
}
|
|
22
|
-
backdrop?: boolean
|
|
23
|
-
temporary?: boolean /* auto remove */
|
|
24
|
-
resizable?: boolean
|
|
25
|
-
template?: TemplateResult
|
|
26
|
-
position?: VIEWPART_POSITION
|
|
27
|
-
templateProperties?: any
|
|
28
|
-
zIndex?: number
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type AppendViewpartAction = {
|
|
32
|
-
name: string
|
|
33
|
-
viewpart: Viewpart
|
|
34
|
-
position: VIEWPART_POSITION
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const appendViewpart = ({ name, viewpart, position }: AppendViewpartAction) => {
|
|
38
|
-
store.dispatch({
|
|
39
|
-
type: APPEND_VIEWPART,
|
|
40
|
-
name,
|
|
41
|
-
viewpart: {
|
|
42
|
-
...viewpart,
|
|
43
|
-
show: viewpart.hovering && viewpart.show ? false : viewpart.show
|
|
44
|
-
},
|
|
45
|
-
position
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
if (viewpart.hovering && viewpart.show) {
|
|
49
|
-
openOverlay(name)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const removeViewpart = (name: string) => {
|
|
54
|
-
store.dispatch({
|
|
55
|
-
type: REMOVE_VIEWPART,
|
|
56
|
-
name
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const updateViewpart = (name: string, override: any) => {
|
|
61
|
-
store.dispatch({
|
|
62
|
-
type: UPDATE_VIEWPART,
|
|
63
|
-
name,
|
|
64
|
-
override
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export const APPEND_VIEWPART = 'APPEND_VIEWPART'
|
|
69
|
-
export const REMOVE_VIEWPART = 'REMOVE_VIEWPART'
|
|
70
|
-
export const UPDATE_VIEWPART = 'UPDATE_VIEWPART'
|
|
71
|
-
|
|
72
|
-
export enum VIEWPART_POSITION {
|
|
73
|
-
HEADERBAR = 'headerbar',
|
|
74
|
-
NAVBAR = 'navbar',
|
|
75
|
-
ASIDEBAR = 'asidebar',
|
|
76
|
-
FOOTERBAR = 'footerbar',
|
|
77
|
-
PAGE_HEADERBAR = 'page-headerbar',
|
|
78
|
-
PAGE_FOOTERBAR = 'page-footerbar'
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* κ° λ·°ννΈ μ€νμ μμλ₯Ό μ νλ μμ±μ΄λ€.
|
|
83
|
-
* λ·°ννΈμ level μμ±μ μ μλλλ‘ νλ€.
|
|
84
|
-
* 맨 μ/μλ/μ’μΈ‘/μ°μΈ‘μ 보μ¬μ ΈμΌνλ λ·°ννΈλ TOPMOST μμ±μ κ°λλ‘ νκ³ ,
|
|
85
|
-
* μμΈ μμλλ‘ λ³΄μ¬μ§λ λ·°ννΈλ NORMAL μμ±μ κ°λλ‘ νλ€.
|
|
86
|
-
* default μμ±μ NORMALμ΄λ€.
|
|
87
|
-
*/
|
|
88
|
-
export enum VIEWPART_LEVEL {
|
|
89
|
-
TOPMOST = 'TOPMOST',
|
|
90
|
-
NORMAL = 'NORMAL'
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export enum TOOL_POSITION {
|
|
94
|
-
FRONT_END = 'FRONT_END',
|
|
95
|
-
FRONT = 'FRONT',
|
|
96
|
-
CENTER = 'CENTER',
|
|
97
|
-
REAR = 'REAR',
|
|
98
|
-
REAR_END = 'REAR_END'
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export const UPDATE_VIEWPORT_WIDTH = 'UPDATE_VIEWPORT_WIDTH'
|
|
102
|
-
|
|
103
|
-
export const updateLayout = (wide?: boolean) => {
|
|
104
|
-
store.dispatch({
|
|
105
|
-
type: UPDATE_VIEWPORT_WIDTH,
|
|
106
|
-
width: wide ? 'WIDE' : 'NARROW'
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/* overlay navigation */
|
|
111
|
-
var overlaySequence = 0
|
|
112
|
-
|
|
113
|
-
export const openOverlay = (name: string, options?: any, silent?: boolean) => {
|
|
114
|
-
var beforeState = history.state
|
|
115
|
-
var beforeOverlay = beforeState ? beforeState.overlay : undefined
|
|
116
|
-
var beforeSequence = !beforeOverlay || beforeOverlay.sequence === undefined ? overlaySequence : beforeOverlay.sequence
|
|
117
|
-
var afterSequence = (overlaySequence = beforeSequence + 1)
|
|
118
|
-
|
|
119
|
-
/* storeμ layoutμ λ΄μ©μ λ³κ²½νλ€. */
|
|
120
|
-
if (!silent && options) {
|
|
121
|
-
store.dispatch({
|
|
122
|
-
type: UPDATE_VIEWPART,
|
|
123
|
-
name,
|
|
124
|
-
override: options
|
|
125
|
-
})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/*
|
|
129
|
-
* νμ¬ history.stateλ₯Ό νμΈνκ³ , overlayμ μ΄λ¦μ΄ κ°μ
|
|
130
|
-
* historyμ μΆκ°νκ³ open λμμ μ€ννλ€.
|
|
131
|
-
*/
|
|
132
|
-
var afterState = Object.assign({}, beforeState || {}, {
|
|
133
|
-
overlay: { name, sequence: afterSequence, escapable: options?.escapable !== false }
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
history.pushState(afterState, '', location.href)
|
|
137
|
-
|
|
138
|
-
window.dispatchEvent(
|
|
139
|
-
new CustomEvent('popstate', {
|
|
140
|
-
detail: { state: afterState }
|
|
141
|
-
})
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export const closeOverlay = (name: string) => {
|
|
146
|
-
/*
|
|
147
|
-
* μ€μ λ‘ overlayλ₯Ό closeνλ μμ
μ window.onpopstate νΈλ€λ¬μμ νλ€.
|
|
148
|
-
*/
|
|
149
|
-
history.back()
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export const toggleOverlay = (name: string, options: any) => {
|
|
153
|
-
var { name: beforeOverlayName } = (history.state && history.state.overlay) || {}
|
|
154
|
-
|
|
155
|
-
if (beforeOverlayName == name) {
|
|
156
|
-
closeOverlay(name)
|
|
157
|
-
} else {
|
|
158
|
-
openOverlay(name, options)
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/*
|
|
163
|
-
* popup handling
|
|
164
|
-
*
|
|
165
|
-
* popupμ overlayμ νΉλ³ν ννμ΄λ€.
|
|
166
|
-
* popupμ openλ λ, viewpartλ₯Ό append νλ©°, close λ λ viewpartλ₯Ό remove νλ€.
|
|
167
|
-
* - name: '$popup-${popupSequence}'
|
|
168
|
-
* - position: VIEWPART_POSITION_HEADERBAR
|
|
169
|
-
* - hovering: 'center' | 'next' | 'edge'
|
|
170
|
-
*/
|
|
171
|
-
var popupSequence = 0
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* open popup in operato application environment
|
|
175
|
-
*
|
|
176
|
-
* @param {*} template html template to be rendered inside the popup
|
|
177
|
-
* @param {PopupOptions} options
|
|
178
|
-
* @returns popup handle object. This object is used to close the popup.
|
|
179
|
-
*/
|
|
180
|
-
export const openPopup = (template: TemplateResult, options: PopupOptions = {}): PopupHandle => {
|
|
181
|
-
var name = `$popup-${popupSequence++}`
|
|
182
|
-
|
|
183
|
-
appendViewpart({
|
|
184
|
-
name,
|
|
185
|
-
viewpart: {
|
|
186
|
-
hovering: 'center',
|
|
187
|
-
closable: true,
|
|
188
|
-
...options,
|
|
189
|
-
backdrop: true,
|
|
190
|
-
show: false,
|
|
191
|
-
temporary: true /* auto remove */,
|
|
192
|
-
template
|
|
193
|
-
},
|
|
194
|
-
position: VIEWPART_POSITION.HEADERBAR
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
openOverlay(name, options, true)
|
|
198
|
-
|
|
199
|
-
var popup = {
|
|
200
|
-
name,
|
|
201
|
-
close: () => {
|
|
202
|
-
/* νμ¬ overlay stateλ₯Ό νμΈν΄μ, μμ μΈ κ²½μ°μ history.back() νλ€. */
|
|
203
|
-
var state = history.state
|
|
204
|
-
var overlay = (state || {}).overlay
|
|
205
|
-
|
|
206
|
-
overlay && overlay.name == name && history.back()
|
|
207
|
-
},
|
|
208
|
-
closed: false
|
|
209
|
-
} as PopupHandle
|
|
210
|
-
|
|
211
|
-
document.addEventListener('overlay-closed', function listener(e) {
|
|
212
|
-
if (name == (e as CustomEvent).detail) {
|
|
213
|
-
popup.closed = true
|
|
214
|
-
popup.onclosed && popup.onclosed()
|
|
215
|
-
document.removeEventListener('overlay-closed', listener)
|
|
216
|
-
}
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
return popup
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
setOpenPopupImplementation(openPopup)
|
package/src/actions/snackbar.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { Action } from 'redux'
|
|
2
|
-
|
|
3
|
-
export const OPEN_SNACKBAR = 'OPEN_SNACKBAR'
|
|
4
|
-
export const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR'
|
|
5
|
-
|
|
6
|
-
var snackbarTimer: number
|
|
7
|
-
|
|
8
|
-
export type NotificationLevel = 'info' | 'warn' | 'error'
|
|
9
|
-
export type Notification = {
|
|
10
|
-
message: string
|
|
11
|
-
level?: NotificationLevel
|
|
12
|
-
option?: any
|
|
13
|
-
ex?: any
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function notify(notification: string | Notification): void {
|
|
17
|
-
if (typeof notification === 'string') {
|
|
18
|
-
return notify({ message: notification })
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
var { message, level, option, ex } = notification as Notification
|
|
22
|
-
|
|
23
|
-
document.dispatchEvent(
|
|
24
|
-
new CustomEvent('notify', {
|
|
25
|
-
detail: { message, level, ex, option }
|
|
26
|
-
})
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type SnackbarAction = {
|
|
31
|
-
type: 'OPEN_SNACKBAR' | 'CLOSE_SNACKBAR'
|
|
32
|
-
level?: NotificationLevel
|
|
33
|
-
message?: string
|
|
34
|
-
action?: any
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const showSnackbar =
|
|
38
|
-
(
|
|
39
|
-
level: NotificationLevel,
|
|
40
|
-
{
|
|
41
|
-
message,
|
|
42
|
-
action,
|
|
43
|
-
timer = 5000
|
|
44
|
-
}: {
|
|
45
|
-
message: string
|
|
46
|
-
action?: any
|
|
47
|
-
timer?: number
|
|
48
|
-
}
|
|
49
|
-
) =>
|
|
50
|
-
(dispatch: (param: SnackbarAction) => Action<any>) => {
|
|
51
|
-
dispatch({
|
|
52
|
-
type: OPEN_SNACKBAR,
|
|
53
|
-
level,
|
|
54
|
-
message,
|
|
55
|
-
action
|
|
56
|
-
})
|
|
57
|
-
window.clearTimeout(snackbarTimer)
|
|
58
|
-
|
|
59
|
-
if (timer != -1) snackbarTimer = window.setTimeout(() => dispatch({ type: CLOSE_SNACKBAR }), timer)
|
|
60
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { LitElement, css, html } from 'lit'
|
|
2
|
-
|
|
3
|
-
import { customElement } from 'lit/decorators.js'
|
|
4
|
-
|
|
5
|
-
@customElement('ox-resize-splitter')
|
|
6
|
-
export class ResizeSplitter extends LitElement {
|
|
7
|
-
static styles = css`
|
|
8
|
-
:host {
|
|
9
|
-
position: relative;
|
|
10
|
-
opacity: 0.7;
|
|
11
|
-
background-color: var(--splitter-background-color);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
:host(:hover) {
|
|
15
|
-
background-color: var(--splitter-hover-background-color);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
div {
|
|
19
|
-
position: absolute;
|
|
20
|
-
width: 100%;
|
|
21
|
-
height: 100%;
|
|
22
|
-
}
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
private dragstart?: { x: number; y: number }
|
|
26
|
-
|
|
27
|
-
connectedCallback() {
|
|
28
|
-
super.connectedCallback()
|
|
29
|
-
|
|
30
|
-
if (this.hasAttribute('vertical')) {
|
|
31
|
-
this.style.width = '3px'
|
|
32
|
-
this.style.height = '100%'
|
|
33
|
-
this.style.cursor = 'col-resize'
|
|
34
|
-
} else {
|
|
35
|
-
this.style.width = '100%'
|
|
36
|
-
this.style.height = '3px'
|
|
37
|
-
this.style.cursor = 'row-resize'
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
render() {
|
|
42
|
-
return html` <div @mousedown=${(e: MouseEvent) => this.onMouseDown(e)}></div> `
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// TODO onDrag μ΄λ²€νΈκ° κ³μ λ°μνλ―λ‘ μ²λ¦¬νλ μ±λ₯ μ νλ¨. κ·Έλμ throttling νλλ‘ ν¨
|
|
46
|
-
_throttled(delay: number, fn: (...args: any) => void) {
|
|
47
|
-
let lastCall = 0
|
|
48
|
-
return function (...args: any) {
|
|
49
|
-
const now = new Date().getTime()
|
|
50
|
-
if (now - lastCall < delay) {
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
lastCall = now
|
|
54
|
-
return fn(...args)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private onMouseDown(e: MouseEvent) {
|
|
59
|
-
this.dragstart = {
|
|
60
|
-
x: e.clientX,
|
|
61
|
-
y: e.clientY
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
this.dispatchEvent(
|
|
65
|
-
new CustomEvent('splitter-dragstart', {
|
|
66
|
-
bubbles: true,
|
|
67
|
-
composed: true
|
|
68
|
-
})
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
window.addEventListener('mousemove', this.onMouseMoveHandler)
|
|
72
|
-
window.addEventListener('mouseup', this.onMouseUpHandler)
|
|
73
|
-
|
|
74
|
-
e.stopPropagation()
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
onMouseMoveHandler = this._throttled(100, this.onMouseMove.bind(this)) // this.onMouseMove.bind(this)
|
|
78
|
-
onMouseUpHandler = this.onMouseUp.bind(this)
|
|
79
|
-
|
|
80
|
-
private onMouseMove(e: MouseEvent) {
|
|
81
|
-
if (!this.dragstart) {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
e.preventDefault()
|
|
86
|
-
|
|
87
|
-
this.dispatchEvent(
|
|
88
|
-
new CustomEvent('splitter-drag', {
|
|
89
|
-
bubbles: true,
|
|
90
|
-
composed: true,
|
|
91
|
-
detail: {
|
|
92
|
-
x: e.clientX - this.dragstart!.x,
|
|
93
|
-
y: e.clientY - this.dragstart!.y
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
)
|
|
97
|
-
requestAnimationFrame(() => {
|
|
98
|
-
dispatchEvent(new Event('resize'))
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
if (this.hasAttribute('vertical')) {
|
|
102
|
-
document.body.style.cursor = 'col-resize'
|
|
103
|
-
} else {
|
|
104
|
-
document.body.style.cursor = 'row-resize'
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
document.body.style.userSelect = 'none'
|
|
108
|
-
|
|
109
|
-
e.stopPropagation()
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
private onMouseUp(e: MouseEvent) {
|
|
113
|
-
window.removeEventListener('mousemove', this.onMouseMoveHandler)
|
|
114
|
-
window.removeEventListener('mouseup', this.onMouseUpHandler)
|
|
115
|
-
|
|
116
|
-
this.dispatchEvent(
|
|
117
|
-
new CustomEvent('splitter-dragend', {
|
|
118
|
-
bubbles: true,
|
|
119
|
-
composed: true,
|
|
120
|
-
detail: {
|
|
121
|
-
x: e.clientX - this.dragstart!.x,
|
|
122
|
-
y: e.clientY - this.dragstart!.y
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
requestAnimationFrame(() => {
|
|
128
|
-
dispatchEvent(new Event('resize'))
|
|
129
|
-
delete this.dragstart
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
document.body.style.cursor = ''
|
|
133
|
-
document.body.style.userSelect = ''
|
|
134
|
-
|
|
135
|
-
e.stopPropagation()
|
|
136
|
-
}
|
|
137
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { LitElement, html, css, PropertyValues, nothing } from 'lit'
|
|
2
|
-
import { customElement, property, query } from 'lit/decorators.js'
|
|
3
|
-
|
|
4
|
-
@customElement('ox-split-pane')
|
|
5
|
-
export class OxSplitPane extends LitElement {
|
|
6
|
-
static styles = css`
|
|
7
|
-
:host {
|
|
8
|
-
display: flex;
|
|
9
|
-
flex-direction: var(--flex-direction, column);
|
|
10
|
-
|
|
11
|
-
width: 100%;
|
|
12
|
-
height: 100%;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
#splitter {
|
|
16
|
-
background-color: #ccc;
|
|
17
|
-
cursor: var(--cursor-shape, col-resize);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
#splitter {
|
|
21
|
-
background-color: #ccc;
|
|
22
|
-
cursor: var(--cursor-shape, col-resize);
|
|
23
|
-
color: var(--md-sys-color-on-primary-container, #ccc);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
:host([direction='row']) #splitter {
|
|
27
|
-
height: 100%;
|
|
28
|
-
width: 4px;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
:host([direction='column']) #splitter {
|
|
32
|
-
width: 100%;
|
|
33
|
-
height: 4px;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
::slotted(*) {
|
|
37
|
-
overflow: hidden;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
slot[name='front']::slotted(*) {
|
|
41
|
-
flex: var(--split-ratio, 0.5);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
slot[name='back']::slotted(*) {
|
|
45
|
-
flex: calc(1 - var(--split-ratio, 0.5));
|
|
46
|
-
}
|
|
47
|
-
`
|
|
48
|
-
|
|
49
|
-
@property({ type: String, attribute: true }) direction: string = 'row'
|
|
50
|
-
@property({ type: Number, attribute: true }) ratio: number = 0.5
|
|
51
|
-
@property({ type: Boolean, attribute: true }) resizable: boolean = false
|
|
52
|
-
|
|
53
|
-
@query('#splitter') splitter!: HTMLDivElement
|
|
54
|
-
|
|
55
|
-
render() {
|
|
56
|
-
return html`
|
|
57
|
-
<slot name="front"></slot>
|
|
58
|
-
${this.resizable
|
|
59
|
-
? html`<div id="splitter" @mousedown=${this.startDragging} direction=${this.direction}></div>`
|
|
60
|
-
: nothing}
|
|
61
|
-
<slot name="back"></slot>
|
|
62
|
-
`
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async updated(changes: PropertyValues<this>) {
|
|
66
|
-
if (changes.has('direction')) {
|
|
67
|
-
this.style.setProperty('--flex-direction', this.direction)
|
|
68
|
-
this.style.setProperty('--cursor-shape', this.direction == 'row' ? 'col-resize' : 'row-resize')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (changes.has('ratio')) {
|
|
72
|
-
this.style.setProperty('--split-ratio', String(this.ratio))
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
startDragging(e: MouseEvent) {
|
|
77
|
-
e.stopPropagation()
|
|
78
|
-
e.preventDefault()
|
|
79
|
-
|
|
80
|
-
document.addEventListener('mousemove', this.drag)
|
|
81
|
-
document.addEventListener('mouseup', this.stopDragging)
|
|
82
|
-
|
|
83
|
-
document.body.style.cursor = this.direction == 'row' ? 'col-resize' : 'row-resize'
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
drag = (e: MouseEvent) => {
|
|
87
|
-
e.stopPropagation()
|
|
88
|
-
e.preventDefault()
|
|
89
|
-
|
|
90
|
-
const { width, height, left, top } = this.getBoundingClientRect()
|
|
91
|
-
|
|
92
|
-
const mouseX = e.clientX - left
|
|
93
|
-
const mouseY = e.clientY - top
|
|
94
|
-
|
|
95
|
-
if (this.direction == 'row') {
|
|
96
|
-
const totalWidth = this.offsetWidth
|
|
97
|
-
this.ratio = mouseX / width
|
|
98
|
-
} else {
|
|
99
|
-
const totalHeight = this.offsetHeight
|
|
100
|
-
this.ratio = mouseY / height
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
stopDragging = (e: MouseEvent) => {
|
|
105
|
-
e.stopPropagation()
|
|
106
|
-
e.preventDefault()
|
|
107
|
-
|
|
108
|
-
document.removeEventListener('mousemove', this.drag)
|
|
109
|
-
document.removeEventListener('mouseup', this.stopDragging)
|
|
110
|
-
|
|
111
|
-
document.body.style.cursor = 'auto'
|
|
112
|
-
}
|
|
113
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import './initializer'
|
|
2
|
-
|
|
3
|
-
export { PopupHandle, PopupOptions } from '@operato/popup'
|
|
4
|
-
|
|
5
|
-
export * from './layouts/ox-snack-bar.js'
|
|
6
|
-
export * from './layouts/ox-header-bar.js'
|
|
7
|
-
export * from './layouts/ox-nav-bar.js'
|
|
8
|
-
export * from './layouts/ox-aside-bar.js'
|
|
9
|
-
export * from './layouts/ox-footer-bar.js'
|
|
10
|
-
export * from './layouts/ox-page-header-bar.js'
|
|
11
|
-
export * from './layouts/ox-page-footer-bar.js'
|
|
12
|
-
|
|
13
|
-
export * from './actions/layout'
|
|
14
|
-
export * from './actions/snackbar'
|
|
15
|
-
|
|
16
|
-
export * from './components/ox-split-pane'
|