goblin-magic 1.0.3

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 (88) hide show
  1. package/.editorconfig +9 -0
  2. package/.zou-flow +2 -0
  3. package/eslint.config.js +65 -0
  4. package/magicNavigation.js +7 -0
  5. package/package.json +45 -0
  6. package/widgets/dialog/widget.js +78 -0
  7. package/widgets/element-helpers/element-has-direct-text.js +9 -0
  8. package/widgets/element-helpers/is-empty-area-element.js +17 -0
  9. package/widgets/element-helpers/is-flat-element.js +52 -0
  10. package/widgets/get-modifiers/get-modifiers.js +34 -0
  11. package/widgets/input-group/styles.js +74 -0
  12. package/widgets/input-group/widget.js +24 -0
  13. package/widgets/magic-action/styles.js +45 -0
  14. package/widgets/magic-action/widget.js +44 -0
  15. package/widgets/magic-background/bg-alps.jpg +0 -0
  16. package/widgets/magic-background/bg-fur.png +0 -0
  17. package/widgets/magic-background/bg-milkyway.png +0 -0
  18. package/widgets/magic-background/bg-space.jpg +0 -0
  19. package/widgets/magic-background/bg-synth.jpg +0 -0
  20. package/widgets/magic-background/bg-white.png +0 -0
  21. package/widgets/magic-background/styles.js +81 -0
  22. package/widgets/magic-background/widget.js +20 -0
  23. package/widgets/magic-box/styles.js +10 -0
  24. package/widgets/magic-box/widget.js +28 -0
  25. package/widgets/magic-box-old/styles.js +111 -0
  26. package/widgets/magic-box-old/widget.js +30 -0
  27. package/widgets/magic-button/styles.js +156 -0
  28. package/widgets/magic-button/widget.js +89 -0
  29. package/widgets/magic-checkbox/styles.js +116 -0
  30. package/widgets/magic-checkbox/widget.js +68 -0
  31. package/widgets/magic-color-field/styles.js +22 -0
  32. package/widgets/magic-color-field/widget.js +68 -0
  33. package/widgets/magic-date-field/styles.js +9 -0
  34. package/widgets/magic-date-field/widget.js +145 -0
  35. package/widgets/magic-datetime-field/styles.js +11 -0
  36. package/widgets/magic-datetime-field/widget.js +95 -0
  37. package/widgets/magic-dialog/styles.js +39 -0
  38. package/widgets/magic-dialog/widget.js +116 -0
  39. package/widgets/magic-div/styles.js +22 -0
  40. package/widgets/magic-div/widget.js +20 -0
  41. package/widgets/magic-emoji/styles.js +14 -0
  42. package/widgets/magic-emoji/widget.js +33 -0
  43. package/widgets/magic-emoji-picker/styles.js +21 -0
  44. package/widgets/magic-emoji-picker/widget.js +44 -0
  45. package/widgets/magic-inplace-input/styles.js +55 -0
  46. package/widgets/magic-inplace-input/widget.js +26 -0
  47. package/widgets/magic-input/styles.js +50 -0
  48. package/widgets/magic-input/widget.js +397 -0
  49. package/widgets/magic-label/styles.js +20 -0
  50. package/widgets/magic-label/widget.js +24 -0
  51. package/widgets/magic-navigation/service.js +1306 -0
  52. package/widgets/magic-navigation/styles.js +103 -0
  53. package/widgets/magic-navigation/view-context.js +15 -0
  54. package/widgets/magic-navigation/widget.js +540 -0
  55. package/widgets/magic-number-field/styles.js +10 -0
  56. package/widgets/magic-number-field/widget.js +103 -0
  57. package/widgets/magic-panel/styles.js +61 -0
  58. package/widgets/magic-panel/widget.js +63 -0
  59. package/widgets/magic-radio/styles.js +93 -0
  60. package/widgets/magic-radio/widget.js +74 -0
  61. package/widgets/magic-scroll/styles.js +22 -0
  62. package/widgets/magic-scroll/widget.js +20 -0
  63. package/widgets/magic-select/styles.js +16 -0
  64. package/widgets/magic-select/widget.js +134 -0
  65. package/widgets/magic-table/reducer.js +63 -0
  66. package/widgets/magic-table/styles.js +170 -0
  67. package/widgets/magic-table/widget.js +627 -0
  68. package/widgets/magic-tag/styles.js +32 -0
  69. package/widgets/magic-tag/widget.js +32 -0
  70. package/widgets/magic-text-field/styles.js +58 -0
  71. package/widgets/magic-text-field/widget.js +66 -0
  72. package/widgets/magic-time-field/styles.js +8 -0
  73. package/widgets/magic-time-field/widget.js +142 -0
  74. package/widgets/magic-timer/styles.js +30 -0
  75. package/widgets/magic-timer/widget.js +162 -0
  76. package/widgets/magic-zen/styles.js +61 -0
  77. package/widgets/magic-zen/widget.js +42 -0
  78. package/widgets/main-tabs/styles.js +106 -0
  79. package/widgets/main-tabs/widget.js +23 -0
  80. package/widgets/menu/styles.js +156 -0
  81. package/widgets/menu/test-menu.html +154 -0
  82. package/widgets/menu/widget.js +575 -0
  83. package/widgets/movable/widget.js +80 -0
  84. package/widgets/splitter/styles.js +57 -0
  85. package/widgets/splitter/widget.js +40 -0
  86. package/widgets/tab-layout/styles.js +31 -0
  87. package/widgets/tab-layout/widget.js +59 -0
  88. package/widgets/with-computed-size/widget.js +52 -0
@@ -0,0 +1,575 @@
1
+ import React from 'react';
2
+ import Widget from 'goblin-laboratory/widgets/widget';
3
+ import * as styles from './styles.js';
4
+ import Dialog from '../dialog/widget.js';
5
+ import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
6
+ import {faBars, faChevronRight} from '@fortawesome/free-solid-svg-icons';
7
+ import MagicButton from 'goblin-magic/widgets/magic-button/widget.js';
8
+ import WithComputedSize from '../with-computed-size/widget.js';
9
+
10
+ const MenuContext = React.createContext();
11
+ const MenuStateContext = React.createContext();
12
+
13
+ class MenuItem extends Widget {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.styles = styles;
17
+ }
18
+
19
+ /**
20
+ * @param {PointerEvent} event
21
+ * @param {Menu} menu
22
+ */
23
+ handleClick(event, menu) {
24
+ const {disabled = false} = this.props;
25
+ if (disabled) {
26
+ return;
27
+ }
28
+
29
+ this.props.onClick?.(event);
30
+ if (!event.nativeEvent.pointerType) {
31
+ // Keyboard action
32
+ if (this.props.onPointerUp && !this.props.onClick) {
33
+ this.props.onPointerUp?.(event);
34
+ }
35
+ if (!event.defaultPrevented) {
36
+ menu.close();
37
+ }
38
+ }
39
+ }
40
+
41
+ /**
42
+ * @param {PointerEvent} event
43
+ * @param {Menu} menu
44
+ */
45
+ handlePointerUp(event, menu) {
46
+ const {disabled = false} = this.props;
47
+ if (disabled) {
48
+ return;
49
+ }
50
+
51
+ this.props.onPointerUp?.(event);
52
+ if (!event.defaultPrevented) {
53
+ menu.close();
54
+ }
55
+ }
56
+
57
+ render() {
58
+ const {className = '', rightIcon, children, ...props} = this.props;
59
+ return (
60
+ <MenuContext.Consumer>
61
+ {(menu) => (
62
+ <button
63
+ {...props}
64
+ className={this.styles.classNames.menuItem + ' ' + className}
65
+ onPointerUp={(event) => this.handlePointerUp(event, menu)}
66
+ onClick={(event) => this.handleClick(event, menu)}
67
+ >
68
+ {children}
69
+ <div className={this.styles.classNames.menuItemRight}>
70
+ {rightIcon}
71
+ </div>
72
+ </button>
73
+ )}
74
+ </MenuContext.Consumer>
75
+ );
76
+ }
77
+ }
78
+
79
+ class MenuTitle extends Widget {
80
+ constructor() {
81
+ super(...arguments);
82
+ this.styles = styles;
83
+ }
84
+
85
+ render() {
86
+ const {className = '', children, ...props} = this.props;
87
+ return (
88
+ <div
89
+ {...props}
90
+ className={this.styles.classNames.menuTitle + ' ' + className}
91
+ >
92
+ {children}
93
+ <hr />
94
+ </div>
95
+ );
96
+ }
97
+ }
98
+
99
+ class Submenu extends Widget {
100
+ constructor() {
101
+ super(...arguments);
102
+ this.styles = styles;
103
+ this.handlePointerUp = this.handlePointerUp.bind(this);
104
+ }
105
+
106
+ handlePointerUp(event) {
107
+ event.preventDefault();
108
+ }
109
+
110
+ // handleKeyDown = (event) => {
111
+ // this.props.onKeyDown?.(event);
112
+ // if (event.key === 'ArrowRight') {
113
+ // event.currentTarget.click();
114
+ // }
115
+ // };
116
+
117
+ render() {
118
+ const {item, ...props} = this.props;
119
+ return (
120
+ <div className={this.styles.classNames.submenu}>
121
+ <MenuItem
122
+ onPointerUp={this.handlePointerUp}
123
+ rightIcon={<FontAwesomeIcon icon={faChevronRight} />}
124
+ // onKeyDown={this.handleKeyDown}
125
+ >
126
+ {item}
127
+ </MenuItem>
128
+ <SubmenuContent {...props} />
129
+ </div>
130
+ );
131
+ }
132
+ }
133
+
134
+ class SubmenuContent extends Widget {
135
+ constructor() {
136
+ super(...arguments);
137
+ this.styles = styles;
138
+ }
139
+ render() {
140
+ const {className = '', children, position, ...props} = this.props;
141
+ return (
142
+ <div
143
+ {...props}
144
+ className={'content ' + className}
145
+ data-position={position}
146
+ >
147
+ {children}
148
+ </div>
149
+ );
150
+ }
151
+ }
152
+
153
+ class MenuHr extends Widget {
154
+ constructor() {
155
+ super(...arguments);
156
+ this.styles = styles;
157
+ }
158
+
159
+ render() {
160
+ const {className = '', ...props} = this.props;
161
+ return (
162
+ <hr
163
+ {...props}
164
+ className={this.styles.classNames.menuHr + ' ' + className}
165
+ />
166
+ );
167
+ }
168
+ }
169
+
170
+ class MenuButton extends Widget {
171
+ constructor() {
172
+ super(...arguments);
173
+ this.stopPropagation = this.stopPropagation.bind(this);
174
+ }
175
+
176
+ componentWillUnmount() {
177
+ window.removeEventListener('click', this.stopPropagation, {
178
+ capture: true,
179
+ once: true,
180
+ });
181
+ }
182
+
183
+ stopPropagation(event) {
184
+ event.stopPropagation();
185
+ }
186
+
187
+ /**
188
+ * @param {PointerEvent} event
189
+ * @param {Menu} menu
190
+ */
191
+ handleClick = (event, menu) => {
192
+ // The click event is called when the space key is pressed
193
+ menu.open(event);
194
+ event.stopPropagation();
195
+ };
196
+
197
+ /**
198
+ * @param {PointerEvent} event
199
+ * @param {Menu} menu
200
+ */
201
+ handlePointerDown = (event, menu) => {
202
+ event.currentTarget?.focus();
203
+ // Prevent click event on parent elements
204
+ window.addEventListener('click', this.stopPropagation, {
205
+ capture: true,
206
+ once: true,
207
+ });
208
+ menu.open(event);
209
+ };
210
+
211
+ render() {
212
+ const {Component = MagicButton, ...props} = this.props;
213
+ return (
214
+ <MenuContext.Consumer>
215
+ {(menu) => (
216
+ <Component
217
+ onPointerDown={(event) => this.handlePointerDown(event, menu)}
218
+ onPointerUp={this.stopPropagation}
219
+ onClick={(event) => this.handleClick(event, menu)}
220
+ {...props}
221
+ >
222
+ {this.props.children || <FontAwesomeIcon icon={faBars} />}
223
+ </Component>
224
+ )}
225
+ </MenuContext.Consumer>
226
+ );
227
+ }
228
+ }
229
+
230
+ class MenuContent extends Widget {
231
+ constructor() {
232
+ super(...arguments);
233
+ this.styles = styles;
234
+ this.handleClose = this.handleClose.bind(this);
235
+ this.stopPropagation = this.stopPropagation.bind(this);
236
+ }
237
+
238
+ /**
239
+ * @param {Event} event
240
+ * @param {Menu} menu
241
+ */
242
+ handleClose(event, menu) {
243
+ menu.close();
244
+ event.stopPropagation();
245
+ }
246
+
247
+ /**
248
+ * @param {Event} event
249
+ */
250
+ stopPropagation(event) {
251
+ event.stopPropagation();
252
+ }
253
+
254
+ focusNext(event, num = 1) {
255
+ const element = event.currentTarget;
256
+ const buttons = [...element.querySelectorAll('button')].filter(
257
+ (element) =>
258
+ element.offsetWidth > 0 ||
259
+ element.offsetHeight > 0 ||
260
+ element === document.activeElement
261
+ );
262
+ const currentIndex = buttons.indexOf(document.activeElement);
263
+ const nextIndex = (currentIndex + num + buttons.length) % buttons.length;
264
+ buttons[nextIndex].focus();
265
+ }
266
+
267
+ handleKeyDown = (event) => {
268
+ this.props.onKeyDown?.(event);
269
+ if (event.key === 'ArrowDown') {
270
+ this.focusNext(event, 1);
271
+ } else if (event.key === 'ArrowUp') {
272
+ this.focusNext(event, -1);
273
+ }
274
+ };
275
+
276
+ getStyle(state, size) {
277
+ let {top, right, bottom, left} = state;
278
+ const {offsetX = 0, offsetY = 0} = this.props;
279
+ top -= 2 - offsetY;
280
+ bottom += 2 + offsetY;
281
+ left -= 1 - offsetX;
282
+ right += 1 + offsetX;
283
+
284
+ const position = state.fromContextMenu
285
+ ? 'bottom right'
286
+ : this.props.position || 'bottom right';
287
+
288
+ if (!size) {
289
+ size = {
290
+ width: 0,
291
+ height: 0,
292
+ };
293
+ }
294
+
295
+ const [firstPos, secondPos] = position.split(' ');
296
+
297
+ const verticalPos = (() => {
298
+ const firstBottom = firstPos === 'bottom';
299
+ const firstTop = firstPos === 'top';
300
+
301
+ if (size.height > window.innerHeight) {
302
+ return 'full';
303
+ }
304
+
305
+ if (firstBottom || firstTop) {
306
+ const notBottom = bottom + size.height > window.innerHeight;
307
+ const notTop = top - size.height < 0;
308
+
309
+ if (firstTop) {
310
+ if (notTop) {
311
+ if (notBottom) {
312
+ return 'start';
313
+ }
314
+ return 'bottom';
315
+ }
316
+ return 'top';
317
+ }
318
+
319
+ if (notBottom) {
320
+ if (notTop) {
321
+ return 'end';
322
+ }
323
+ return 'top';
324
+ }
325
+ return 'bottom';
326
+ }
327
+
328
+ const notSpanBottom = top + size.height > window.innerHeight;
329
+ const notSpanTop = bottom - size.height < 0;
330
+
331
+ if (secondPos === 'top') {
332
+ if (notSpanTop) {
333
+ return 'start';
334
+ }
335
+ return 'span-top';
336
+ }
337
+
338
+ if (notSpanBottom) {
339
+ return 'end';
340
+ }
341
+ return 'span-bottom';
342
+ })();
343
+
344
+ const verticalStyle = {
345
+ 'bottom': {top: bottom},
346
+ 'top': {bottom: `calc(100% - ${top}px)`},
347
+ 'span-bottom': {top},
348
+ 'span-top': {bottom: `calc(100% - ${bottom}px)`},
349
+ 'start': {top: 0},
350
+ 'end': {bottom: 0},
351
+ 'full': {top: 0, bottom: 0},
352
+ }[verticalPos];
353
+
354
+ const horizontalPos = (() => {
355
+ const firstRight = firstPos === 'right';
356
+ const firstLeft = firstPos === 'left';
357
+
358
+ if (size.width > window.innerWidth) {
359
+ return 'full';
360
+ }
361
+
362
+ if (firstRight || firstLeft) {
363
+ const notRight = right + size.width > window.innerWidth;
364
+ const notLeft = left - size.width < 0;
365
+
366
+ if (firstLeft) {
367
+ if (notLeft) {
368
+ if (notRight) {
369
+ return 'start';
370
+ }
371
+ return 'right';
372
+ }
373
+ return 'left';
374
+ }
375
+
376
+ if (notRight) {
377
+ if (notLeft) {
378
+ return 'end';
379
+ }
380
+ return 'left';
381
+ }
382
+ return 'right';
383
+ }
384
+
385
+ const notSpanRight = left + size.width > window.innerWidth;
386
+ const notSpanLeft = right - size.width < 0;
387
+
388
+ if (secondPos === 'left') {
389
+ if (notSpanLeft) {
390
+ return 'start';
391
+ }
392
+ return 'span-left';
393
+ }
394
+
395
+ if (notSpanRight) {
396
+ return 'end';
397
+ }
398
+ return 'span-right';
399
+ })();
400
+
401
+ const horizontalStyle = {
402
+ 'right': {left: right},
403
+ 'left': {right: `calc(100% - ${left}px)`},
404
+ 'span-right': {left},
405
+ 'span-left': {right: `calc(100% - ${right}px)`},
406
+ 'start': {left: 0},
407
+ 'end': {right: 0},
408
+ 'full': {left: 0, right: 0},
409
+ }[horizontalPos];
410
+
411
+ // console.log(verticalPos, horizontalPos, {
412
+ // ...verticalStyle,
413
+ // ...horizontalStyle,
414
+ // });
415
+
416
+ return {...verticalStyle, ...horizontalStyle};
417
+ }
418
+
419
+ renderDialog(state, menu) {
420
+ const {open} = state;
421
+ const {
422
+ className = '',
423
+ modal = true,
424
+ children,
425
+ offsetX,
426
+ offsetY,
427
+ portal = modal,
428
+ ...props
429
+ } = this.props;
430
+ return (
431
+ <Dialog
432
+ open={open}
433
+ modal={modal}
434
+ onClose={(event) => this.handleClose(event, menu)}
435
+ className={this.styles.classNames.menuDialog}
436
+ portal={portal}
437
+ onClick={this.stopPropagation}
438
+ onPointerUp={this.stopPropagation}
439
+ onPointerDown={this.stopPropagation}
440
+ onContextMenu={this.stopPropagation}
441
+ onKeyDown={this.handleKeyDown}
442
+ >
443
+ {open && (
444
+ <WithComputedSize>
445
+ {(ref, toComputeSizeStyle, size) => {
446
+ return (
447
+ <div
448
+ ref={ref}
449
+ className={this.styles.classNames.menuPosition}
450
+ style={toComputeSizeStyle || this.getStyle(state, size)}
451
+ >
452
+ <div
453
+ {...props}
454
+ className={
455
+ this.styles.classNames.menuContent + ' ' + className
456
+ }
457
+ >
458
+ <div tabIndex={0} />
459
+ {children}
460
+ </div>
461
+ </div>
462
+ );
463
+ }}
464
+ </WithComputedSize>
465
+ )}
466
+ </Dialog>
467
+ );
468
+ }
469
+
470
+ render() {
471
+ return (
472
+ <MenuStateContext.Consumer>
473
+ {(state) => (
474
+ <MenuContext.Consumer>
475
+ {(menu) => this.renderDialog(state, menu)}
476
+ </MenuContext.Consumer>
477
+ )}
478
+ </MenuStateContext.Consumer>
479
+ );
480
+ }
481
+ }
482
+
483
+ export default class Menu extends Widget {
484
+ constructor() {
485
+ super(...arguments);
486
+ this.styles = styles;
487
+ this.state = {
488
+ open: false,
489
+ x: null,
490
+ y: null,
491
+ };
492
+ this.open = this.open.bind(this);
493
+ this.close = this.close.bind(this);
494
+ this.toggle = this.toggle.bind(this);
495
+ this.handleContextMenu = this.handleContextMenu.bind(this);
496
+ this.menuContext = {
497
+ open: this.open,
498
+ close: this.close,
499
+ toggle: this.toggle,
500
+ };
501
+ }
502
+
503
+ /**
504
+ * @param {MouseEvent} event
505
+ */
506
+ open(event) {
507
+ const rect = event.currentTarget.getBoundingClientRect();
508
+ const {top, right, bottom, left} = rect;
509
+ this.setState({
510
+ open: true,
511
+ top,
512
+ right,
513
+ bottom,
514
+ left,
515
+ fromContextMenu: false,
516
+ });
517
+ event.stopPropagation();
518
+ }
519
+
520
+ close() {
521
+ this.setState({open: false});
522
+ }
523
+
524
+ toggle(event) {
525
+ if (this.state.open) {
526
+ this.close();
527
+ } else {
528
+ this.open(event);
529
+ }
530
+ }
531
+
532
+ /**
533
+ * @param {MouseEvent} event
534
+ */
535
+ handleContextMenu(event) {
536
+ event.preventDefault();
537
+ this.setState({
538
+ open: true,
539
+ left: event.clientX,
540
+ right: event.clientX,
541
+ top: event.clientY,
542
+ bottom: event.clientY,
543
+ fromContextMenu: true,
544
+ });
545
+ event.stopPropagation();
546
+ }
547
+
548
+ render() {
549
+ return (
550
+ <MenuContext.Provider value={this.menuContext}>
551
+ <MenuStateContext.Provider value={this.state}>
552
+ {React.Children.map(this.props.children, (child) => {
553
+ if (!React.isValidElement(child)) {
554
+ return child;
555
+ }
556
+ if (child.type === MenuContent) {
557
+ return child;
558
+ }
559
+ return React.cloneElement(child, {
560
+ onContextMenu: this.handleContextMenu,
561
+ });
562
+ })}
563
+ </MenuStateContext.Provider>
564
+ </MenuContext.Provider>
565
+ );
566
+ }
567
+
568
+ static Context = MenuContext;
569
+ static Content = MenuContent;
570
+ static Item = MenuItem;
571
+ static Title = MenuTitle;
572
+ static Submenu = Submenu;
573
+ static Hr = MenuHr;
574
+ static Button = MenuButton;
575
+ }
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import Widget from 'goblin-laboratory/widgets/widget/index.js';
3
+ import isEmptyAreaElement from '../element-helpers/is-empty-area-element.js';
4
+
5
+ class Movable extends Widget {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.currentTranslate = {x: 0, y: 0};
9
+ /** @type {HTMLElement | null} */
10
+ this.element = null;
11
+ }
12
+
13
+ /**
14
+ * @param {PointerEvent} event
15
+ */
16
+ handlePointerMove = (event) => {
17
+ const elementRect = this.element.getBoundingClientRect();
18
+ let x = event.clientX - this.pointerDiff.x - this.elementStart.x;
19
+ let y = event.clientY - this.pointerDiff.y - this.elementStart.y;
20
+ const maxX = window.innerWidth - elementRect.width - this.elementStart.x;
21
+ if (x > maxX) {
22
+ x = maxX;
23
+ }
24
+ const minX = -this.elementStart.x;
25
+ if (x < minX) {
26
+ x = minX;
27
+ }
28
+ const maxY = window.innerHeight - elementRect.height - this.elementStart.y;
29
+ if (y > maxY) {
30
+ y = maxY;
31
+ }
32
+ const minY = -this.elementStart.y;
33
+ if (y < minY) {
34
+ y = minY;
35
+ }
36
+ this.element.style.transform = `translate(${Math.round(x)}px, ${Math.round(
37
+ y
38
+ )}px)`;
39
+ this.currentTranslate = {x, y};
40
+ };
41
+
42
+ /**
43
+ * @param {PointerEvent} event
44
+ */
45
+ handlePointerDown = (event) => {
46
+ this.element = event.currentTarget;
47
+ if (
48
+ this.element.contains(event.target) &&
49
+ isEmptyAreaElement(event.target, this.element)
50
+ ) {
51
+ const elementRect = this.element.getBoundingClientRect();
52
+ this.elementStart = {
53
+ x: elementRect.x - this.currentTranslate.x,
54
+ y: elementRect.y - this.currentTranslate.y,
55
+ };
56
+ this.pointerDiff = {
57
+ x: event.clientX - elementRect.x,
58
+ y: event.clientY - elementRect.y,
59
+ };
60
+ window.addEventListener('pointermove', this.handlePointerMove);
61
+ window.addEventListener(
62
+ 'pointerup',
63
+ () => {
64
+ document.body.style.cursor = 'auto';
65
+ window.removeEventListener('pointermove', this.handlePointerMove);
66
+ },
67
+ {once: true}
68
+ );
69
+ document.body.style.cursor = 'grabbing';
70
+ }
71
+ };
72
+
73
+ render() {
74
+ return this.props.children({
75
+ onPointerDown: this.handlePointerDown,
76
+ });
77
+ }
78
+ }
79
+
80
+ export default Movable;
@@ -0,0 +1,57 @@
1
+ export default function styles() {
2
+ const splitter = {
3
+ 'position': 'relative',
4
+ 'display': 'flex',
5
+ 'flexDirection': 'row',
6
+ 'width': '100%',
7
+ 'height': '100%',
8
+ 'overflow': 'hidden',
9
+
10
+ '&.splitter-layout > .layout-splitter': {
11
+ 'backgroundColor': 'unset',
12
+ 'transition': 'all 400ms ease-out',
13
+ ':hover': {
14
+ backgroundColor:
15
+ 'color-mix(in srgb, var(--text-color), transparent 78%)',
16
+ },
17
+ },
18
+
19
+ '&.splitter-layout:not(.splitter-layout-vertical) > .layout-splitter': {
20
+ // 'width': '6px',
21
+ // borderLeft: '1px dashed rgba(209, 213, 219, 0.3)',
22
+ // borderRight: '1px dashed rgba(209, 213, 219, 0.3)',
23
+ 'width': '5px',
24
+ 'position': 'relative',
25
+ '&::after': {
26
+ content: "''",
27
+ position: 'absolute',
28
+ borderRight:
29
+ '1px dashed color-mix(in srgb, var(--text-color), transparent 78%)',
30
+ width: '2px',
31
+ height: '100%',
32
+ },
33
+ },
34
+
35
+ '&.splitter-layout-vertical > .layout-splitter': {
36
+ // 'height': '6px',
37
+ // borderBottom: '1px dashed rgba(209, 213, 219, 0.3)',
38
+ // borderTop: '1px dashed rgba(209, 213, 219, 0.3)',
39
+ 'height': '5px',
40
+ 'position': 'relative',
41
+ '&::after': {
42
+ content: "''",
43
+ position: 'absolute',
44
+ borderBottom:
45
+ '1px dashed color-mix(in srgb, var(--text-color), transparent 78%)',
46
+ width: '100%',
47
+ height: '2px',
48
+ },
49
+ },
50
+ };
51
+
52
+ return {
53
+ splitter,
54
+ };
55
+ }
56
+
57
+ /******************************************************************************/