@operato/property-panel 10.20.0 → 10.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/src/ox-property-panel.d.ts +1 -0
  3. package/dist/src/ox-property-panel.js +15 -0
  4. package/dist/src/ox-property-panel.js.map +1 -1
  5. package/dist/src/property-panel/data-binding/data-binding-mapper.js +20 -7
  6. package/dist/src/property-panel/data-binding/data-binding-mapper.js.map +1 -1
  7. package/dist/src/property-panel/data-binding/data-binding.d.ts +4 -0
  8. package/dist/src/property-panel/data-binding/data-binding.js +167 -56
  9. package/dist/src/property-panel/data-binding/data-binding.js.map +1 -1
  10. package/dist/src/property-panel/event-handlers/event-handlers-mapper.js +37 -16
  11. package/dist/src/property-panel/event-handlers/event-handlers-mapper.js.map +1 -1
  12. package/dist/src/property-panel/event-handlers/event-handlers-popup.d.ts +1 -0
  13. package/dist/src/property-panel/event-handlers/event-handlers-popup.js +48 -0
  14. package/dist/src/property-panel/event-handlers/event-handlers-popup.js.map +1 -1
  15. package/dist/src/property-panel/event-handlers/event-handlers.d.ts +3 -0
  16. package/dist/src/property-panel/event-handlers/event-handlers.js +173 -86
  17. package/dist/src/property-panel/event-handlers/event-handlers.js.map +1 -1
  18. package/dist/src/property-panel/shapes/shapes.d.ts +2 -0
  19. package/dist/src/property-panel/shapes/shapes.js +78 -29
  20. package/dist/src/property-panel/shapes/shapes.js.map +1 -1
  21. package/dist/src/property-panel/specifics/specifics.js +62 -6
  22. package/dist/src/property-panel/specifics/specifics.js.map +1 -1
  23. package/dist/src/property-panel/styles/styles.js +61 -31
  24. package/dist/src/property-panel/styles/styles.js.map +1 -1
  25. package/dist/src/property-panel/threed/property-material3d.js +10 -9
  26. package/dist/src/property-panel/threed/property-material3d.js.map +1 -1
  27. package/dist/src/property-panel/threed/property-scene3d.js +11 -9
  28. package/dist/src/property-panel/threed/property-scene3d.js.map +1 -1
  29. package/dist/src/property-panel/threed/threed.js +41 -18
  30. package/dist/src/property-panel/threed/threed.js.map +1 -1
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +6 -6
@@ -44,7 +44,9 @@ export class PropertyStyles extends AbstractProperty {
44
44
  <legend>
45
45
  <ox-title-with-help topic="board-modeller/styles/opacity" msgid="label.opacity">opacity</ox-title-with-help>
46
46
  </legend>
47
- <ox-input-range min="0" max="1" step="0.1" value-key="alpha" .value=${alpha} editable> </ox-input-range>
47
+ <div class="opacity">
48
+ <ox-input-range min="0" max="1" step="0.1" value-key="alpha" .value=${alpha} editable> </ox-input-range>
49
+ </div>
48
50
  </fieldset>
49
51
 
50
52
  <fieldset>
@@ -55,28 +57,28 @@ export class PropertyStyles extends AbstractProperty {
55
57
  </legend>
56
58
 
57
59
  <div class="property-grid">
58
- <label>
59
- <ox-i18n msgid="label.font-family">Font Family</ox-i18n>
60
- </label>
61
-
60
+ <label><ox-i18n msgid="label.font-family">Font</ox-i18n></label>
62
61
  <ox-font-selector class="custom-editor" value-key="fontFamily" .value=${fontFamily}></ox-font-selector>
63
62
 
64
- <label class="onethird-label icon-only-label"><md-icon>format_size</md-icon></label>
65
- <input type="number" value-key="fontSize" .value=${fontSize} class="onethird-editor" />
66
-
67
- <label class="onethird-label icon-only-label"><md-icon>format_line_spacing</md-icon></label>
68
- <input type="number" value-key="lineHeight" .value=${lineHeight} class="onethird-editor" />
69
-
70
- <label class="onethird-label icon-only-label"><md-icon>format_letter_spacing</md-icon></label>
71
- <input type="number" value-key="letterSpacing" .value=${letterSpacing} class="onethird-editor" />
72
-
73
- <label class="twothird-label icon-only-label"><md-icon>format_color_text</md-icon></label>
74
- <ox-input-color value-key="fontColor" .value=${fontColor} class="twothird-editor"> </ox-input-color>
75
-
76
- <div class="onethird-full btn-group" @click=${this.onButtonGroupClick}>
63
+ <div class="field half" title="font size">
64
+ <span>Size</span>
65
+ <input type="number" value-key="fontSize" .value=${fontSize} />
66
+ </div>
67
+ <div class="field half" title="line height">
68
+ <span>Line</span>
69
+ <input type="number" value-key="lineHeight" .value=${lineHeight} />
70
+ </div>
71
+ <div class="field half" title="letter spacing">
72
+ <span>Space</span>
73
+ <input type="number" value-key="letterSpacing" .value=${letterSpacing} />
74
+ </div>
75
+ <div class="half btn-group" @click=${this.onButtonGroupClick} title="bold / italic">
77
76
  <md-icon value-key="bold" ?active=${bold}>format_bold</md-icon>
78
77
  <md-icon value-key="italic" ?active=${italic}>format_italic</md-icon>
79
78
  </div>
79
+
80
+ <label><ox-i18n msgid="label.font-color">Color</ox-i18n></label>
81
+ <ox-input-color value-key="fontColor" .value=${fontColor} class="custom-editor"> </ox-input-color>
80
82
  </div>
81
83
  </fieldset>
82
84
 
@@ -96,11 +98,14 @@ export class PropertyStyles extends AbstractProperty {
96
98
  </legend>
97
99
 
98
100
  <div class="property-grid">
99
- <label class="half-label icon-only-label"><md-icon>line_weight</md-icon></label>
100
- <input type="number" value-key="lineWidth" .value=${lineWidth} class="half-editor" />
101
-
102
- <label class="half-label icon-only-label"><md-icon>border_color</md-icon></label>
103
- <ox-input-color value-key="strokeStyle" .value=${strokeStyle} class="half-editor"> </ox-input-color>
101
+ <div class="field half" title="line width">
102
+ <span>Width</span>
103
+ <input type="number" value-key="lineWidth" .value=${lineWidth} />
104
+ </div>
105
+ <div class="field half" title="line color">
106
+ <span>Color</span>
107
+ <ox-input-color value-key="strokeStyle" .value=${strokeStyle}></ox-input-color>
108
+ </div>
104
109
 
105
110
  <label>
106
111
  <ox-i18n msgid="label.line-type">line type</ox-i18n>
@@ -235,22 +240,47 @@ PropertyStyles.styles = [
235
240
  width: 100%;
236
241
  }
237
242
 
243
+ /* Bold / italic: two toggles on one segmented track, same as the alignment controls. */
238
244
  .btn-group {
245
+ display: flex;
246
+ align-items: stretch;
247
+ gap: 2px;
248
+ padding: 0;
249
+ min-height: 24px;
250
+ }
251
+
252
+ .btn-group > md-icon {
253
+ flex: 0 0 24px;
254
+ width: 24px;
255
+ height: 24px;
239
256
  display: flex;
240
257
  align-items: center;
241
258
  justify-content: center;
242
- gap: var(--spacing-medium, 8px);
259
+ border-radius: 4px;
260
+ color: var(--md-sys-color-on-surface-variant);
261
+ cursor: pointer;
262
+ --md-icon-size: 15px;
243
263
  }
244
264
 
245
- .btn-group * {
246
- width: 30px;
247
- min-width: initial;
248
- border-radius: 0;
249
- border-bottom: 2px solid #fff;
265
+ .btn-group > md-icon:hover {
266
+ color: var(--md-sys-color-on-surface);
267
+ background-color: var(--md-sys-color-surface-container-high);
268
+ }
269
+
270
+ .btn-group > md-icon[active] {
271
+ color: var(--md-sys-color-on-secondary-container);
272
+ background-color: var(--md-sys-color-secondary-container);
273
+ }
274
+
275
+ /* The opacity row: slider and its number as one line, aligned to the editor column. */
276
+ .opacity {
277
+ display: flex;
278
+ align-items: center;
279
+ gap: 10px;
250
280
  }
251
281
 
252
- .btn-group [active] {
253
- border-bottom: 2px solid #f2471c;
282
+ .opacity > ox-input-range {
283
+ flex: 1;
254
284
  }
255
285
  `
256
286
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../../src/property-panel/styles/styles.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/help/ox-title-with-help.js'\nimport '@operato/popup/ox-popup-list.js'\nimport '@operato/input/ox-input-range.js'\nimport '@operato/input/ox-input-color.js'\nimport '@operato/input/ox-input-fill-style.js'\nimport '@operato/input/ox-select.js'\nimport '@operato/font/ox-font-selector.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html, nothing } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Component } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\nimport { LineStyles } from '@operato/styles/line-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\nexport class PropertyStyles extends AbstractProperty {\n static styles = [\n PropertyGridStyles,\n LineStyles,\n css`\n ox-input-range {\n width: 100%;\n }\n\n .btn-group {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-medium, 8px);\n }\n\n .btn-group * {\n width: 30px;\n min-width: initial;\n border-radius: 0;\n border-bottom: 2px solid #fff;\n }\n\n .btn-group [active] {\n border-bottom: 2px solid #f2471c;\n }\n `\n ]\n\n @property({ type: Object }) value: any = {}\n @property({ type: Array }) selected: Component[] = []\n @property({ type: Array }) fonts: any[] = []\n @property({ type: Boolean, attribute: 'is-line' }) isLine: boolean = false\n\n connectedCallback() {\n super.connectedCallback()\n\n this.renderRoot.addEventListener('change', this.onValueChange.bind(this))\n }\n\n onButtonGroupClick(e: Event) {\n const target = e.target as HTMLElement\n\n if (target.hasAttribute('value-key')) {\n target.toggleAttribute('active')\n\n target.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true\n })\n )\n }\n }\n\n render() {\n var {\n alpha = 1,\n fontFamily,\n fontSize,\n lineHeight,\n fontColor,\n letterSpacing,\n bold,\n italic,\n fillStyle,\n lineWidth,\n strokeStyle,\n lineDash = 'solid',\n lineCap,\n lineJoin,\n begin = 'none',\n beginSize = 'size1',\n end = 'none',\n endSize = 'size1'\n } = this.value || {}\n\n return html`\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/styles/opacity\" msgid=\"label.opacity\">opacity</ox-title-with-help>\n </legend>\n <ox-input-range min=\"0\" max=\"1\" step=\"0.1\" value-key=\"alpha\" .value=${alpha} editable> </ox-input-range>\n </fieldset>\n\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/styles/text-style\" msgid=\"label.text-style\"\n >text style</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label>\n <ox-i18n msgid=\"label.font-family\">Font Family</ox-i18n>\n </label>\n\n <ox-font-selector class=\"custom-editor\" value-key=\"fontFamily\" .value=${fontFamily}></ox-font-selector>\n\n <label class=\"onethird-label icon-only-label\"><md-icon>format_size</md-icon></label>\n <input type=\"number\" value-key=\"fontSize\" .value=${fontSize} class=\"onethird-editor\" />\n\n <label class=\"onethird-label icon-only-label\"><md-icon>format_line_spacing</md-icon></label>\n <input type=\"number\" value-key=\"lineHeight\" .value=${lineHeight} class=\"onethird-editor\" />\n\n <label class=\"onethird-label icon-only-label\"><md-icon>format_letter_spacing</md-icon></label>\n <input type=\"number\" value-key=\"letterSpacing\" .value=${letterSpacing} class=\"onethird-editor\" />\n\n <label class=\"twothird-label icon-only-label\"><md-icon>format_color_text</md-icon></label>\n <ox-input-color value-key=\"fontColor\" .value=${fontColor} class=\"twothird-editor\"> </ox-input-color>\n\n <div class=\"onethird-full btn-group\" @click=${this.onButtonGroupClick}>\n <md-icon value-key=\"bold\" ?active=${bold}>format_bold</md-icon>\n <md-icon value-key=\"italic\" ?active=${italic}>format_italic</md-icon>\n </div>\n </div>\n </fieldset>\n\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/styles/fill-style\" msgid=\"label.fill-style\"\n >fill style</ox-title-with-help\n >\n </legend>\n\n <ox-input-fill-style value-key=\"fillStyle\" .value=${fillStyle}> </ox-input-fill-style>\n </fieldset>\n\n <fieldset>\n <legend>\n <ox-title-with-help msgid=\"label.line-style\" topic=\"board-modeller/styles/line-style\"></ox-title-with-help>\n </legend>\n\n <div class=\"property-grid\">\n <label class=\"half-label icon-only-label\"><md-icon>line_weight</md-icon></label>\n <input type=\"number\" value-key=\"lineWidth\" .value=${lineWidth} class=\"half-editor\" />\n\n <label class=\"half-label icon-only-label\"><md-icon>border_color</md-icon></label>\n <ox-input-color value-key=\"strokeStyle\" .value=${strokeStyle} class=\"half-editor\"> </ox-input-color>\n\n <label>\n <ox-i18n msgid=\"label.line-type\">line type</ox-i18n>\n </label>\n <ox-select value-key=\"lineDash\" .value=${lineDash} class=\"custom-editor\">\n <div class=\"line-type ${lineDash}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"line-type solid\" value=\"solid\" option></div>\n <div class=\"line-type round-dot\" value=\"round-dot\" option></div>\n <div class=\"line-type square-dot\" value=\"square-dot\" option></div>\n <div class=\"line-type dash\" value=\"dash\" option></div>\n <div class=\"line-type dash-dot\" value=\"dash-dot\" option></div>\n <div class=\"line-type long-dash\" value=\"long-dash\" option></div>\n <div class=\"line-type long-dash-dot\" value=\"long-dash-dot\" option></div>\n <div class=\"line-type long-dash-dot-dot\" value=\"long-dash-dot-dot\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.cap-type\">cap type</ox-i18n>\n </label>\n <select value-key=\"lineCap\" .value=${lineCap}>\n <option value=\"butt\"><ox-i18n msgid=\"label.square\">square</ox-i18n></option>\n <option value=\"round\"><ox-i18n msgid=\"label.round\">round</ox-i18n></option>\n </select>\n\n <label>\n <ox-i18n msgid=\"label.join-type\">join type</ox-i18n>\n </label>\n <select value-key=\"lineJoin\" .value=${lineJoin}>\n <option value=\"miter\"><ox-i18n msgid=\"label.miter\">miter</ox-i18n></option>\n <option value=\"round\"><ox-i18n msgid=\"label.round\">round</ox-i18n></option>\n <option value=\"bevel\"><ox-i18n msgid=\"label.bevel\">bevel</ox-i18n></option>\n </select>\n\n ${this.isLine\n ? html`\n <label>\n <ox-i18n msgid=\"label.begin-type\">begin type</ox-i18n>\n </label>\n <ox-select value-key=\"begin\" .value=${begin} class=\"custom-editor\">\n <div class=\"arrow-type ${begin ? `begin-${begin}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type begin-none\" value=\"none\" option></div>\n <div class=\"arrow-type begin-arrow\" value=\"arrow\" option></div>\n <div class=\"arrow-type begin-open-arrow\" value=\"open-arrow\" option></div>\n <div class=\"arrow-type begin-sharp-arrow\" value=\"sharp-arrow\" option></div>\n <div class=\"arrow-type begin-diamond\" value=\"diamond\" option></div>\n <div class=\"arrow-type begin-oval\" value=\"oval\" option></div>\n <div class=\"arrow-type begin-cross\" value=\"cross\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.begin-size\">begin size</ox-i18n>\n </label>\n <ox-select value-key=\"beginSize\" .value=${beginSize} class=\"custom-editor\">\n <div class=\"arrow-type ${beginSize ? `begin-${beginSize}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type begin-size1\" value=\"size1\" option></div>\n <div class=\"arrow-type begin-size2\" value=\"size2\" option></div>\n <div class=\"arrow-type begin-size3\" value=\"size3\" option></div>\n <div class=\"arrow-type begin-size4\" value=\"size4\" option></div>\n <div class=\"arrow-type begin-size5\" value=\"size5\" option></div>\n <div class=\"arrow-type begin-size6\" value=\"size6\" option></div>\n <div class=\"arrow-type begin-size7\" value=\"size7\" option></div>\n <div class=\"arrow-type begin-size8\" value=\"size8\" option></div>\n <div class=\"arrow-type begin-size9\" value=\"size9\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.end-type\">end type</ox-i18n>\n </label>\n <ox-select value-key=\"end\" .value=${end} class=\"custom-editor\">\n <div class=\"arrow-type ${end ? `end-${end}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type end-none\" value=\"none\" option></div>\n <div class=\"arrow-type end-arrow\" value=\"arrow\" option></div>\n <div class=\"arrow-type end-open-arrow\" value=\"open-arrow\" option></div>\n <div class=\"arrow-type end-sharp-arrow\" value=\"sharp-arrow\" option></div>\n <div class=\"arrow-type end-diamond\" value=\"diamond\" option></div>\n <div class=\"arrow-type end-oval\" value=\"oval\" option></div>\n <div class=\"arrow-type end-cross\" value=\"cross\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.end-size\">end size</ox-i18n>\n </label>\n <ox-select value-key=\"endSize\" .value=${endSize} class=\"custom-editor\">\n <div class=\"arrow-type ${endSize ? `end-${endSize}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type end-size1\" value=\"size1\" option></div>\n <div class=\"arrow-type end-size2\" value=\"size2\" option></div>\n <div class=\"arrow-type end-size3\" value=\"size3\" option></div>\n <div class=\"arrow-type end-size4\" value=\"size4\" option></div>\n <div class=\"arrow-type end-size5\" value=\"size5\" option></div>\n <div class=\"arrow-type end-size6\" value=\"size6\" option></div>\n <div class=\"arrow-type end-size7\" value=\"size7\" option></div>\n <div class=\"arrow-type end-size8\" value=\"size8\" option></div>\n <div class=\"arrow-type end-size9\" value=\"size9\" option></div>\n </ox-popup-list>\n </ox-select>\n `\n : html``}\n </div>\n </fieldset>\n `\n }\n}\n"]}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../../src/property-panel/styles/styles.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/help/ox-title-with-help.js'\nimport '@operato/popup/ox-popup-list.js'\nimport '@operato/input/ox-input-range.js'\nimport '@operato/input/ox-input-color.js'\nimport '@operato/input/ox-input-fill-style.js'\nimport '@operato/input/ox-select.js'\nimport '@operato/font/ox-font-selector.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html, nothing } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Component } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\nimport { LineStyles } from '@operato/styles/line-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\nexport class PropertyStyles extends AbstractProperty {\n static styles = [\n PropertyGridStyles,\n LineStyles,\n css`\n ox-input-range {\n width: 100%;\n }\n\n /* Bold / italic: two toggles on one segmented track, same as the alignment controls. */\n .btn-group {\n display: flex;\n align-items: stretch;\n gap: 2px;\n padding: 0;\n min-height: 24px;\n }\n\n .btn-group > md-icon {\n flex: 0 0 24px;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n color: var(--md-sys-color-on-surface-variant);\n cursor: pointer;\n --md-icon-size: 15px;\n }\n\n .btn-group > md-icon:hover {\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container-high);\n }\n\n .btn-group > md-icon[active] {\n color: var(--md-sys-color-on-secondary-container);\n background-color: var(--md-sys-color-secondary-container);\n }\n\n /* The opacity row: slider and its number as one line, aligned to the editor column. */\n .opacity {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .opacity > ox-input-range {\n flex: 1;\n }\n `\n ]\n\n @property({ type: Object }) value: any = {}\n @property({ type: Array }) selected: Component[] = []\n @property({ type: Array }) fonts: any[] = []\n @property({ type: Boolean, attribute: 'is-line' }) isLine: boolean = false\n\n connectedCallback() {\n super.connectedCallback()\n\n this.renderRoot.addEventListener('change', this.onValueChange.bind(this))\n }\n\n onButtonGroupClick(e: Event) {\n const target = e.target as HTMLElement\n\n if (target.hasAttribute('value-key')) {\n target.toggleAttribute('active')\n\n target.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true\n })\n )\n }\n }\n\n render() {\n var {\n alpha = 1,\n fontFamily,\n fontSize,\n lineHeight,\n fontColor,\n letterSpacing,\n bold,\n italic,\n fillStyle,\n lineWidth,\n strokeStyle,\n lineDash = 'solid',\n lineCap,\n lineJoin,\n begin = 'none',\n beginSize = 'size1',\n end = 'none',\n endSize = 'size1'\n } = this.value || {}\n\n return html`\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/styles/opacity\" msgid=\"label.opacity\">opacity</ox-title-with-help>\n </legend>\n <div class=\"opacity\">\n <ox-input-range min=\"0\" max=\"1\" step=\"0.1\" value-key=\"alpha\" .value=${alpha} editable> </ox-input-range>\n </div>\n </fieldset>\n\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/styles/text-style\" msgid=\"label.text-style\"\n >text style</ox-title-with-help\n >\n </legend>\n\n <div class=\"property-grid\">\n <label><ox-i18n msgid=\"label.font-family\">Font</ox-i18n></label>\n <ox-font-selector class=\"custom-editor\" value-key=\"fontFamily\" .value=${fontFamily}></ox-font-selector>\n\n <div class=\"field half\" title=\"font size\">\n <span>Size</span>\n <input type=\"number\" value-key=\"fontSize\" .value=${fontSize} />\n </div>\n <div class=\"field half\" title=\"line height\">\n <span>Line</span>\n <input type=\"number\" value-key=\"lineHeight\" .value=${lineHeight} />\n </div>\n <div class=\"field half\" title=\"letter spacing\">\n <span>Space</span>\n <input type=\"number\" value-key=\"letterSpacing\" .value=${letterSpacing} />\n </div>\n <div class=\"half btn-group\" @click=${this.onButtonGroupClick} title=\"bold / italic\">\n <md-icon value-key=\"bold\" ?active=${bold}>format_bold</md-icon>\n <md-icon value-key=\"italic\" ?active=${italic}>format_italic</md-icon>\n </div>\n\n <label><ox-i18n msgid=\"label.font-color\">Color</ox-i18n></label>\n <ox-input-color value-key=\"fontColor\" .value=${fontColor} class=\"custom-editor\"> </ox-input-color>\n </div>\n </fieldset>\n\n <fieldset>\n <legend>\n <ox-title-with-help topic=\"board-modeller/styles/fill-style\" msgid=\"label.fill-style\"\n >fill style</ox-title-with-help\n >\n </legend>\n\n <ox-input-fill-style value-key=\"fillStyle\" .value=${fillStyle}> </ox-input-fill-style>\n </fieldset>\n\n <fieldset>\n <legend>\n <ox-title-with-help msgid=\"label.line-style\" topic=\"board-modeller/styles/line-style\"></ox-title-with-help>\n </legend>\n\n <div class=\"property-grid\">\n <div class=\"field half\" title=\"line width\">\n <span>Width</span>\n <input type=\"number\" value-key=\"lineWidth\" .value=${lineWidth} />\n </div>\n <div class=\"field half\" title=\"line color\">\n <span>Color</span>\n <ox-input-color value-key=\"strokeStyle\" .value=${strokeStyle}></ox-input-color>\n </div>\n\n <label>\n <ox-i18n msgid=\"label.line-type\">line type</ox-i18n>\n </label>\n <ox-select value-key=\"lineDash\" .value=${lineDash} class=\"custom-editor\">\n <div class=\"line-type ${lineDash}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"line-type solid\" value=\"solid\" option></div>\n <div class=\"line-type round-dot\" value=\"round-dot\" option></div>\n <div class=\"line-type square-dot\" value=\"square-dot\" option></div>\n <div class=\"line-type dash\" value=\"dash\" option></div>\n <div class=\"line-type dash-dot\" value=\"dash-dot\" option></div>\n <div class=\"line-type long-dash\" value=\"long-dash\" option></div>\n <div class=\"line-type long-dash-dot\" value=\"long-dash-dot\" option></div>\n <div class=\"line-type long-dash-dot-dot\" value=\"long-dash-dot-dot\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.cap-type\">cap type</ox-i18n>\n </label>\n <select value-key=\"lineCap\" .value=${lineCap}>\n <option value=\"butt\"><ox-i18n msgid=\"label.square\">square</ox-i18n></option>\n <option value=\"round\"><ox-i18n msgid=\"label.round\">round</ox-i18n></option>\n </select>\n\n <label>\n <ox-i18n msgid=\"label.join-type\">join type</ox-i18n>\n </label>\n <select value-key=\"lineJoin\" .value=${lineJoin}>\n <option value=\"miter\"><ox-i18n msgid=\"label.miter\">miter</ox-i18n></option>\n <option value=\"round\"><ox-i18n msgid=\"label.round\">round</ox-i18n></option>\n <option value=\"bevel\"><ox-i18n msgid=\"label.bevel\">bevel</ox-i18n></option>\n </select>\n\n ${this.isLine\n ? html`\n <label>\n <ox-i18n msgid=\"label.begin-type\">begin type</ox-i18n>\n </label>\n <ox-select value-key=\"begin\" .value=${begin} class=\"custom-editor\">\n <div class=\"arrow-type ${begin ? `begin-${begin}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type begin-none\" value=\"none\" option></div>\n <div class=\"arrow-type begin-arrow\" value=\"arrow\" option></div>\n <div class=\"arrow-type begin-open-arrow\" value=\"open-arrow\" option></div>\n <div class=\"arrow-type begin-sharp-arrow\" value=\"sharp-arrow\" option></div>\n <div class=\"arrow-type begin-diamond\" value=\"diamond\" option></div>\n <div class=\"arrow-type begin-oval\" value=\"oval\" option></div>\n <div class=\"arrow-type begin-cross\" value=\"cross\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.begin-size\">begin size</ox-i18n>\n </label>\n <ox-select value-key=\"beginSize\" .value=${beginSize} class=\"custom-editor\">\n <div class=\"arrow-type ${beginSize ? `begin-${beginSize}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type begin-size1\" value=\"size1\" option></div>\n <div class=\"arrow-type begin-size2\" value=\"size2\" option></div>\n <div class=\"arrow-type begin-size3\" value=\"size3\" option></div>\n <div class=\"arrow-type begin-size4\" value=\"size4\" option></div>\n <div class=\"arrow-type begin-size5\" value=\"size5\" option></div>\n <div class=\"arrow-type begin-size6\" value=\"size6\" option></div>\n <div class=\"arrow-type begin-size7\" value=\"size7\" option></div>\n <div class=\"arrow-type begin-size8\" value=\"size8\" option></div>\n <div class=\"arrow-type begin-size9\" value=\"size9\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.end-type\">end type</ox-i18n>\n </label>\n <ox-select value-key=\"end\" .value=${end} class=\"custom-editor\">\n <div class=\"arrow-type ${end ? `end-${end}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type end-none\" value=\"none\" option></div>\n <div class=\"arrow-type end-arrow\" value=\"arrow\" option></div>\n <div class=\"arrow-type end-open-arrow\" value=\"open-arrow\" option></div>\n <div class=\"arrow-type end-sharp-arrow\" value=\"sharp-arrow\" option></div>\n <div class=\"arrow-type end-diamond\" value=\"diamond\" option></div>\n <div class=\"arrow-type end-oval\" value=\"oval\" option></div>\n <div class=\"arrow-type end-cross\" value=\"cross\" option></div>\n </ox-popup-list>\n </ox-select>\n\n <label>\n <ox-i18n msgid=\"label.end-size\">end size</ox-i18n>\n </label>\n <ox-select value-key=\"endSize\" .value=${endSize} class=\"custom-editor\">\n <div class=\"arrow-type ${endSize ? `end-${endSize}` : nothing}\" slot=\"label\"></div>\n <ox-popup-list align-left nowrap>\n <style>\n ${LineStyles.cssText}\n </style>\n <div class=\"arrow-type end-size1\" value=\"size1\" option></div>\n <div class=\"arrow-type end-size2\" value=\"size2\" option></div>\n <div class=\"arrow-type end-size3\" value=\"size3\" option></div>\n <div class=\"arrow-type end-size4\" value=\"size4\" option></div>\n <div class=\"arrow-type end-size5\" value=\"size5\" option></div>\n <div class=\"arrow-type end-size6\" value=\"size6\" option></div>\n <div class=\"arrow-type end-size7\" value=\"size7\" option></div>\n <div class=\"arrow-type end-size8\" value=\"size8\" option></div>\n <div class=\"arrow-type end-size9\" value=\"size9\" option></div>\n </ox-popup-list>\n </ox-select>\n `\n : html``}\n </div>\n </fieldset>\n `\n }\n}\n"]}
@@ -162,24 +162,25 @@ PropertyMaterial3d.styles = [
162
162
  PropertyGridStyles,
163
163
  css `
164
164
  .range-with-value {
165
- grid-column: 9 / -1;
165
+ grid-column: 10 / -1;
166
166
  display: flex;
167
167
  align-items: center;
168
- gap: 4px;
168
+ gap: 8px;
169
+ min-width: 0;
169
170
  }
170
171
 
171
172
  .range-with-value input[type='range'] {
172
- flex: 1;
173
- border: none;
174
- background: transparent;
175
- padding: 0;
173
+ flex: 1 1 0;
174
+ min-width: 0;
176
175
  }
177
176
 
178
177
  .range-with-value span {
179
- min-width: 2.5em;
178
+ flex: none;
179
+ min-width: 2.6em;
180
180
  text-align: right;
181
- font-size: 11px;
182
- color: var(--md-sys-color-on-secondary-container);
181
+ font-size: 0.74rem;
182
+ font-variant-numeric: tabular-nums;
183
+ color: var(--md-sys-color-on-surface-variant);
183
184
  }
184
185
  `
185
186
  ];
@@ -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 // 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"]}
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: 10 / -1;\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n }\n\n .range-with-value input[type='range'] {\n flex: 1 1 0;\n min-width: 0;\n }\n\n .range-with-value span {\n flex: none;\n min-width: 2.6em;\n text-align: right;\n font-size: 0.74rem;\n font-variant-numeric: tabular-nums;\n color: var(--md-sys-color-on-surface-variant);\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"]}
@@ -502,25 +502,27 @@ export class PropertyScene3D extends AbstractProperty {
502
502
  PropertyScene3D.styles = [
503
503
  PropertyGridStyles,
504
504
  css `
505
+ /* Same row as its label, same as the material sliders: the editor column starts at 10. */
505
506
  .range-with-value {
506
- grid-column: 9 / -1;
507
+ grid-column: 10 / -1;
507
508
  display: flex;
508
509
  align-items: center;
509
- gap: 4px;
510
+ gap: 8px;
511
+ min-width: 0;
510
512
  }
511
513
 
512
514
  .range-with-value input[type='range'] {
513
- flex: 1;
514
- border: none;
515
- background: transparent;
516
- padding: 0;
515
+ flex: 1 1 0;
516
+ min-width: 0;
517
517
  }
518
518
 
519
519
  .range-with-value span {
520
- min-width: 2.5em;
520
+ flex: none;
521
+ min-width: 2.6em;
521
522
  text-align: right;
522
- font-size: 11px;
523
- color: var(--md-sys-color-on-secondary-container);
523
+ font-size: 0.74rem;
524
+ font-variant-numeric: tabular-nums;
525
+ color: var(--md-sys-color-on-surface-variant);
524
526
  }
525
527
 
526
528
  .camera-actions {
@@ -1 +1 @@
1
- {"version":3,"file":"property-scene3d.js","sourceRoot":"","sources":["../../../../src/property-panel/threed/property-scene3d.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-color.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport './property-material3d.js'\n\nimport { css, html } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Properties, Scene } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\n/**\n * Environment별 기본 조명 프로파일.\n * Environment 드롭다운에서 선택 시 sky 값과 함께 이 조명 필드들이 자동 적용된다.\n * Light Mood(아래)는 이 위에 얹는 오버라이드 역할.\n */\nconst ENVIRONMENT_DEFAULTS: Record<string, Record<string, unknown>> = {\n // 실내\n studio: {\n hemiSkyColor: '#ffffff', hemiGroundColor: '#888888', hemiIntensity: 3.0,\n dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 2.0,\n dirLightFollowCamera: true\n },\n warehouse: {\n hemiSkyColor: '#e0e4ea', hemiGroundColor: '#707880', hemiIntensity: 2.5,\n dirLightEnabled: true, dirLightColor: '#f8fafc', dirLightIntensity: 1.8,\n dirLightFollowCamera: true\n },\n factory: {\n hemiSkyColor: '#d8dce2', hemiGroundColor: '#606870', hemiIntensity: 2.0,\n dirLightEnabled: true, dirLightColor: '#e8eef2', dirLightIntensity: 2.0,\n dirLightFollowCamera: true\n },\n office: {\n hemiSkyColor: '#ffffff', hemiGroundColor: '#aaaaaa', hemiIntensity: 3.0,\n dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 1.5,\n dirLightFollowCamera: true\n },\n home: {\n hemiSkyColor: '#ffe8c8', hemiGroundColor: '#7a5a40', hemiIntensity: 2.0,\n dirLightEnabled: true, dirLightColor: '#ffd8a0', dirLightIntensity: 1.5,\n dirLightFollowCamera: true\n },\n // 실외 (날씨)\n sunny: {\n hemiSkyColor: '#87ceeb', hemiGroundColor: '#8b7355', hemiIntensity: 2.0,\n dirLightEnabled: true, dirLightColor: '#fff4cf', dirLightIntensity: 3.0,\n dirLightFollowCamera: false, dirLightAzimuth: 135, dirLightElevation: 60\n },\n cloudy: {\n hemiSkyColor: '#c8cbd0', hemiGroundColor: '#9ba1a8', hemiIntensity: 3.0,\n dirLightEnabled: true, dirLightColor: '#e8e8e8', dirLightIntensity: 0.6,\n dirLightFollowCamera: false, dirLightAzimuth: 120, dirLightElevation: 50\n },\n rainy: {\n hemiSkyColor: '#8a909a', hemiGroundColor: '#4a4f55', hemiIntensity: 1.5,\n dirLightEnabled: true, dirLightColor: '#b8c0c8', dirLightIntensity: 0.3,\n dirLightFollowCamera: false, dirLightAzimuth: 110, dirLightElevation: 40\n }\n}\n\n/**\n * Light Mood 프리셋 — Environment 기본값 위에 얹는 분위기 오버라이드.\n * Environment(지금 씬이 어디에 있는가)와 독립적으로 작동하며 sky는 건드리지 않는다.\n * 원자 조명 필드(hemi/dir)만 세팅.\n */\nconst LIGHTING_PRESETS: Record<string, Record<string, unknown>> = {\n Bright: { hemiIntensity: 3.0, dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 2.5 },\n Dim: { hemiIntensity: 0.5, dirLightEnabled: true, dirLightColor: '#fff5e0', dirLightIntensity: 0.5 },\n Warm: { hemiIntensity: 1.5, dirLightEnabled: true, dirLightColor: '#ffaa55', dirLightIntensity: 2.0 },\n Cool: { hemiIntensity: 1.5, dirLightEnabled: true, dirLightColor: '#88bbff', dirLightIntensity: 2.0 },\n Dramatic: { hemiIntensity: 0.3, dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 3.0 },\n Flat: { hemiIntensity: 3.0, dirLightEnabled: false, dirLightColor: '#ffffff', dirLightIntensity: 0 }\n}\n\n/**\n * Scene-level 3D settings for model-layer.\n * Includes 3D mode, camera, renderer, lighting, presets, and floor configuration.\n */\nexport class PropertyScene3D extends AbstractProperty {\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 .camera-actions {\n display: flex;\n justify-content: flex-end;\n margin-top: 6px;\n }\n\n .camera-actions button {\n font-size: 12px;\n padding: 4px 10px;\n border: 1px solid var(--md-sys-color-outline, #c4c7c5);\n border-radius: 4px;\n background: var(--md-sys-color-surface, #fff);\n color: var(--md-sys-color-on-surface, #1c1b1f);\n cursor: pointer;\n }\n\n .camera-actions button:hover {\n background: var(--md-sys-color-surface-variant, #e7e0ec);\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n @property({ type: Object }) scene: Scene | null = null\n\n render() {\n const value = this.value || {}\n\n return html`\n ${this._renderMode(value)} ${this._renderPlacement(value)}\n ${this._renderCamera(value)}\n ${this._renderRenderer(value)} ${this._renderSky(value)}\n ${this._renderHemisphereLight(value)} ${this._renderKeyLight(value)} ${this._renderLightingPresets()}\n ${this._renderFloor(value)}\n `\n }\n\n /**\n * Camera 초기 설정 — Initial View(뷰 프리셋), FOV/Near/Far, 현재 카메라 저장 버튼.\n * 사용자가 씬을 3D로 돌려본 후 \"이 각도가 마음에 든다\" 싶으면\n * Save Current View로 현재 viewport의 position을 모델에 기록 → 다음 로드 시 같은 각도로 시작.\n */\n private _renderCamera(value: Properties) {\n const views = [\n { value: 'perspective', label: 'Perspective' },\n { value: 'top', label: 'Top' },\n { value: 'front', label: 'Front' },\n { value: 'back', label: 'Back' },\n { value: 'right', label: 'Right' },\n { value: 'left', label: 'Left' }\n ]\n const currentView = (value.initialCameraView as string) || 'perspective'\n const fov = Number(value.fov ?? 45)\n const near = Number(value.near ?? 0.1)\n const far = Number(value.far ?? 20000)\n\n return html`\n <fieldset>\n <legend>Camera</legend>\n <div class=\"property-grid\">\n <label>Initial View</label>\n <select value-key=\"initialCameraView\">\n ${views.map(\n v => html`<option value=${v.value} ?selected=${currentView === v.value}>${v.label}</option>`\n )}\n </select>\n\n <label>FOV</label>\n <input type=\"number\" value-key=\"fov\" step=\"1\" min=\"1\" max=\"170\" .value=${String(fov)} />\n\n <label>Near</label>\n <input type=\"number\" value-key=\"near\" step=\"0.1\" min=\"0.01\" .value=${String(near)} />\n\n <label>Far</label>\n <input type=\"number\" value-key=\"far\" step=\"100\" min=\"1\" .value=${String(far)} />\n </div>\n\n <div class=\"camera-actions\">\n <button type=\"button\" @click=${this._onSaveCameraView}>Save Current View</button>\n </div>\n </fieldset>\n `\n }\n\n /**\n * 현재 3D viewport의 카메라 상태를 모델에 저장한다.\n * scene의 getCameraState를 호출하여 view/cameraX/cameraY/cameraZ를 얻어 property-change로 전파.\n */\n private _onSaveCameraView() {\n const cap = (this.scene?.rootContainer as any)?.model_layer?._threeCapability\n if (!cap?.getCameraState) return\n const state = cap.getCameraState()\n if (!state) return\n\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: {\n initialCameraView: state.view,\n cameraX: state.cameraX,\n cameraY: state.cameraY,\n cameraZ: state.cameraZ\n }\n })\n )\n }\n\n /**\n * Scene placement 모드 선택 — zPos 해석과 볼륨 origin 방향을 씬 전체에 일관 적용.\n * floor : zPos=바닥 높이, 볼륨이 위로 쌓임 (공장/창고/건축)\n * space : zPos=볼륨 중심 Y, 바닥 개념 없음 (우주/추상/전시)\n * inverted: zPos=천장, 볼륨이 아래로 매달림 (천장 설비, 베타)\n */\n private _renderPlacement(value: Properties) {\n const options = [\n { value: 'floor', label: 'Floor (default)' },\n { value: 'space', label: 'Space' },\n { value: 'inverted', label: 'Inverted (beta)' }\n ]\n const current = (value.placement as string) || 'floor'\n\n return html`\n <fieldset>\n <legend>Placement</legend>\n <div class=\"property-grid\">\n <label>Mode</label>\n <select value-key=\"placement\">\n ${options.map(\n o => html`<option value=${o.value} ?selected=${current === o.value}>${o.label}</option>`\n )}\n </select>\n </div>\n </fieldset>\n `\n }\n\n private _renderMode(value: Properties) {\n return html`\n <fieldset>\n <legend>3D Mode</legend>\n <div class=\"property-grid\">\n <input id=\"cb-threed\" type=\"checkbox\" value-key=\"threed\" .checked=${!!value.threed} />\n <label for=\"cb-threed\"><ox-i18n msgid=\"label.start-in-3d\">Start in 3D</ox-i18n></label>\n\n <label>Viewer Auto</label>\n <select value-key=\"cameraAutoPlay\">\n ${[\n { value: '', label: 'None' },\n { value: 'orbit', label: 'Orbit' },\n { value: 'play', label: 'Play Bookmarks' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.cameraAutoPlay || '') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n\n <input\n id=\"cb-floor-constraint\"\n type=\"checkbox\"\n value-key=\"cameraFloorConstraint\"\n .checked=${!!value.cameraFloorConstraint}\n />\n <label for=\"cb-floor-constraint\"><ox-i18n msgid=\"label.keep-above-ground\">Keep Above Ground</ox-i18n></label>\n </div>\n </fieldset>\n `\n }\n\n private _renderRenderer(value: Properties) {\n const exposure = Number(value.exposure ?? 1.2)\n return html`\n <fieldset>\n <legend>Renderer</legend>\n <div class=\"property-grid\">\n <input id=\"cb-antialias\" type=\"checkbox\" value-key=\"antialias\" .checked=${value.antialias !== false} />\n <label for=\"cb-antialias\">Anti-alias</label>\n\n <label>Precision</label>\n <select value-key=\"precision\">\n ${[\n { value: 'highp', label: 'High' },\n { value: 'mediump', label: 'Medium' },\n { value: 'lowp', label: 'Low' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.precision || 'highp') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n\n <label>Exposure</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0.3\"\n max=\"2.5\"\n step=\"0.05\"\n value-key=\"exposure\"\n .value=${String(exposure)}\n />\n <span>${exposure.toFixed(2)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n /**\n * Environment 드롭다운 — 씬의 공간적 맥락을 정의.\n * 선택 시 sky 값과 함께 ENVIRONMENT_DEFAULTS의 기본 조명까지 한 번에 적용한다.\n * \"원클릭 전체 look\" — 사용자가 원하면 Light Mood/원자 컨트롤로 위에 얹어 조정.\n */\n private _renderSky(value: Properties) {\n const envOptions = [\n { value: '', label: 'None', group: 'basic' },\n { value: 'color', label: 'Color', group: 'basic' },\n { value: 'studio', label: 'Studio', group: 'indoor' },\n { value: 'warehouse', label: 'Warehouse', group: 'indoor' },\n { value: 'factory', label: 'Factory', group: 'indoor' },\n { value: 'office', label: 'Office', group: 'indoor' },\n { value: 'home', label: 'Home', group: 'indoor' },\n { value: 'sunny', label: 'Sunny', group: 'outdoor' },\n { value: 'cloudy', label: 'Cloudy', group: 'outdoor' },\n { value: 'rainy', label: 'Rainy', group: 'outdoor' }\n ]\n\n return html`\n <fieldset>\n <legend>Environment</legend>\n <div class=\"property-grid\">\n <label>Preset</label>\n <select @change=${this._onEnvironmentChange}>\n <optgroup label=\"Basic\">\n ${envOptions\n .filter(o => o.group === 'basic')\n .map(o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`)}\n </optgroup>\n <optgroup label=\"Indoor\">\n ${envOptions\n .filter(o => o.group === 'indoor')\n .map(o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`)}\n </optgroup>\n <optgroup label=\"Outdoor\">\n ${envOptions\n .filter(o => o.group === 'outdoor')\n .map(o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`)}\n </optgroup>\n </select>\n\n ${value.sky === 'color'\n ? html`\n <label>Color</label>\n <ox-input-color value-key=\"skyColor\" .value=${value.skyColor || '#87ceeb'}> </ox-input-color>\n `\n : ''}\n </div>\n </fieldset>\n `\n }\n\n /**\n * Environment 선택 핸들러 — sky 필드만 바꾸는 게 아니라 ENVIRONMENT_DEFAULTS에\n * 정의된 hemi/dir 기본 조명까지 한 번의 property-change로 함께 적용한다.\n */\n private _onEnvironmentChange(e: Event) {\n const select = e.target as HTMLSelectElement\n const sky = select.value\n const detail: Record<string, unknown> = { sky }\n const defaults = ENVIRONMENT_DEFAULTS[sky]\n if (defaults) {\n Object.assign(detail, defaults)\n }\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail\n })\n )\n }\n\n private _renderHemisphereLight(value: Properties) {\n return html`\n <fieldset>\n <legend>Hemisphere Light</legend>\n <div class=\"property-grid\">\n <label>Sky</label>\n <ox-input-color value-key=\"hemiSkyColor\" .value=${value.hemiSkyColor || '#ffffff'}></ox-input-color>\n\n <label>Ground</label>\n <ox-input-color value-key=\"hemiGroundColor\" .value=${value.hemiGroundColor || '#444444'}></ox-input-color>\n\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"hemiIntensity\"\n .value=${String(value.hemiIntensity ?? 0.6)}\n />\n <span>${(value.hemiIntensity ?? 0.6).toFixed(1)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderKeyLight(value: Properties) {\n const followCamera = value.dirLightFollowCamera !== false\n const shadowEnabled = value.dirShadowEnabled !== false\n return html`\n <fieldset>\n <legend>Key Light</legend>\n <div class=\"property-grid\">\n <input\n id=\"cb-dirlight\"\n type=\"checkbox\"\n value-key=\"dirLightEnabled\"\n .checked=${value.dirLightEnabled !== false}\n />\n <label for=\"cb-dirlight\">Enabled</label>\n\n <label>Color</label>\n <ox-input-color value-key=\"dirLightColor\" .value=${value.dirLightColor || '#ffffff'}> </ox-input-color>\n\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"dirLightIntensity\"\n .value=${String(value.dirLightIntensity ?? 0.5)}\n />\n <span>${(value.dirLightIntensity ?? 0.5).toFixed(1)}</span>\n </div>\n\n <input\n id=\"cb-dirlight-follow\"\n type=\"checkbox\"\n value-key=\"dirLightFollowCamera\"\n .checked=${followCamera}\n />\n <label for=\"cb-dirlight-follow\">Follow Camera</label>\n\n ${!followCamera\n ? html`\n <label>Azimuth</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"360\"\n step=\"5\"\n value-key=\"dirLightAzimuth\"\n .value=${String(value.dirLightAzimuth ?? 30)}\n />\n <span>${Math.round((value.dirLightAzimuth ?? 30) as number)}°</span>\n </div>\n\n <label>Elevation</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"90\"\n step=\"5\"\n value-key=\"dirLightElevation\"\n .value=${String(value.dirLightElevation ?? 45)}\n />\n <span>${Math.round((value.dirLightElevation ?? 45) as number)}°</span>\n </div>\n `\n : ''}\n\n <input\n id=\"cb-dirlight-shadow\"\n type=\"checkbox\"\n value-key=\"dirShadowEnabled\"\n .checked=${shadowEnabled}\n />\n <label for=\"cb-dirlight-shadow\">Cast Shadow</label>\n\n ${shadowEnabled\n ? html`\n <label>Shadow Bias</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"-0.01\"\n max=\"0.01\"\n step=\"0.0001\"\n value-key=\"dirShadowBias\"\n .value=${String(value.dirShadowBias ?? -0.0005)}\n />\n <span>${(value.dirShadowBias ?? -0.0005).toFixed(4)}</span>\n </div>\n `\n : ''}\n </div>\n </fieldset>\n `\n }\n\n /**\n * Light Mood — Environment가 설정한 기본 조명 위에 얹는 분위기 오버라이드.\n * sky는 건드리지 않고 hemi/dir 값만 적용. Environment와 독립적으로 조합 가능.\n */\n private _renderLightingPresets() {\n return html`\n <fieldset>\n <legend>Light Mood</legend>\n <div class=\"property-grid\">\n <label>Apply</label>\n <select @change=${this._onPresetChange}>\n <option value=\"\" selected>Select...</option>\n ${Object.keys(LIGHTING_PRESETS).map(\n name => html`<option value=${name}>${name}</option>`\n )}\n </select>\n </div>\n </fieldset>\n `\n }\n\n private _onPresetChange(e: Event) {\n const select = e.target as HTMLSelectElement\n const name = select.value\n if (!name) return\n const preset = LIGHTING_PRESETS[name]\n if (preset) this._applyLightingPreset(preset)\n // 동일 preset을 다시 선택할 수 있도록 초기값으로 리셋\n select.value = ''\n }\n\n private _renderFloor(value: Properties) {\n return html`\n <property-material3d\n legend=\"Floor Material\"\n .value=${value.floorMaterial3d || { receiveShadow: true }}\n @property-change=${this._onFloorMaterialChange}\n >\n </property-material3d>\n `\n }\n\n private _applyLightingPreset(values: Record<string, unknown>) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: values\n })\n )\n }\n\n private _onFloorMaterialChange(e: CustomEvent) {\n e.stopPropagation()\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: { floorMaterial3d: e.detail.material3d }\n })\n )\n }\n\n}\n"]}
1
+ {"version":3,"file":"property-scene3d.js","sourceRoot":"","sources":["../../../../src/property-panel/threed/property-scene3d.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-color.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport './property-material3d.js'\n\nimport { css, html } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Properties, Scene } from '@hatiolab/things-scene'\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { AbstractProperty } from '../abstract-property.js'\n\n/**\n * Environment별 기본 조명 프로파일.\n * Environment 드롭다운에서 선택 시 sky 값과 함께 이 조명 필드들이 자동 적용된다.\n * Light Mood(아래)는 이 위에 얹는 오버라이드 역할.\n */\nconst ENVIRONMENT_DEFAULTS: Record<string, Record<string, unknown>> = {\n // 실내\n studio: {\n hemiSkyColor: '#ffffff', hemiGroundColor: '#888888', hemiIntensity: 3.0,\n dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 2.0,\n dirLightFollowCamera: true\n },\n warehouse: {\n hemiSkyColor: '#e0e4ea', hemiGroundColor: '#707880', hemiIntensity: 2.5,\n dirLightEnabled: true, dirLightColor: '#f8fafc', dirLightIntensity: 1.8,\n dirLightFollowCamera: true\n },\n factory: {\n hemiSkyColor: '#d8dce2', hemiGroundColor: '#606870', hemiIntensity: 2.0,\n dirLightEnabled: true, dirLightColor: '#e8eef2', dirLightIntensity: 2.0,\n dirLightFollowCamera: true\n },\n office: {\n hemiSkyColor: '#ffffff', hemiGroundColor: '#aaaaaa', hemiIntensity: 3.0,\n dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 1.5,\n dirLightFollowCamera: true\n },\n home: {\n hemiSkyColor: '#ffe8c8', hemiGroundColor: '#7a5a40', hemiIntensity: 2.0,\n dirLightEnabled: true, dirLightColor: '#ffd8a0', dirLightIntensity: 1.5,\n dirLightFollowCamera: true\n },\n // 실외 (날씨)\n sunny: {\n hemiSkyColor: '#87ceeb', hemiGroundColor: '#8b7355', hemiIntensity: 2.0,\n dirLightEnabled: true, dirLightColor: '#fff4cf', dirLightIntensity: 3.0,\n dirLightFollowCamera: false, dirLightAzimuth: 135, dirLightElevation: 60\n },\n cloudy: {\n hemiSkyColor: '#c8cbd0', hemiGroundColor: '#9ba1a8', hemiIntensity: 3.0,\n dirLightEnabled: true, dirLightColor: '#e8e8e8', dirLightIntensity: 0.6,\n dirLightFollowCamera: false, dirLightAzimuth: 120, dirLightElevation: 50\n },\n rainy: {\n hemiSkyColor: '#8a909a', hemiGroundColor: '#4a4f55', hemiIntensity: 1.5,\n dirLightEnabled: true, dirLightColor: '#b8c0c8', dirLightIntensity: 0.3,\n dirLightFollowCamera: false, dirLightAzimuth: 110, dirLightElevation: 40\n }\n}\n\n/**\n * Light Mood 프리셋 — Environment 기본값 위에 얹는 분위기 오버라이드.\n * Environment(지금 씬이 어디에 있는가)와 독립적으로 작동하며 sky는 건드리지 않는다.\n * 원자 조명 필드(hemi/dir)만 세팅.\n */\nconst LIGHTING_PRESETS: Record<string, Record<string, unknown>> = {\n Bright: { hemiIntensity: 3.0, dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 2.5 },\n Dim: { hemiIntensity: 0.5, dirLightEnabled: true, dirLightColor: '#fff5e0', dirLightIntensity: 0.5 },\n Warm: { hemiIntensity: 1.5, dirLightEnabled: true, dirLightColor: '#ffaa55', dirLightIntensity: 2.0 },\n Cool: { hemiIntensity: 1.5, dirLightEnabled: true, dirLightColor: '#88bbff', dirLightIntensity: 2.0 },\n Dramatic: { hemiIntensity: 0.3, dirLightEnabled: true, dirLightColor: '#ffffff', dirLightIntensity: 3.0 },\n Flat: { hemiIntensity: 3.0, dirLightEnabled: false, dirLightColor: '#ffffff', dirLightIntensity: 0 }\n}\n\n/**\n * Scene-level 3D settings for model-layer.\n * Includes 3D mode, camera, renderer, lighting, presets, and floor configuration.\n */\nexport class PropertyScene3D extends AbstractProperty {\n static styles = [\n PropertyGridStyles,\n css`\n /* Same row as its label, same as the material sliders: the editor column starts at 10. */\n .range-with-value {\n grid-column: 10 / -1;\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n }\n\n .range-with-value input[type='range'] {\n flex: 1 1 0;\n min-width: 0;\n }\n\n .range-with-value span {\n flex: none;\n min-width: 2.6em;\n text-align: right;\n font-size: 0.74rem;\n font-variant-numeric: tabular-nums;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .camera-actions {\n display: flex;\n justify-content: flex-end;\n margin-top: 6px;\n }\n\n .camera-actions button {\n font-size: 12px;\n padding: 4px 10px;\n border: 1px solid var(--md-sys-color-outline, #c4c7c5);\n border-radius: 4px;\n background: var(--md-sys-color-surface, #fff);\n color: var(--md-sys-color-on-surface, #1c1b1f);\n cursor: pointer;\n }\n\n .camera-actions button:hover {\n background: var(--md-sys-color-surface-variant, #e7e0ec);\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n @property({ type: Object }) scene: Scene | null = null\n\n render() {\n const value = this.value || {}\n\n return html`\n ${this._renderMode(value)} ${this._renderPlacement(value)}\n ${this._renderCamera(value)}\n ${this._renderRenderer(value)} ${this._renderSky(value)}\n ${this._renderHemisphereLight(value)} ${this._renderKeyLight(value)} ${this._renderLightingPresets()}\n ${this._renderFloor(value)}\n `\n }\n\n /**\n * Camera 초기 설정 — Initial View(뷰 프리셋), FOV/Near/Far, 현재 카메라 저장 버튼.\n * 사용자가 씬을 3D로 돌려본 후 \"이 각도가 마음에 든다\" 싶으면\n * Save Current View로 현재 viewport의 position을 모델에 기록 → 다음 로드 시 같은 각도로 시작.\n */\n private _renderCamera(value: Properties) {\n const views = [\n { value: 'perspective', label: 'Perspective' },\n { value: 'top', label: 'Top' },\n { value: 'front', label: 'Front' },\n { value: 'back', label: 'Back' },\n { value: 'right', label: 'Right' },\n { value: 'left', label: 'Left' }\n ]\n const currentView = (value.initialCameraView as string) || 'perspective'\n const fov = Number(value.fov ?? 45)\n const near = Number(value.near ?? 0.1)\n const far = Number(value.far ?? 20000)\n\n return html`\n <fieldset>\n <legend>Camera</legend>\n <div class=\"property-grid\">\n <label>Initial View</label>\n <select value-key=\"initialCameraView\">\n ${views.map(\n v => html`<option value=${v.value} ?selected=${currentView === v.value}>${v.label}</option>`\n )}\n </select>\n\n <label>FOV</label>\n <input type=\"number\" value-key=\"fov\" step=\"1\" min=\"1\" max=\"170\" .value=${String(fov)} />\n\n <label>Near</label>\n <input type=\"number\" value-key=\"near\" step=\"0.1\" min=\"0.01\" .value=${String(near)} />\n\n <label>Far</label>\n <input type=\"number\" value-key=\"far\" step=\"100\" min=\"1\" .value=${String(far)} />\n </div>\n\n <div class=\"camera-actions\">\n <button type=\"button\" @click=${this._onSaveCameraView}>Save Current View</button>\n </div>\n </fieldset>\n `\n }\n\n /**\n * 현재 3D viewport의 카메라 상태를 모델에 저장한다.\n * scene의 getCameraState를 호출하여 view/cameraX/cameraY/cameraZ를 얻어 property-change로 전파.\n */\n private _onSaveCameraView() {\n const cap = (this.scene?.rootContainer as any)?.model_layer?._threeCapability\n if (!cap?.getCameraState) return\n const state = cap.getCameraState()\n if (!state) return\n\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: {\n initialCameraView: state.view,\n cameraX: state.cameraX,\n cameraY: state.cameraY,\n cameraZ: state.cameraZ\n }\n })\n )\n }\n\n /**\n * Scene placement 모드 선택 — zPos 해석과 볼륨 origin 방향을 씬 전체에 일관 적용.\n * floor : zPos=바닥 높이, 볼륨이 위로 쌓임 (공장/창고/건축)\n * space : zPos=볼륨 중심 Y, 바닥 개념 없음 (우주/추상/전시)\n * inverted: zPos=천장, 볼륨이 아래로 매달림 (천장 설비, 베타)\n */\n private _renderPlacement(value: Properties) {\n const options = [\n { value: 'floor', label: 'Floor (default)' },\n { value: 'space', label: 'Space' },\n { value: 'inverted', label: 'Inverted (beta)' }\n ]\n const current = (value.placement as string) || 'floor'\n\n return html`\n <fieldset>\n <legend>Placement</legend>\n <div class=\"property-grid\">\n <label>Mode</label>\n <select value-key=\"placement\">\n ${options.map(\n o => html`<option value=${o.value} ?selected=${current === o.value}>${o.label}</option>`\n )}\n </select>\n </div>\n </fieldset>\n `\n }\n\n private _renderMode(value: Properties) {\n return html`\n <fieldset>\n <legend>3D Mode</legend>\n <div class=\"property-grid\">\n <input id=\"cb-threed\" type=\"checkbox\" value-key=\"threed\" .checked=${!!value.threed} />\n <label for=\"cb-threed\"><ox-i18n msgid=\"label.start-in-3d\">Start in 3D</ox-i18n></label>\n\n <label>Viewer Auto</label>\n <select value-key=\"cameraAutoPlay\">\n ${[\n { value: '', label: 'None' },\n { value: 'orbit', label: 'Orbit' },\n { value: 'play', label: 'Play Bookmarks' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.cameraAutoPlay || '') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n\n <input\n id=\"cb-floor-constraint\"\n type=\"checkbox\"\n value-key=\"cameraFloorConstraint\"\n .checked=${!!value.cameraFloorConstraint}\n />\n <label for=\"cb-floor-constraint\"><ox-i18n msgid=\"label.keep-above-ground\">Keep Above Ground</ox-i18n></label>\n </div>\n </fieldset>\n `\n }\n\n private _renderRenderer(value: Properties) {\n const exposure = Number(value.exposure ?? 1.2)\n return html`\n <fieldset>\n <legend>Renderer</legend>\n <div class=\"property-grid\">\n <input id=\"cb-antialias\" type=\"checkbox\" value-key=\"antialias\" .checked=${value.antialias !== false} />\n <label for=\"cb-antialias\">Anti-alias</label>\n\n <label>Precision</label>\n <select value-key=\"precision\">\n ${[\n { value: 'highp', label: 'High' },\n { value: 'mediump', label: 'Medium' },\n { value: 'lowp', label: 'Low' }\n ].map(\n o =>\n html`<option value=${o.value} ?selected=${(value.precision || 'highp') === o.value}>\n ${o.label}\n </option>`\n )}\n </select>\n\n <label>Exposure</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0.3\"\n max=\"2.5\"\n step=\"0.05\"\n value-key=\"exposure\"\n .value=${String(exposure)}\n />\n <span>${exposure.toFixed(2)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n /**\n * Environment 드롭다운 — 씬의 공간적 맥락을 정의.\n * 선택 시 sky 값과 함께 ENVIRONMENT_DEFAULTS의 기본 조명까지 한 번에 적용한다.\n * \"원클릭 전체 look\" — 사용자가 원하면 Light Mood/원자 컨트롤로 위에 얹어 조정.\n */\n private _renderSky(value: Properties) {\n const envOptions = [\n { value: '', label: 'None', group: 'basic' },\n { value: 'color', label: 'Color', group: 'basic' },\n { value: 'studio', label: 'Studio', group: 'indoor' },\n { value: 'warehouse', label: 'Warehouse', group: 'indoor' },\n { value: 'factory', label: 'Factory', group: 'indoor' },\n { value: 'office', label: 'Office', group: 'indoor' },\n { value: 'home', label: 'Home', group: 'indoor' },\n { value: 'sunny', label: 'Sunny', group: 'outdoor' },\n { value: 'cloudy', label: 'Cloudy', group: 'outdoor' },\n { value: 'rainy', label: 'Rainy', group: 'outdoor' }\n ]\n\n return html`\n <fieldset>\n <legend>Environment</legend>\n <div class=\"property-grid\">\n <label>Preset</label>\n <select @change=${this._onEnvironmentChange}>\n <optgroup label=\"Basic\">\n ${envOptions\n .filter(o => o.group === 'basic')\n .map(o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`)}\n </optgroup>\n <optgroup label=\"Indoor\">\n ${envOptions\n .filter(o => o.group === 'indoor')\n .map(o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`)}\n </optgroup>\n <optgroup label=\"Outdoor\">\n ${envOptions\n .filter(o => o.group === 'outdoor')\n .map(o => html`<option value=${o.value} ?selected=${(value.sky || '') === o.value}>${o.label}</option>`)}\n </optgroup>\n </select>\n\n ${value.sky === 'color'\n ? html`\n <label>Color</label>\n <ox-input-color value-key=\"skyColor\" .value=${value.skyColor || '#87ceeb'}> </ox-input-color>\n `\n : ''}\n </div>\n </fieldset>\n `\n }\n\n /**\n * Environment 선택 핸들러 — sky 필드만 바꾸는 게 아니라 ENVIRONMENT_DEFAULTS에\n * 정의된 hemi/dir 기본 조명까지 한 번의 property-change로 함께 적용한다.\n */\n private _onEnvironmentChange(e: Event) {\n const select = e.target as HTMLSelectElement\n const sky = select.value\n const detail: Record<string, unknown> = { sky }\n const defaults = ENVIRONMENT_DEFAULTS[sky]\n if (defaults) {\n Object.assign(detail, defaults)\n }\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail\n })\n )\n }\n\n private _renderHemisphereLight(value: Properties) {\n return html`\n <fieldset>\n <legend>Hemisphere Light</legend>\n <div class=\"property-grid\">\n <label>Sky</label>\n <ox-input-color value-key=\"hemiSkyColor\" .value=${value.hemiSkyColor || '#ffffff'}></ox-input-color>\n\n <label>Ground</label>\n <ox-input-color value-key=\"hemiGroundColor\" .value=${value.hemiGroundColor || '#444444'}></ox-input-color>\n\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"hemiIntensity\"\n .value=${String(value.hemiIntensity ?? 0.6)}\n />\n <span>${(value.hemiIntensity ?? 0.6).toFixed(1)}</span>\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _renderKeyLight(value: Properties) {\n const followCamera = value.dirLightFollowCamera !== false\n const shadowEnabled = value.dirShadowEnabled !== false\n return html`\n <fieldset>\n <legend>Key Light</legend>\n <div class=\"property-grid\">\n <input\n id=\"cb-dirlight\"\n type=\"checkbox\"\n value-key=\"dirLightEnabled\"\n .checked=${value.dirLightEnabled !== false}\n />\n <label for=\"cb-dirlight\">Enabled</label>\n\n <label>Color</label>\n <ox-input-color value-key=\"dirLightColor\" .value=${value.dirLightColor || '#ffffff'}> </ox-input-color>\n\n <label>Intensity</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.1\"\n value-key=\"dirLightIntensity\"\n .value=${String(value.dirLightIntensity ?? 0.5)}\n />\n <span>${(value.dirLightIntensity ?? 0.5).toFixed(1)}</span>\n </div>\n\n <input\n id=\"cb-dirlight-follow\"\n type=\"checkbox\"\n value-key=\"dirLightFollowCamera\"\n .checked=${followCamera}\n />\n <label for=\"cb-dirlight-follow\">Follow Camera</label>\n\n ${!followCamera\n ? html`\n <label>Azimuth</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"360\"\n step=\"5\"\n value-key=\"dirLightAzimuth\"\n .value=${String(value.dirLightAzimuth ?? 30)}\n />\n <span>${Math.round((value.dirLightAzimuth ?? 30) as number)}°</span>\n </div>\n\n <label>Elevation</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"90\"\n step=\"5\"\n value-key=\"dirLightElevation\"\n .value=${String(value.dirLightElevation ?? 45)}\n />\n <span>${Math.round((value.dirLightElevation ?? 45) as number)}°</span>\n </div>\n `\n : ''}\n\n <input\n id=\"cb-dirlight-shadow\"\n type=\"checkbox\"\n value-key=\"dirShadowEnabled\"\n .checked=${shadowEnabled}\n />\n <label for=\"cb-dirlight-shadow\">Cast Shadow</label>\n\n ${shadowEnabled\n ? html`\n <label>Shadow Bias</label>\n <div class=\"range-with-value\">\n <input\n type=\"range\"\n min=\"-0.01\"\n max=\"0.01\"\n step=\"0.0001\"\n value-key=\"dirShadowBias\"\n .value=${String(value.dirShadowBias ?? -0.0005)}\n />\n <span>${(value.dirShadowBias ?? -0.0005).toFixed(4)}</span>\n </div>\n `\n : ''}\n </div>\n </fieldset>\n `\n }\n\n /**\n * Light Mood — Environment가 설정한 기본 조명 위에 얹는 분위기 오버라이드.\n * sky는 건드리지 않고 hemi/dir 값만 적용. Environment와 독립적으로 조합 가능.\n */\n private _renderLightingPresets() {\n return html`\n <fieldset>\n <legend>Light Mood</legend>\n <div class=\"property-grid\">\n <label>Apply</label>\n <select @change=${this._onPresetChange}>\n <option value=\"\" selected>Select...</option>\n ${Object.keys(LIGHTING_PRESETS).map(\n name => html`<option value=${name}>${name}</option>`\n )}\n </select>\n </div>\n </fieldset>\n `\n }\n\n private _onPresetChange(e: Event) {\n const select = e.target as HTMLSelectElement\n const name = select.value\n if (!name) return\n const preset = LIGHTING_PRESETS[name]\n if (preset) this._applyLightingPreset(preset)\n // 동일 preset을 다시 선택할 수 있도록 초기값으로 리셋\n select.value = ''\n }\n\n private _renderFloor(value: Properties) {\n return html`\n <property-material3d\n legend=\"Floor Material\"\n .value=${value.floorMaterial3d || { receiveShadow: true }}\n @property-change=${this._onFloorMaterialChange}\n >\n </property-material3d>\n `\n }\n\n private _applyLightingPreset(values: Record<string, unknown>) {\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: values\n })\n )\n }\n\n private _onFloorMaterialChange(e: CustomEvent) {\n e.stopPropagation()\n this.dispatchEvent(\n new CustomEvent('property-change', {\n bubbles: true,\n composed: true,\n detail: { floorMaterial3d: e.detail.material3d }\n })\n )\n }\n\n}\n"]}
@@ -18,6 +18,11 @@ import { html } from 'lit';
18
18
  import { property } from 'lit/decorators.js';
19
19
  import { PropertyGridStyles } from '@operato/styles/property-grid-styles.js';
20
20
  import { AbstractProperty } from '../abstract-property.js';
21
+ /** A coordinate as the panel shows it: at most two decimals, never the float's full tail. */
22
+ function fmtNumber(value) {
23
+ const n = typeof value === 'number' ? value : parseFloat(String(value !== null && value !== void 0 ? value : ''));
24
+ return Number.isFinite(n) ? String(Math.round(n * 100) / 100) : '';
25
+ }
21
26
  export class Property3D extends AbstractProperty {
22
27
  constructor() {
23
28
  super(...arguments);
@@ -35,36 +40,54 @@ export class Property3D extends AbstractProperty {
35
40
  <fieldset>
36
41
  <legend>Size</legend>
37
42
  <div class="property-grid">
38
- <label class="onethird-label">W</label>
39
- <input class="onethird-editor" type="number" value-key="bounds.width" .value=${String(width)} />
40
- <label class="onethird-label">H</label>
41
- <input class="onethird-editor" type="number" value-key="bounds.height" .value=${String(height)} />
42
- <label class="onethird-label">D</label>
43
- <input class="onethird-editor" type="number" value-key="depth" .value=${(_a = value.depth) !== null && _a !== void 0 ? _a : 0} />
43
+ <div class="field third" title="W">
44
+ <span>W</span>
45
+ <input type="number" value-key="bounds.width" .value=${fmtNumber(width)} />
46
+ </div>
47
+ <div class="field third" title="H">
48
+ <span>H</span>
49
+ <input type="number" value-key="bounds.height" .value=${fmtNumber(height)} />
50
+ </div>
51
+ <div class="field third" title="D">
52
+ <span>D</span>
53
+ <input type="number" value-key="depth" .value=${(_a = value.depth) !== null && _a !== void 0 ? _a : 0} />
54
+ </div>
44
55
  </div>
45
56
  </fieldset>
46
57
 
47
58
  <fieldset>
48
59
  <legend>Position</legend>
49
60
  <div class="property-grid">
50
- <label class="onethird-label">X</label>
51
- <input class="onethird-editor" type="number" value-key="bounds.left" .value=${String(left)} />
52
- <label class="onethird-label">Y</label>
53
- <input class="onethird-editor" type="number" value-key="bounds.top" .value=${String(top)} />
54
- <label class="onethird-label">Z</label>
55
- <input class="onethird-editor" type="number" value-key="zPos" .value=${(_b = value.zPos) !== null && _b !== void 0 ? _b : 0} />
61
+ <div class="field third" title="X">
62
+ <span>X</span>
63
+ <input type="number" value-key="bounds.left" .value=${fmtNumber(left)} />
64
+ </div>
65
+ <div class="field third" title="Y">
66
+ <span>Y</span>
67
+ <input type="number" value-key="bounds.top" .value=${fmtNumber(top)} />
68
+ </div>
69
+ <div class="field third" title="Z">
70
+ <span>Z</span>
71
+ <input type="number" value-key="zPos" .value=${(_b = value.zPos) !== null && _b !== void 0 ? _b : 0} />
72
+ </div>
56
73
  </div>
57
74
  </fieldset>
58
75
 
59
76
  <fieldset>
60
77
  <legend>Rotation</legend>
61
78
  <div class="property-grid">
62
- <label class="onethird-label">RX</label>
63
- <ox-input-angle class="onethird-editor" value-key="rotationX" .value=${(_c = value.rotationX) !== null && _c !== void 0 ? _c : 0}></ox-input-angle>
64
- <label class="onethird-label">RY</label>
65
- <ox-input-angle class="onethird-editor" value-key="rotationY" .value=${(_d = value.rotationY) !== null && _d !== void 0 ? _d : 0}></ox-input-angle>
66
- <label class="onethird-label">RZ</label>
67
- <ox-input-angle class="onethird-editor" value-key="rotation" .value=${(_e = value.rotation) !== null && _e !== void 0 ? _e : 0}></ox-input-angle>
79
+ <div class="field third" title="RX">
80
+ <span>RX</span>
81
+ <ox-input-angle value-key="rotationX" .value=${(_c = value.rotationX) !== null && _c !== void 0 ? _c : 0}></ox-input-angle>
82
+ </div>
83
+ <div class="field third" title="RY">
84
+ <span>RY</span>
85
+ <ox-input-angle value-key="rotationY" .value=${(_d = value.rotationY) !== null && _d !== void 0 ? _d : 0}></ox-input-angle>
86
+ </div>
87
+ <div class="field third" title="RZ">
88
+ <span>RZ</span>
89
+ <ox-input-angle value-key="rotation" .value=${(_e = value.rotation) !== null && _e !== void 0 ? _e : 0}></ox-input-angle>
90
+ </div>
68
91
  </div>
69
92
  </fieldset>
70
93