@operato/board 10.0.0-beta.11 → 10.0.0-beta.13

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 CHANGED
@@ -3,6 +3,23 @@
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
+ ## [10.0.0-beta.13](https://github.com/hatiolab/operato/compare/v10.0.0-beta.12...v10.0.0-beta.13) (2026-03-19)
7
+
8
+
9
+ ### :bug: Bug Fix
10
+
11
+ * **board:** 편집 툴바 조건부 버튼 이벤트 바인딩 + dimension 초기화 ([e642ffa](https://github.com/hatiolab/operato/commit/e642ffa8be05cf4305f857fd4bef633611401c42))
12
+
13
+
14
+
15
+ ## [10.0.0-beta.12](https://github.com/hatiolab/operato/compare/v10.0.0-beta.11...v10.0.0-beta.12) (2026-03-17)
16
+
17
+ **Note:** Version bump only for package @operato/board
18
+
19
+
20
+
21
+
22
+
6
23
  ## [10.0.0-beta.11](https://github.com/hatiolab/operato/compare/v10.0.0-beta.10...v10.0.0-beta.11) (2026-03-15)
7
24
 
8
25
 
@@ -11,22 +11,6 @@ export declare class EditToolbar extends LitElement {
11
11
  private _dimension;
12
12
  private _gizmoAttached;
13
13
  private cliped?;
14
- private redo;
15
- private undo;
16
- private fullscreen;
17
- private styleCopy;
18
- private databindCopy;
19
- private cut;
20
- private copy;
21
- private paste;
22
- private delete;
23
- private forward;
24
- private backward;
25
- private front;
26
- private back;
27
- private aligners;
28
- private zorders;
29
- private distributes;
30
14
  firstUpdated(): void;
31
15
  updated(changes: PropertyValues<this>): void;
32
16
  render(): import("lit-html").TemplateResult<1>;
@@ -34,6 +18,7 @@ export declare class EditToolbar extends LitElement {
34
18
  getSymbol(key: string): string;
35
19
  private getShortcutString;
36
20
  onShortcut(e: KeyboardEvent): boolean;
21
+ private _setDisabled;
37
22
  onExecute(command: string, undoable: boolean, redoable: boolean): void;
38
23
  onUndo(undoable: boolean, redoable: boolean): void;
39
24
  onRedo(undoable: boolean, redoable: boolean): void;
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { __decorate } from "tslib";
5
5
  import { html, LitElement } from 'lit';
6
- import { property, state, query, queryAll } from 'lit/decorators.js';
6
+ import { property, state } from 'lit/decorators.js';
7
7
  import { copyToClipboard, isMacOS } from '@operato/utils';
8
8
  import { style } from './edit-toolbar-style.js';
9
9
  const MACOS = isMacOS();
@@ -16,7 +16,6 @@ export class EditToolbar extends LitElement {
16
16
  this._gizmoAttached = false;
17
17
  }
18
18
  firstUpdated() {
19
- var _a, _b;
20
19
  this.addEventListener('mousewheel', this.onWheelEvent.bind(this), false);
21
20
  // 툴바 버튼 클릭 후 씬으로 포커스를 돌려서 키보드 단축키가 계속 작동하도록 한다
22
21
  this.addEventListener('click', () => {
@@ -33,33 +32,7 @@ export class EditToolbar extends LitElement {
33
32
  console.error('model paste failed', e);
34
33
  }
35
34
  });
36
- this.aligners.forEach(aligner => aligner.addEventListener('click', this.onTapAlign.bind(this)));
37
- this.zorders.forEach(zorder => zorder.addEventListener('click', this.onTapZorder.bind(this)));
38
- this.distributes.forEach(distribute => distribute.addEventListener('click', this.onTapDistribute.bind(this)));
39
- this.undo.addEventListener('click', this.onTapUndo.bind(this));
40
- this.redo.addEventListener('click', this.onTapRedo.bind(this));
41
- this.fullscreen.addEventListener('click', this.onTapFullscreen.bind(this));
42
- this.styleCopy.addEventListener('click', this.onStartStylePasteMode.bind(this));
43
- this.databindCopy.addEventListener('click', this.onStartDatabindPasteMode.bind(this));
44
- this.cut.addEventListener('click', this.onTapCut.bind(this));
45
- this.copy.addEventListener('click', this.onTapCopy.bind(this));
46
- this.paste.addEventListener('click', this.onTapPaste.bind(this));
47
- this.delete.addEventListener('click', this.onTapDelete.bind(this));
48
- this.renderRoot
49
- .querySelector('#font-increase')
50
- .addEventListener('click', this.onTapFontIncrease.bind(this));
51
- this.renderRoot
52
- .querySelector('#font-decrease')
53
- .addEventListener('click', this.onTapFontDecrease.bind(this));
54
- (_a = this.renderRoot.querySelector('#group')) === null || _a === void 0 ? void 0 : _a.addEventListener('click', this.onTapGroup.bind(this));
55
- (_b = this.renderRoot.querySelector('#ungroup')) === null || _b === void 0 ? void 0 : _b.addEventListener('click', this.onTapUngroup.bind(this));
56
- this.renderRoot
57
- .querySelector('#toggle-property')
58
- .addEventListener('click', this.onTapToggle.bind(this));
59
- this.renderRoot
60
- .querySelector('#fit-scene')
61
- .addEventListener('click', this.onTapFitScene.bind(this));
62
- this.renderRoot.querySelector('#preview').addEventListener('click', this.onTapPreview.bind(this));
35
+ // 모든 버튼은 템플릿 @click 디렉티브로 바인딩 — 조건부 렌더링 시에도 정상 작동
63
36
  }
64
37
  updated(changes) {
65
38
  changes.has('scene') && this.onSceneChanged(this.scene, changes.get('scene'));
@@ -70,82 +43,43 @@ export class EditToolbar extends LitElement {
70
43
  <div tools>
71
44
  <span><slot></slot></span>
72
45
 
73
- <span button id="undo" title="undo (${this.getShortcutString('cmd', 'z')})"> </span>
74
- <span button id="redo" title="redo (${this.getShortcutString('cmd', 'shift', 'z')})"> </span>
46
+ <span button id="undo" title="undo (${this.getShortcutString('cmd', 'z')})" @click=${this.onTapUndo}> </span>
47
+ <span button id="redo" title="redo (${this.getShortcutString('cmd', 'shift', 'z')})" @click=${this.onTapRedo}> </span>
75
48
 
76
49
  <span class="vline"></span>
77
50
 
78
- <span button id="style-copy" title="style copy (${this.getShortcutString('cmd', '1')})"> </span>
79
- <span button id="databind-copy" title="databind copy (${this.getShortcutString('cmd', '2')})"> </span>
51
+ <span button id="style-copy" title="style copy (${this.getShortcutString('cmd', '1')})" @click=${this.onStartStylePasteMode}> </span>
52
+ <span button id="databind-copy" title="databind copy (${this.getShortcutString('cmd', '2')})" @click=${this.onStartDatabindPasteMode}> </span>
80
53
 
81
54
  <span class="vline"></span>
82
55
 
83
- <span button id="cut" title="cut (${this.getShortcutString('cmd', 'x')})"> </span>
84
- <span button id="copy" title="copy (${this.getShortcutString('cmd', 'c')})"> </span>
85
- <span button id="paste" title="paste (${this.getShortcutString('cmd', 'v')})"> </span>
86
- <span
87
- button
88
- id="delete"
56
+ <span button id="cut" title="cut (${this.getShortcutString('cmd', 'x')})" @click=${this.onTapCut}> </span>
57
+ <span button id="copy" title="copy (${this.getShortcutString('cmd', 'c')})" @click=${this.onTapCopy}> </span>
58
+ <span button id="paste" title="paste (${this.getShortcutString('cmd', 'v')})" @click=${this.onTapPaste}> </span>
59
+ <span button id="delete"
89
60
  title="delete (${this.getShortcutString('backspace')}, ${this.getShortcutString('delete')})"
90
- >
91
- </span>
61
+ @click=${this.onTapDelete}> </span>
92
62
 
93
63
  <span class="vline"></span>
94
64
 
95
- <span
96
- button
97
- data-align="left"
98
- id="align-left"
99
- title="align left (${this.getShortcutString('alt', 'shift', 'l')})"
100
- >
101
- </span>
102
- <span
103
- button
104
- data-align="center"
105
- id="align-center"
106
- title="align center (${this.getShortcutString('alt', 'shift', 'c')})"
107
- >
108
- </span>
109
- <span
110
- button
111
- data-align="right"
112
- id="align-right"
113
- title="align right (${this.getShortcutString('alt', 'shift', 'r')})"
114
- >
115
- </span>
116
-
117
- <span button data-align="top" id="align-top" title="align top (${this.getShortcutString('alt', 'shift', 't')})">
118
- </span>
119
- <span
120
- button
121
- data-align="middle"
122
- id="align-middle"
123
- title="align middle (${this.getShortcutString('alt', 'shift', 'm')})"
124
- >
125
- </span>
126
- <span
127
- button
128
- data-align="bottom"
129
- id="align-bottom"
130
- title="align bottom (${this.getShortcutString('alt', 'shift', 'b')})"
131
- >
132
- </span>
65
+ <span button data-align="left" id="align-left"
66
+ title="align left (${this.getShortcutString('alt', 'shift', 'l')})" @click=${this.onTapAlign}> </span>
67
+ <span button data-align="center" id="align-center"
68
+ title="align center (${this.getShortcutString('alt', 'shift', 'c')})" @click=${this.onTapAlign}> </span>
69
+ <span button data-align="right" id="align-right"
70
+ title="align right (${this.getShortcutString('alt', 'shift', 'r')})" @click=${this.onTapAlign}> </span>
133
71
 
134
- <span
135
- button
136
- data-distribute="HORIZONTAL"
137
- id="distribute-horizontal"
138
- title="distribute horizontally (${this.getShortcutString('alt', 'shift', 'h')})"
139
- >
140
- </span>
72
+ <span button data-align="top" id="align-top"
73
+ title="align top (${this.getShortcutString('alt', 'shift', 't')})" @click=${this.onTapAlign}> </span>
74
+ <span button data-align="middle" id="align-middle"
75
+ title="align middle (${this.getShortcutString('alt', 'shift', 'm')})" @click=${this.onTapAlign}> </span>
76
+ <span button data-align="bottom" id="align-bottom"
77
+ title="align bottom (${this.getShortcutString('alt', 'shift', 'b')})" @click=${this.onTapAlign}> </span>
141
78
 
142
- <span
143
- button
144
- data-distribute="VERTICAL"
145
- id="distribute-vertical"
146
- title="distribute vertically (${this.getShortcutString('alt', 'shift', 'v')})"
147
- >
148
- </span>
79
+ <span button data-distribute="HORIZONTAL" id="distribute-horizontal"
80
+ title="distribute horizontally (${this.getShortcutString('alt', 'shift', 'h')})" @click=${this.onTapDistribute}> </span>
81
+ <span button data-distribute="VERTICAL" id="distribute-vertical"
82
+ title="distribute vertically (${this.getShortcutString('alt', 'shift', 'v')})" @click=${this.onTapDistribute}> </span>
149
83
 
150
84
  ${this._dimension === '3d'
151
85
  ? html `
@@ -160,42 +94,22 @@ export class EditToolbar extends LitElement {
160
94
  ? html `
161
95
  <span class="vline"></span>
162
96
 
163
- <span
164
- button
165
- id="front"
166
- data-zorder="front"
167
- title="bring to front (${this.getShortcutString('cmd', 'shift', 'f')})"
168
- >
169
- </span>
170
- <span
171
- button
172
- id="back"
173
- data-zorder="back"
174
- title="send to back (${this.getShortcutString('cmd', 'shift', 'b')})"
175
- >
176
- </span>
177
- <span
178
- button
179
- id="forward"
180
- data-zorder="forward"
181
- title="bring forward (${this.getShortcutString('cmd', 'f')})"
182
- >
183
- </span>
184
- <span
185
- button
186
- id="backward"
187
- data-zorder="backward"
188
- title="send backward (${this.getShortcutString('cmd', 'b')})"
189
- >
190
- </span>
97
+ <span button id="front" data-zorder="front"
98
+ title="bring to front (${this.getShortcutString('cmd', 'shift', 'f')})" @click=${this.onTapZorder}> </span>
99
+ <span button id="back" data-zorder="back"
100
+ title="send to back (${this.getShortcutString('cmd', 'shift', 'b')})" @click=${this.onTapZorder}> </span>
101
+ <span button id="forward" data-zorder="forward"
102
+ title="bring forward (${this.getShortcutString('cmd', 'f')})" @click=${this.onTapZorder}> </span>
103
+ <span button id="backward" data-zorder="backward"
104
+ title="send backward (${this.getShortcutString('cmd', 'b')})" @click=${this.onTapZorder}> </span>
191
105
  `
192
106
  : ''}
193
107
 
194
108
  ${this._dimension === '2d' ? html `
195
109
  <span class="vline"></span>
196
110
 
197
- <span button id="group" title="group (${this.getShortcutString('cmd', 'g')})"> </span>
198
- <span button id="ungroup" title="ungroup (${this.getShortcutString('cmd', 'shift', 'g')})"> </span>
111
+ <span button id="group" title="group (${this.getShortcutString('cmd', 'g')})" @click=${this.onTapGroup}> </span>
112
+ <span button id="ungroup" title="ungroup (${this.getShortcutString('cmd', 'shift', 'g')})" @click=${this.onTapUngroup}> </span>
199
113
  ` : this._dimension === '3d' ? html `
200
114
  <span class="vline"></span>
201
115
 
@@ -228,27 +142,23 @@ export class EditToolbar extends LitElement {
228
142
 
229
143
  <span class="vline"></span>
230
144
 
231
- <span button id="font-increase" title="increase font size"></span>
232
- <span button id="font-decrease" title="decrease font size" style="scale: 0.7;"></span>
145
+ <span button id="font-increase" title="increase font size" @click=${this.onTapFontIncrease}></span>
146
+ <span button id="font-decrease" title="decrease font size" style="scale: 0.7;" @click=${this.onTapFontDecrease}></span>
233
147
 
234
148
  <span class="vline"></span>
235
149
  <span padding></span>
236
150
 
237
- <span button id="fit-scene" title="fit scene (${this.getShortcutString('cmd', 'd')})"> </span>
151
+ <span button id="fit-scene" title="fit scene (${this.getShortcutString('cmd', 'd')})" @click=${this.onTapFitScene}> </span>
238
152
 
239
153
  <span class="vline"></span>
240
154
 
241
- <span button id="preview" title="preview (${this.getShortcutString('ctrl', 'p')})"> </span>
155
+ <span button id="preview" title="preview (${this.getShortcutString('ctrl', 'p')})" @click=${this.onTapPreview}> </span>
242
156
 
243
- <span button id="fullscreen" title="fullscreen (${this.getShortcutString('f11')})"> </span>
157
+ <span button id="fullscreen" title="fullscreen (${this.getShortcutString('f11')})" @click=${this.onTapFullscreen}> </span>
244
158
 
245
- <span
246
- button
247
- id="toggle-property"
159
+ <span button id="toggle-property"
248
160
  title="toggle property panel (${this.getShortcutString('cmd', 'h')})"
249
- toggles="true"
250
- >
251
- </span>
161
+ toggles="true" @click=${this.onTapToggle}> </span>
252
162
  </div>
253
163
  `;
254
164
  }
@@ -435,19 +345,24 @@ export class EditToolbar extends LitElement {
435
345
  e.preventDefault();
436
346
  return true;
437
347
  }
348
+ _setDisabled(id, disabled) {
349
+ const el = this.renderRoot.querySelector(`#${id}`);
350
+ disabled ? el === null || el === void 0 ? void 0 : el.setAttribute('disabled', '') : el === null || el === void 0 ? void 0 : el.removeAttribute('disabled');
351
+ }
438
352
  onExecute(command, undoable, redoable) {
439
- !undoable ? this.undo.setAttribute('disabled', '') : this.undo.removeAttribute('disabled');
440
- !redoable ? this.redo.setAttribute('disabled', '') : this.redo.removeAttribute('disabled');
353
+ this._setDisabled('undo', !undoable);
354
+ this._setDisabled('redo', !redoable);
441
355
  }
442
356
  onUndo(undoable, redoable) {
443
- !undoable ? this.undo.setAttribute('disabled', '') : this.undo.removeAttribute('disabled');
444
- !redoable ? this.redo.setAttribute('disabled', '') : this.redo.removeAttribute('disabled');
357
+ this._setDisabled('undo', !undoable);
358
+ this._setDisabled('redo', !redoable);
445
359
  }
446
360
  onRedo(undoable, redoable) {
447
- !undoable ? this.undo.setAttribute('disabled', '') : this.undo.removeAttribute('disabled');
448
- !redoable ? this.redo.setAttribute('disabled', '') : this.redo.removeAttribute('disabled');
361
+ this._setDisabled('undo', !undoable);
362
+ this._setDisabled('redo', !redoable);
449
363
  }
450
364
  onSceneChanged(after, before) {
365
+ var _a, _b;
451
366
  if (before) {
452
367
  before.off('execute', this.onExecute, this);
453
368
  before.off('undo', this.onUndo, this);
@@ -461,6 +376,9 @@ export class EditToolbar extends LitElement {
461
376
  after.on('redo', this.onRedo, this);
462
377
  after.on('dimension', this._onDimensionChanged, this);
463
378
  after.on('gizmoattach', this._onGizmoAttachChanged, this);
379
+ // scene 설정 시 현재 dimension을 즉시 반영 (초기 이벤트를 놓친 경우 대비)
380
+ const threed = (_b = (_a = after.model_layer) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.threed;
381
+ this._dimension = threed ? '3d' : '2d';
464
382
  }
465
383
  }
466
384
  _onDimensionChanged(dimension) {
@@ -475,27 +393,23 @@ export class EditToolbar extends LitElement {
475
393
  (_b = (_a = this.scene) === null || _a === void 0 ? void 0 : _a.root) === null || _b === void 0 ? void 0 : _b.setGizmoMode(mode);
476
394
  }
477
395
  onSelectedChanged(after, before) {
478
- var _a, _b, _c, _d, _e, _f, _g, _h;
479
396
  var hasSelection = after.length > 0;
480
397
  var alignable = after.length > 1;
481
- // 선택 필요 버튼: 스타일 복사, 데이터바인드 복사, cut, copy, delete
482
- const selectionButtons = [this.styleCopy, this.databindCopy, this.cut, this.copy, this.delete];
483
- selectionButtons.forEach(btn => {
484
- hasSelection ? btn === null || btn === void 0 ? void 0 : btn.removeAttribute('disabled') : btn === null || btn === void 0 ? void 0 : btn.setAttribute('disabled', '');
485
- });
486
- this.aligners.forEach(aligner => alignable ? aligner.removeAttribute('disabled') : aligner.setAttribute('disabled', ''));
398
+ ['style-copy', 'databind-copy', 'cut', 'copy', 'delete'].forEach(id => this._setDisabled(id, !hasSelection));
399
+ // 정렬 버튼
400
+ this.renderRoot.querySelectorAll('[data-align]').forEach(el => alignable ? el.removeAttribute('disabled') : el.setAttribute('disabled', ''));
487
401
  if (this._dimension === '2d') {
488
402
  var movable = after.length === 1;
489
403
  /* forward, backward 이동은 한 컴포넌트만 가능하다. */
490
- !movable ? (_a = this.forward) === null || _a === void 0 ? void 0 : _a.setAttribute('disabled', '') : (_b = this.forward) === null || _b === void 0 ? void 0 : _b.removeAttribute('disabled');
491
- !movable ? (_c = this.backward) === null || _c === void 0 ? void 0 : _c.setAttribute('disabled', '') : (_d = this.backward) === null || _d === void 0 ? void 0 : _d.removeAttribute('disabled');
404
+ this._setDisabled('forward', !movable);
405
+ this._setDisabled('backward', !movable);
492
406
  /* 여러 컴포넌트는 front, back 이동이 가능하다. */
493
- !(alignable || movable) ? (_e = this.front) === null || _e === void 0 ? void 0 : _e.setAttribute('disabled', '') : (_f = this.front) === null || _f === void 0 ? void 0 : _f.removeAttribute('disabled');
494
- !(alignable || movable) ? (_g = this.back) === null || _g === void 0 ? void 0 : _g.setAttribute('disabled', '') : (_h = this.back) === null || _h === void 0 ? void 0 : _h.removeAttribute('disabled');
407
+ this._setDisabled('front', !(alignable || movable));
408
+ this._setDisabled('back', !(alignable || movable));
495
409
  }
496
- this.distributes.forEach(distribute => alignable ? distribute.removeAttribute('disabled') : distribute.setAttribute('disabled', ''));
410
+ // 분배 버튼
411
+ this.renderRoot.querySelectorAll('[data-distribute]').forEach(el => alignable ? el.removeAttribute('disabled') : el.setAttribute('disabled', ''));
497
412
  if (this._dimension === '3d') {
498
- const hasSelection = after.length > 0;
499
413
  this.renderRoot.querySelectorAll('.gizmo-btn').forEach(btn => {
500
414
  hasSelection ? btn.removeAttribute('disabled') : btn.setAttribute('disabled', '');
501
415
  });
@@ -668,52 +582,4 @@ __decorate([
668
582
  __decorate([
669
583
  state()
670
584
  ], EditToolbar.prototype, "_gizmoAttached", void 0);
671
- __decorate([
672
- query('#redo')
673
- ], EditToolbar.prototype, "redo", void 0);
674
- __decorate([
675
- query('#undo')
676
- ], EditToolbar.prototype, "undo", void 0);
677
- __decorate([
678
- query('#fullscreen')
679
- ], EditToolbar.prototype, "fullscreen", void 0);
680
- __decorate([
681
- query('#style-copy')
682
- ], EditToolbar.prototype, "styleCopy", void 0);
683
- __decorate([
684
- query('#databind-copy')
685
- ], EditToolbar.prototype, "databindCopy", void 0);
686
- __decorate([
687
- query('#cut')
688
- ], EditToolbar.prototype, "cut", void 0);
689
- __decorate([
690
- query('#copy')
691
- ], EditToolbar.prototype, "copy", void 0);
692
- __decorate([
693
- query('#paste')
694
- ], EditToolbar.prototype, "paste", void 0);
695
- __decorate([
696
- query('#delete')
697
- ], EditToolbar.prototype, "delete", void 0);
698
- __decorate([
699
- query('#forward')
700
- ], EditToolbar.prototype, "forward", void 0);
701
- __decorate([
702
- query('#backward')
703
- ], EditToolbar.prototype, "backward", void 0);
704
- __decorate([
705
- query('#front')
706
- ], EditToolbar.prototype, "front", void 0);
707
- __decorate([
708
- query('#back')
709
- ], EditToolbar.prototype, "back", void 0);
710
- __decorate([
711
- queryAll('[data-align]')
712
- ], EditToolbar.prototype, "aligners", void 0);
713
- __decorate([
714
- queryAll('[data-zorder]')
715
- ], EditToolbar.prototype, "zorders", void 0);
716
- __decorate([
717
- queryAll('[data-distribute]')
718
- ], EditToolbar.prototype, "distributes", void 0);
719
585
  //# sourceMappingURL=edit-toolbar.js.map