@operato/property-panel 10.0.0-beta.43 → 10.0.0-beta.45

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,25 @@
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.45](https://github.com/hatiolab/operato/compare/v10.0.0-beta.44...v10.0.0-beta.45) (2026-04-30)
7
+
8
+
9
+ ### :rocket: New Features
10
+
11
+ * **board,property-panel:** logistics group split + NaN-safe number inputs ([aa3aa37](https://github.com/hatiolab/operato/commit/aa3aa376802d2296ee9a8315b4490b8a2a34b223))
12
+ * **board,property-panel:** manufacturing group + dynamic nature refresh ([a82cab7](https://github.com/hatiolab/operato/commit/a82cab79dded6b5996c554dfbcaf6f578f303861))
13
+
14
+
15
+
16
+ ## [10.0.0-beta.44](https://github.com/hatiolab/operato/compare/v10.0.0-beta.43...v10.0.0-beta.44) (2026-04-28)
17
+
18
+
19
+ ### :house: Code Refactoring
20
+
21
+ * **shadow:** property panel 에디터를 신규 키 (offsetX/offsetY/blur) 로 현행화 ([aee4dbe](https://github.com/hatiolab/operato/commit/aee4dbef842606bc31b6ad3f2161ffa22c2d3221))
22
+
23
+
24
+
6
25
  ## [10.0.0-beta.43](https://github.com/hatiolab/operato/compare/v10.0.0-beta.42...v10.0.0-beta.43) (2026-04-24)
7
26
 
8
27
  **Note:** Version bump only for package @operato/property-panel
@@ -40,6 +40,12 @@ export declare class OxPropertyPanel extends OxPropertyPanel_base {
40
40
  private hasGroup;
41
41
  render(): import("lit-html").TemplateResult<1>;
42
42
  private onPropertyChanged;
43
+ /**
44
+ * 새 properties 배열이 현재 specificProps 와 *구조상* 다른지 빠르게 검사.
45
+ * 단순히 length + 각 항목의 name 만 비교 — value 변경은 model 측에서 처리되므로
46
+ * specificProps 의 reference 를 바꿀 필요가 없다.
47
+ */
48
+ private specificPropsChanged;
43
49
  private onBoundsChanged;
44
50
  private onChangedByScene;
45
51
  private setPropertyTargetAsDefault;
@@ -147,16 +147,40 @@ let OxPropertyPanel = class OxPropertyPanel extends ScopedElementsMixin(LitEleme
147
147
  `;
148
148
  }
149
149
  onPropertyChanged(e) {
150
+ var _a;
150
151
  var detail = e.detail;
151
152
  if (this.propertyTarget) {
152
153
  /* 단일 컴포넌트의 경우에 적용 */
153
154
  this.scene && this.scene.undoableChange(() => this.propertyTarget.set(detail));
155
+ // nature.properties 가 동적인 컴포넌트(예: robot-arm 의 chainPreset
156
+ // 변경 시 joint 개수 변화)를 위해 set 직후 nature 재평가.
157
+ // 정적 nature 컴포넌트는 동일한 배열이 반환되어 비용 미미.
158
+ const nextProps = (_a = this.propertyTarget.nature) === null || _a === void 0 ? void 0 : _a.properties;
159
+ if (nextProps && this.specificPropsChanged(nextProps)) {
160
+ this.specificProps = deepClone(nextProps);
161
+ }
154
162
  }
155
163
  else {
156
164
  /* 여러 컴포넌트의 경우에 적용 */
157
165
  this.scene && this.scene.undoableChange(() => this.selected.forEach(component => component.set(detail)));
158
166
  }
159
167
  }
168
+ /**
169
+ * 새 properties 배열이 현재 specificProps 와 *구조상* 다른지 빠르게 검사.
170
+ * 단순히 length + 각 항목의 name 만 비교 — value 변경은 model 측에서 처리되므로
171
+ * specificProps 의 reference 를 바꿀 필요가 없다.
172
+ */
173
+ specificPropsChanged(next) {
174
+ var _a, _b;
175
+ const cur = this.specificProps;
176
+ if (!cur || cur.length !== next.length)
177
+ return true;
178
+ for (let i = 0; i < next.length; i++) {
179
+ if (((_a = cur[i]) === null || _a === void 0 ? void 0 : _a.name) !== ((_b = next[i]) === null || _b === void 0 ? void 0 : _b.name))
180
+ return true;
181
+ }
182
+ return false;
183
+ }
160
184
  onBoundsChanged(e) {
161
185
  var detail = e.detail;
162
186
  if (!this.scene) {
@@ -1 +1 @@
1
- {"version":3,"file":"ox-property-panel.js","sourceRoot":"","sources":["../../src/ox-property-panel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport deepClone from 'lodash-es/cloneDeep.js'\n\nimport { BOUNDS, Component, Model, Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { PropertyDataBinding } from './property-panel/data-binding/data-binding.js'\nimport { PropertyEffects } from './property-panel/effects/effects.js'\nimport { SceneInspector } from './property-panel/inspector/inspector.js'\nimport { PropertyShapes } from './property-panel/shapes/shapes.js'\nimport { PropertySpecific } from './property-panel/specifics/specifics.js'\nimport { PropertyStyles } from './property-panel/styles/styles.js'\nimport { Property3D } from './property-panel/threed/threed.js'\nimport { PropertyScene3D } from './property-panel/threed/property-scene3d.js'\n\n@customElement('ox-property-panel')\nexport class OxPropertyPanel extends ScopedElementsMixin(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n border-left: 1px solid var(--md-sys-color-border, #ccc);\n width: 270px;\n display: flex;\n flex-direction: column;\n background-color: var(--property-sidebar-background-color, var(--md-sys-color-secondary-container));\n color: var(--property-sidebar-color, var(--md-sys-color-on-secondary-container));\n user-select: none;\n\n --input-padding: var(--spacing-small);\n --label-font: var(--property-sidebar-fieldset-label, roboto);\n }\n\n [tab] {\n display: flex;\n background-color: rgba(0, 0, 0, 0.08);\n opacity: 0.85;\n }\n\n [tab] md-icon {\n flex: 1;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n color: var(--property-sidebar-tab-icon-color);\n height: 40px;\n }\n\n [tab] [selected] {\n background-color: var(--property-sidebar-background-color, var(--md-sys-color-secondary-container));\n border-left: 1px solid rgba(255, 255, 255, 0.5);\n border-right: 1px solid rgba(0, 0, 0, 0.15);\n opacity: 1;\n }\n\n [content] {\n flex: 1;\n\n overflow: hidden;\n overflow-y: auto;\n\n --md-icon-size: 22px;\n }\n\n [content] > :not([active]) {\n display: none;\n }\n `\n ]\n\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: Object }) bounds: any = {}\n @property({ type: Object }) model: Model | null = {}\n @property({ type: Array }) selected: Component[] = []\n @property({ type: Array }) specificProps: any\n @property({ type: String }) tabName: string | null = 'shape'\n @property({ type: Boolean }) collapsed: boolean = false\n @property({ type: Array }) fonts: any[] = []\n @property({ type: Array }) propertyEditor: any[] = []\n\n propertyTarget: Component | null = null\n\n firstUpdated() {\n this.renderRoot.addEventListener('property-change', this.onPropertyChanged.bind(this) as EventListener)\n this.renderRoot.addEventListener('bounds-change', this.onBoundsChanged.bind(this) as EventListener)\n }\n\n updated(change: PropertyValues<this>) {\n change.has('scene') && this.onSceneChanged()\n change.has('selected') && this.onSelectedChanged(this.selected)\n change.has('collapsed') && this.onCollapsed(this.collapsed)\n }\n\n static get scopedElements() {\n return {\n 'property-shape': PropertyShapes,\n 'property-style': PropertyStyles,\n 'property-effect': PropertyEffects,\n 'property-specific': PropertySpecific,\n 'property-3d': Property3D,\n 'property-scene3d': PropertyScene3D,\n 'property-data-binding': PropertyDataBinding,\n 'scene-inspector': SceneInspector\n }\n }\n\n private hasGroup(selected: Component[]) {\n return selected.some(c => c?.model?.type === 'group')\n }\n\n render() {\n var tabName = this.tabName ? this.tabName : 'shape'\n return html`\n <div\n tab\n @click=${(e: MouseEvent) => {\n this.tabName = (e.target as HTMLElement).getAttribute('name')\n }}\n >\n <md-icon name=\"shape\" ?selected=${tabName == 'shape'}>format_shapes</md-icon>\n <md-icon name=\"style\" ?selected=${tabName == 'style'}>palette</md-icon>\n <md-icon name=\"threed\" ?selected=${tabName == 'threed'}>view_in_ar</md-icon>\n <md-icon name=\"effect\" ?selected=${tabName == 'effect'}>movie_filter</md-icon>\n <md-icon name=\"specific\" ?selected=${tabName == 'specific'}>tune</md-icon>\n <md-icon name=\"data-binding\" ?selected=${tabName == 'data-binding'}>share</md-icon>\n <md-icon name=\"inspector\" ?selected=${tabName == 'inspector'}>visibility</md-icon>\n </div>\n\n <div content>\n ${html`\n ${{\n shape: html`\n <property-shape\n .value=${this.model}\n .bounds=${this.bounds}\n .selected=${this.selected}\n ?active=${tabName == 'shape'}\n >\n </property-shape>\n `,\n style: html`\n <property-style\n .value=${this.model}\n .selected=${this.selected}\n .fonts=${this.fonts}\n ?active=${tabName == 'style'}\n ?is-line=${this.isLine(this.selected)}\n >\n </property-style>\n `,\n threed: !this.is3dish(this.selected)\n ? html`\n <div style=\"display:flex;align-items:center;justify-content:center;height:100%;color:var(--md-sys-color-on-surface-variant,#666);font-size:12px;opacity:0.7;padding:16px;text-align:center;\">\n Selected component(s) do not support 3D properties\n </div>\n `\n : this.isRootModel(this.selected)\n ? html`\n <property-scene3d\n .value=${this.model}\n .scene=${this.scene}\n ?active=${tabName == 'threed'}\n >\n </property-scene3d>\n `\n : html`\n <property-3d\n .value=${this.model}\n .bounds=${this.bounds}\n .selected=${this.selected}\n ?active=${tabName == 'threed'}\n >\n </property-3d>\n `,\n effect: html`\n <property-effect .value=${this.model} .scene=${this.scene} ?active=${tabName == 'effect'}>\n </property-effect>\n `,\n specific: this.hasGroup(this.selected)\n ? html``\n : html`\n <property-specific\n .value=${this.model}\n .scene=${this.scene}\n .selected=${this.selected}\n .props=${this.specificProps}\n .propertyEditor=${this.propertyEditor}\n ?active=${tabName == 'specific'}\n >\n </property-specific>\n `,\n 'data-binding': html`\n <property-data-binding .scene=${this.scene} .value=${this.model} ?active=${tabName == 'data-binding'}>\n </property-data-binding>\n `,\n inspector: html`\n <scene-inspector .scene=${this.scene} ?active=${tabName == 'inspector'}></scene-inspector>\n `\n }[this.tabName!]}\n `}\n </div>\n `\n }\n\n private onPropertyChanged(e: CustomEvent) {\n var detail = e.detail\n\n if (this.propertyTarget) {\n /* 단일 컴포넌트의 경우에 적용 */\n this.scene && this.scene.undoableChange(() => this.propertyTarget!.set(detail))\n } else {\n /* 여러 컴포넌트의 경우에 적용 */\n this.scene && this.scene.undoableChange(() => this.selected.forEach(component => component.set(detail)))\n }\n }\n\n private onBoundsChanged(e: CustomEvent) {\n var detail = e.detail\n\n if (!this.scene) {\n return\n }\n\n if (this.propertyTarget) {\n /* 단일 컴포넌트의 경우에 적용 */\n this.scene.undoableChange(() => {\n this.propertyTarget!.bounds = {\n ...this.propertyTarget!.bounds,\n ...detail\n }\n })\n } else {\n /* 여러 컴포넌트의 경우에 적용 */\n this.scene.undoableChange(() => {\n this.selected.forEach(component => {\n component.bounds = {\n ...component.bounds,\n ...detail\n }\n })\n })\n }\n }\n\n private onChangedByScene() {\n if (this.propertyTarget) {\n this.model = {\n ...this.propertyTarget.model\n }\n this.setBounds(this.propertyTarget.bounds)\n }\n }\n\n private setPropertyTargetAsDefault() {\n if (!this.scene) {\n this.setPropertyTarget(null)\n this.specificProps = []\n this.model = null\n this.bounds = {}\n } else {\n this.scene.select('model-layer')\n }\n }\n\n private onCollapsed(collapsed: boolean) {\n this.style.display = collapsed ? 'none' : ''\n dispatchEvent(new Event('resize'))\n }\n\n private async onSceneChanged() {\n await this.updateComplete\n\n if (this.scene) this.selected = this.scene.select('model-layer')\n }\n\n private async onSelectedChanged(after: Component[]) {\n await this.updateComplete\n\n\n if (after.length == 1) {\n this.setPropertyTarget(after[0])\n // 컴포넌트 특성 속성(specific properties)을 먼저 바꾸고, 모델을 바꾸어준다.\n // 컴포넌트 속성에 따라 UI 컴포넌트가 준비되고, 이후에 모델값을 보여주도록 하기 위해서이다.\n this.specificProps = deepClone(this.propertyTarget!.nature.properties)\n this.model = {\n ...this.propertyTarget!.model\n }\n this.setBounds(this.propertyTarget!.bounds)\n } else if (after.length == 0) {\n // 선택이 안된 경우\n\n this.setPropertyTargetAsDefault()\n } else {\n // 다중 선택된 경우\n\n var type = after[0].model.type\n for (let i = 1; i < after.length; i++) {\n if (after[i].model.type != type) {\n type = undefined\n break\n }\n }\n\n this.setPropertyTarget(null)\n\n if (type) this.specificProps = deepClone(after[0].nature.properties)\n else this.specificProps = null\n\n this.model = {\n type: type,\n alpha: 1\n }\n this.bounds = {}\n }\n }\n\n private setPropertyTarget(newTarget: Component | null) {\n var oldTarget = this.propertyTarget\n\n if (oldTarget) {\n oldTarget.off('change', this.onChangedByScene, this)\n }\n if (newTarget) {\n newTarget.on('change', this.onChangedByScene, this)\n }\n\n this.propertyTarget = newTarget\n }\n\n private setBounds(bounds: BOUNDS) {\n this.bounds = {\n left: bounds.left,\n top: bounds.top,\n width: Math.round(bounds.width),\n height: Math.round(bounds.height)\n }\n }\n\n private is3dish(selected: Component[]) {\n if (selected.length === 0) return false\n const first = selected[0]\n return first?.is3dish?.() || first?.isRootModel?.()\n }\n\n private isRootModel(selected: Component[]) {\n return selected.length > 0 && selected[0]?.isRootModel?.()\n }\n\n private isLine(selected: Component[]) {\n var isLine = false\n\n for (var i = 0; i < selected.length; i++) {\n var comp = selected[i]\n\n if (!comp.isLine || !comp.isLine()) {\n isLine = false\n return isLine\n }\n\n isLine = true\n }\n\n return isLine\n }\n}\n"]}
1
+ {"version":3,"file":"ox-property-panel.js","sourceRoot":"","sources":["../../src/ox-property-panel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport deepClone from 'lodash-es/cloneDeep.js'\n\nimport { BOUNDS, Component, Model, Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { PropertyDataBinding } from './property-panel/data-binding/data-binding.js'\nimport { PropertyEffects } from './property-panel/effects/effects.js'\nimport { SceneInspector } from './property-panel/inspector/inspector.js'\nimport { PropertyShapes } from './property-panel/shapes/shapes.js'\nimport { PropertySpecific } from './property-panel/specifics/specifics.js'\nimport { PropertyStyles } from './property-panel/styles/styles.js'\nimport { Property3D } from './property-panel/threed/threed.js'\nimport { PropertyScene3D } from './property-panel/threed/property-scene3d.js'\n\n@customElement('ox-property-panel')\nexport class OxPropertyPanel extends ScopedElementsMixin(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n border-left: 1px solid var(--md-sys-color-border, #ccc);\n width: 270px;\n display: flex;\n flex-direction: column;\n background-color: var(--property-sidebar-background-color, var(--md-sys-color-secondary-container));\n color: var(--property-sidebar-color, var(--md-sys-color-on-secondary-container));\n user-select: none;\n\n --input-padding: var(--spacing-small);\n --label-font: var(--property-sidebar-fieldset-label, roboto);\n }\n\n [tab] {\n display: flex;\n background-color: rgba(0, 0, 0, 0.08);\n opacity: 0.85;\n }\n\n [tab] md-icon {\n flex: 1;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n color: var(--property-sidebar-tab-icon-color);\n height: 40px;\n }\n\n [tab] [selected] {\n background-color: var(--property-sidebar-background-color, var(--md-sys-color-secondary-container));\n border-left: 1px solid rgba(255, 255, 255, 0.5);\n border-right: 1px solid rgba(0, 0, 0, 0.15);\n opacity: 1;\n }\n\n [content] {\n flex: 1;\n\n overflow: hidden;\n overflow-y: auto;\n\n --md-icon-size: 22px;\n }\n\n [content] > :not([active]) {\n display: none;\n }\n `\n ]\n\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: Object }) bounds: any = {}\n @property({ type: Object }) model: Model | null = {}\n @property({ type: Array }) selected: Component[] = []\n @property({ type: Array }) specificProps: any\n @property({ type: String }) tabName: string | null = 'shape'\n @property({ type: Boolean }) collapsed: boolean = false\n @property({ type: Array }) fonts: any[] = []\n @property({ type: Array }) propertyEditor: any[] = []\n\n propertyTarget: Component | null = null\n\n firstUpdated() {\n this.renderRoot.addEventListener('property-change', this.onPropertyChanged.bind(this) as EventListener)\n this.renderRoot.addEventListener('bounds-change', this.onBoundsChanged.bind(this) as EventListener)\n }\n\n updated(change: PropertyValues<this>) {\n change.has('scene') && this.onSceneChanged()\n change.has('selected') && this.onSelectedChanged(this.selected)\n change.has('collapsed') && this.onCollapsed(this.collapsed)\n }\n\n static get scopedElements() {\n return {\n 'property-shape': PropertyShapes,\n 'property-style': PropertyStyles,\n 'property-effect': PropertyEffects,\n 'property-specific': PropertySpecific,\n 'property-3d': Property3D,\n 'property-scene3d': PropertyScene3D,\n 'property-data-binding': PropertyDataBinding,\n 'scene-inspector': SceneInspector\n }\n }\n\n private hasGroup(selected: Component[]) {\n return selected.some(c => c?.model?.type === 'group')\n }\n\n render() {\n var tabName = this.tabName ? this.tabName : 'shape'\n return html`\n <div\n tab\n @click=${(e: MouseEvent) => {\n this.tabName = (e.target as HTMLElement).getAttribute('name')\n }}\n >\n <md-icon name=\"shape\" ?selected=${tabName == 'shape'}>format_shapes</md-icon>\n <md-icon name=\"style\" ?selected=${tabName == 'style'}>palette</md-icon>\n <md-icon name=\"threed\" ?selected=${tabName == 'threed'}>view_in_ar</md-icon>\n <md-icon name=\"effect\" ?selected=${tabName == 'effect'}>movie_filter</md-icon>\n <md-icon name=\"specific\" ?selected=${tabName == 'specific'}>tune</md-icon>\n <md-icon name=\"data-binding\" ?selected=${tabName == 'data-binding'}>share</md-icon>\n <md-icon name=\"inspector\" ?selected=${tabName == 'inspector'}>visibility</md-icon>\n </div>\n\n <div content>\n ${html`\n ${{\n shape: html`\n <property-shape\n .value=${this.model}\n .bounds=${this.bounds}\n .selected=${this.selected}\n ?active=${tabName == 'shape'}\n >\n </property-shape>\n `,\n style: html`\n <property-style\n .value=${this.model}\n .selected=${this.selected}\n .fonts=${this.fonts}\n ?active=${tabName == 'style'}\n ?is-line=${this.isLine(this.selected)}\n >\n </property-style>\n `,\n threed: !this.is3dish(this.selected)\n ? html`\n <div style=\"display:flex;align-items:center;justify-content:center;height:100%;color:var(--md-sys-color-on-surface-variant,#666);font-size:12px;opacity:0.7;padding:16px;text-align:center;\">\n Selected component(s) do not support 3D properties\n </div>\n `\n : this.isRootModel(this.selected)\n ? html`\n <property-scene3d\n .value=${this.model}\n .scene=${this.scene}\n ?active=${tabName == 'threed'}\n >\n </property-scene3d>\n `\n : html`\n <property-3d\n .value=${this.model}\n .bounds=${this.bounds}\n .selected=${this.selected}\n ?active=${tabName == 'threed'}\n >\n </property-3d>\n `,\n effect: html`\n <property-effect .value=${this.model} .scene=${this.scene} ?active=${tabName == 'effect'}>\n </property-effect>\n `,\n specific: this.hasGroup(this.selected)\n ? html``\n : html`\n <property-specific\n .value=${this.model}\n .scene=${this.scene}\n .selected=${this.selected}\n .props=${this.specificProps}\n .propertyEditor=${this.propertyEditor}\n ?active=${tabName == 'specific'}\n >\n </property-specific>\n `,\n 'data-binding': html`\n <property-data-binding .scene=${this.scene} .value=${this.model} ?active=${tabName == 'data-binding'}>\n </property-data-binding>\n `,\n inspector: html`\n <scene-inspector .scene=${this.scene} ?active=${tabName == 'inspector'}></scene-inspector>\n `\n }[this.tabName!]}\n `}\n </div>\n `\n }\n\n private onPropertyChanged(e: CustomEvent) {\n var detail = e.detail\n\n if (this.propertyTarget) {\n /* 단일 컴포넌트의 경우에 적용 */\n this.scene && this.scene.undoableChange(() => this.propertyTarget!.set(detail))\n\n // nature.properties 가 동적인 컴포넌트(예: robot-arm 의 chainPreset\n // 변경 시 joint 개수 변화)를 위해 set 직후 nature 재평가.\n // 정적 nature 컴포넌트는 동일한 배열이 반환되어 비용 미미.\n const nextProps = this.propertyTarget.nature?.properties\n if (nextProps && this.specificPropsChanged(nextProps)) {\n this.specificProps = deepClone(nextProps)\n }\n } else {\n /* 여러 컴포넌트의 경우에 적용 */\n this.scene && this.scene.undoableChange(() => this.selected.forEach(component => component.set(detail)))\n }\n }\n\n /**\n * 새 properties 배열이 현재 specificProps 와 *구조상* 다른지 빠르게 검사.\n * 단순히 length + 각 항목의 name 만 비교 — value 변경은 model 측에서 처리되므로\n * specificProps 의 reference 를 바꿀 필요가 없다.\n */\n private specificPropsChanged(next: any[]): boolean {\n const cur = this.specificProps\n if (!cur || cur.length !== next.length) return true\n for (let i = 0; i < next.length; i++) {\n if (cur[i]?.name !== next[i]?.name) return true\n }\n return false\n }\n\n private onBoundsChanged(e: CustomEvent) {\n var detail = e.detail\n\n if (!this.scene) {\n return\n }\n\n if (this.propertyTarget) {\n /* 단일 컴포넌트의 경우에 적용 */\n this.scene.undoableChange(() => {\n this.propertyTarget!.bounds = {\n ...this.propertyTarget!.bounds,\n ...detail\n }\n })\n } else {\n /* 여러 컴포넌트의 경우에 적용 */\n this.scene.undoableChange(() => {\n this.selected.forEach(component => {\n component.bounds = {\n ...component.bounds,\n ...detail\n }\n })\n })\n }\n }\n\n private onChangedByScene() {\n if (this.propertyTarget) {\n this.model = {\n ...this.propertyTarget.model\n }\n this.setBounds(this.propertyTarget.bounds)\n }\n }\n\n private setPropertyTargetAsDefault() {\n if (!this.scene) {\n this.setPropertyTarget(null)\n this.specificProps = []\n this.model = null\n this.bounds = {}\n } else {\n this.scene.select('model-layer')\n }\n }\n\n private onCollapsed(collapsed: boolean) {\n this.style.display = collapsed ? 'none' : ''\n dispatchEvent(new Event('resize'))\n }\n\n private async onSceneChanged() {\n await this.updateComplete\n\n if (this.scene) this.selected = this.scene.select('model-layer')\n }\n\n private async onSelectedChanged(after: Component[]) {\n await this.updateComplete\n\n\n if (after.length == 1) {\n this.setPropertyTarget(after[0])\n // 컴포넌트 특성 속성(specific properties)을 먼저 바꾸고, 모델을 바꾸어준다.\n // 컴포넌트 속성에 따라 UI 컴포넌트가 준비되고, 이후에 모델값을 보여주도록 하기 위해서이다.\n this.specificProps = deepClone(this.propertyTarget!.nature.properties)\n this.model = {\n ...this.propertyTarget!.model\n }\n this.setBounds(this.propertyTarget!.bounds)\n } else if (after.length == 0) {\n // 선택이 안된 경우\n\n this.setPropertyTargetAsDefault()\n } else {\n // 다중 선택된 경우\n\n var type = after[0].model.type\n for (let i = 1; i < after.length; i++) {\n if (after[i].model.type != type) {\n type = undefined\n break\n }\n }\n\n this.setPropertyTarget(null)\n\n if (type) this.specificProps = deepClone(after[0].nature.properties)\n else this.specificProps = null\n\n this.model = {\n type: type,\n alpha: 1\n }\n this.bounds = {}\n }\n }\n\n private setPropertyTarget(newTarget: Component | null) {\n var oldTarget = this.propertyTarget\n\n if (oldTarget) {\n oldTarget.off('change', this.onChangedByScene, this)\n }\n if (newTarget) {\n newTarget.on('change', this.onChangedByScene, this)\n }\n\n this.propertyTarget = newTarget\n }\n\n private setBounds(bounds: BOUNDS) {\n this.bounds = {\n left: bounds.left,\n top: bounds.top,\n width: Math.round(bounds.width),\n height: Math.round(bounds.height)\n }\n }\n\n private is3dish(selected: Component[]) {\n if (selected.length === 0) return false\n const first = selected[0]\n return first?.is3dish?.() || first?.isRootModel?.()\n }\n\n private isRootModel(selected: Component[]) {\n return selected.length > 0 && selected[0]?.isRootModel?.()\n }\n\n private isLine(selected: Component[]) {\n var isLine = false\n\n for (var i = 0; i < selected.length; i++) {\n var comp = selected[i]\n\n if (!comp.isLine || !comp.isLine()) {\n isLine = false\n return isLine\n }\n\n isLine = true\n }\n\n return isLine\n }\n}\n"]}
@@ -24,9 +24,18 @@ export class AbstractProperty extends LitElement {
24
24
  value = element.checked;
25
25
  break;
26
26
  case 'number':
27
- case 'range':
28
- value = Number(element.valueAsNumber);
27
+ case 'range': {
28
+ // Empty or invalid numeric input (user cleared the field, typed
29
+ // garbage, etc.) yields NaN via `valueAsNumber`. Persisting NaN
30
+ // poisons every downstream Math.* calculation and surfaces as
31
+ // "BufferGeometry computeBoundingSphere: radius is NaN" or
32
+ // similar. Emit `undefined` so the component's resolution chain
33
+ // (e.g. RealObject.effectiveDepth → Placeable defaultDepth → 1)
34
+ // takes over and the geometry stays well-formed.
35
+ const n = element.valueAsNumber;
36
+ value = Number.isFinite(n) ? n : undefined;
29
37
  break;
38
+ }
30
39
  case 'text':
31
40
  value = String(element.value);
32
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"abstract-property.js","sourceRoot":"","sources":["../../../src/property-panel/abstract-property.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAEhC,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC9C,YAAY;QACV,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3E,CAAC;IAES,aAAa,CAAC,CAAQ;QAC9B,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,IAAI,KAAK,GAAG,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAA;QAEjD,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACrC,CAAC;IAES,uBAAuB,CAAC,OAAoB;QACpD,IAAI,KAAK,CAAA;QAET,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;YACxB,KAAK,OAAO;gBACV,QAAS,OAAe,CAAC,IAAI,EAAE,CAAC;oBAC9B,KAAK,UAAU;wBACb,KAAK,GAAI,OAAe,CAAC,OAAO,CAAA;wBAChC,MAAK;oBACP,KAAK,QAAQ,CAAC;oBACd,KAAK,OAAO;wBACV,KAAK,GAAG,MAAM,CAAE,OAAe,CAAC,aAAa,CAAC,CAAA;wBAC9C,MAAK;oBACP,KAAK,MAAM;wBACT,KAAK,GAAG,MAAM,CAAE,OAAe,CAAC,KAAK,CAAC,CAAA;gBAC1C,CAAC;gBACD,MAAK;YAEP,KAAK,SAAS;gBACZ,KAAK,GAAI,OAAe,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;gBAC/C,MAAK;YAEP;gBACE,KAAK,GAAI,OAAe,CAAC,KAAK,CAAA;gBAC9B,MAAK;QACT,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAES,kBAAkB,CAAC,GAAW,EAAE,KAAU;QAClD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,iBAAiB,EAAE;YACjC,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,CAAC,GAAG,CAAC,EAAE,KAAK;aACb;SACF,CAAC,CACH,CAAA;IACH,CAAC;CACF","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { LitElement } from 'lit'\n\nexport class AbstractProperty extends LitElement {\n firstUpdated() {\n this.renderRoot.addEventListener('change', this.onValueChange.bind(this))\n }\n\n protected 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 var value = this.getValueFromEventTarget(element)\n\n this.onAfterValueChange(key, value)\n }\n\n protected getValueFromEventTarget(element: HTMLElement) {\n var value\n\n switch (element.tagName) {\n case 'INPUT':\n switch ((element as any).type) {\n case 'checkbox':\n value = (element as any).checked\n break\n case 'number':\n case 'range':\n value = Number((element as any).valueAsNumber)\n break\n case 'text':\n value = String((element as any).value)\n }\n break\n\n case 'MD-ICON':\n value = (element as any).hasAttribute('active')\n break\n\n default:\n value = (element as any).value\n break\n }\n\n return value\n }\n\n protected onAfterValueChange(key: string, value: any) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: {\n [key]: value\n }\n })\n )\n }\n}\n"]}
1
+ {"version":3,"file":"abstract-property.js","sourceRoot":"","sources":["../../../src/property-panel/abstract-property.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAEhC,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC9C,YAAY;QACV,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3E,CAAC;IAES,aAAa,CAAC,CAAQ;QAC9B,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,IAAI,KAAK,GAAG,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAA;QAEjD,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACrC,CAAC;IAES,uBAAuB,CAAC,OAAoB;QACpD,IAAI,KAAK,CAAA;QAET,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;YACxB,KAAK,OAAO;gBACV,QAAS,OAAe,CAAC,IAAI,EAAE,CAAC;oBAC9B,KAAK,UAAU;wBACb,KAAK,GAAI,OAAe,CAAC,OAAO,CAAA;wBAChC,MAAK;oBACP,KAAK,QAAQ,CAAC;oBACd,KAAK,OAAO,CAAC,CAAC,CAAC;wBACb,gEAAgE;wBAChE,gEAAgE;wBAChE,8DAA8D;wBAC9D,2DAA2D;wBAC3D,gEAAgE;wBAChE,gEAAgE;wBAChE,iDAAiD;wBACjD,MAAM,CAAC,GAAI,OAAe,CAAC,aAAa,CAAA;wBACxC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;wBAC1C,MAAK;oBACP,CAAC;oBACD,KAAK,MAAM;wBACT,KAAK,GAAG,MAAM,CAAE,OAAe,CAAC,KAAK,CAAC,CAAA;gBAC1C,CAAC;gBACD,MAAK;YAEP,KAAK,SAAS;gBACZ,KAAK,GAAI,OAAe,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;gBAC/C,MAAK;YAEP;gBACE,KAAK,GAAI,OAAe,CAAC,KAAK,CAAA;gBAC9B,MAAK;QACT,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAES,kBAAkB,CAAC,GAAW,EAAE,KAAU;QAClD,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,iBAAiB,EAAE;YACjC,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,CAAC,GAAG,CAAC,EAAE,KAAK;aACb;SACF,CAAC,CACH,CAAA;IACH,CAAC;CACF","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { LitElement } from 'lit'\n\nexport class AbstractProperty extends LitElement {\n firstUpdated() {\n this.renderRoot.addEventListener('change', this.onValueChange.bind(this))\n }\n\n protected 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 var value = this.getValueFromEventTarget(element)\n\n this.onAfterValueChange(key, value)\n }\n\n protected getValueFromEventTarget(element: HTMLElement) {\n var value\n\n switch (element.tagName) {\n case 'INPUT':\n switch ((element as any).type) {\n case 'checkbox':\n value = (element as any).checked\n break\n case 'number':\n case 'range': {\n // Empty or invalid numeric input (user cleared the field, typed\n // garbage, etc.) yields NaN via `valueAsNumber`. Persisting NaN\n // poisons every downstream Math.* calculation and surfaces as\n // \"BufferGeometry computeBoundingSphere: radius is NaN\" or\n // similar. Emit `undefined` so the component's resolution chain\n // (e.g. RealObject.effectiveDepth → Placeable defaultDepth → 1)\n // takes over and the geometry stays well-formed.\n const n = (element as any).valueAsNumber\n value = Number.isFinite(n) ? n : undefined\n break\n }\n case 'text':\n value = String((element as any).value)\n }\n break\n\n case 'MD-ICON':\n value = (element as any).hasAttribute('active')\n break\n\n default:\n value = (element as any).value\n break\n }\n\n return value\n }\n\n protected onAfterValueChange(key: string, value: any) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: {\n [key]: value\n }\n })\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
- const value = this.value || {};
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="left" .value=${value.left} />
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="top" .value=${value.top} />
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="blurSize" .value=${value.blurSize} />
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
- ...this.value,
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;QACJ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;QAE9B,OAAO,IAAI,CAAA;;;uDAGwC,KAAK,CAAC,IAAI;;;sDAGX,KAAK,CAAC,GAAG;;;2DAGJ,KAAK,CAAC,QAAQ;;;mDAGtB,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,IAAI,CAAC,KAAK,GAAG;YACX,GAAG,IAAI,CAAC,KAAK;YACb,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;;AAjDM,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 || {}\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=\"left\" .value=${value.left} />\n\n <label> <ox-i18n msgid=\"label.shadowOffsetY\">offset-Y</ox-i18n> </label>\n <input type=\"number\" value-key=\"top\" .value=${value.top} />\n\n <label> <ox-i18n msgid=\"label.shadowSize\">Size</ox-i18n> </label>\n <input type=\"number\" value-key=\"blurSize\" .value=${value.blurSize} />\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 this.value = {\n ...this.value,\n [key]: convert(element)\n }\n\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n }\n}\n"]}
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"]}
@@ -135,7 +135,14 @@ let PropertyMaterial3d = class PropertyMaterial3d extends LitElement {
135
135
  });
136
136
  }
137
137
  _onRange(key, e) {
138
- this._dispatch({ ...this.value, [key]: parseFloat(e.target.value) });
138
+ // Range inputs always carry a finite number, but parseFloat('') is NaN
139
+ // — be defensive in case a parent rebinds the input mid-edit and the
140
+ // value is briefly empty. NaN material props (e.g. metalness/roughness)
141
+ // would surface as console warnings from three.js.
142
+ const n = parseFloat(e.target.value);
143
+ if (!Number.isFinite(n))
144
+ return;
145
+ this._dispatch({ ...this.value, [key]: n });
139
146
  }
140
147
  _onSideChange(e) {
141
148
  this._dispatch({ ...this.value, side: e.target.value });
@@ -1 +1 @@
1
- {"version":3,"file":"property-material3d.js","sourceRoot":"","sources":["../../../../src/property-panel/threed/property-material3d.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\ninterface Material3DValue {\n preset?: string\n metalness?: number\n roughness?: number\n opacity?: number\n envMapIntensity?: number\n side?: string\n castShadow?: boolean\n receiveShadow?: boolean\n [key: string]: unknown\n}\n\nconst PRESETS: Record<string, { metalness: number; roughness: number; opacity?: number; envMapIntensity?: number }> = {\n default: { metalness: 0, roughness: 0.4 },\n metal: { metalness: 1.0, roughness: 0.3, envMapIntensity: 1.0 },\n glass: { metalness: 0, roughness: 0.1, opacity: 0.3, envMapIntensity: 1.5 },\n plastic: { metalness: 0, roughness: 0.4 },\n wood: { metalness: 0, roughness: 0.8, envMapIntensity: 0.3 },\n ceramic: { metalness: 0.1, roughness: 0.2, envMapIntensity: 0.3 },\n rubber: { metalness: 0, roughness: 0.9, envMapIntensity: 0.3 }\n}\n\nconst PRESET_NAMES = Object.keys(PRESETS)\n\nfunction resolve(m?: Material3DValue) {\n const preset = PRESETS[m?.preset ?? 'default'] ?? PRESETS.default\n return {\n metalness: m?.metalness ?? preset.metalness,\n roughness: m?.roughness ?? preset.roughness,\n opacity: m?.opacity ?? preset.opacity ?? 1,\n envMapIntensity: m?.envMapIntensity ?? preset.envMapIntensity ?? 0.5,\n side: m?.side ?? 'double',\n castShadow: m?.castShadow ?? true,\n receiveShadow: m?.receiveShadow ?? false\n }\n}\n\n@customElement('property-material3d')\nexport class PropertyMaterial3d extends LitElement {\n static styles = [\n PropertyGridStyles,\n css`\n .range-with-value {\n grid-column: 9 / -1;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .range-with-value input[type='range'] {\n flex: 1;\n border: none;\n background: transparent;\n padding: 0;\n }\n\n .range-with-value span {\n min-width: 2.5em;\n text-align: right;\n font-size: 11px;\n color: var(--md-sys-color-on-secondary-container);\n }\n `\n ]\n\n @property({ type: Object }) value: Material3DValue = {}\n @property({ type: String }) legend: string = 'Material 3D'\n\n render() {\n const r = resolve(this.value)\n const preset = this.value?.preset ?? 'default'\n\n return html`\n <fieldset>\n <legend>${this.legend}</legend>\n <div class=\"property-grid\">\n <label>Preset</label>\n <select @change=${this._onPresetChange}>\n ${PRESET_NAMES.map(name => html`<option value=${name} ?selected=${preset === name}>${name}</option>`)}\n </select>\n\n <label>Metalness</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n .value=${String(r.metalness)}\n @change=${(e: Event) => this._onRange('metalness', e)}\n />\n <span>${r.metalness.toFixed(2)}</span>\n </div>\n\n <label>Roughness</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n .value=${String(r.roughness)}\n @change=${(e: Event) => this._onRange('roughness', e)}\n />\n <span>${r.roughness.toFixed(2)}</span>\n </div>\n\n <label>Opacity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n .value=${String(r.opacity)}\n @change=${(e: Event) => this._onRange('opacity', e)}\n />\n <span>${r.opacity.toFixed(2)}</span>\n </div>\n\n <label>Env Map</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n .value=${String(r.envMapIntensity)}\n @change=${(e: Event) => this._onRange('envMapIntensity', e)}\n />\n <span>${r.envMapIntensity.toFixed(1)}</span>\n </div>\n\n <label>Side</label>\n <select @change=${this._onSideChange}>\n ${['double', 'front', 'back'].map(\n s => html`<option value=${s} ?selected=${r.side === s}>${s}</option>`\n )}\n </select>\n\n <input\n id=\"cb-cast\"\n type=\"checkbox\"\n .checked=${r.castShadow}\n @change=${(e: Event) => this._onCheck('castShadow', e)}\n />\n <label for=\"cb-cast\">Cast Shadow</label>\n\n <input\n id=\"cb-recv\"\n type=\"checkbox\"\n .checked=${r.receiveShadow}\n @change=${(e: Event) => this._onCheck('receiveShadow', e)}\n />\n <label for=\"cb-recv\">Receive Shadow</label>\n </div>\n </fieldset>\n `\n }\n\n private _onPresetChange(e: Event) {\n const preset = (e.target as HTMLSelectElement).value\n // Preset 변경 시 PBR 값을 리셋하고 프리셋 기본값 사용 (side, shadow는 유지)\n this._dispatch({\n preset,\n side: this.value?.side,\n castShadow: this.value?.castShadow,\n receiveShadow: this.value?.receiveShadow\n })\n }\n\n private _onRange(key: string, e: Event) {\n this._dispatch({ ...this.value, [key]: parseFloat((e.target as HTMLInputElement).value) })\n }\n\n private _onSideChange(e: Event) {\n this._dispatch({ ...this.value, side: (e.target as HTMLSelectElement).value })\n }\n\n private _onCheck(key: string, e: Event) {\n this._dispatch({ ...this.value, [key]: (e.target as HTMLInputElement).checked })\n }\n\n private _dispatch(material3d: Material3DValue) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: { material3d }\n })\n )\n }\n}\n"]}
1
+ {"version":3,"file":"property-material3d.js","sourceRoot":"","sources":["../../../../src/property-panel/threed/property-material3d.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\ninterface Material3DValue {\n preset?: string\n metalness?: number\n roughness?: number\n opacity?: number\n envMapIntensity?: number\n side?: string\n castShadow?: boolean\n receiveShadow?: boolean\n [key: string]: unknown\n}\n\nconst PRESETS: Record<string, { metalness: number; roughness: number; opacity?: number; envMapIntensity?: number }> = {\n default: { metalness: 0, roughness: 0.4 },\n metal: { metalness: 1.0, roughness: 0.3, envMapIntensity: 1.0 },\n glass: { metalness: 0, roughness: 0.1, opacity: 0.3, envMapIntensity: 1.5 },\n plastic: { metalness: 0, roughness: 0.4 },\n wood: { metalness: 0, roughness: 0.8, envMapIntensity: 0.3 },\n ceramic: { metalness: 0.1, roughness: 0.2, envMapIntensity: 0.3 },\n rubber: { metalness: 0, roughness: 0.9, envMapIntensity: 0.3 }\n}\n\nconst PRESET_NAMES = Object.keys(PRESETS)\n\nfunction resolve(m?: Material3DValue) {\n const preset = PRESETS[m?.preset ?? 'default'] ?? PRESETS.default\n return {\n metalness: m?.metalness ?? preset.metalness,\n roughness: m?.roughness ?? preset.roughness,\n opacity: m?.opacity ?? preset.opacity ?? 1,\n envMapIntensity: m?.envMapIntensity ?? preset.envMapIntensity ?? 0.5,\n side: m?.side ?? 'double',\n castShadow: m?.castShadow ?? true,\n receiveShadow: m?.receiveShadow ?? false\n }\n}\n\n@customElement('property-material3d')\nexport class PropertyMaterial3d extends LitElement {\n static styles = [\n PropertyGridStyles,\n css`\n .range-with-value {\n grid-column: 9 / -1;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .range-with-value input[type='range'] {\n flex: 1;\n border: none;\n background: transparent;\n padding: 0;\n }\n\n .range-with-value span {\n min-width: 2.5em;\n text-align: right;\n font-size: 11px;\n color: var(--md-sys-color-on-secondary-container);\n }\n `\n ]\n\n @property({ type: Object }) value: Material3DValue = {}\n @property({ type: String }) legend: string = 'Material 3D'\n\n render() {\n const r = resolve(this.value)\n const preset = this.value?.preset ?? 'default'\n\n return html`\n <fieldset>\n <legend>${this.legend}</legend>\n <div class=\"property-grid\">\n <label>Preset</label>\n <select @change=${this._onPresetChange}>\n ${PRESET_NAMES.map(name => html`<option value=${name} ?selected=${preset === name}>${name}</option>`)}\n </select>\n\n <label>Metalness</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n .value=${String(r.metalness)}\n @change=${(e: Event) => this._onRange('metalness', e)}\n />\n <span>${r.metalness.toFixed(2)}</span>\n </div>\n\n <label>Roughness</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n .value=${String(r.roughness)}\n @change=${(e: Event) => this._onRange('roughness', e)}\n />\n <span>${r.roughness.toFixed(2)}</span>\n </div>\n\n <label>Opacity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n .value=${String(r.opacity)}\n @change=${(e: Event) => this._onRange('opacity', e)}\n />\n <span>${r.opacity.toFixed(2)}</span>\n </div>\n\n <label>Env Map</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n .value=${String(r.envMapIntensity)}\n @change=${(e: Event) => this._onRange('envMapIntensity', e)}\n />\n <span>${r.envMapIntensity.toFixed(1)}</span>\n </div>\n\n <label>Side</label>\n <select @change=${this._onSideChange}>\n ${['double', 'front', 'back'].map(\n s => html`<option value=${s} ?selected=${r.side === s}>${s}</option>`\n )}\n </select>\n\n <input\n id=\"cb-cast\"\n type=\"checkbox\"\n .checked=${r.castShadow}\n @change=${(e: Event) => this._onCheck('castShadow', e)}\n />\n <label for=\"cb-cast\">Cast Shadow</label>\n\n <input\n id=\"cb-recv\"\n type=\"checkbox\"\n .checked=${r.receiveShadow}\n @change=${(e: Event) => this._onCheck('receiveShadow', e)}\n />\n <label for=\"cb-recv\">Receive Shadow</label>\n </div>\n </fieldset>\n `\n }\n\n private _onPresetChange(e: Event) {\n const preset = (e.target as HTMLSelectElement).value\n // Preset 변경 시 PBR 값을 리셋하고 프리셋 기본값 사용 (side, shadow는 유지)\n this._dispatch({\n preset,\n side: this.value?.side,\n castShadow: this.value?.castShadow,\n receiveShadow: this.value?.receiveShadow\n })\n }\n\n private _onRange(key: string, e: Event) {\n // Range inputs always carry a finite number, but parseFloat('') is NaN\n // — be defensive in case a parent rebinds the input mid-edit and the\n // value is briefly empty. NaN material props (e.g. metalness/roughness)\n // would surface as console warnings from three.js.\n const n = parseFloat((e.target as HTMLInputElement).value)\n if (!Number.isFinite(n)) return\n this._dispatch({ ...this.value, [key]: n })\n }\n\n private _onSideChange(e: Event) {\n this._dispatch({ ...this.value, side: (e.target as HTMLSelectElement).value })\n }\n\n private _onCheck(key: string, e: Event) {\n this._dispatch({ ...this.value, [key]: (e.target as HTMLInputElement).checked })\n }\n\n private _dispatch(material3d: Material3DValue) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: { material3d }\n })\n )\n }\n}\n"]}