@operato/popup 8.0.0-alpha.51 → 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 +17 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/.editorconfig +0 -29
- package/.storybook/main.js +0 -3
- package/.storybook/preview.js +0 -52
- package/.storybook/server.mjs +0 -8
- package/src/index.ts +0 -7
- package/src/open-popup.ts +0 -166
- package/src/ox-floating-overlay.ts +0 -618
- package/src/ox-popup-list.ts +0 -577
- package/src/ox-popup-menu.ts +0 -247
- package/src/ox-popup-menuitem.ts +0 -187
- package/src/ox-popup.ts +0 -400
- package/src/ox-prompt.ts +0 -549
- package/src/position-converter.ts +0 -37
- package/stories/open-popup.stories.ts +0 -104
- package/stories/ox-popup-list-sortable.stories.ts +0 -215
- package/stories/ox-popup-list.stories.ts +0 -121
- package/stories/ox-popup-menu.stories.ts +0 -188
- package/stories/ox-popup.stories.ts +0 -79
- package/stories/ox-prompt-icon.stories.ts +0 -87
- package/stories/ox-prompt-normal.stories.ts +0 -80
- package/stories/ox-prompt.stories.ts +0 -82
- package/tsconfig.json +0 -25
- package/web-dev-server.config.mjs +0 -27
- package/web-test-runner.config.mjs +0 -41
@@ -1,618 +0,0 @@
|
|
1
|
-
import '@material/web/icon/icon.js'
|
2
|
-
// 순환 참조가 되어서 일단 코멘트 처리함.
|
3
|
-
// import '@operato/input/ox-input-search.js'
|
4
|
-
|
5
|
-
import { css, html, LitElement, PropertyValues } from 'lit'
|
6
|
-
import { customElement, property, query } from 'lit/decorators.js'
|
7
|
-
import { ifDefined } from 'lit/directives/if-defined.js'
|
8
|
-
|
9
|
-
import { ScrollbarStyles } from '@operato/styles'
|
10
|
-
import { isHandheldDevice } from '@operato/utils'
|
11
|
-
|
12
|
-
function getPoint(e: Event): { x: number; y: number } | undefined {
|
13
|
-
if ((e as MouseEvent).button == 0) {
|
14
|
-
return {
|
15
|
-
x: (e as MouseEvent).clientX,
|
16
|
-
y: (e as MouseEvent).clientY
|
17
|
-
}
|
18
|
-
} else if ((e as TouchEvent).touches?.length == 1) {
|
19
|
-
const touch = (e as TouchEvent).touches[0]
|
20
|
-
return {
|
21
|
-
x: touch.clientX,
|
22
|
-
y: touch.clientY
|
23
|
-
}
|
24
|
-
} else {
|
25
|
-
return
|
26
|
-
}
|
27
|
-
}
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Custom element for creating floating overlays.
|
31
|
-
* These overlays can have various properties like direction, size, title, and more.
|
32
|
-
* They are often used for modal dialogs, pop-ups, and similar UI elements.
|
33
|
-
*/
|
34
|
-
@customElement('ox-floating-overlay')
|
35
|
-
export class OxFloatingOverlay extends LitElement {
|
36
|
-
static styles = [
|
37
|
-
ScrollbarStyles,
|
38
|
-
css`
|
39
|
-
/* for layout style */
|
40
|
-
:host {
|
41
|
-
position: relative;
|
42
|
-
z-index: var(--z-index, 10);
|
43
|
-
box-shadow: 2px 3px 10px 5px rgba(0, 0, 0, 0.15);
|
44
|
-
}
|
45
|
-
|
46
|
-
:host([hovering='edge']) {
|
47
|
-
/* edge hovering 인 경우에는 상위 relative position 크기와 위치를 반영한다. */
|
48
|
-
position: initial;
|
49
|
-
}
|
50
|
-
|
51
|
-
#backdrop {
|
52
|
-
position: fixed;
|
53
|
-
left: 0;
|
54
|
-
top: 0;
|
55
|
-
|
56
|
-
width: 100vw;
|
57
|
-
height: 100vh;
|
58
|
-
height: 100dvh;
|
59
|
-
|
60
|
-
background-color: var(--md-sys-color-shadow, #000);
|
61
|
-
opacity: 0.4;
|
62
|
-
}
|
63
|
-
|
64
|
-
[overlayed] {
|
65
|
-
position: absolute;
|
66
|
-
|
67
|
-
display: flex;
|
68
|
-
flex-direction: column;
|
69
|
-
overflow: hidden;
|
70
|
-
}
|
71
|
-
|
72
|
-
[overlayed][hovering='center'] {
|
73
|
-
position: fixed;
|
74
|
-
|
75
|
-
left: 50%;
|
76
|
-
top: 50%;
|
77
|
-
transform: translate(-50%, -50%);
|
78
|
-
|
79
|
-
opacity: 0;
|
80
|
-
border: 2px solid var(--md-sys-color-primary);
|
81
|
-
}
|
82
|
-
|
83
|
-
[overlayed][hovering='center'][opened] {
|
84
|
-
opacity: 1;
|
85
|
-
transition: opacity 0.3s ease-in;
|
86
|
-
background-color: var(--md-sys-color-surface-container-lowest);
|
87
|
-
}
|
88
|
-
|
89
|
-
[hovering='center'] {
|
90
|
-
width: var(--overlay-center-normal-width, 60%);
|
91
|
-
height: var(--overlay-center-normal-height, 60%);
|
92
|
-
}
|
93
|
-
|
94
|
-
[hovering='center'][size='small'] {
|
95
|
-
width: var(--overlay-center-small-width, 40%);
|
96
|
-
height: var(--overlay-center-small-height, 40%);
|
97
|
-
}
|
98
|
-
|
99
|
-
[hovering='center'][size='large'] {
|
100
|
-
width: var(--overlay-center-large-width, 100%);
|
101
|
-
height: var(--overlay-center-large-height, 100%);
|
102
|
-
}
|
103
|
-
|
104
|
-
[header] {
|
105
|
-
--help-icon-color: var(--md-sys-color-on-primary-container);
|
106
|
-
--help-icon-hover-color: var(--md-sys-color-on-primary-container);
|
107
|
-
|
108
|
-
pointer-events: initial;
|
109
|
-
}
|
110
|
-
|
111
|
-
[content] {
|
112
|
-
flex: 1;
|
113
|
-
overflow: hidden;
|
114
|
-
}
|
115
|
-
|
116
|
-
::slotted(*) {
|
117
|
-
box-sizing: border-box;
|
118
|
-
pointer-events: initial;
|
119
|
-
}
|
120
|
-
|
121
|
-
[hovering='center'] [content] ::slotted(*) {
|
122
|
-
width: 100%;
|
123
|
-
height: 100%;
|
124
|
-
}
|
125
|
-
[direction='up'],
|
126
|
-
[direction='down'] {
|
127
|
-
width: 100%;
|
128
|
-
|
129
|
-
max-height: 0;
|
130
|
-
transition: max-height 0.7s ease-in;
|
131
|
-
}
|
132
|
-
[direction='up'] {
|
133
|
-
bottom: 0;
|
134
|
-
}
|
135
|
-
[direction='down'] {
|
136
|
-
top: 0;
|
137
|
-
}
|
138
|
-
|
139
|
-
[direction='up'][opened],
|
140
|
-
[direction='down'][opened] {
|
141
|
-
max-height: 100vh;
|
142
|
-
max-height: 100dvh;
|
143
|
-
}
|
144
|
-
|
145
|
-
[settled][direction='down'] [content],
|
146
|
-
[settled][direction='up'] [content] {
|
147
|
-
overflow-y: auto;
|
148
|
-
}
|
149
|
-
|
150
|
-
[direction='left'],
|
151
|
-
[direction='right'] {
|
152
|
-
height: 100%;
|
153
|
-
|
154
|
-
max-width: 0;
|
155
|
-
transition: max-width 0.5s ease-in;
|
156
|
-
}
|
157
|
-
[direction='left'] {
|
158
|
-
right: 0;
|
159
|
-
}
|
160
|
-
[direction='right'] {
|
161
|
-
left: 0;
|
162
|
-
}
|
163
|
-
|
164
|
-
[direction='left'][opened],
|
165
|
-
[direction='right'][opened] {
|
166
|
-
max-width: 100vw;
|
167
|
-
}
|
168
|
-
|
169
|
-
[settled][direction='left'] [content],
|
170
|
-
[settled][direction='right'] [content] {
|
171
|
-
overflow-x: auto;
|
172
|
-
}
|
173
|
-
|
174
|
-
@media screen and (max-width: 460px) {
|
175
|
-
[direction='up'],
|
176
|
-
[direction='down'] {
|
177
|
-
max-height: 100vh;
|
178
|
-
max-height: 100dvh;
|
179
|
-
}
|
180
|
-
|
181
|
-
[direction='left'],
|
182
|
-
[direction='right'] {
|
183
|
-
max-width: 100vw;
|
184
|
-
}
|
185
|
-
}
|
186
|
-
`,
|
187
|
-
css`
|
188
|
-
/* for header style */
|
189
|
-
[header] {
|
190
|
-
display: flex;
|
191
|
-
flex-direction: row;
|
192
|
-
align-items: center;
|
193
|
-
background-color: var(--md-sys-color-primary);
|
194
|
-
font-weight: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500));
|
195
|
-
color: var(--md-sys-color-on-primary);
|
196
|
-
}
|
197
|
-
|
198
|
-
slot[name='header'] {
|
199
|
-
flex: 1;
|
200
|
-
|
201
|
-
display: flex;
|
202
|
-
flex-direction: row;
|
203
|
-
align-items: center;
|
204
|
-
justify-content: center;
|
205
|
-
text-transform: capitalize;
|
206
|
-
}
|
207
|
-
|
208
|
-
[name='header']::slotted(*) {
|
209
|
-
margin: 0 auto;
|
210
|
-
}
|
211
|
-
|
212
|
-
[name='header'] > h1 {
|
213
|
-
font-size: var(--md-sys-typescale-title-medium-size, 1rem);
|
214
|
-
margin-block: 0.4rem;
|
215
|
-
}
|
216
|
-
|
217
|
-
[historyback] {
|
218
|
-
margin-left: var(--spacing-medium);
|
219
|
-
margin-right: auto;
|
220
|
-
}
|
221
|
-
|
222
|
-
[close] {
|
223
|
-
margin-left: auto;
|
224
|
-
margin-right: var(--spacing-medium);
|
225
|
-
}
|
226
|
-
|
227
|
-
[historyback],
|
228
|
-
[close] {
|
229
|
-
display: none;
|
230
|
-
}
|
231
|
-
|
232
|
-
[closable][close] {
|
233
|
-
display: block;
|
234
|
-
cursor: pointer;
|
235
|
-
}
|
236
|
-
|
237
|
-
[search] ox-help-icon {
|
238
|
-
color: var(--md-sys-color-on-secondary-container);
|
239
|
-
}
|
240
|
-
|
241
|
-
[search] {
|
242
|
-
--help-icon-color: var(--md-sys-color-primary);
|
243
|
-
--help-icon-hover-color: var(--md-sys-color-primary);
|
244
|
-
--help-icon-opacity: 0.2;
|
245
|
-
--help-icon-size: 20px;
|
246
|
-
|
247
|
-
--md-icon-size: 20px;
|
248
|
-
|
249
|
-
--input-search-padding: var(--spacing-medium);
|
250
|
-
--input-search-focus-border-bottom: none;
|
251
|
-
--input-search-font: normal 16px var(--theme-font);
|
252
|
-
|
253
|
-
display: flex;
|
254
|
-
justify-content: space-between;
|
255
|
-
align-items: center;
|
256
|
-
|
257
|
-
align-self: center;
|
258
|
-
color: var(--md-sys-color-primary);
|
259
|
-
background-color: var(--md-sys-color-on-primary);
|
260
|
-
border-radius: 999em;
|
261
|
-
padding: 0 var(--spacing-medium);
|
262
|
-
}
|
263
|
-
|
264
|
-
[search] > * {
|
265
|
-
align-self: center;
|
266
|
-
}
|
267
|
-
|
268
|
-
ox-input-search {
|
269
|
-
color: var(--md-sys-color-primary);
|
270
|
-
background-color: var(--md-sys-color-on-primary);
|
271
|
-
border-radius: var(--md-sys-shape-corner-full);
|
272
|
-
}
|
273
|
-
|
274
|
-
@media screen and (max-width: 460px) {
|
275
|
-
[closable][historyback] {
|
276
|
-
display: block;
|
277
|
-
}
|
278
|
-
|
279
|
-
[closable][close] {
|
280
|
-
display: none;
|
281
|
-
}
|
282
|
-
}
|
283
|
-
`
|
284
|
-
]
|
285
|
-
|
286
|
-
/**
|
287
|
-
* A boolean property that determines whether a backdrop should be displayed behind the overlay.
|
288
|
-
* Backdrop provides a semi-transparent background that covers the entire screen when the overlay is open.
|
289
|
-
*/
|
290
|
-
@property({ type: Boolean }) backdrop?: boolean = false
|
291
|
-
|
292
|
-
/**
|
293
|
-
* A string property that specifies the direction in which the overlay should appear.
|
294
|
-
* Possible values are: 'up', 'down', 'left', or 'right'.
|
295
|
-
*/
|
296
|
-
@property({ type: String }) direction?: 'up' | 'down' | 'left' | 'right'
|
297
|
-
|
298
|
-
/**
|
299
|
-
* A string property that reflects the hovering state of the overlay.
|
300
|
-
* Possible values are: 'center', 'edge', or 'next'.
|
301
|
-
*/
|
302
|
-
@property({ type: String, reflect: true }) hovering?: 'center' | 'edge' | 'next'
|
303
|
-
|
304
|
-
/**
|
305
|
-
* A string property that specifies the size of the overlay.
|
306
|
-
* Possible values are: 'small', 'medium', or 'large'.
|
307
|
-
*/
|
308
|
-
@property({ type: String }) size?: 'small' | 'medium' | 'large'
|
309
|
-
|
310
|
-
/**
|
311
|
-
* A string property that represents the name of the overlay.
|
312
|
-
* This can be used for identification or other purposes.
|
313
|
-
*/
|
314
|
-
@property({ type: String }) name?: string
|
315
|
-
|
316
|
-
/**
|
317
|
-
* A string property that sets the title of the overlay.
|
318
|
-
* The title is typically displayed in the header of the overlay.
|
319
|
-
*/
|
320
|
-
@property({ type: String }) title: string = ''
|
321
|
-
|
322
|
-
/**
|
323
|
-
* A boolean property that determines whether the overlay can be closed by the user.
|
324
|
-
* If set to true, a close button will be displayed in the header.
|
325
|
-
*/
|
326
|
-
@property({ type: Boolean }) closable?: boolean = false
|
327
|
-
|
328
|
-
/**
|
329
|
-
* An object property that can hold custom properties for the template of the overlay.
|
330
|
-
* These properties can be used to customize the template's behavior.
|
331
|
-
*/
|
332
|
-
@property({ type: Object }) templateProperties: any
|
333
|
-
|
334
|
-
/**
|
335
|
-
* An object property that can hold information related to help or assistance for the overlay.
|
336
|
-
* This information may be used to provide additional guidance to users.
|
337
|
-
*/
|
338
|
-
@property({ type: Object }) help: any
|
339
|
-
|
340
|
-
/**
|
341
|
-
* A boolean property that determines whether the overlay is considered historical.
|
342
|
-
* Historical overlays may have specific behavior or interactions, such as navigating back in history.
|
343
|
-
*/
|
344
|
-
@property({ type: Boolean }) historical?: boolean = false
|
345
|
-
|
346
|
-
/**
|
347
|
-
* A boolean property that determines whether the overlay can be moved by dragging.
|
348
|
-
* If set to true, the overlay can be repositioned by dragging its header.
|
349
|
-
*/
|
350
|
-
@property({ type: Boolean }) movable?: boolean = false
|
351
|
-
|
352
|
-
/**
|
353
|
-
* An object property that can hold information related to a search feature within the overlay.
|
354
|
-
* It can include properties like 'value', 'handler', and 'placeholder'.
|
355
|
-
*/
|
356
|
-
@property({ type: Object }) search?: {
|
357
|
-
value?: string
|
358
|
-
handler?: (instance: any, value: string) => void
|
359
|
-
placeholder?: string
|
360
|
-
}
|
361
|
-
|
362
|
-
/**
|
363
|
-
* An object property that can hold information related to a filter feature within the overlay.
|
364
|
-
* It can include a 'handler' function for filtering content.
|
365
|
-
*/
|
366
|
-
@property({ type: Object }) filter?: { handler?: (instance: any) => void }
|
367
|
-
|
368
|
-
/**
|
369
|
-
* A numeric property that specifies the z-index of the overlay.
|
370
|
-
* The z-index determines the stacking order of the overlay in relation to other elements on the page.
|
371
|
-
*/
|
372
|
-
@property({ type: Number, attribute: 'z-index' }) zIndex?: number
|
373
|
-
|
374
|
-
private dragStart?: { x: number; y: number }
|
375
|
-
private dragEndHandler = this.onDragEnd.bind(this) as EventListener
|
376
|
-
private dragMoveHandler = this.onDragMove.bind(this) as EventListener
|
377
|
-
|
378
|
-
@query('[overlayed]') overlayed!: HTMLDivElement
|
379
|
-
@query('[content]') content!: HTMLDivElement
|
380
|
-
|
381
|
-
render() {
|
382
|
-
const direction = this.hovering == 'center' ? undefined : this.direction
|
383
|
-
|
384
|
-
const { value = '', handler: searchHandler, placeholder = '', autofocus = true } = this.search || ({} as any)
|
385
|
-
const { handler: filterHandler } = this.filter || ({} as any)
|
386
|
-
|
387
|
-
const searchable = typeof searchHandler == 'function'
|
388
|
-
const filterable = typeof filterHandler == 'function'
|
389
|
-
|
390
|
-
return html`
|
391
|
-
${Boolean(this.backdrop)
|
392
|
-
? html`
|
393
|
-
<div
|
394
|
-
id="backdrop"
|
395
|
-
?hidden=${!this.backdrop}
|
396
|
-
@click=${(e: Event) => this.onClose(e, true /* escape */)}
|
397
|
-
></div>
|
398
|
-
`
|
399
|
-
: html``}
|
400
|
-
|
401
|
-
<div
|
402
|
-
overlayed
|
403
|
-
hovering=${this.hovering || 'center'}
|
404
|
-
direction=${ifDefined(direction)}
|
405
|
-
size=${this.size || 'medium'}
|
406
|
-
@close-overlay=${(e: Event) => {
|
407
|
-
e.stopPropagation()
|
408
|
-
this.onClose(e)
|
409
|
-
}}
|
410
|
-
@transitionstart=${(e: Event) => {
|
411
|
-
/* to hide scrollbar during transition */
|
412
|
-
;(e.target as HTMLElement).removeAttribute('settled')
|
413
|
-
}}
|
414
|
-
@transitionend=${(e: Event) => {
|
415
|
-
;(e.target as HTMLElement).setAttribute('settled', '')
|
416
|
-
}}
|
417
|
-
@click=${(e: MouseEvent) => {
|
418
|
-
if (this.backdrop && e.target === this.content) {
|
419
|
-
this.onClose(e, true /* escape */)
|
420
|
-
}
|
421
|
-
}}
|
422
|
-
>
|
423
|
-
<div
|
424
|
-
header
|
425
|
-
@mousedown=${this.onDragStart.bind(this)}
|
426
|
-
@touchstart=${this.onDragStart.bind(this)}
|
427
|
-
draggable="false"
|
428
|
-
>
|
429
|
-
<md-icon @click=${(e: Event) => this.onClose(e)} ?closable=${this.closable} historyback>arrow_back</md-icon>
|
430
|
-
${this.movable ? html`<md-icon>drag_indicator</md-icon>` : html``}
|
431
|
-
<slot name="header">
|
432
|
-
${this.title || this.closable
|
433
|
-
? html`
|
434
|
-
<h1>
|
435
|
-
${this.title || ''} ${this.help
|
436
|
-
? html`<ox-help-icon .topic=${this.help}></ox-help-icon>`
|
437
|
-
: html``}
|
438
|
-
</h1>
|
439
|
-
`
|
440
|
-
: html``}
|
441
|
-
${searchable || filterable
|
442
|
-
? html`
|
443
|
-
<div search>
|
444
|
-
${searchable
|
445
|
-
? html` <ox-input-search
|
446
|
-
.placeholder=${placeholder}
|
447
|
-
.value=${value || ''}
|
448
|
-
?autofocus=${autofocus}
|
449
|
-
@change=${(e: Event) => {
|
450
|
-
searchHandler(this.firstElementChild, (e.target as any).value)
|
451
|
-
}}
|
452
|
-
></ox-input-search>`
|
453
|
-
: html``}
|
454
|
-
${this.help && searchable ? html`<ox-help-icon .topic=${this.help}></ox-help-icon>` : html``}
|
455
|
-
${filterable
|
456
|
-
? html`<md-icon @click=${(e: MouseEvent) => filterHandler(this.firstElementChild)}>tune</md-icon>`
|
457
|
-
: html``}
|
458
|
-
</div>
|
459
|
-
`
|
460
|
-
: html``}
|
461
|
-
${this.help && !searchable && !this.title /* help only */
|
462
|
-
? html`<ox-help-icon .topic=${this.help}></ox-help-icon>`
|
463
|
-
: html``}
|
464
|
-
</slot>
|
465
|
-
<md-icon @click=${(e: Event) => this.onClose(e)} ?closable=${this.closable} close>close</md-icon>
|
466
|
-
</div>
|
467
|
-
|
468
|
-
<div content>
|
469
|
-
<slot> </slot>
|
470
|
-
</div>
|
471
|
-
</div>
|
472
|
-
`
|
473
|
-
}
|
474
|
-
|
475
|
-
updated(changes: PropertyValues<this>) {
|
476
|
-
if (changes.has('templateProperties') && this.templateProperties) {
|
477
|
-
var template = this.firstElementChild
|
478
|
-
if (template) {
|
479
|
-
for (let prop in this.templateProperties) {
|
480
|
-
//@ts-ignore
|
481
|
-
template[prop] = this.templateProperties[prop]
|
482
|
-
}
|
483
|
-
}
|
484
|
-
}
|
485
|
-
}
|
486
|
-
|
487
|
-
firstUpdated() {
|
488
|
-
if (this.zIndex) {
|
489
|
-
this.style.setProperty('--z-index', String(this.zIndex))
|
490
|
-
}
|
491
|
-
|
492
|
-
requestAnimationFrame(() => {
|
493
|
-
/* transition(animation) 효과를 위해 'opened' 속성을 변화시킨다. */
|
494
|
-
this.overlayed?.setAttribute('opened', 'true')
|
495
|
-
})
|
496
|
-
}
|
497
|
-
|
498
|
-
connectedCallback(): void {
|
499
|
-
super.connectedCallback()
|
500
|
-
|
501
|
-
this.movable = this.movable && !isHandheldDevice()
|
502
|
-
|
503
|
-
if (this.movable) {
|
504
|
-
document.addEventListener('mouseup', this.dragEndHandler)
|
505
|
-
document.addEventListener('touchend', this.dragEndHandler)
|
506
|
-
document.addEventListener('touchcancel', this.dragEndHandler)
|
507
|
-
document.addEventListener('mousemove', this.dragMoveHandler)
|
508
|
-
document.addEventListener('touchmove', this.dragMoveHandler)
|
509
|
-
}
|
510
|
-
}
|
511
|
-
|
512
|
-
disconnectedCallback() {
|
513
|
-
document.dispatchEvent(
|
514
|
-
new CustomEvent('overlay-closed', {
|
515
|
-
detail: this.name
|
516
|
-
})
|
517
|
-
)
|
518
|
-
|
519
|
-
if (this.movable) {
|
520
|
-
document.removeEventListener('mouseup', this.dragEndHandler!)
|
521
|
-
document.removeEventListener('touchend', this.dragEndHandler!)
|
522
|
-
document.removeEventListener('touchcancel', this.dragEndHandler!)
|
523
|
-
document.removeEventListener('mousemove', this.dragMoveHandler!)
|
524
|
-
document.removeEventListener('touchmove', this.dragMoveHandler!)
|
525
|
-
}
|
526
|
-
|
527
|
-
super.disconnectedCallback()
|
528
|
-
}
|
529
|
-
|
530
|
-
onDragStart(e: Event) {
|
531
|
-
if (!this.movable) {
|
532
|
-
return
|
533
|
-
}
|
534
|
-
|
535
|
-
const point = getPoint(e)
|
536
|
-
|
537
|
-
if (point) {
|
538
|
-
this.dragStart = point
|
539
|
-
e.stopPropagation()
|
540
|
-
return false
|
541
|
-
}
|
542
|
-
}
|
543
|
-
|
544
|
-
onDragMove(e: Event) {
|
545
|
-
if (!this.movable || !this.dragStart) {
|
546
|
-
return false
|
547
|
-
}
|
548
|
-
|
549
|
-
const point = getPoint(e)
|
550
|
-
|
551
|
-
if (!point) {
|
552
|
-
return false
|
553
|
-
}
|
554
|
-
|
555
|
-
e.stopPropagation()
|
556
|
-
e.preventDefault()
|
557
|
-
|
558
|
-
const dragStart = point
|
559
|
-
var { x, y } = point
|
560
|
-
|
561
|
-
x -= this.dragStart.x
|
562
|
-
y -= this.dragStart.y
|
563
|
-
|
564
|
-
this.dragStart = dragStart
|
565
|
-
|
566
|
-
const overlayed = this.overlayed
|
567
|
-
|
568
|
-
var boundingRect = overlayed.getBoundingClientRect()
|
569
|
-
|
570
|
-
overlayed.style.left =
|
571
|
-
Math.min(document.body.offsetWidth - 40, Math.max(40 - overlayed.offsetWidth, boundingRect.left + x)) + 'px'
|
572
|
-
overlayed.style.top = Math.min(document.body.offsetHeight - 40, Math.max(0, boundingRect.top + y)) + 'px'
|
573
|
-
|
574
|
-
overlayed.style.transform = 'initial'
|
575
|
-
|
576
|
-
return false
|
577
|
-
}
|
578
|
-
|
579
|
-
onDragEnd(e: Event) {
|
580
|
-
if (this.movable && this.dragStart) {
|
581
|
-
e.stopPropagation()
|
582
|
-
e.preventDefault()
|
583
|
-
|
584
|
-
delete this.dragStart
|
585
|
-
}
|
586
|
-
}
|
587
|
-
|
588
|
-
/**
|
589
|
-
* A method that closes the overlay by removing it from its parent node in the DOM.
|
590
|
-
* When called, this method removes the overlay element, effectively hiding it from the user interface.
|
591
|
-
*/
|
592
|
-
close() {
|
593
|
-
this.parentNode?.removeChild(this)
|
594
|
-
}
|
595
|
-
|
596
|
-
onClose(e: Event, escape?: boolean) {
|
597
|
-
e.stopPropagation()
|
598
|
-
/* 현재 overlay state를 확인해서, 자신이 포함하고 있는 템플릿인 경우에 history.back() 한다. */
|
599
|
-
|
600
|
-
if (this.historical) {
|
601
|
-
var state = history.state
|
602
|
-
var overlay = (state || {}).overlay
|
603
|
-
|
604
|
-
if (!overlay || overlay.name !== this.name) {
|
605
|
-
return
|
606
|
-
}
|
607
|
-
|
608
|
-
/* Backdrop click 경우는 escape 시도라고 정의한다. overlay 속성이 escapable이 아닌 경우에는 동작하지 않는다. */
|
609
|
-
if (escape && !overlay.escapable) {
|
610
|
-
return true
|
611
|
-
}
|
612
|
-
|
613
|
-
history.back()
|
614
|
-
} else {
|
615
|
-
this.close()
|
616
|
-
}
|
617
|
-
}
|
618
|
-
}
|