@operato/property-panel 10.0.0-beta.53 → 10.0.0-beta.58

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 (27) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/src/index.d.ts +3 -0
  3. package/dist/src/index.js +5 -0
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/property-panel/data-binding/data-binding.js +4 -3
  6. package/dist/src/property-panel/data-binding/data-binding.js.map +1 -1
  7. package/dist/src/property-panel/effects/effects.js +1 -1
  8. package/dist/src/property-panel/effects/effects.js.map +1 -1
  9. package/dist/src/property-panel/effects/property-event.d.ts +15 -7
  10. package/dist/src/property-panel/effects/property-event.js +17 -38
  11. package/dist/src/property-panel/effects/property-event.js.map +1 -1
  12. package/dist/src/property-panel/event-handlers/event-handlers-mapper.d.ts +31 -0
  13. package/dist/src/property-panel/event-handlers/event-handlers-mapper.js +176 -0
  14. package/dist/src/property-panel/event-handlers/event-handlers-mapper.js.map +1 -0
  15. package/dist/src/property-panel/event-handlers/event-handlers-popup.d.ts +35 -0
  16. package/dist/src/property-panel/event-handlers/event-handlers-popup.js +325 -0
  17. package/dist/src/property-panel/event-handlers/event-handlers-popup.js.map +1 -0
  18. package/dist/src/property-panel/event-handlers/event-handlers.d.ts +54 -0
  19. package/dist/src/property-panel/event-handlers/event-handlers.js +378 -0
  20. package/dist/src/property-panel/event-handlers/event-handlers.js.map +1 -0
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +7 -7
  23. package/translations/en.json +7 -0
  24. package/translations/ja.json +7 -0
  25. package/translations/ko.json +7 -0
  26. package/translations/ms.json +7 -0
  27. package/translations/zh.json +7 -0
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @license Copyright © HatioLab Inc. All rights reserved.
3
+ *
4
+ * EventHandlers popup — N 핸들러 large editor. data-binding-popup 의 형제.
5
+ *
6
+ * 2-column layout:
7
+ * Left: handler list — add / duplicate / disable / reorder / delete
8
+ * Right: 선택된 handler 의 mapper (큰 code editor 영역)
9
+ */
10
+ import '@material/web/icon/icon.js';
11
+ import '@operato/i18n/ox-i18n.js';
12
+ import { LitElement } from 'lit';
13
+ import type { Scene } from '@hatiolab/things-scene';
14
+ import { EventHandlersMapper, type EventHandlerSpec } from './event-handlers-mapper.js';
15
+ declare const EventHandlersPopup_base: typeof LitElement & import("@open-wc/dedupe-mixin").Constructor<import("@open-wc/scoped-elements/types.js").ScopedElementsHost>;
16
+ export declare class EventHandlersPopup extends EventHandlersPopup_base {
17
+ static get scopedElements(): {
18
+ 'event-handlers-mapper': typeof EventHandlersMapper;
19
+ };
20
+ static styles: import("lit").CSSResult[];
21
+ handlers: EventHandlerSpec[];
22
+ scene?: Scene;
23
+ selectedIndex: number;
24
+ render(): import("lit-html").TemplateResult<1>;
25
+ private _renderListItem;
26
+ private _summarize;
27
+ private _addHandler;
28
+ private _duplicateHandler;
29
+ private _toggleDisabled;
30
+ private _moveHandler;
31
+ private _removeHandler;
32
+ private _onHandlerChanged;
33
+ private _dispatch;
34
+ }
35
+ export {};
@@ -0,0 +1,325 @@
1
+ /**
2
+ * @license Copyright © HatioLab Inc. All rights reserved.
3
+ *
4
+ * EventHandlers popup — N 핸들러 large editor. data-binding-popup 의 형제.
5
+ *
6
+ * 2-column layout:
7
+ * Left: handler list — add / duplicate / disable / reorder / delete
8
+ * Right: 선택된 handler 의 mapper (큰 code editor 영역)
9
+ */
10
+ import { __decorate } from "tslib";
11
+ import '@material/web/icon/icon.js';
12
+ import '@operato/i18n/ox-i18n.js';
13
+ import { css, html, LitElement } from 'lit';
14
+ import { customElement, property, state } from 'lit/decorators.js';
15
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
16
+ import { EventHandlersMapper } from './event-handlers-mapper.js';
17
+ let EventHandlersPopup = class EventHandlersPopup extends ScopedElementsMixin(LitElement) {
18
+ constructor() {
19
+ super(...arguments);
20
+ this.handlers = [];
21
+ this.selectedIndex = 0;
22
+ }
23
+ static get scopedElements() {
24
+ return {
25
+ 'event-handlers-mapper': EventHandlersMapper
26
+ };
27
+ }
28
+ render() {
29
+ var _a;
30
+ const handlers = (_a = this.handlers) !== null && _a !== void 0 ? _a : [];
31
+ const current = handlers[this.selectedIndex];
32
+ return html `
33
+ <div handler-list>
34
+ <header>
35
+ <span><ox-i18n msgid="label.handlers">Handlers</ox-i18n> (${handlers.length})</span>
36
+ <md-icon @click=${() => this._addHandler()} title="add">add</md-icon>
37
+ </header>
38
+ ${handlers.length === 0
39
+ ? html `<div empty><ox-i18n msgid="label.no-handlers">No handlers — add one</ox-i18n></div>`
40
+ : html `<ul>${handlers.map((h, i) => this._renderListItem(h, i, handlers.length))}</ul>`}
41
+ </div>
42
+
43
+ <div editor>
44
+ ${current
45
+ ? html `
46
+ <event-handlers-mapper
47
+ .handler=${current}
48
+ .scene=${this.scene}
49
+ @value-change=${(e) => this._onHandlerChanged(e)}
50
+ ></event-handlers-mapper>
51
+ `
52
+ : html `<div empty><ox-i18n msgid="label.select-or-add-handler">Select or add a handler</ox-i18n></div>`}
53
+ </div>
54
+ `;
55
+ }
56
+ _renderListItem(h, i, total) {
57
+ return html `
58
+ <li
59
+ ?active=${i === this.selectedIndex}
60
+ ?disabled=${h.disabled}
61
+ @click=${() => (this.selectedIndex = i)}
62
+ >
63
+ <div class="meta">
64
+ <span class="trigger">${h.trigger}${h.disabled ? ' (off)' : ''}</span>
65
+ <span class="summary">${this._summarize(h)}</span>
66
+ </div>
67
+ <md-icon
68
+ @click=${(e) => this._toggleDisabled(i, e)}
69
+ title=${h.disabled ? 'enable' : 'disable'}
70
+ >${h.disabled ? 'toggle_off' : 'toggle_on'}</md-icon>
71
+ <md-icon
72
+ @click=${(e) => this._duplicateHandler(i, e)}
73
+ title="duplicate"
74
+ >content_copy</md-icon>
75
+ <md-icon
76
+ @click=${(e) => this._moveHandler(i, -1, e)}
77
+ title="move up"
78
+ ?style=${i === 0 ? 'opacity:0.2;pointer-events:none' : ''}
79
+ >arrow_upward</md-icon>
80
+ <md-icon
81
+ @click=${(e) => this._moveHandler(i, +1, e)}
82
+ title="move down"
83
+ ?style=${i === total - 1 ? 'opacity:0.2;pointer-events:none' : ''}
84
+ >arrow_downward</md-icon>
85
+ <md-icon
86
+ class="danger"
87
+ @click=${(e) => this._removeHandler(i, e)}
88
+ title="delete"
89
+ >delete</md-icon>
90
+ </li>
91
+ `;
92
+ }
93
+ _summarize(h) {
94
+ if (h.action === 'script') {
95
+ const c = (h.code || '').replace(/\s+/g, ' ').trim();
96
+ return 'script · ' + (c.length > 60 ? c.slice(0, 60) + '…' : (c || '(empty)'));
97
+ }
98
+ return [h.action || '(none)', h.target ? `→${h.target}` : ''].filter(Boolean).join(' ');
99
+ }
100
+ _addHandler() {
101
+ const next = { trigger: 'click', action: '' };
102
+ this.handlers = [...(this.handlers || []), next];
103
+ this.selectedIndex = this.handlers.length - 1;
104
+ this._dispatch();
105
+ }
106
+ _duplicateHandler(idx, e) {
107
+ e.stopPropagation();
108
+ const original = this.handlers[idx];
109
+ if (!original)
110
+ return;
111
+ const copy = JSON.parse(JSON.stringify(original));
112
+ const next = [...(this.handlers || [])];
113
+ next.splice(idx + 1, 0, copy);
114
+ this.handlers = next;
115
+ this.selectedIndex = idx + 1;
116
+ this._dispatch();
117
+ }
118
+ _toggleDisabled(idx, e) {
119
+ e.stopPropagation();
120
+ const next = [...(this.handlers || [])];
121
+ next[idx] = { ...next[idx], disabled: !next[idx].disabled };
122
+ this.handlers = next;
123
+ this._dispatch();
124
+ }
125
+ _moveHandler(idx, delta, e) {
126
+ e.stopPropagation();
127
+ const next = [...(this.handlers || [])];
128
+ const newIdx = idx + delta;
129
+ if (newIdx < 0 || newIdx >= next.length)
130
+ return;
131
+ const [m] = next.splice(idx, 1);
132
+ next.splice(newIdx, 0, m);
133
+ this.handlers = next;
134
+ if (this.selectedIndex === idx)
135
+ this.selectedIndex = newIdx;
136
+ this._dispatch();
137
+ }
138
+ _removeHandler(idx, e) {
139
+ e.stopPropagation();
140
+ const next = [...(this.handlers || [])];
141
+ next.splice(idx, 1);
142
+ this.handlers = next;
143
+ this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, next.length - 1));
144
+ this._dispatch();
145
+ }
146
+ _onHandlerChanged(e) {
147
+ var _a;
148
+ const handler = (_a = e.detail) === null || _a === void 0 ? void 0 : _a.handler;
149
+ if (!handler)
150
+ return;
151
+ const next = [...(this.handlers || [])];
152
+ next[this.selectedIndex] = handler;
153
+ this.handlers = next;
154
+ this._dispatch();
155
+ }
156
+ _dispatch() {
157
+ this.dispatchEvent(new CustomEvent('handlers-change', {
158
+ bubbles: true,
159
+ composed: true,
160
+ detail: { handlers: this.handlers }
161
+ }));
162
+ }
163
+ };
164
+ EventHandlersPopup.styles = [
165
+ css `
166
+ :host {
167
+ display: flex;
168
+ width: 1100px;
169
+ height: 680px;
170
+ overflow: hidden;
171
+ font-family: 'Roboto', Arial, sans-serif;
172
+ font-size: 13px;
173
+ color: var(--md-sys-color-on-surface, #1c1b1f);
174
+ background: var(--md-sys-color-surface, #fff);
175
+ }
176
+
177
+ [handler-list] {
178
+ width: 280px;
179
+ min-width: 280px;
180
+ border-right: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));
181
+ display: flex;
182
+ flex-direction: column;
183
+ background: var(--md-sys-color-surface-container-low, #f7f2fa);
184
+ }
185
+
186
+ [handler-list] header {
187
+ display: flex;
188
+ align-items: center;
189
+ justify-content: space-between;
190
+ padding: 10px 12px;
191
+ font-weight: 600;
192
+ font-size: 12px;
193
+ text-transform: uppercase;
194
+ letter-spacing: 0.5px;
195
+ color: var(--md-sys-color-on-surface-variant, #49454f);
196
+ border-bottom: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));
197
+ }
198
+
199
+ [handler-list] header md-icon {
200
+ cursor: pointer;
201
+ --md-icon-size: 18px;
202
+ border-radius: 4px;
203
+ padding: 2px;
204
+ }
205
+
206
+ [handler-list] header md-icon:hover {
207
+ background: rgba(0, 0, 0, 0.05);
208
+ }
209
+
210
+ [handler-list] ul {
211
+ list-style: none;
212
+ margin: 0;
213
+ padding: 0;
214
+ overflow-y: auto;
215
+ flex: 1;
216
+ }
217
+
218
+ [handler-list] li {
219
+ padding: 8px 10px;
220
+ cursor: pointer;
221
+ border-bottom: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.08));
222
+ display: flex;
223
+ align-items: center;
224
+ gap: 6px;
225
+ }
226
+
227
+ [handler-list] li[active] {
228
+ background: var(--md-sys-color-secondary-container, #e8def8);
229
+ color: var(--md-sys-color-on-secondary-container, #1d192b);
230
+ }
231
+
232
+ [handler-list] li[disabled] {
233
+ opacity: 0.5;
234
+ font-style: italic;
235
+ }
236
+
237
+ [handler-list] li:hover {
238
+ background: rgba(0, 0, 0, 0.04);
239
+ }
240
+
241
+ [handler-list] li .meta {
242
+ display: flex;
243
+ flex-direction: column;
244
+ flex: 1;
245
+ min-width: 0;
246
+ }
247
+
248
+ [handler-list] li .trigger {
249
+ font-weight: 600;
250
+ font-size: 12px;
251
+ }
252
+
253
+ [handler-list] li .summary {
254
+ font-size: 11px;
255
+ opacity: 0.7;
256
+ white-space: nowrap;
257
+ overflow: hidden;
258
+ text-overflow: ellipsis;
259
+ margin-top: 2px;
260
+ }
261
+
262
+ [handler-list] li md-icon {
263
+ --md-icon-size: 16px;
264
+ opacity: 0.5;
265
+ cursor: pointer;
266
+ padding: 3px;
267
+ border-radius: 4px;
268
+ flex-shrink: 0;
269
+ }
270
+
271
+ [handler-list] li md-icon:hover {
272
+ opacity: 1;
273
+ background: rgba(0, 0, 0, 0.05);
274
+ }
275
+
276
+ [handler-list] li md-icon.danger:hover {
277
+ color: var(--md-sys-color-error, #b3261e);
278
+ }
279
+
280
+ [handler-list] [empty] {
281
+ padding: 24px 12px;
282
+ text-align: center;
283
+ color: var(--md-sys-color-on-surface-variant, #49454f);
284
+ opacity: 0.6;
285
+ font-size: 12px;
286
+ }
287
+
288
+ [editor] {
289
+ flex: 1;
290
+ display: flex;
291
+ flex-direction: column;
292
+ overflow-y: auto;
293
+ padding: 16px 20px;
294
+ background: var(--md-sys-color-surface, #fff);
295
+ }
296
+
297
+ [editor] [empty] {
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+ flex: 1;
302
+ color: var(--md-sys-color-on-surface-variant, #49454f);
303
+ font-size: 13px;
304
+ opacity: 0.6;
305
+ }
306
+
307
+ [editor] event-handlers-mapper {
308
+ min-height: 100%;
309
+ }
310
+ `
311
+ ];
312
+ __decorate([
313
+ property({ type: Array })
314
+ ], EventHandlersPopup.prototype, "handlers", void 0);
315
+ __decorate([
316
+ property({ type: Object })
317
+ ], EventHandlersPopup.prototype, "scene", void 0);
318
+ __decorate([
319
+ state()
320
+ ], EventHandlersPopup.prototype, "selectedIndex", void 0);
321
+ EventHandlersPopup = __decorate([
322
+ customElement('event-handlers-popup')
323
+ ], EventHandlersPopup);
324
+ export { EventHandlersPopup };
325
+ //# sourceMappingURL=event-handlers-popup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-handlers-popup.js","sourceRoot":"","sources":["../../../../src/property-panel/event-handlers/event-handlers-popup.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n *\n * EventHandlers popup — N 핸들러 large editor. data-binding-popup 의 형제.\n *\n * 2-column layout:\n * Left: handler list — add / duplicate / disable / reorder / delete\n * Right: 선택된 handler 의 mapper (큰 code editor 영역)\n */\n\nimport '@material/web/icon/icon.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport type { Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { EventHandlersMapper, type EventHandlerSpec } from './event-handlers-mapper.js'\n\n@customElement('event-handlers-popup')\nexport class EventHandlersPopup extends ScopedElementsMixin(LitElement) {\n static get scopedElements() {\n return {\n 'event-handlers-mapper': EventHandlersMapper\n }\n }\n\n static styles = [\n css`\n :host {\n display: flex;\n width: 1100px;\n height: 680px;\n overflow: hidden;\n font-family: 'Roboto', Arial, sans-serif;\n font-size: 13px;\n color: var(--md-sys-color-on-surface, #1c1b1f);\n background: var(--md-sys-color-surface, #fff);\n }\n\n [handler-list] {\n width: 280px;\n min-width: 280px;\n border-right: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));\n display: flex;\n flex-direction: column;\n background: var(--md-sys-color-surface-container-low, #f7f2fa);\n }\n\n [handler-list] header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 12px;\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--md-sys-color-on-surface-variant, #49454f);\n border-bottom: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));\n }\n\n [handler-list] header md-icon {\n cursor: pointer;\n --md-icon-size: 18px;\n border-radius: 4px;\n padding: 2px;\n }\n\n [handler-list] header md-icon:hover {\n background: rgba(0, 0, 0, 0.05);\n }\n\n [handler-list] ul {\n list-style: none;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n flex: 1;\n }\n\n [handler-list] li {\n padding: 8px 10px;\n cursor: pointer;\n border-bottom: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.08));\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n [handler-list] li[active] {\n background: var(--md-sys-color-secondary-container, #e8def8);\n color: var(--md-sys-color-on-secondary-container, #1d192b);\n }\n\n [handler-list] li[disabled] {\n opacity: 0.5;\n font-style: italic;\n }\n\n [handler-list] li:hover {\n background: rgba(0, 0, 0, 0.04);\n }\n\n [handler-list] li .meta {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n }\n\n [handler-list] li .trigger {\n font-weight: 600;\n font-size: 12px;\n }\n\n [handler-list] li .summary {\n font-size: 11px;\n opacity: 0.7;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: 2px;\n }\n\n [handler-list] li md-icon {\n --md-icon-size: 16px;\n opacity: 0.5;\n cursor: pointer;\n padding: 3px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n [handler-list] li md-icon:hover {\n opacity: 1;\n background: rgba(0, 0, 0, 0.05);\n }\n\n [handler-list] li md-icon.danger:hover {\n color: var(--md-sys-color-error, #b3261e);\n }\n\n [handler-list] [empty] {\n padding: 24px 12px;\n text-align: center;\n color: var(--md-sys-color-on-surface-variant, #49454f);\n opacity: 0.6;\n font-size: 12px;\n }\n\n [editor] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n padding: 16px 20px;\n background: var(--md-sys-color-surface, #fff);\n }\n\n [editor] [empty] {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1;\n color: var(--md-sys-color-on-surface-variant, #49454f);\n font-size: 13px;\n opacity: 0.6;\n }\n\n [editor] event-handlers-mapper {\n min-height: 100%;\n }\n `\n ]\n\n @property({ type: Array }) handlers: EventHandlerSpec[] = []\n @property({ type: Object }) scene?: Scene\n @state() selectedIndex: number = 0\n\n render() {\n const handlers = this.handlers ?? []\n const current = handlers[this.selectedIndex]\n\n return html`\n <div handler-list>\n <header>\n <span><ox-i18n msgid=\"label.handlers\">Handlers</ox-i18n> (${handlers.length})</span>\n <md-icon @click=${() => this._addHandler()} title=\"add\">add</md-icon>\n </header>\n ${handlers.length === 0\n ? html`<div empty><ox-i18n msgid=\"label.no-handlers\">No handlers — add one</ox-i18n></div>`\n : html`<ul>${handlers.map((h, i) => this._renderListItem(h, i, handlers.length))}</ul>`}\n </div>\n\n <div editor>\n ${current\n ? html`\n <event-handlers-mapper\n .handler=${current}\n .scene=${this.scene}\n @value-change=${(e: CustomEvent) => this._onHandlerChanged(e)}\n ></event-handlers-mapper>\n `\n : html`<div empty><ox-i18n msgid=\"label.select-or-add-handler\">Select or add a handler</ox-i18n></div>`}\n </div>\n `\n }\n\n private _renderListItem(h: EventHandlerSpec, i: number, total: number) {\n return html`\n <li\n ?active=${i === this.selectedIndex}\n ?disabled=${h.disabled}\n @click=${() => (this.selectedIndex = i)}\n >\n <div class=\"meta\">\n <span class=\"trigger\">${h.trigger}${h.disabled ? ' (off)' : ''}</span>\n <span class=\"summary\">${this._summarize(h)}</span>\n </div>\n <md-icon\n @click=${(e: Event) => this._toggleDisabled(i, e)}\n title=${h.disabled ? 'enable' : 'disable'}\n >${h.disabled ? 'toggle_off' : 'toggle_on'}</md-icon>\n <md-icon\n @click=${(e: Event) => this._duplicateHandler(i, e)}\n title=\"duplicate\"\n >content_copy</md-icon>\n <md-icon\n @click=${(e: Event) => this._moveHandler(i, -1, e)}\n title=\"move up\"\n ?style=${i === 0 ? 'opacity:0.2;pointer-events:none' : ''}\n >arrow_upward</md-icon>\n <md-icon\n @click=${(e: Event) => this._moveHandler(i, +1, e)}\n title=\"move down\"\n ?style=${i === total - 1 ? 'opacity:0.2;pointer-events:none' : ''}\n >arrow_downward</md-icon>\n <md-icon\n class=\"danger\"\n @click=${(e: Event) => this._removeHandler(i, e)}\n title=\"delete\"\n >delete</md-icon>\n </li>\n `\n }\n\n private _summarize(h: EventHandlerSpec): string {\n if (h.action === 'script') {\n const c = (h.code || '').replace(/\\s+/g, ' ').trim()\n return 'script · ' + (c.length > 60 ? c.slice(0, 60) + '…' : (c || '(empty)'))\n }\n return [h.action || '(none)', h.target ? `→${h.target}` : ''].filter(Boolean).join(' ')\n }\n\n private _addHandler() {\n const next: EventHandlerSpec = { trigger: 'click', action: '' }\n this.handlers = [...(this.handlers || []), next]\n this.selectedIndex = this.handlers.length - 1\n this._dispatch()\n }\n\n private _duplicateHandler(idx: number, e: Event) {\n e.stopPropagation()\n const original = this.handlers[idx]\n if (!original) return\n const copy: EventHandlerSpec = JSON.parse(JSON.stringify(original))\n const next = [...(this.handlers || [])]\n next.splice(idx + 1, 0, copy)\n this.handlers = next\n this.selectedIndex = idx + 1\n this._dispatch()\n }\n\n private _toggleDisabled(idx: number, e: Event) {\n e.stopPropagation()\n const next = [...(this.handlers || [])]\n next[idx] = { ...next[idx], disabled: !next[idx].disabled }\n this.handlers = next\n this._dispatch()\n }\n\n private _moveHandler(idx: number, delta: -1 | 1, e: Event) {\n e.stopPropagation()\n const next = [...(this.handlers || [])]\n const newIdx = idx + delta\n if (newIdx < 0 || newIdx >= next.length) return\n const [m] = next.splice(idx, 1)\n next.splice(newIdx, 0, m)\n this.handlers = next\n if (this.selectedIndex === idx) this.selectedIndex = newIdx\n this._dispatch()\n }\n\n private _removeHandler(idx: number, e: Event) {\n e.stopPropagation()\n const next = [...(this.handlers || [])]\n next.splice(idx, 1)\n this.handlers = next\n this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, next.length - 1))\n this._dispatch()\n }\n\n private _onHandlerChanged(e: CustomEvent) {\n const handler = e.detail?.handler as EventHandlerSpec\n if (!handler) return\n const next = [...(this.handlers || [])]\n next[this.selectedIndex] = handler\n this.handlers = next\n this._dispatch()\n }\n\n private _dispatch() {\n this.dispatchEvent(\n new CustomEvent('handlers-change', {\n bubbles: true,\n composed: true,\n detail: { handlers: this.handlers }\n })\n )\n }\n}\n"]}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license Copyright © HatioLab Inc. All rights reserved.
3
+ *
4
+ * EventHandlers panel — 컴포넌트의 `state.eventHandlers[]` 편집기.
5
+ *
6
+ * 데이터바인딩 panel 의 형제로 *완전 분리*. 데이터바인딩은 데이터 흐름 전용,
7
+ * eventHandlers 는 사용자 액션 (tap / hover / 등) 의 first-class 핸들러 등록.
8
+ *
9
+ * data-binding 패턴 그대로 — tabs (N handlers) + handler mapper + add/delete/copy/paste.
10
+ */
11
+ import '@material/web/icon/icon.js';
12
+ import '@operato/help/ox-title-with-help.js';
13
+ import '@operato/input/ox-buttons-radio.js';
14
+ import '@operato/i18n/ox-i18n.js';
15
+ import { PropertyValues } from 'lit';
16
+ import type { Properties, Scene } from '@hatiolab/things-scene';
17
+ import { AbstractProperty } from '../abstract-property.js';
18
+ import { EventHandlersMapper, type EventHandlerSpec } from './event-handlers-mapper.js';
19
+ declare const PropertyEventHandlers_base: typeof AbstractProperty & import("@open-wc/dedupe-mixin").Constructor<import("@open-wc/scoped-elements/types.js").ScopedElementsHost>;
20
+ export declare class PropertyEventHandlers extends PropertyEventHandlers_base {
21
+ static styles: import("lit").CSSResult[];
22
+ value?: Properties;
23
+ scene?: Scene;
24
+ handlerIndex: number;
25
+ _afterRender?: Function | null;
26
+ tabs: HTMLElement;
27
+ tabNavLeftButton: HTMLElement;
28
+ tabNavRightButton: HTMLElement;
29
+ /**
30
+ * 두 속성 통합 — 신규 `eventHandlers` 우선, 없으면 legacy `event` 객체를
31
+ * *read-only* 변환해 표시. 사용자가 수정 시 `eventHandlers` 에만 저장 — legacy
32
+ * 는 손대지 않음 (옛 코드 호환 / rollback 안전망).
33
+ */
34
+ get handlers(): EventHandlerSpec[];
35
+ firstUpdated(): void;
36
+ updated(changes: PropertyValues<this>): void;
37
+ static get scopedElements(): {
38
+ 'event-handlers-mapper': typeof EventHandlersMapper;
39
+ };
40
+ render(): import("lit-html").TemplateResult<1>;
41
+ _setHandlerIndex(idx: number): void;
42
+ _clearHandler(): void;
43
+ _copyHandler(): void;
44
+ _pasteHandler(): void;
45
+ _onHandlerChanged(e: CustomEvent): void;
46
+ private _dispatchHandlersChange;
47
+ onValueChanged(): Promise<void>;
48
+ _openHandlersPopup(): Promise<void>;
49
+ get tabContainer(): HTMLElement;
50
+ _onTabScroll(): void;
51
+ _onTabScrollNavLeft(): void;
52
+ _onTabScrollNavRight(): void;
53
+ }
54
+ export {};