@operato/property-panel 10.0.0-beta.6 → 10.0.0-beta.60
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 +395 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/ox-property-panel.d.ts +7 -0
- package/dist/src/ox-property-panel.js +62 -34
- package/dist/src/ox-property-panel.js.map +1 -1
- package/dist/src/property-panel/abstract-property.js +11 -2
- package/dist/src/property-panel/abstract-property.js.map +1 -1
- package/dist/src/property-panel/data-binding/data-binding-mapper.js +11 -3
- package/dist/src/property-panel/data-binding/data-binding-mapper.js.map +1 -1
- package/dist/src/property-panel/data-binding/data-binding-popup.d.ts +63 -0
- package/dist/src/property-panel/data-binding/data-binding-popup.js +1414 -0
- package/dist/src/property-panel/data-binding/data-binding-popup.js.map +1 -0
- package/dist/src/property-panel/data-binding/data-binding.d.ts +1 -0
- package/dist/src/property-panel/data-binding/data-binding.js +37 -5
- package/dist/src/property-panel/data-binding/data-binding.js.map +1 -1
- package/dist/src/property-panel/effects/effects.js +1 -1
- package/dist/src/property-panel/effects/effects.js.map +1 -1
- package/dist/src/property-panel/effects/property-event-hover.d.ts +1 -1
- package/dist/src/property-panel/effects/property-event-tap.js +21 -1
- package/dist/src/property-panel/effects/property-event-tap.js.map +1 -1
- package/dist/src/property-panel/effects/property-event.d.ts +15 -7
- package/dist/src/property-panel/effects/property-event.js +17 -38
- package/dist/src/property-panel/effects/property-event.js.map +1 -1
- package/dist/src/property-panel/effects/property-shadow.js +14 -5
- package/dist/src/property-panel/effects/property-shadow.js.map +1 -1
- package/dist/src/property-panel/event-handlers/event-handlers-help.d.ts +23 -0
- package/dist/src/property-panel/event-handlers/event-handlers-help.js +356 -0
- package/dist/src/property-panel/event-handlers/event-handlers-help.js.map +1 -0
- package/dist/src/property-panel/event-handlers/event-handlers-mapper.d.ts +31 -0
- package/dist/src/property-panel/event-handlers/event-handlers-mapper.js +238 -0
- package/dist/src/property-panel/event-handlers/event-handlers-mapper.js.map +1 -0
- package/dist/src/property-panel/event-handlers/event-handlers-popup.d.ts +42 -0
- package/dist/src/property-panel/event-handlers/event-handlers-popup.js +375 -0
- package/dist/src/property-panel/event-handlers/event-handlers-popup.js.map +1 -0
- package/dist/src/property-panel/event-handlers/event-handlers.d.ts +54 -0
- package/dist/src/property-panel/event-handlers/event-handlers.js +410 -0
- package/dist/src/property-panel/event-handlers/event-handlers.js.map +1 -0
- package/dist/src/property-panel/shapes/ox-placeholder-convert-editor.d.ts +20 -0
- package/dist/src/property-panel/shapes/ox-placeholder-convert-editor.js +125 -0
- package/dist/src/property-panel/shapes/ox-placeholder-convert-editor.js.map +1 -0
- package/dist/src/property-panel/shapes/placeholder-convert.d.ts +34 -0
- package/dist/src/property-panel/shapes/placeholder-convert.js +117 -0
- package/dist/src/property-panel/shapes/placeholder-convert.js.map +1 -0
- package/dist/src/property-panel/shapes/shapes.js +28 -10
- package/dist/src/property-panel/shapes/shapes.js.map +1 -1
- package/dist/src/property-panel/specifics/specifics.d.ts +1 -0
- package/dist/src/property-panel/specifics/specifics.js +2 -1
- package/dist/src/property-panel/specifics/specifics.js.map +1 -1
- package/dist/src/property-panel/styles/styles.js +2 -0
- package/dist/src/property-panel/styles/styles.js.map +1 -1
- package/dist/src/property-panel/threed/property-material3d.js +8 -1
- package/dist/src/property-panel/threed/property-material3d.js.map +1 -1
- package/dist/src/property-panel/threed/property-scene3d.d.ts +34 -6
- package/dist/src/property-panel/threed/property-scene3d.js +332 -201
- package/dist/src/property-panel/threed/property-scene3d.js.map +1 -1
- package/dist/src/property-panel/threed/threed.js +8 -0
- package/dist/src/property-panel/threed/threed.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/themes/grist-theme.css +1 -1
- package/translations/en.json +34 -1
- package/translations/ja.json +34 -1
- package/translations/ko.json +34 -1
- package/translations/ms.json +34 -1
- package/translations/zh.json +34 -1
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* PropertyEvent — effects tab 안의 이벤트 핸들러 진입점.
|
|
5
|
+
*
|
|
6
|
+
* data-binding 패턴 동일 — inline `<property-event-handlers>` (기본 UI: tabs +
|
|
7
|
+
* mapper + add/delete/copy/paste) 를 host. inline panel 의 우상단 `open_in_new`
|
|
8
|
+
* 클릭 시 *큰 popup* 으로 펼침.
|
|
9
|
+
*
|
|
10
|
+
* 자동 마이그레이션 — things-scene 의 Component constructor 가 legacy
|
|
11
|
+
* `state.event = { tap, hover, ... }` 를 *load 시점* 에 `state.eventHandlers[]`
|
|
12
|
+
* 로 변환. UI 는 항상 `eventHandlers` 만 read/write.
|
|
13
|
+
*
|
|
14
|
+
* Legacy 컴포넌트 (PropertyEventHover / PropertyEventTap) 파일은 *코드 유지*
|
|
15
|
+
* (rollback 안전망). UI 진입점만 끊음.
|
|
3
16
|
*/
|
|
4
|
-
import '@operato/help/ox-title-with-help.js';
|
|
5
17
|
import { LitElement } from 'lit';
|
|
6
18
|
import { Properties, Scene } from '@hatiolab/things-scene';
|
|
7
|
-
import {
|
|
8
|
-
import { PropertyEventTap } from './property-event-tap.js';
|
|
19
|
+
import { PropertyEventHandlers } from '../event-handlers/event-handlers.js';
|
|
9
20
|
declare const PropertyEvent_base: typeof LitElement & import("@open-wc/dedupe-mixin").Constructor<import("@open-wc/scoped-elements/types.js").ScopedElementsHost>;
|
|
10
21
|
export declare class PropertyEvent extends PropertyEvent_base {
|
|
11
22
|
static styles: import("lit").CSSResult[];
|
|
12
23
|
value?: Properties;
|
|
13
24
|
scene?: Scene;
|
|
14
|
-
firstUpdated(): void;
|
|
15
25
|
static get scopedElements(): {
|
|
16
|
-
'property-event-
|
|
17
|
-
'property-event-tap': typeof PropertyEventTap;
|
|
26
|
+
'property-event-handlers': typeof PropertyEventHandlers;
|
|
18
27
|
};
|
|
19
28
|
render(): import("lit-html").TemplateResult<1>;
|
|
20
|
-
onValueChange(e: Event): void;
|
|
21
29
|
}
|
|
22
30
|
export {};
|
|
@@ -1,58 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* PropertyEvent — effects tab 안의 이벤트 핸들러 진입점.
|
|
5
|
+
*
|
|
6
|
+
* data-binding 패턴 동일 — inline `<property-event-handlers>` (기본 UI: tabs +
|
|
7
|
+
* mapper + add/delete/copy/paste) 를 host. inline panel 의 우상단 `open_in_new`
|
|
8
|
+
* 클릭 시 *큰 popup* 으로 펼침.
|
|
9
|
+
*
|
|
10
|
+
* 자동 마이그레이션 — things-scene 의 Component constructor 가 legacy
|
|
11
|
+
* `state.event = { tap, hover, ... }` 를 *load 시점* 에 `state.eventHandlers[]`
|
|
12
|
+
* 로 변환. UI 는 항상 `eventHandlers` 만 read/write.
|
|
13
|
+
*
|
|
14
|
+
* Legacy 컴포넌트 (PropertyEventHover / PropertyEventTap) 파일은 *코드 유지*
|
|
15
|
+
* (rollback 안전망). UI 진입점만 끊음.
|
|
3
16
|
*/
|
|
4
17
|
import { __decorate } from "tslib";
|
|
5
|
-
import '@operato/help/ox-title-with-help.js';
|
|
6
18
|
import { html, LitElement } from 'lit';
|
|
7
19
|
import { property } from 'lit/decorators.js';
|
|
8
20
|
import { ScopedElementsMixin } from '@open-wc/scoped-elements';
|
|
9
21
|
import { PropertyGridStyles } from '@operato/styles/property-grid-styles.js';
|
|
10
|
-
import {
|
|
11
|
-
import { PropertyEventTap } from './property-event-tap.js';
|
|
12
|
-
import { convert } from './value-converter.js';
|
|
22
|
+
import { PropertyEventHandlers } from '../event-handlers/event-handlers.js';
|
|
13
23
|
export class PropertyEvent extends ScopedElementsMixin(LitElement) {
|
|
14
|
-
firstUpdated() {
|
|
15
|
-
this.renderRoot.addEventListener('change', this.onValueChange.bind(this));
|
|
16
|
-
}
|
|
17
24
|
static get scopedElements() {
|
|
18
25
|
return {
|
|
19
|
-
'property-event-
|
|
20
|
-
'property-event-tap': PropertyEventTap
|
|
26
|
+
'property-event-handlers': PropertyEventHandlers
|
|
21
27
|
};
|
|
22
28
|
}
|
|
23
29
|
render() {
|
|
24
|
-
const value = this.value || {};
|
|
25
30
|
return html `
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
<ox-title-with-help msgid="label.hover-event" topic="board-modeller/effects/hover-event"></ox-title-with-help>
|
|
29
|
-
</legend>
|
|
30
|
-
|
|
31
|
-
<property-event-hover value-key="hover" .scene=${this.scene} .value=${value.hover || {}}>
|
|
32
|
-
</property-event-hover>
|
|
33
|
-
</fieldset>
|
|
34
|
-
|
|
35
|
-
<fieldset>
|
|
36
|
-
<legend>
|
|
37
|
-
<ox-title-with-help msgid="label.tap-event" topic="board-modeller/effects/tap-event"></ox-title-with-help>
|
|
38
|
-
</legend>
|
|
39
|
-
|
|
40
|
-
<property-event-tap value-key="tap" .scene=${this.scene} .value=${value.tap || {}}> </property-event-tap>
|
|
41
|
-
</fieldset>
|
|
31
|
+
<property-event-handlers .value=${this.value} .scene=${this.scene}>
|
|
32
|
+
</property-event-handlers>
|
|
42
33
|
`;
|
|
43
34
|
}
|
|
44
|
-
onValueChange(e) {
|
|
45
|
-
var element = e.target;
|
|
46
|
-
var key = element.getAttribute('value-key');
|
|
47
|
-
if (!key) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
this.value = {
|
|
51
|
-
...this.value,
|
|
52
|
-
[key]: convert(element)
|
|
53
|
-
};
|
|
54
|
-
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
|
|
55
|
-
}
|
|
56
35
|
}
|
|
57
36
|
PropertyEvent.styles = [PropertyGridStyles];
|
|
58
37
|
__decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"property-event.js","sourceRoot":"","sources":["../../../../src/property-panel/effects/property-event.ts"],"names":[],"mappings":"AAAA;;
|
|
1
|
+
{"version":3,"file":"property-event.js","sourceRoot":"","sources":["../../../../src/property-panel/effects/property-event.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAG5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAE5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAE3E,MAAM,OAAO,aAAc,SAAQ,mBAAmB,CAAC,UAAU,CAAC;IAMhE,MAAM,KAAK,cAAc;QACvB,OAAO;YACL,yBAAyB,EAAE,qBAAqB;SACjD,CAAA;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;wCACyB,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK;;KAElE,CAAA;IACH,CAAC;;AAhBM,oBAAM,GAAG,CAAC,kBAAkB,CAAC,CAAA;AAER;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAAmB;AAClB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAAc","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n *\n * PropertyEvent — effects tab 안의 이벤트 핸들러 진입점.\n *\n * data-binding 패턴 동일 — inline `<property-event-handlers>` (기본 UI: tabs +\n * mapper + add/delete/copy/paste) 를 host. inline panel 의 우상단 `open_in_new`\n * 클릭 시 *큰 popup* 으로 펼침.\n *\n * 자동 마이그레이션 — things-scene 의 Component constructor 가 legacy\n * `state.event = { tap, hover, ... }` 를 *load 시점* 에 `state.eventHandlers[]`\n * 로 변환. UI 는 항상 `eventHandlers` 만 read/write.\n *\n * Legacy 컴포넌트 (PropertyEventHover / PropertyEventTap) 파일은 *코드 유지*\n * (rollback 안전망). UI 진입점만 끊음.\n */\n\nimport { html, LitElement } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Properties, Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { PropertyEventHandlers } from '../event-handlers/event-handlers.js'\n\nexport class PropertyEvent extends ScopedElementsMixin(LitElement) {\n static styles = [PropertyGridStyles]\n\n @property({ type: Object }) value?: Properties\n @property({ type: Object }) scene?: Scene\n\n static get scopedElements() {\n return {\n 'property-event-handlers': PropertyEventHandlers\n }\n }\n\n render() {\n return html`\n <property-event-handlers .value=${this.value} .scene=${this.scene}>\n </property-event-handlers>\n `\n }\n}\n"]}
|
|
@@ -22,17 +22,23 @@ export class PropertyShadow extends LitElement {
|
|
|
22
22
|
this.renderRoot.addEventListener('change', this.onValueChange.bind(this));
|
|
23
23
|
}
|
|
24
24
|
render() {
|
|
25
|
-
|
|
25
|
+
var _a, _b, _c;
|
|
26
|
+
const value = (this.value || {});
|
|
27
|
+
// 옛 모델 (left/top/blurSize) 도 표시 가능하도록 fallback 으로 읽는다.
|
|
28
|
+
// 새 키 우선, 없으면 옛 키 — drawer (things-scene/effect/shadow.ts) 와 동일 규칙.
|
|
29
|
+
const offsetX = (_a = value.offsetX) !== null && _a !== void 0 ? _a : value.left;
|
|
30
|
+
const offsetY = (_b = value.offsetY) !== null && _b !== void 0 ? _b : value.top;
|
|
31
|
+
const blur = (_c = value.blur) !== null && _c !== void 0 ? _c : value.blurSize;
|
|
26
32
|
return html `
|
|
27
33
|
<div class="property-grid">
|
|
28
34
|
<label> <ox-i18n msgid="label.shadowOffsetX">offset-X</ox-i18n> </label>
|
|
29
|
-
<input type="number" value-key="
|
|
35
|
+
<input type="number" value-key="offsetX" .value=${offsetX} />
|
|
30
36
|
|
|
31
37
|
<label> <ox-i18n msgid="label.shadowOffsetY">offset-Y</ox-i18n> </label>
|
|
32
|
-
<input type="number" value-key="
|
|
38
|
+
<input type="number" value-key="offsetY" .value=${offsetY} />
|
|
33
39
|
|
|
34
40
|
<label> <ox-i18n msgid="label.shadowSize">Size</ox-i18n> </label>
|
|
35
|
-
<input type="number" value-key="
|
|
41
|
+
<input type="number" value-key="blur" .value=${blur} />
|
|
36
42
|
|
|
37
43
|
<label class="icon-only-label color"><md-icon>format_color_fill</md-icon></label>
|
|
38
44
|
<ox-input-color value-key="color" .value=${value.color}> </ox-input-color>
|
|
@@ -45,8 +51,11 @@ export class PropertyShadow extends LitElement {
|
|
|
45
51
|
if (!key) {
|
|
46
52
|
return;
|
|
47
53
|
}
|
|
54
|
+
// 새 키로 통일해 저장하면서 옛 키 (left/top/blurSize) 는 제거 — 양쪽이
|
|
55
|
+
// 동시에 남아있으면 drawer fallback 우선순위 때문에 가시값과 어긋날 수 있다.
|
|
56
|
+
const { left, top, blurSize, ...rest } = (this.value || {});
|
|
48
57
|
this.value = {
|
|
49
|
-
...
|
|
58
|
+
...rest,
|
|
50
59
|
[key]: convert(element)
|
|
51
60
|
};
|
|
52
61
|
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"property-shadow.js","sourceRoot":"","sources":["../../../../src/property-panel/effects/property-shadow.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,OAAO,0BAA0B,CAAA;AACjC,OAAO,kCAAkC,CAAA;AAEzC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAE9C;;;;;;;;GAQG;AAEH,MAAM,OAAO,cAAe,SAAQ,UAAU;IAY5C,YAAY;QACV,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3E,CAAC;IAED,MAAM
|
|
1
|
+
{"version":3,"file":"property-shadow.js","sourceRoot":"","sources":["../../../../src/property-panel/effects/property-shadow.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,OAAO,0BAA0B,CAAA;AACjC,OAAO,kCAAkC,CAAA;AAEzC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAE9C;;;;;;;;GAQG;AAEH,MAAM,OAAO,cAAe,SAAQ,UAAU;IAY5C,YAAY;QACV,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3E,CAAC;IAED,MAAM;;QACJ,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAO9B,CAAA;QAED,uDAAuD;QACvD,oEAAoE;QACpE,MAAM,OAAO,GAAG,MAAA,KAAK,CAAC,OAAO,mCAAI,KAAK,CAAC,IAAI,CAAA;QAC3C,MAAM,OAAO,GAAG,MAAA,KAAK,CAAC,OAAO,mCAAI,KAAK,CAAC,GAAG,CAAA;QAC1C,MAAM,IAAI,GAAG,MAAA,KAAK,CAAC,IAAI,mCAAI,KAAK,CAAC,QAAQ,CAAA;QAEzC,OAAO,IAAI,CAAA;;;0DAG2C,OAAO;;;0DAGP,OAAO;;;uDAGV,IAAI;;;mDAGR,KAAK,CAAC,KAAK;;KAEzD,CAAA;IACH,CAAC;IAED,aAAa,CAAC,CAAQ;QACpB,IAAI,OAAO,GAAG,CAAC,CAAC,MAAqB,CAAA;QACrC,IAAI,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;QAE3C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAM;QACR,CAAC;QAED,oDAAoD;QACpD,oDAAoD;QACpD,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAIzD,CAAA;QAED,IAAI,CAAC,KAAK,GAAG;YACX,GAAG,IAAI;YACP,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;SACxB,CAAA;QAED,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAClF,CAAC;;AAtEM,qBAAM,GAAG;IACd,kBAAkB;IAClB,GAAG,CAAA;;;;KAIF;CACF,CAAA;AAE2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CAAmB","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/i18n/ox-i18n.js'\nimport '@operato/input/ox-input-color.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Properties } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { convert } from './value-converter.js'\n\n/**\n * 컴포넌트의 그림자 속성을 편집하는 element\n *\n * Example:\n * <property-shadow\n * @change=\"${e => { this.shadow = e.target.value }}\"\n * value=\"${this.shadow}\"\n * ></property-shadow>\n */\n\nexport class PropertyShadow extends LitElement {\n static styles = [\n PropertyGridStyles,\n css`\n :host {\n display: flex;\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', this.onValueChange.bind(this))\n }\n\n render() {\n const value = (this.value || {}) as Properties & {\n offsetX?: number\n offsetY?: number\n blur?: number\n left?: number\n top?: number\n blurSize?: number\n }\n\n // 옛 모델 (left/top/blurSize) 도 표시 가능하도록 fallback 으로 읽는다.\n // 새 키 우선, 없으면 옛 키 — drawer (things-scene/effect/shadow.ts) 와 동일 규칙.\n const offsetX = value.offsetX ?? value.left\n const offsetY = value.offsetY ?? value.top\n const blur = value.blur ?? value.blurSize\n\n return html`\n <div class=\"property-grid\">\n <label> <ox-i18n msgid=\"label.shadowOffsetX\">offset-X</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetX\" .value=${offsetX} />\n\n <label> <ox-i18n msgid=\"label.shadowOffsetY\">offset-Y</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetY\" .value=${offsetY} />\n\n <label> <ox-i18n msgid=\"label.shadowSize\">Size</ox-i18n> </label>\n <input type=\"number\" value-key=\"blur\" .value=${blur} />\n\n <label class=\"icon-only-label color\"><md-icon>format_color_fill</md-icon></label>\n <ox-input-color value-key=\"color\" .value=${value.color}> </ox-input-color>\n </div>\n `\n }\n\n onValueChange(e: Event) {\n var element = e.target as HTMLElement\n var key = element.getAttribute('value-key')\n\n if (!key) {\n return\n }\n\n // 새 키로 통일해 저장하면서 옛 키 (left/top/blurSize) 는 제거 — 양쪽이\n // 동시에 남아있으면 drawer fallback 우선순위 때문에 가시값과 어긋날 수 있다.\n const { left, top, blurSize, ...rest } = (this.value || {}) as Properties & {\n left?: number\n top?: number\n blurSize?: number\n }\n\n this.value = {\n ...rest,\n [key]: convert(element)\n }\n\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* EventHandlers help pane — popup 의 우측 docs 컬럼.
|
|
5
|
+
*
|
|
6
|
+
* 현재 선택된 handler 의 trigger / action / target / value (또는 script vars)
|
|
7
|
+
* 의미를 *동적으로* 안내. script 모드에서는 자주 쓰는 코드 snippet 을
|
|
8
|
+
* 삽입할 수 있는 버튼도 제공.
|
|
9
|
+
*
|
|
10
|
+
* 다국어 — 1차안은 한국어 hard-code (5 언어 동시 유지 부담 회피).
|
|
11
|
+
* 추후 안정화 후 i18n 키로 분리.
|
|
12
|
+
*/
|
|
13
|
+
import '@material/web/icon/icon.js';
|
|
14
|
+
import { LitElement } from 'lit';
|
|
15
|
+
import type { EventHandlerSpec } from './event-handlers-mapper.js';
|
|
16
|
+
export declare class EventHandlersHelp extends LitElement {
|
|
17
|
+
static styles: import("lit").CSSResult[];
|
|
18
|
+
handler?: EventHandlerSpec;
|
|
19
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
20
|
+
private _renderDeclarativeHelp;
|
|
21
|
+
private _renderScriptHelp;
|
|
22
|
+
private _emitSnippet;
|
|
23
|
+
}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* EventHandlers help pane — popup 의 우측 docs 컬럼.
|
|
5
|
+
*
|
|
6
|
+
* 현재 선택된 handler 의 trigger / action / target / value (또는 script vars)
|
|
7
|
+
* 의미를 *동적으로* 안내. script 모드에서는 자주 쓰는 코드 snippet 을
|
|
8
|
+
* 삽입할 수 있는 버튼도 제공.
|
|
9
|
+
*
|
|
10
|
+
* 다국어 — 1차안은 한국어 hard-code (5 언어 동시 유지 부담 회피).
|
|
11
|
+
* 추후 안정화 후 i18n 키로 분리.
|
|
12
|
+
*/
|
|
13
|
+
import { __decorate } from "tslib";
|
|
14
|
+
import '@material/web/icon/icon.js';
|
|
15
|
+
import { css, html, LitElement } from 'lit';
|
|
16
|
+
import { property } from 'lit/decorators.js';
|
|
17
|
+
import { ScrollbarStyles } from '@operato/styles';
|
|
18
|
+
const TRIGGER_DESC = {
|
|
19
|
+
click: {
|
|
20
|
+
summary: '마우스 클릭 (터치 환경에선 tap 과 동일).',
|
|
21
|
+
example: '가장 일반적인 버튼/아이콘 액션에 사용.'
|
|
22
|
+
},
|
|
23
|
+
tap: {
|
|
24
|
+
summary: 'click 의 alias (legacy 호환). 신규 등록은 click 권장.'
|
|
25
|
+
},
|
|
26
|
+
dblclick: {
|
|
27
|
+
summary: '더블 클릭. 빠른 연속 2회 클릭으로만 발화.'
|
|
28
|
+
},
|
|
29
|
+
mouseenter: {
|
|
30
|
+
summary: '포인터가 컴포넌트 영역에 *진입* 한 순간 1회.',
|
|
31
|
+
example: 'hover 강조 / tooltip 표시에 사용.'
|
|
32
|
+
},
|
|
33
|
+
hover: {
|
|
34
|
+
summary: 'mouseenter 의 alias (legacy). 신규 등록은 mouseenter 권장.'
|
|
35
|
+
},
|
|
36
|
+
mouseleave: {
|
|
37
|
+
summary: '포인터가 컴포넌트 영역을 *이탈* 한 순간 1회.',
|
|
38
|
+
example: 'mouseenter 와 짝지어 강조 해제에 사용.'
|
|
39
|
+
},
|
|
40
|
+
longpress: {
|
|
41
|
+
summary: '약 500ms 이상 누름. 클릭과 별개로 발화.'
|
|
42
|
+
},
|
|
43
|
+
mousedown: {
|
|
44
|
+
summary: '버튼 누름 시작 시점. mouseup 과 짝지어 pressed 패턴 가능.'
|
|
45
|
+
},
|
|
46
|
+
mouseup: {
|
|
47
|
+
summary: '버튼 누름 해제 시점.'
|
|
48
|
+
},
|
|
49
|
+
pressed: {
|
|
50
|
+
summary: 'mousedown ↔ mouseup 페어 자동 매핑 (legacy 호환).'
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const ACTION_DESC = {
|
|
54
|
+
'': {
|
|
55
|
+
summary: '액션이 선택되지 않음. 핸들러는 등록되지만 아무 동작도 하지 않는다.'
|
|
56
|
+
},
|
|
57
|
+
script: {
|
|
58
|
+
summary: '자유 JavaScript 코드. component / scene / event / targets / value 를 변수로 받아 임의 동작을 수행.',
|
|
59
|
+
example: 'await 사용 가능 — 비동기 동작도 그대로 작성.'
|
|
60
|
+
},
|
|
61
|
+
'data-toggle': {
|
|
62
|
+
summary: 'target 컴포넌트의 data 값을 truthy ↔ falsy 로 토글.',
|
|
63
|
+
example: 'value 필드는 무시. target 미설정 시 자기 자신.'
|
|
64
|
+
},
|
|
65
|
+
'data-tristate': {
|
|
66
|
+
summary: 'target 의 data 값을 0 → 1 → 2 → 0 순환.',
|
|
67
|
+
example: '세 상태 토글 (off / on / mixed 같은) 용.'
|
|
68
|
+
},
|
|
69
|
+
'data-spreading': {
|
|
70
|
+
summary: 'target 들에 value 를 분배 (배열 또는 매핑).',
|
|
71
|
+
example: 'value 가 배열이면 target N개에 각각 매칭.'
|
|
72
|
+
},
|
|
73
|
+
'data-set': {
|
|
74
|
+
summary: 'target 의 data 를 value 로 설정. value 는 정적 값 또는 accessor.',
|
|
75
|
+
example: '예) value=1 / value=accessor.someField'
|
|
76
|
+
},
|
|
77
|
+
'partial-data-set': {
|
|
78
|
+
summary: 'target.data 가 객체일 때, value 의 키들만 partial merge.',
|
|
79
|
+
example: 'value 는 객체 또는 객체를 가리키는 accessor.'
|
|
80
|
+
},
|
|
81
|
+
'value-set': {
|
|
82
|
+
summary: 'target 의 value 속성을 value 로 설정.',
|
|
83
|
+
example: 'data 가 아니라 value 속성을 다루는 컴포넌트용.'
|
|
84
|
+
},
|
|
85
|
+
'partial-value-set': {
|
|
86
|
+
summary: 'target.value 가 객체일 때, partial merge.'
|
|
87
|
+
},
|
|
88
|
+
'info-window': {
|
|
89
|
+
summary: 'target 의 info-window (팝업) 를 띄움.',
|
|
90
|
+
example: 'target 컴포넌트의 popup 정보가 미리 정의되어 있어야 함.'
|
|
91
|
+
},
|
|
92
|
+
emphasize: {
|
|
93
|
+
summary: 'target 을 시각적으로 강조 (애니메이션).',
|
|
94
|
+
example: 'mouseenter / mouseleave 와 짝지어 emphasize/restore 패턴 자주 사용.'
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const SCRIPT_VARS = [
|
|
98
|
+
{ name: 'component', desc: '핸들러가 등록된 현재 컴포넌트.' },
|
|
99
|
+
{ name: 'scene', desc: '루트 scene. scene.root 로 다른 컴포넌트 검색.' },
|
|
100
|
+
{ name: 'event', desc: '원본 DOM 이벤트 (또는 합성 이벤트) 객체.' },
|
|
101
|
+
{ name: 'targets', desc: 'target selector 로 찾은 컴포넌트 배열. target 비면 빈 배열.' },
|
|
102
|
+
{ name: 'value', desc: '핸들러의 value 필드 (정적 또는 accessor).' }
|
|
103
|
+
];
|
|
104
|
+
const SNIPPETS = [
|
|
105
|
+
{
|
|
106
|
+
label: 'console.log',
|
|
107
|
+
code: `console.log('event handler', { component, event })`
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: 'data 토글',
|
|
111
|
+
code: `component.data = !component.data`
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: 'targets 에 값 세팅',
|
|
115
|
+
code: `targets.forEach(t => { t.data = value })`
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: 'findById 로 특정 컴포넌트 변경',
|
|
119
|
+
code: `// '#someId' 는 대상 컴포넌트의 id 로 바꿔 쓴다.
|
|
120
|
+
const target = scene.root.findAll('#someId', component)[0]
|
|
121
|
+
if (target) {
|
|
122
|
+
target.data = component.data
|
|
123
|
+
}`
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
label: 'async fetch + data 반영',
|
|
127
|
+
code: `const res = await fetch('/api/something')
|
|
128
|
+
const json = await res.json()
|
|
129
|
+
component.data = json`
|
|
130
|
+
}
|
|
131
|
+
];
|
|
132
|
+
export class EventHandlersHelp extends LitElement {
|
|
133
|
+
render() {
|
|
134
|
+
var _a;
|
|
135
|
+
const h = this.handler || { trigger: 'click', action: '' };
|
|
136
|
+
const trigDesc = TRIGGER_DESC[h.trigger] || { summary: '(unknown trigger)' };
|
|
137
|
+
const actDesc = ACTION_DESC[(_a = h.action) !== null && _a !== void 0 ? _a : ''] || { summary: '(unknown action)' };
|
|
138
|
+
const isScript = h.action === 'script';
|
|
139
|
+
return html `
|
|
140
|
+
<section>
|
|
141
|
+
<h4>Trigger</h4>
|
|
142
|
+
<div class="name">${h.trigger}</div>
|
|
143
|
+
<p class="summary">${trigDesc.summary}</p>
|
|
144
|
+
${trigDesc.example ? html `<div class="example">${trigDesc.example}</div>` : ''}
|
|
145
|
+
</section>
|
|
146
|
+
|
|
147
|
+
<section>
|
|
148
|
+
<h4>Action</h4>
|
|
149
|
+
<div class="name">${h.action || '(none)'}</div>
|
|
150
|
+
<p class="summary">${actDesc.summary}</p>
|
|
151
|
+
${actDesc.example ? html `<div class="example">${actDesc.example}</div>` : ''}
|
|
152
|
+
</section>
|
|
153
|
+
|
|
154
|
+
${isScript ? this._renderScriptHelp() : this._renderDeclarativeHelp()}
|
|
155
|
+
`;
|
|
156
|
+
}
|
|
157
|
+
_renderDeclarativeHelp() {
|
|
158
|
+
return html `
|
|
159
|
+
<section>
|
|
160
|
+
<h4>Target selector</h4>
|
|
161
|
+
<div class="selector-grid">
|
|
162
|
+
<code>#id</code><span>id 일치</span>
|
|
163
|
+
<code>.class</code><span>class 일치 (공백 구분 다중)</span>
|
|
164
|
+
<code><타입></code><span>type 일치 (예: rect, button)</span>
|
|
165
|
+
<code>(self)</code><span>현재 컴포넌트 자기 자신</span>
|
|
166
|
+
<code>(all)</code><span>모든 컴포넌트</span>
|
|
167
|
+
<code>(root)</code><span>루트 컴포넌트</span>
|
|
168
|
+
<code>(parent)</code><span>부모</span>
|
|
169
|
+
<code>(children)</code><span>직접 자식들</span>
|
|
170
|
+
<code>(siblings)</code><span>형제들 (자기 제외)</span>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="example" style="margin-top:6px">
|
|
173
|
+
비워두면 매칭 없음 — 자기 자신을 대상으로 하려면 <code style="background:transparent;padding:0">(self)</code>.
|
|
174
|
+
</div>
|
|
175
|
+
</section>
|
|
176
|
+
|
|
177
|
+
<section>
|
|
178
|
+
<h4>Value</h4>
|
|
179
|
+
<p class="summary">정적 값 또는 accessor 표현식. accessor 인 경우 component.access(value) 로 평가되어 컴포넌트 컨텍스트의 데이터를 참조한다.</p>
|
|
180
|
+
</section>
|
|
181
|
+
`;
|
|
182
|
+
}
|
|
183
|
+
_renderScriptHelp() {
|
|
184
|
+
return html `
|
|
185
|
+
<section>
|
|
186
|
+
<h4>Script 변수</h4>
|
|
187
|
+
<ul class="vars">
|
|
188
|
+
${SCRIPT_VARS.map(v => html `
|
|
189
|
+
<li><code>${v.name}</code>${v.desc}</li>
|
|
190
|
+
`)}
|
|
191
|
+
</ul>
|
|
192
|
+
<div class="example" style="margin-top:8px">
|
|
193
|
+
<code style="background:transparent;padding:0">await</code> 키워드 사용 시 스크립트는 비동기로 실행. 결과 wait 후 다음 핸들러가 영향 받지는 않는다 (각 핸들러는 독립 실행).
|
|
194
|
+
</div>
|
|
195
|
+
</section>
|
|
196
|
+
|
|
197
|
+
<section>
|
|
198
|
+
<h4>Snippet 삽입</h4>
|
|
199
|
+
<div class="snippet-list">
|
|
200
|
+
${SNIPPETS.map(s => html `
|
|
201
|
+
<button
|
|
202
|
+
type="button"
|
|
203
|
+
class="snippet-btn"
|
|
204
|
+
@click=${() => this._emitSnippet(s.code)}
|
|
205
|
+
title="현재 스크립트 영역에 삽입 (덮어쓰지 않고 끝에 추가)"
|
|
206
|
+
>
|
|
207
|
+
<span>${s.label}</span>
|
|
208
|
+
<md-icon>add</md-icon>
|
|
209
|
+
</button>
|
|
210
|
+
`)}
|
|
211
|
+
</div>
|
|
212
|
+
</section>
|
|
213
|
+
`;
|
|
214
|
+
}
|
|
215
|
+
_emitSnippet(code) {
|
|
216
|
+
this.dispatchEvent(new CustomEvent('insert-snippet', {
|
|
217
|
+
bubbles: true,
|
|
218
|
+
composed: true,
|
|
219
|
+
detail: { code }
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
EventHandlersHelp.styles = [
|
|
224
|
+
ScrollbarStyles,
|
|
225
|
+
css `
|
|
226
|
+
:host {
|
|
227
|
+
display: flex;
|
|
228
|
+
flex-direction: column;
|
|
229
|
+
width: 100%;
|
|
230
|
+
height: 100%;
|
|
231
|
+
box-sizing: border-box;
|
|
232
|
+
background: var(--md-sys-color-surface-container-lowest, #fffbfe);
|
|
233
|
+
border-left: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));
|
|
234
|
+
padding: 16px 18px;
|
|
235
|
+
overflow-y: auto;
|
|
236
|
+
font-family: 'Roboto', Arial, sans-serif;
|
|
237
|
+
font-size: 12.5px;
|
|
238
|
+
color: var(--md-sys-color-on-surface, #1c1b1f);
|
|
239
|
+
line-height: 1.5;
|
|
240
|
+
min-width: 0;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
h4 {
|
|
244
|
+
margin: 0 0 6px 0;
|
|
245
|
+
font-size: 11px;
|
|
246
|
+
font-weight: 700;
|
|
247
|
+
letter-spacing: 0.5px;
|
|
248
|
+
text-transform: uppercase;
|
|
249
|
+
color: var(--md-sys-color-on-surface-variant, #49454f);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
section {
|
|
253
|
+
margin-bottom: 18px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.name {
|
|
257
|
+
display: inline-block;
|
|
258
|
+
padding: 2px 6px;
|
|
259
|
+
margin-bottom: 6px;
|
|
260
|
+
background: var(--md-sys-color-secondary-container, #e8def8);
|
|
261
|
+
color: var(--md-sys-color-on-secondary-container, #1d192b);
|
|
262
|
+
border-radius: 4px;
|
|
263
|
+
font-weight: 600;
|
|
264
|
+
font-size: 11.5px;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.summary {
|
|
268
|
+
margin: 0 0 6px 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.example {
|
|
272
|
+
margin: 4px 0 0 0;
|
|
273
|
+
padding: 6px 8px;
|
|
274
|
+
background: rgba(0, 0, 0, 0.04);
|
|
275
|
+
border-left: 2px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.2));
|
|
276
|
+
font-size: 11.5px;
|
|
277
|
+
color: var(--md-sys-color-on-surface-variant, #49454f);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
ul.vars {
|
|
281
|
+
list-style: none;
|
|
282
|
+
margin: 0;
|
|
283
|
+
padding: 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
ul.vars li {
|
|
287
|
+
padding: 4px 0;
|
|
288
|
+
border-bottom: 1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.08));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
ul.vars li:last-child {
|
|
292
|
+
border-bottom: none;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
ul.vars code {
|
|
296
|
+
display: inline-block;
|
|
297
|
+
padding: 1px 5px;
|
|
298
|
+
margin-right: 6px;
|
|
299
|
+
background: var(--md-sys-color-surface-container-high, #ede7f6);
|
|
300
|
+
border-radius: 3px;
|
|
301
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
302
|
+
font-size: 11px;
|
|
303
|
+
color: var(--md-sys-color-on-surface, #1c1b1f);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.snippet-list {
|
|
307
|
+
display: flex;
|
|
308
|
+
flex-direction: column;
|
|
309
|
+
gap: 6px;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.snippet-btn {
|
|
313
|
+
display: flex;
|
|
314
|
+
align-items: center;
|
|
315
|
+
justify-content: space-between;
|
|
316
|
+
gap: 6px;
|
|
317
|
+
padding: 6px 10px;
|
|
318
|
+
border: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.18));
|
|
319
|
+
border-radius: 4px;
|
|
320
|
+
background: var(--md-sys-color-surface, #fff);
|
|
321
|
+
color: var(--md-sys-color-on-surface, #1c1b1f);
|
|
322
|
+
font-size: 12px;
|
|
323
|
+
cursor: pointer;
|
|
324
|
+
text-align: left;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.snippet-btn:hover {
|
|
328
|
+
background: var(--md-sys-color-surface-container-low, #f7f2fa);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.snippet-btn md-icon {
|
|
332
|
+
--md-icon-size: 16px;
|
|
333
|
+
opacity: 0.7;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.selector-grid {
|
|
337
|
+
display: grid;
|
|
338
|
+
grid-template-columns: max-content 1fr;
|
|
339
|
+
column-gap: 10px;
|
|
340
|
+
row-gap: 4px;
|
|
341
|
+
font-size: 11.5px;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.selector-grid code {
|
|
345
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
346
|
+
background: var(--md-sys-color-surface-container-high, #ede7f6);
|
|
347
|
+
padding: 1px 5px;
|
|
348
|
+
border-radius: 3px;
|
|
349
|
+
}
|
|
350
|
+
`
|
|
351
|
+
];
|
|
352
|
+
__decorate([
|
|
353
|
+
property({ type: Object })
|
|
354
|
+
], EventHandlersHelp.prototype, "handler", void 0);
|
|
355
|
+
customElements.define('event-handlers-help', EventHandlersHelp);
|
|
356
|
+
//# sourceMappingURL=event-handlers-help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-handlers-help.js","sourceRoot":"","sources":["../../../../src/property-panel/event-handlers/event-handlers-help.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n *\n * EventHandlers help pane — popup 의 우측 docs 컬럼.\n *\n * 현재 선택된 handler 의 trigger / action / target / value (또는 script vars)\n * 의미를 *동적으로* 안내. script 모드에서는 자주 쓰는 코드 snippet 을\n * 삽입할 수 있는 버튼도 제공.\n *\n * 다국어 — 1차안은 한국어 hard-code (5 언어 동시 유지 부담 회피).\n * 추후 안정화 후 i18n 키로 분리.\n */\n\nimport '@material/web/icon/icon.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport type { EventHandlerSpec } from './event-handlers-mapper.js'\n\ntype DescEntry = { summary: string; example?: string }\n\nconst TRIGGER_DESC: Record<string, DescEntry> = {\n click: {\n summary: '마우스 클릭 (터치 환경에선 tap 과 동일).',\n example: '가장 일반적인 버튼/아이콘 액션에 사용.'\n },\n tap: {\n summary: 'click 의 alias (legacy 호환). 신규 등록은 click 권장.'\n },\n dblclick: {\n summary: '더블 클릭. 빠른 연속 2회 클릭으로만 발화.'\n },\n mouseenter: {\n summary: '포인터가 컴포넌트 영역에 *진입* 한 순간 1회.',\n example: 'hover 강조 / tooltip 표시에 사용.'\n },\n hover: {\n summary: 'mouseenter 의 alias (legacy). 신규 등록은 mouseenter 권장.'\n },\n mouseleave: {\n summary: '포인터가 컴포넌트 영역을 *이탈* 한 순간 1회.',\n example: 'mouseenter 와 짝지어 강조 해제에 사용.'\n },\n longpress: {\n summary: '약 500ms 이상 누름. 클릭과 별개로 발화.'\n },\n mousedown: {\n summary: '버튼 누름 시작 시점. mouseup 과 짝지어 pressed 패턴 가능.'\n },\n mouseup: {\n summary: '버튼 누름 해제 시점.'\n },\n pressed: {\n summary: 'mousedown ↔ mouseup 페어 자동 매핑 (legacy 호환).'\n }\n}\n\nconst ACTION_DESC: Record<string, DescEntry> = {\n '': {\n summary: '액션이 선택되지 않음. 핸들러는 등록되지만 아무 동작도 하지 않는다.'\n },\n script: {\n summary: '자유 JavaScript 코드. component / scene / event / targets / value 를 변수로 받아 임의 동작을 수행.',\n example: 'await 사용 가능 — 비동기 동작도 그대로 작성.'\n },\n 'data-toggle': {\n summary: 'target 컴포넌트의 data 값을 truthy ↔ falsy 로 토글.',\n example: 'value 필드는 무시. target 미설정 시 자기 자신.'\n },\n 'data-tristate': {\n summary: 'target 의 data 값을 0 → 1 → 2 → 0 순환.',\n example: '세 상태 토글 (off / on / mixed 같은) 용.'\n },\n 'data-spreading': {\n summary: 'target 들에 value 를 분배 (배열 또는 매핑).',\n example: 'value 가 배열이면 target N개에 각각 매칭.'\n },\n 'data-set': {\n summary: 'target 의 data 를 value 로 설정. value 는 정적 값 또는 accessor.',\n example: '예) value=1 / value=accessor.someField'\n },\n 'partial-data-set': {\n summary: 'target.data 가 객체일 때, value 의 키들만 partial merge.',\n example: 'value 는 객체 또는 객체를 가리키는 accessor.'\n },\n 'value-set': {\n summary: 'target 의 value 속성을 value 로 설정.',\n example: 'data 가 아니라 value 속성을 다루는 컴포넌트용.'\n },\n 'partial-value-set': {\n summary: 'target.value 가 객체일 때, partial merge.'\n },\n 'info-window': {\n summary: 'target 의 info-window (팝업) 를 띄움.',\n example: 'target 컴포넌트의 popup 정보가 미리 정의되어 있어야 함.'\n },\n emphasize: {\n summary: 'target 을 시각적으로 강조 (애니메이션).',\n example: 'mouseenter / mouseleave 와 짝지어 emphasize/restore 패턴 자주 사용.'\n }\n}\n\nconst SCRIPT_VARS = [\n { name: 'component', desc: '핸들러가 등록된 현재 컴포넌트.' },\n { name: 'scene', desc: '루트 scene. scene.root 로 다른 컴포넌트 검색.' },\n { name: 'event', desc: '원본 DOM 이벤트 (또는 합성 이벤트) 객체.' },\n { name: 'targets', desc: 'target selector 로 찾은 컴포넌트 배열. target 비면 빈 배열.' },\n { name: 'value', desc: '핸들러의 value 필드 (정적 또는 accessor).' }\n]\n\nconst SNIPPETS: { label: string; code: string }[] = [\n {\n label: 'console.log',\n code: `console.log('event handler', { component, event })`\n },\n {\n label: 'data 토글',\n code: `component.data = !component.data`\n },\n {\n label: 'targets 에 값 세팅',\n code: `targets.forEach(t => { t.data = value })`\n },\n {\n label: 'findById 로 특정 컴포넌트 변경',\n code: `// '#someId' 는 대상 컴포넌트의 id 로 바꿔 쓴다.\nconst target = scene.root.findAll('#someId', component)[0]\nif (target) {\n target.data = component.data\n}`\n },\n {\n label: 'async fetch + data 반영',\n code: `const res = await fetch('/api/something')\nconst json = await res.json()\ncomponent.data = json`\n }\n]\n\nexport class EventHandlersHelp extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n background: var(--md-sys-color-surface-container-lowest, #fffbfe);\n border-left: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.12));\n padding: 16px 18px;\n overflow-y: auto;\n font-family: 'Roboto', Arial, sans-serif;\n font-size: 12.5px;\n color: var(--md-sys-color-on-surface, #1c1b1f);\n line-height: 1.5;\n min-width: 0;\n }\n\n h4 {\n margin: 0 0 6px 0;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.5px;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, #49454f);\n }\n\n section {\n margin-bottom: 18px;\n }\n\n .name {\n display: inline-block;\n padding: 2px 6px;\n margin-bottom: 6px;\n background: var(--md-sys-color-secondary-container, #e8def8);\n color: var(--md-sys-color-on-secondary-container, #1d192b);\n border-radius: 4px;\n font-weight: 600;\n font-size: 11.5px;\n }\n\n .summary {\n margin: 0 0 6px 0;\n }\n\n .example {\n margin: 4px 0 0 0;\n padding: 6px 8px;\n background: rgba(0, 0, 0, 0.04);\n border-left: 2px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.2));\n font-size: 11.5px;\n color: var(--md-sys-color-on-surface-variant, #49454f);\n }\n\n ul.vars {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n ul.vars li {\n padding: 4px 0;\n border-bottom: 1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.08));\n }\n\n ul.vars li:last-child {\n border-bottom: none;\n }\n\n ul.vars code {\n display: inline-block;\n padding: 1px 5px;\n margin-right: 6px;\n background: var(--md-sys-color-surface-container-high, #ede7f6);\n border-radius: 3px;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--md-sys-color-on-surface, #1c1b1f);\n }\n\n .snippet-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .snippet-btn {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n padding: 6px 10px;\n border: 1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, 0.18));\n border-radius: 4px;\n background: var(--md-sys-color-surface, #fff);\n color: var(--md-sys-color-on-surface, #1c1b1f);\n font-size: 12px;\n cursor: pointer;\n text-align: left;\n }\n\n .snippet-btn:hover {\n background: var(--md-sys-color-surface-container-low, #f7f2fa);\n }\n\n .snippet-btn md-icon {\n --md-icon-size: 16px;\n opacity: 0.7;\n }\n\n .selector-grid {\n display: grid;\n grid-template-columns: max-content 1fr;\n column-gap: 10px;\n row-gap: 4px;\n font-size: 11.5px;\n }\n\n .selector-grid code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n background: var(--md-sys-color-surface-container-high, #ede7f6);\n padding: 1px 5px;\n border-radius: 3px;\n }\n `\n ]\n\n @property({ type: Object }) handler?: EventHandlerSpec\n\n render() {\n const h = this.handler || { trigger: 'click', action: '' }\n const trigDesc = TRIGGER_DESC[h.trigger] || { summary: '(unknown trigger)' }\n const actDesc = ACTION_DESC[h.action ?? ''] || { summary: '(unknown action)' }\n const isScript = h.action === 'script'\n\n return html`\n <section>\n <h4>Trigger</h4>\n <div class=\"name\">${h.trigger}</div>\n <p class=\"summary\">${trigDesc.summary}</p>\n ${trigDesc.example ? html`<div class=\"example\">${trigDesc.example}</div>` : ''}\n </section>\n\n <section>\n <h4>Action</h4>\n <div class=\"name\">${h.action || '(none)'}</div>\n <p class=\"summary\">${actDesc.summary}</p>\n ${actDesc.example ? html`<div class=\"example\">${actDesc.example}</div>` : ''}\n </section>\n\n ${isScript ? this._renderScriptHelp() : this._renderDeclarativeHelp()}\n `\n }\n\n private _renderDeclarativeHelp() {\n return html`\n <section>\n <h4>Target selector</h4>\n <div class=\"selector-grid\">\n <code>#id</code><span>id 일치</span>\n <code>.class</code><span>class 일치 (공백 구분 다중)</span>\n <code><타입></code><span>type 일치 (예: rect, button)</span>\n <code>(self)</code><span>현재 컴포넌트 자기 자신</span>\n <code>(all)</code><span>모든 컴포넌트</span>\n <code>(root)</code><span>루트 컴포넌트</span>\n <code>(parent)</code><span>부모</span>\n <code>(children)</code><span>직접 자식들</span>\n <code>(siblings)</code><span>형제들 (자기 제외)</span>\n </div>\n <div class=\"example\" style=\"margin-top:6px\">\n 비워두면 매칭 없음 — 자기 자신을 대상으로 하려면 <code style=\"background:transparent;padding:0\">(self)</code>.\n </div>\n </section>\n\n <section>\n <h4>Value</h4>\n <p class=\"summary\">정적 값 또는 accessor 표현식. accessor 인 경우 component.access(value) 로 평가되어 컴포넌트 컨텍스트의 데이터를 참조한다.</p>\n </section>\n `\n }\n\n private _renderScriptHelp() {\n return html`\n <section>\n <h4>Script 변수</h4>\n <ul class=\"vars\">\n ${SCRIPT_VARS.map(\n v => html`\n <li><code>${v.name}</code>${v.desc}</li>\n `\n )}\n </ul>\n <div class=\"example\" style=\"margin-top:8px\">\n <code style=\"background:transparent;padding:0\">await</code> 키워드 사용 시 스크립트는 비동기로 실행. 결과 wait 후 다음 핸들러가 영향 받지는 않는다 (각 핸들러는 독립 실행).\n </div>\n </section>\n\n <section>\n <h4>Snippet 삽입</h4>\n <div class=\"snippet-list\">\n ${SNIPPETS.map(\n s => html`\n <button\n type=\"button\"\n class=\"snippet-btn\"\n @click=${() => this._emitSnippet(s.code)}\n title=\"현재 스크립트 영역에 삽입 (덮어쓰지 않고 끝에 추가)\"\n >\n <span>${s.label}</span>\n <md-icon>add</md-icon>\n </button>\n `\n )}\n </div>\n </section>\n `\n }\n\n private _emitSnippet(code: string) {\n this.dispatchEvent(\n new CustomEvent('insert-snippet', {\n bubbles: true,\n composed: true,\n detail: { code }\n })\n )\n }\n}\n\ncustomElements.define('event-handlers-help', EventHandlersHelp)\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Single EventHandler editor — trigger / action / (code 또는 target+value).
|
|
5
|
+
*
|
|
6
|
+
* 'script' 도 action 의 한 값. action='script' 시 code 필드를, 다른 declarative
|
|
7
|
+
* action 시 target+value 필드를 노출. action 미선택 (= '') 시 no-op.
|
|
8
|
+
*/
|
|
9
|
+
import '@operato/input/ox-input-code.js';
|
|
10
|
+
import '@operato/i18n/ox-i18n.js';
|
|
11
|
+
import { LitElement } from 'lit';
|
|
12
|
+
import type { Scene } from '@hatiolab/things-scene';
|
|
13
|
+
/** EventHandler model — things-scene 의 EventHandler interface 와 호환. */
|
|
14
|
+
export type EventHandlerSpec = {
|
|
15
|
+
trigger: string;
|
|
16
|
+
action?: string;
|
|
17
|
+
code?: string;
|
|
18
|
+
target?: string;
|
|
19
|
+
value?: any;
|
|
20
|
+
options?: Record<string, any>;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
};
|
|
23
|
+
export declare class EventHandlersMapper extends LitElement {
|
|
24
|
+
static styles: import("lit").CSSResult[];
|
|
25
|
+
handler: EventHandlerSpec;
|
|
26
|
+
scene?: Scene;
|
|
27
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
28
|
+
private _renderScriptFields;
|
|
29
|
+
private _renderActionFields;
|
|
30
|
+
private _update;
|
|
31
|
+
}
|