@operato/gantt 7.1.27 → 7.1.32

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.
@@ -1,518 +0,0 @@
1
- import './ox-task-tooltip.js'
2
- import './ox-resource-chart.js'
3
-
4
- import { LitElement, html, css, PropertyValues, PropertyValueMap } from 'lit'
5
- import { customElement, property, query } from 'lit/decorators.js'
6
- import * as d3 from 'd3'
7
- import { locales } from './locales'
8
-
9
- import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
10
- import { ScrollbarStyles } from '@operato/styles'
11
- import { GanttChartController } from './gantt-chart-controller'
12
- import { Task, TimeScale } from './types.js'
13
- import { levelDown, levelUp } from './utils'
14
- import { OxTaskTooltip } from './ox-task-tooltip.js'
15
-
16
- @customElement('ox-gantt-chart')
17
- export class OxGanttChart extends LitElement {
18
- static styles = [
19
- MDTypeScaleStyles,
20
- ScrollbarStyles,
21
- css`
22
- :host {
23
- display: flex;
24
- overflow: hidden;
25
- position: relative;
26
- }
27
- div[chart-container] {
28
- display: block;
29
- overflow-x: auto;
30
- overflow-y: hidden;
31
- }
32
- svg {
33
- min-width: 100%;
34
- }
35
- svg[header] {
36
- display: block;
37
- min-width: 100%;
38
- box-sizing: border-box;
39
- height: 40px;
40
- color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));
41
- background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));
42
- border-bottom: 1px solid var(--ox-gantt-header-border-color, var(--md-sys-color-outline));
43
- position: sticky;
44
- top: 0;
45
- z-index: 1;
46
- }
47
- .scroll-buttons {
48
- position: absolute;
49
- top: 44px; /* 헤더 바로 아래 위치 */
50
- right: 4px;
51
- display: flex;
52
- align-items: center;
53
- gap: 2px;
54
- }
55
- .scroll-button {
56
- width: 10px;
57
- height: 10px;
58
- background-color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));
59
- clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
60
- cursor: pointer;
61
- transform: rotate(90deg);
62
- }
63
- .scroll-button.left {
64
- transform: rotate(-90deg);
65
- }
66
- .scroll-button.right {
67
- transform: rotate(90deg);
68
- }
69
- `
70
- ]
71
-
72
- @property({ type: String, attribute: 'from-date' }) fromDate: string = new Date(new Date().getFullYear(), 0, 1)
73
- .toISOString()
74
- .split('T')[0]
75
- @property({ type: String, attribute: 'to-date' }) toDate: string = new Date(new Date().getFullYear(), 11, 31)
76
- .toISOString()
77
- .split('T')[0]
78
- @property({ type: String, attribute: 'axis-scale' }) axisScale: TimeScale = 'week-day'
79
- @property({ type: Array }) tasks: Task[] = []
80
- @property({ type: String, attribute: 'selected-task-id' }) selectedTaskId?: string
81
- @property({ type: String }) locale: string = 'en-US'
82
- @property({ type: Object }) colorProvider!: (task: Task) => string
83
-
84
- @query('svg[header]') svgHeader!: SVGElement
85
- @query('svg[body]') svgBody!: SVGElement
86
- @query('[chart-container]') container!: HTMLDivElement
87
- @query('ox-task-tooltip') tooltip!: OxTaskTooltip
88
-
89
- private ganttChartController: GanttChartController
90
-
91
- constructor() {
92
- super()
93
- this.ganttChartController = new GanttChartController(this, this.fromDate, this.toDate, this.axisScale)
94
- }
95
-
96
- protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
97
- this.initHeaderGestureHandlers()
98
- }
99
-
100
- updated(changedProperties: PropertyValues<this>) {
101
- if (changedProperties.has('fromDate') || changedProperties.has('toDate')) {
102
- this.ganttChartController.updateRange(this.fromDate, this.toDate)
103
- }
104
-
105
- if (changedProperties.has('tasks')) {
106
- this.ganttChartController.setTasks(this.flattenTasks(this.tasks))
107
- this.svgBody.style.height = Math.max(this.tasks.length * 30, 2000) + 'px'
108
- }
109
-
110
- if (changedProperties.has('locale')) {
111
- this.updateLocale(this.locale)
112
- }
113
-
114
- if (changedProperties.has('selectedTaskId')) {
115
- this.ganttChartController.selectedTaskId = this.selectedTaskId
116
- }
117
-
118
- if (changedProperties.has('axisScale')) {
119
- this.ganttChartController.level = this.axisScale
120
- this.ganttChartController.updateTimeScale()
121
- }
122
-
123
- if (changedProperties.has('colorProvider')) {
124
- this.ganttChartController.setColorProvider(this.colorProvider)
125
- }
126
-
127
- this.ganttChartController.drawAxes(this.svgHeader)
128
- this.ganttChartController.drawBody(this.svgBody, this.tooltip)
129
- }
130
-
131
- render() {
132
- return html`
133
- <div
134
- chart-container
135
- @wheel=${(e: WheelEvent) => this.ganttChartController.handleWheelForBody(e, this.container)}
136
- @touchstart=${(e: TouchEvent) => this.ganttChartController.handleTouchStartForBody(e, this.container)}
137
- @touchmove=${(e: TouchEvent) => this.ganttChartController.handleTouchMoveForBody(e, this.container)}
138
- >
139
- <svg
140
- header
141
- @date-range-selected=${(e: CustomEvent) => this.handleDateRangeSelected(e)}
142
- @wheel=${this.handleWheelForHeader.bind(this)}
143
- ></svg>
144
- <svg body></svg>
145
- <div class="scroll-buttons">
146
- <div class="scroll-button left" @click=${this.scrollToStart}></div>
147
- <div class="scroll-button right" @click=${this.scrollToEnd}></div>
148
- </div>
149
- <ox-task-tooltip></ox-task-tooltip>
150
- </div>
151
- `
152
- }
153
-
154
- scrollToStart() {
155
- this.container.scrollTo({ left: 0, behavior: 'auto' })
156
-
157
- this.syncScrollPosition()
158
- }
159
-
160
- scrollToEnd() {
161
- this.container.scrollTo({ left: this.container.scrollWidth, behavior: 'auto' })
162
- this.syncScrollPosition()
163
- }
164
-
165
- syncScrollPosition() {
166
- const scrollLeft = this.container.scrollLeft
167
- const customEvent = new CustomEvent('scroll', {
168
- detail: { scrollLeft },
169
- bubbles: true,
170
- composed: true
171
- })
172
-
173
- this.dispatchEvent(customEvent)
174
- }
175
-
176
- setVerticalOffset(offset: number) {
177
- this.container.scrollTop = offset
178
- }
179
-
180
- getVerticalOffset(): number {
181
- return this.container.scrollTop
182
- }
183
-
184
- setHorizontalOffset(offset: number) {
185
- this.container.scrollLeft = offset
186
- }
187
-
188
- getHorizontalOffset(): number {
189
- return this.container.scrollLeft
190
- }
191
-
192
- flattenTasks(tasks: Task[], level: number = 0): Task[] {
193
- return tasks.flatMap(task =>
194
- task.collapsed ? [{ ...task, level }] : [{ ...task, level }, ...this.flattenTasks(task.children || [], level + 1)]
195
- )
196
- }
197
-
198
- // 나머지 메서드는 기존 코드와 동일하게 유지
199
- handleWheelForHeader(event: WheelEvent) {
200
- event.preventDefault()
201
- event.stopPropagation()
202
-
203
- const deltaModeFactor =
204
- event.deltaMode === WheelEvent.DOM_DELTA_LINE
205
- ? 16
206
- : event.deltaMode === WheelEvent.DOM_DELTA_PAGE
207
- ? this.container.clientHeight
208
- : 1
209
-
210
- // deltaY 값이 0인 경우, deltaX 값을 사용하여 확대/축소를 처리
211
- const delta = event.deltaY !== 0 ? event.deltaY : event.deltaX
212
- const adjustedDelta = delta * deltaModeFactor
213
-
214
- // 확대/축소 처리
215
- const zoomFactor = adjustedDelta < 0 ? 1.1 : 0.9
216
- this.ganttChartController.baseWidth *= zoomFactor
217
-
218
- if (this.ganttChartController.baseWidth > 40) {
219
- if (this.ganttChartController.level === 'week-day') {
220
- this.ganttChartController.baseWidth = 40
221
- } else {
222
- this.ganttChartController.level = levelDown(this.ganttChartController.level)
223
- this.ganttChartController.baseWidth = 30
224
- }
225
- } else if (this.ganttChartController.baseWidth < 30) {
226
- if (this.ganttChartController.level === 'year-quarter') {
227
- this.ganttChartController.baseWidth = 30
228
- }
229
- }
230
-
231
- if (this.ganttChartController.baseWidth < 20) {
232
- this.ganttChartController.level = levelUp(this.ganttChartController.level)
233
- this.ganttChartController.baseWidth = 30
234
- }
235
-
236
- this.ganttChartController.updateTimeScale()
237
- this.requestUpdate()
238
-
239
- // Dispatch custom event to sync with ox-resource-chart
240
- const customEvent = new CustomEvent('timescale-changed', {
241
- detail: {
242
- baseWidth: this.ganttChartController.baseWidth,
243
- level: this.ganttChartController.level
244
- },
245
- bubbles: true,
246
- composed: true
247
- })
248
- this.dispatchEvent(customEvent)
249
- }
250
-
251
- handleDateRangeSelected(event: CustomEvent) {
252
- const detail = event.detail
253
- this.dispatchEvent(new CustomEvent('date-range-selected', { detail }))
254
- }
255
-
256
- updateLocale(locale: string) {
257
- const localeDefinition = (locales as any)[locale || 'en-US']
258
- if (localeDefinition) {
259
- d3.timeFormatDefaultLocale(localeDefinition)
260
- this.ganttChartController.updateTimeScale()
261
- }
262
- }
263
-
264
- initHeaderGestureHandlers() {
265
- const header = d3.select(this.svgHeader)
266
-
267
- let isDragging = false
268
- let startX: number | null = null
269
- let lastTouchDistance: number | null = null
270
-
271
- const handleTouchStart = (event: TouchEvent) => {
272
- event.preventDefault()
273
-
274
- if (event.touches.length === 2) {
275
- lastTouchDistance = getTouchDistance(event.touches)
276
- } else {
277
- isDragging = true
278
- const touch = event.touches[0]
279
- const containerOffsetX = header.node()!.getBoundingClientRect().left
280
- startX = touch.clientX - containerOffsetX
281
- }
282
- }
283
-
284
- const handleTouchMove = (event: TouchEvent) => {
285
- event.preventDefault()
286
-
287
- if (event.touches.length === 2 && lastTouchDistance !== null) {
288
- const currentDistance = getTouchDistance(event.touches)
289
- const zoomFactor = currentDistance / lastTouchDistance
290
- this.ganttChartController.baseWidth *= zoomFactor
291
-
292
- if (this.ganttChartController.baseWidth > 60) {
293
- if (this.ganttChartController.level == 'year-quarter') {
294
- this.ganttChartController.baseWidth = 60
295
- } else {
296
- this.ganttChartController.level = levelUp(this.ganttChartController.level)
297
- this.ganttChartController.baseWidth = 30
298
- }
299
- } else if (this.ganttChartController.baseWidth < 30) {
300
- if (this.ganttChartController.level == 'week-day') {
301
- this.ganttChartController.baseWidth = 30
302
- } else {
303
- this.ganttChartController.level = levelDown(this.ganttChartController.level)
304
- this.ganttChartController.baseWidth = 60
305
- }
306
- }
307
-
308
- lastTouchDistance = currentDistance
309
- this.ganttChartController.updateTimeScale()
310
- this.requestUpdate()
311
-
312
- // Dispatch custom event to sync with ox-resource-chart
313
- const customEvent = new CustomEvent('timescale-changed', {
314
- detail: {
315
- baseWidth: this.ganttChartController.baseWidth,
316
- level: this.ganttChartController.level
317
- },
318
- bubbles: true,
319
- composed: true
320
- })
321
- this.dispatchEvent(customEvent)
322
- } else if (isDragging && startX !== null) {
323
- const touch = event.touches[0]
324
- const containerOffsetX = header.node()!.getBoundingClientRect().left
325
- const currentX = touch.clientX - containerOffsetX
326
- this.highlightSelection(startX, currentX)
327
- }
328
- }
329
-
330
- const handleTouchEnd = (event: TouchEvent) => {
331
- event.preventDefault()
332
-
333
- if (event.touches.length < 2) {
334
- lastTouchDistance = null
335
- }
336
-
337
- if (!isDragging || startX === null) {
338
- const touch = event.changedTouches[0]
339
- const containerOffsetX = header.node()!.getBoundingClientRect().left
340
- const clickX = touch.clientX - containerOffsetX
341
- this.finalizeSelection(clickX, clickX)
342
- return
343
- }
344
-
345
- const touch = event.changedTouches[0]
346
- const containerOffsetX = header.node()!.getBoundingClientRect().left
347
- const endX = touch.clientX - containerOffsetX
348
- this.finalizeSelection(startX, endX)
349
-
350
- isDragging = false
351
- startX = null
352
- }
353
-
354
- const getTouchDistance = (touches: TouchList): number => {
355
- const dx = touches[0].clientX - touches[1].clientX
356
- const dy = touches[0].clientY - touches[1].clientY
357
- return Math.sqrt(dx * dx + dy * dy)
358
- }
359
-
360
- const handleMouseDown = (event: MouseEvent) => {
361
- isDragging = true
362
- const containerOffsetX = header.node()!.getBoundingClientRect().left
363
- startX = event.clientX - containerOffsetX
364
- }
365
-
366
- const handleMouseMove = (event: MouseEvent) => {
367
- if (!isDragging || startX === null) return
368
-
369
- const containerOffsetX = header.node()!.getBoundingClientRect().left
370
- const currentX = event.clientX - containerOffsetX
371
- this.highlightSelection(startX, currentX)
372
- }
373
-
374
- const handleMouseUp = (event: MouseEvent) => {
375
- if (!isDragging || startX === null) {
376
- const containerOffsetX = header.node()!.getBoundingClientRect().left
377
- const clickX = event.clientX - containerOffsetX
378
- this.finalizeSelection(clickX, clickX)
379
- return
380
- }
381
-
382
- const containerOffsetX = header.node()!.getBoundingClientRect().left
383
- const endX = event.clientX - containerOffsetX
384
- this.finalizeSelection(startX, endX)
385
-
386
- isDragging = false
387
- startX = null
388
- }
389
-
390
- header.on('mousedown', handleMouseDown)
391
- header.on('mousemove', handleMouseMove)
392
- header.on('mouseup', handleMouseUp)
393
- header.on('touchstart', handleTouchStart)
394
- header.on('touchmove', handleTouchMove)
395
- header.on('touchend', handleTouchEnd)
396
- }
397
-
398
- highlightSelection(startX: number, endX: number) {
399
- const header = d3.select(this.svgHeader)
400
- const body = d3.select(this.svgBody)
401
-
402
- let startDate = this.ganttChartController.timeScale.invert(startX)
403
- let endDate = this.ganttChartController.timeScale.invert(endX)
404
-
405
- let start, end
406
-
407
- if (this.ganttChartController.level === 'week-day') {
408
- start = d3.timeDay.floor(d3.min([startDate, endDate])!)
409
- end = d3.timeDay.offset(d3.timeDay.ceil(d3.max([startDate, endDate])!), -1)
410
- } else if (this.ganttChartController.level === 'quarter-week') {
411
- start = d3.timeWeek.floor(d3.min([startDate, endDate])!)
412
- end = d3.timeDay.offset(d3.timeWeek.ceil(d3.max([startDate, endDate])!), -1)
413
- } else if (this.ganttChartController.level === 'year-month') {
414
- start = d3.timeMonth.floor(d3.min([startDate, endDate])!)
415
- end = d3.timeDay.offset(d3.timeMonth.ceil(d3.max([startDate, endDate])!), -1)
416
- } else if (this.ganttChartController.level === 'year-quarter') {
417
- start = d3.timeMonth.every(3)!.floor(d3.min([startDate, endDate])!)
418
- end = d3.timeDay.offset(d3.timeMonth.every(3)!.ceil(d3.max([startDate, endDate])!), -1)
419
- }
420
-
421
- header.selectAll('.selection-rect').remove()
422
- body.selectAll('.selection-rect').remove()
423
-
424
- header
425
- .append('rect')
426
- .attr('class', 'selection-rect')
427
- .attr('x', this.ganttChartController.timeScale(start!))
428
- .attr('y', 20)
429
- .attr(
430
- 'width',
431
- this.ganttChartController.timeScale(end!) -
432
- this.ganttChartController.timeScale(start!) +
433
- this.ganttChartController.baseWidth / this.ganttChartController.getScale()
434
- )
435
- .attr('height', 20)
436
- .attr('fill', 'var(--ox-gantt-selection-color, var(--md-sys-color-on-primary-container))')
437
- .attr('opacity', '.2')
438
-
439
- body
440
- .append('rect')
441
- .attr('class', 'selection-rect')
442
- .attr('x', this.ganttChartController.timeScale(start!))
443
- .attr('y', 0)
444
- .attr(
445
- 'width',
446
- this.ganttChartController.timeScale(end!) -
447
- this.ganttChartController.timeScale(start!) +
448
- this.ganttChartController.baseWidth / this.ganttChartController.getScale()
449
- )
450
- .attr('height', '100%')
451
- .attr('fill', 'var(--ox-gantt-selection-color, var(--md-sys-color-on-primary-container))')
452
- .attr('opacity', '.2')
453
- }
454
-
455
- finalizeSelection(startX: number, endX: number) {
456
- const header = d3.select(this.svgHeader)
457
- const body = d3.select(this.svgBody)
458
-
459
- let startDate = this.ganttChartController.timeScale.invert(startX)
460
- let endDate = this.ganttChartController.timeScale.invert(endX)
461
-
462
- let start, end
463
-
464
- if (this.ganttChartController.level === 'week-day') {
465
- start = d3.timeDay.floor(d3.min([startDate, endDate])!)
466
- end = d3.timeDay.offset(d3.timeDay.ceil(d3.max([startDate, endDate])!), -1)
467
- } else if (this.ganttChartController.level === 'quarter-week') {
468
- start = d3.timeWeek.floor(d3.min([startDate, endDate])!)
469
- end = d3.timeDay.offset(d3.timeWeek.ceil(d3.max([startDate, endDate])!), -1)
470
- } else if (this.ganttChartController.level === 'year-month') {
471
- start = d3.timeMonth.floor(d3.min([startDate, endDate])!)
472
- end = d3.timeDay.offset(d3.timeMonth.ceil(d3.max([startDate, endDate])!), -1)
473
- } else if (this.ganttChartController.level === 'year-quarter') {
474
- start = d3.timeMonth.every(3)!.floor(d3.min([startDate, endDate])!)
475
- end = d3.timeDay.offset(d3.timeMonth.every(3)!.ceil(d3.max([startDate, endDate])!), -1)
476
- }
477
-
478
- header.selectAll('.selection-rect').remove()
479
- body.selectAll('.selection-rect').remove()
480
-
481
- header
482
- .append('rect')
483
- .attr('class', 'selection-rect')
484
- .attr('x', this.ganttChartController.timeScale(start!))
485
- .attr('y', 20)
486
- .attr(
487
- 'width',
488
- this.ganttChartController.timeScale(end!) -
489
- this.ganttChartController.timeScale(start!) +
490
- this.ganttChartController.baseWidth / this.ganttChartController.getScale()
491
- )
492
- .attr('height', 20)
493
- .attr('fill', 'var(--ox-gantt-selection-color, var(--md-sys-color-on-primary-container))')
494
- .attr('opacity', '.2')
495
-
496
- body
497
- .append('rect')
498
- .attr('class', 'selection-rect')
499
- .attr('x', this.ganttChartController.timeScale(start!))
500
- .attr('y', 0)
501
- .attr(
502
- 'width',
503
- this.ganttChartController.timeScale(end!) -
504
- this.ganttChartController.timeScale(start!) +
505
- this.ganttChartController.baseWidth / this.ganttChartController.getScale()
506
- )
507
- .attr('height', '100%')
508
- .attr('fill', 'var(--ox-gantt-selection-color, var(--md-sys-color-on-primary-container))')
509
- .attr('opacity', '.2')
510
-
511
- const formatDate = d3.timeFormat('%Y-%m-%d')
512
- const customEvent = new CustomEvent('date-range-selected', {
513
- detail: { start: formatDate(start!), end: formatDate(end!) }
514
- })
515
-
516
- header.node()?.dispatchEvent(customEvent)
517
- }
518
- }
@@ -1,131 +0,0 @@
1
- import { LitElement, css, html } from 'lit'
2
- import { customElement } from 'lit/decorators.js'
3
-
4
- @customElement('ox-gantt-resize-splitter')
5
- export class OxGanttResizeSplitter extends LitElement {
6
- static styles = css`
7
- :host {
8
- position: relative;
9
- opacity: 0.7;
10
- background-color: var(--splitter-background-color);
11
- width: var(--width);
12
- height: var(--height);
13
- }
14
-
15
- :host(:hover) {
16
- background-color: var(--splitter-hover-background-color);
17
- }
18
-
19
- div {
20
- width: var(--width);
21
- height: var(--height);
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.setProperty('--width', '3px')
32
- this.style.setProperty('--height', '100%')
33
- this.style.cursor = 'col-resize'
34
- } else {
35
- this.style.setProperty('--height', '3px')
36
- this.style.setProperty('--width', '100%')
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
- private onMouseDown(e: MouseEvent) {
46
- this.dragstart = {
47
- x: e.clientX,
48
- y: e.clientY
49
- }
50
-
51
- this.dispatchEvent(
52
- new CustomEvent('splitter-dragstart', {
53
- bubbles: true,
54
- composed: true
55
- })
56
- )
57
-
58
- this.parentElement!.addEventListener('mousemove', this.onMouseMoveHandler)
59
- this.parentElement!.addEventListener('mouseup', this.onMouseUpHandler)
60
- window.addEventListener('mousemove', this.onMouseMoveHandler)
61
- window.addEventListener('mouseup', this.onMouseUpHandler)
62
-
63
- e.stopPropagation()
64
- }
65
-
66
- private onMouseMoveHandler = (e: MouseEvent) => this.onMouseMove(e)
67
- private onMouseUpHandler = (e: MouseEvent) => this.onMouseUp(e)
68
-
69
- private onMouseMove(e: MouseEvent) {
70
- if (!this.dragstart) {
71
- return
72
- }
73
-
74
- const parentRect = this.parentElement!.getBoundingClientRect()
75
- if (
76
- e.clientX < parentRect.left ||
77
- e.clientX > parentRect.right ||
78
- e.clientY < parentRect.top ||
79
- e.clientY > parentRect.bottom
80
- ) {
81
- this.onMouseUp(e)
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
-
98
- if (this.hasAttribute('vertical')) {
99
- document.body.style.cursor = 'col-resize'
100
- } else {
101
- document.body.style.cursor = 'row-resize'
102
- }
103
-
104
- document.body.style.userSelect = 'none'
105
-
106
- e.stopPropagation()
107
- }
108
-
109
- private onMouseUp(e: MouseEvent) {
110
- this.parentElement!.removeEventListener('mousemove', this.onMouseMoveHandler)
111
- this.parentElement!.removeEventListener('mouseup', this.onMouseUpHandler)
112
- window.removeEventListener('mousemove', this.onMouseMoveHandler)
113
- window.removeEventListener('mouseup', this.onMouseUpHandler)
114
-
115
- this.dispatchEvent(
116
- new CustomEvent('splitter-dragend', {
117
- bubbles: true,
118
- composed: true,
119
- detail: {
120
- x: e.clientX - this.dragstart!.x,
121
- y: e.clientY - this.dragstart!.y
122
- }
123
- })
124
- )
125
-
126
- document.body.style.cursor = ''
127
- document.body.style.userSelect = ''
128
-
129
- e.stopPropagation()
130
- }
131
- }