@fmsim/board 2.0.0-beta.64 → 2.0.0-beta.67
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/custom-elements.json +2264 -1914
- package/dist/src/component/index.d.ts +1 -0
- package/dist/src/component/index.js +1 -0
- package/dist/src/component/index.js.map +1 -1
- package/dist/src/component/restful-property-editor-backdrop-faces.d.ts +50 -0
- package/dist/src/component/restful-property-editor-backdrop-faces.js +524 -0
- package/dist/src/component/restful-property-editor-backdrop-faces.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/component/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAA;AAChD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,UAAU,CAAA","sourcesContent":["export * from './restful-attachment-selector.js'\nexport * from './restful-input-fill-style.js'\nexport * from './etc.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/component/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAA;AAChD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,6CAA6C,CAAA;AAC3D,cAAc,UAAU,CAAA","sourcesContent":["export * from './restful-attachment-selector.js'\nexport * from './restful-input-fill-style.js'\nexport * from './restful-property-editor-backdrop-faces.js'\nexport * from './etc.js'\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* fmsim-restful 환경에서는 GraphQL/attachment 의존이 있는 ox-input-fill-style 대신
|
|
5
|
+
* restful-input-fill-style 을 사용해야 한다. ox-property-editor-backdrop-faces 와
|
|
6
|
+
* 동일한 cube-picker UI 를 유지하되 fillStyle 에디터만 restful 버전으로 교체.
|
|
7
|
+
*
|
|
8
|
+
* 양쪽 동기화 시 주의: ox-property-editor-backdrop-faces.ts (operato/property-editor)
|
|
9
|
+
* 변경 시 이 파일도 함께 업데이트.
|
|
10
|
+
*/
|
|
11
|
+
import './restful-input-fill-style.js';
|
|
12
|
+
import '@operato/i18n/ox-i18n.js';
|
|
13
|
+
import { LitElement, type TemplateResult } from 'lit';
|
|
14
|
+
import { OxPropertyEditor } from '@operato/property-editor';
|
|
15
|
+
import type { PropertySpec } from '@operato/property-editor';
|
|
16
|
+
type FaceName = 'east' | 'west' | 'north' | 'south' | 'ceiling' | 'floor';
|
|
17
|
+
interface FaceState {
|
|
18
|
+
fillStyle?: any;
|
|
19
|
+
visible?: boolean;
|
|
20
|
+
alpha?: number;
|
|
21
|
+
rotation?: 0 | 90 | 180 | 270;
|
|
22
|
+
mirror?: boolean;
|
|
23
|
+
}
|
|
24
|
+
type FacesValue = Partial<Record<FaceName, FaceState>>;
|
|
25
|
+
export declare class RestfulInputBackdropFaces extends LitElement {
|
|
26
|
+
value: FacesValue;
|
|
27
|
+
private _selected;
|
|
28
|
+
static styles: import("lit").CSSResult;
|
|
29
|
+
private _face;
|
|
30
|
+
private _swatchColor;
|
|
31
|
+
private _select;
|
|
32
|
+
private _commit;
|
|
33
|
+
private _patchFace;
|
|
34
|
+
private _onFillStyleChange;
|
|
35
|
+
private _onVisibleChange;
|
|
36
|
+
private _onAlphaChange;
|
|
37
|
+
private _onRotationChange;
|
|
38
|
+
private _onMirrorChange;
|
|
39
|
+
private _copyToOpposite;
|
|
40
|
+
private _copyToAllWalls;
|
|
41
|
+
private _renderLabel;
|
|
42
|
+
private _faceClass;
|
|
43
|
+
private _ghostClass;
|
|
44
|
+
render(): TemplateResult<1>;
|
|
45
|
+
}
|
|
46
|
+
export declare class RestfulPropertyEditorBackdropFaces extends OxPropertyEditor {
|
|
47
|
+
static styles: import("lit").CSSResult[];
|
|
48
|
+
editorTemplate(value: any, spec: PropertySpec): TemplateResult;
|
|
49
|
+
}
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* fmsim-restful 환경에서는 GraphQL/attachment 의존이 있는 ox-input-fill-style 대신
|
|
5
|
+
* restful-input-fill-style 을 사용해야 한다. ox-property-editor-backdrop-faces 와
|
|
6
|
+
* 동일한 cube-picker UI 를 유지하되 fillStyle 에디터만 restful 버전으로 교체.
|
|
7
|
+
*
|
|
8
|
+
* 양쪽 동기화 시 주의: ox-property-editor-backdrop-faces.ts (operato/property-editor)
|
|
9
|
+
* 변경 시 이 파일도 함께 업데이트.
|
|
10
|
+
*/
|
|
11
|
+
import { __decorate } from "tslib";
|
|
12
|
+
import './restful-input-fill-style.js';
|
|
13
|
+
import '@operato/i18n/ox-i18n.js';
|
|
14
|
+
import { css, html, LitElement, nothing } from 'lit';
|
|
15
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
16
|
+
import { OxPropertyEditor } from '@operato/property-editor';
|
|
17
|
+
const OPPOSITE = {
|
|
18
|
+
east: 'west',
|
|
19
|
+
west: 'east',
|
|
20
|
+
north: 'south',
|
|
21
|
+
south: 'north',
|
|
22
|
+
ceiling: 'floor',
|
|
23
|
+
floor: 'ceiling'
|
|
24
|
+
};
|
|
25
|
+
const AXIS_LABEL = {
|
|
26
|
+
east: '+X',
|
|
27
|
+
west: '−X',
|
|
28
|
+
north: '−Z',
|
|
29
|
+
south: '+Z',
|
|
30
|
+
ceiling: '+Y',
|
|
31
|
+
floor: '−Y'
|
|
32
|
+
};
|
|
33
|
+
const DEFAULT_FACES = {
|
|
34
|
+
east: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },
|
|
35
|
+
west: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },
|
|
36
|
+
north: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },
|
|
37
|
+
south: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },
|
|
38
|
+
ceiling: { fillStyle: '#e8e8ec', visible: true, alpha: 1.0, rotation: 0, mirror: false },
|
|
39
|
+
floor: { fillStyle: '#9c9c9c', visible: true, alpha: 1.0, rotation: 0, mirror: false }
|
|
40
|
+
};
|
|
41
|
+
let RestfulInputBackdropFaces = class RestfulInputBackdropFaces extends LitElement {
|
|
42
|
+
constructor() {
|
|
43
|
+
super(...arguments);
|
|
44
|
+
this.value = {};
|
|
45
|
+
this._selected = 'ceiling';
|
|
46
|
+
}
|
|
47
|
+
_face(name) {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
return { ...DEFAULT_FACES[name], ...((_b = (_a = this.value) === null || _a === void 0 ? void 0 : _a[name]) !== null && _b !== void 0 ? _b : {}) };
|
|
50
|
+
}
|
|
51
|
+
_swatchColor(name) {
|
|
52
|
+
var _a;
|
|
53
|
+
const fs = this._face(name).fillStyle;
|
|
54
|
+
if (typeof fs === 'string' && fs && fs !== 'transparent')
|
|
55
|
+
return fs;
|
|
56
|
+
if (fs && typeof fs === 'object') {
|
|
57
|
+
if (fs.type === 'gradient' && Array.isArray(fs.colorStops) && ((_a = fs.colorStops[0]) === null || _a === void 0 ? void 0 : _a.color)) {
|
|
58
|
+
return fs.colorStops[0].color;
|
|
59
|
+
}
|
|
60
|
+
if (fs.color)
|
|
61
|
+
return fs.color;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
_select(name) {
|
|
66
|
+
this._selected = name;
|
|
67
|
+
}
|
|
68
|
+
_commit(next) {
|
|
69
|
+
this.value = next;
|
|
70
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
|
|
71
|
+
}
|
|
72
|
+
_patchFace(name, patch) {
|
|
73
|
+
const next = { ...(this.value || {}) };
|
|
74
|
+
next[name] = { ...this._face(name), ...patch };
|
|
75
|
+
this._commit(next);
|
|
76
|
+
}
|
|
77
|
+
_onFillStyleChange(e) {
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
const target = e.target;
|
|
80
|
+
this._patchFace(this._selected, { fillStyle: target.value });
|
|
81
|
+
}
|
|
82
|
+
_onVisibleChange(e) {
|
|
83
|
+
e.stopPropagation();
|
|
84
|
+
const target = e.target;
|
|
85
|
+
this._patchFace(this._selected, { visible: target.checked });
|
|
86
|
+
}
|
|
87
|
+
_onAlphaChange(e) {
|
|
88
|
+
e.stopPropagation();
|
|
89
|
+
const target = e.target;
|
|
90
|
+
const v = parseFloat(target.value);
|
|
91
|
+
const alpha = Number.isFinite(v) ? Math.max(0, Math.min(1, v)) : 1;
|
|
92
|
+
this._patchFace(this._selected, { alpha });
|
|
93
|
+
}
|
|
94
|
+
_onRotationChange(e) {
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
const target = e.target;
|
|
97
|
+
const n = parseInt(target.value, 10);
|
|
98
|
+
const rotation = n === 90 || n === 180 || n === 270 ? n : 0;
|
|
99
|
+
this._patchFace(this._selected, { rotation });
|
|
100
|
+
}
|
|
101
|
+
_onMirrorChange(e) {
|
|
102
|
+
e.stopPropagation();
|
|
103
|
+
const target = e.target;
|
|
104
|
+
this._patchFace(this._selected, { mirror: target.checked });
|
|
105
|
+
}
|
|
106
|
+
_copyToOpposite() {
|
|
107
|
+
const src = this._face(this._selected);
|
|
108
|
+
const opposite = OPPOSITE[this._selected];
|
|
109
|
+
const next = { ...(this.value || {}) };
|
|
110
|
+
next[opposite] = { ...src };
|
|
111
|
+
this._commit(next);
|
|
112
|
+
}
|
|
113
|
+
_copyToAllWalls() {
|
|
114
|
+
const src = this._face(this._selected);
|
|
115
|
+
const next = { ...(this.value || {}) };
|
|
116
|
+
for (const w of ['east', 'west', 'north', 'south']) {
|
|
117
|
+
next[w] = { ...src };
|
|
118
|
+
}
|
|
119
|
+
this._commit(next);
|
|
120
|
+
}
|
|
121
|
+
_renderLabel(name, x, y) {
|
|
122
|
+
const f = this._face(name);
|
|
123
|
+
const swatch = this._swatchColor(name);
|
|
124
|
+
const selected = this._selected === name;
|
|
125
|
+
return html `
|
|
126
|
+
<div
|
|
127
|
+
class="face-label ${selected ? 'selected' : ''}"
|
|
128
|
+
style="left: ${x}px; top: ${y}px;"
|
|
129
|
+
@click=${() => this._select(name)}
|
|
130
|
+
title=${`${name} (${AXIS_LABEL[name]})`}
|
|
131
|
+
>
|
|
132
|
+
<span
|
|
133
|
+
class="swatch"
|
|
134
|
+
style=${swatch ? `background: ${swatch};` : ''}
|
|
135
|
+
?data-empty=${!swatch}
|
|
136
|
+
></span>
|
|
137
|
+
<ox-i18n msgid="label.${name}">${name}</ox-i18n>
|
|
138
|
+
${f.visible === false ? html `<span class="eye" title="hidden">⊘</span>` : nothing}
|
|
139
|
+
</div>
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
_faceClass(name) {
|
|
143
|
+
const cls = ['face-poly'];
|
|
144
|
+
if (this._selected === name)
|
|
145
|
+
cls.push('selected');
|
|
146
|
+
if (this._face(name).visible === false)
|
|
147
|
+
cls.push('hidden-face');
|
|
148
|
+
return cls.join(' ');
|
|
149
|
+
}
|
|
150
|
+
_ghostClass(name) {
|
|
151
|
+
const cls = ['face-ghost'];
|
|
152
|
+
if (this._selected === name)
|
|
153
|
+
cls.push('selected');
|
|
154
|
+
if (this._face(name).visible === false)
|
|
155
|
+
cls.push('invisible');
|
|
156
|
+
return cls.join(' ');
|
|
157
|
+
}
|
|
158
|
+
render() {
|
|
159
|
+
var _a, _b, _c, _d, _e, _f;
|
|
160
|
+
const sel = this._face(this._selected);
|
|
161
|
+
return html `
|
|
162
|
+
<div class="cube-picker">
|
|
163
|
+
<svg viewBox="0 0 288 160" aria-label="Backdrop face picker">
|
|
164
|
+
<polygon
|
|
165
|
+
class=${this._faceClass('ceiling')}
|
|
166
|
+
points="90,69 170,69 198,41 118,41"
|
|
167
|
+
fill="${(_a = this._swatchColor('ceiling')) !== null && _a !== void 0 ? _a : '#fff8e1'}"
|
|
168
|
+
@click=${() => this._select('ceiling')}
|
|
169
|
+
/>
|
|
170
|
+
<polygon
|
|
171
|
+
class=${this._faceClass('east')}
|
|
172
|
+
points="170,125 198,97 198,41 170,69"
|
|
173
|
+
fill="${(_b = this._swatchColor('east')) !== null && _b !== void 0 ? _b : '#ffcdd2'}"
|
|
174
|
+
@click=${() => this._select('east')}
|
|
175
|
+
/>
|
|
176
|
+
<polygon
|
|
177
|
+
class=${this._faceClass('south')}
|
|
178
|
+
points="90,125 170,125 170,69 90,69"
|
|
179
|
+
fill="${(_c = this._swatchColor('south')) !== null && _c !== void 0 ? _c : '#c8e6c9'}"
|
|
180
|
+
@click=${() => this._select('south')}
|
|
181
|
+
/>
|
|
182
|
+
|
|
183
|
+
<polygon
|
|
184
|
+
class=${this._ghostClass('north')}
|
|
185
|
+
points="118,97 198,97 198,41 118,41"
|
|
186
|
+
@click=${() => this._select('north')}
|
|
187
|
+
/>
|
|
188
|
+
<polygon
|
|
189
|
+
class=${this._ghostClass('west')}
|
|
190
|
+
points="118,97 90,125 90,69 118,41"
|
|
191
|
+
@click=${() => this._select('west')}
|
|
192
|
+
/>
|
|
193
|
+
<polygon
|
|
194
|
+
class=${this._ghostClass('floor')}
|
|
195
|
+
points="118,97 198,97 170,125 90,125"
|
|
196
|
+
@click=${() => this._select('floor')}
|
|
197
|
+
/>
|
|
198
|
+
</svg>
|
|
199
|
+
|
|
200
|
+
${this._renderLabel('ceiling', 144, 20)} ${this._renderLabel('floor', 144, 146)}
|
|
201
|
+
${this._renderLabel('east', 220, 83)} ${this._renderLabel('west', 38, 83)}
|
|
202
|
+
${this._renderLabel('north', 220, 51)} ${this._renderLabel('south', 38, 115)}
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<div class="face-detail">
|
|
206
|
+
<div class="face-detail-title">
|
|
207
|
+
<span><ox-i18n msgid="label.${this._selected}">${this._selected}</ox-i18n></span>
|
|
208
|
+
<small>${AXIS_LABEL[this._selected]}</small>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<div class="row">
|
|
212
|
+
<label><ox-i18n msgid="label.visible">visible</ox-i18n></label>
|
|
213
|
+
<div class="ctl">
|
|
214
|
+
<input type="checkbox" ?checked=${sel.visible !== false} @change=${this._onVisibleChange} />
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class="fill-row">
|
|
219
|
+
<restful-input-fill-style .value=${sel.fillStyle} @change=${this._onFillStyleChange}>
|
|
220
|
+
</restful-input-fill-style>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div class="row">
|
|
224
|
+
<label><ox-i18n msgid="label.alpha">alpha</ox-i18n></label>
|
|
225
|
+
<div class="ctl">
|
|
226
|
+
<input
|
|
227
|
+
type="range"
|
|
228
|
+
min="0"
|
|
229
|
+
max="1"
|
|
230
|
+
step="0.05"
|
|
231
|
+
.value=${String((_d = sel.alpha) !== null && _d !== void 0 ? _d : 1)}
|
|
232
|
+
@input=${this._onAlphaChange}
|
|
233
|
+
/>
|
|
234
|
+
<span class="alpha-readout">${((_e = sel.alpha) !== null && _e !== void 0 ? _e : 1).toFixed(2)}</span>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<div class="row">
|
|
239
|
+
<label><ox-i18n msgid="label.rotation">rotation</ox-i18n></label>
|
|
240
|
+
<div class="ctl">
|
|
241
|
+
<select .value=${String((_f = sel.rotation) !== null && _f !== void 0 ? _f : 0)} @change=${this._onRotationChange}>
|
|
242
|
+
<option value="0">0°</option>
|
|
243
|
+
<option value="90">90°</option>
|
|
244
|
+
<option value="180">180°</option>
|
|
245
|
+
<option value="270">270°</option>
|
|
246
|
+
</select>
|
|
247
|
+
<label class="mirror-toggle">
|
|
248
|
+
<input type="checkbox" ?checked=${sel.mirror === true} @change=${this._onMirrorChange} />
|
|
249
|
+
<ox-i18n msgid="label.mirror">mirror</ox-i18n>
|
|
250
|
+
</label>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<div class="actions">
|
|
255
|
+
<button @click=${this._copyToOpposite} title="Copy current face to opposite">
|
|
256
|
+
↔ <ox-i18n msgid="label.copy-to-opposite">opposite</ox-i18n>
|
|
257
|
+
</button>
|
|
258
|
+
<button @click=${this._copyToAllWalls} title="Copy current face to all 4 walls">
|
|
259
|
+
<ox-i18n msgid="label.copy-to-walls">all walls</ox-i18n>
|
|
260
|
+
</button>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
`;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
RestfulInputBackdropFaces.styles = css `
|
|
267
|
+
:host {
|
|
268
|
+
display: block;
|
|
269
|
+
font: 12px Arial, sans-serif;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.cube-picker {
|
|
273
|
+
position: relative;
|
|
274
|
+
width: 100%;
|
|
275
|
+
max-width: 260px;
|
|
276
|
+
height: 160px;
|
|
277
|
+
margin: 0 auto 8px;
|
|
278
|
+
}
|
|
279
|
+
.cube-picker svg {
|
|
280
|
+
display: block;
|
|
281
|
+
width: 100%;
|
|
282
|
+
height: 100%;
|
|
283
|
+
overflow: visible;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.face-poly {
|
|
287
|
+
cursor: pointer;
|
|
288
|
+
stroke: #3a3f4a;
|
|
289
|
+
stroke-width: 1;
|
|
290
|
+
stroke-linejoin: round;
|
|
291
|
+
transition:
|
|
292
|
+
filter 0.15s,
|
|
293
|
+
stroke 0.15s,
|
|
294
|
+
stroke-width 0.15s;
|
|
295
|
+
}
|
|
296
|
+
.face-poly:hover {
|
|
297
|
+
filter: brightness(1.15);
|
|
298
|
+
}
|
|
299
|
+
.face-poly.selected {
|
|
300
|
+
stroke: var(--md-sys-color-primary, #e15c5c);
|
|
301
|
+
stroke-width: 2.5;
|
|
302
|
+
}
|
|
303
|
+
.face-poly.hidden-face {
|
|
304
|
+
stroke-dasharray: 3 2;
|
|
305
|
+
opacity: 0.4;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.face-ghost {
|
|
309
|
+
cursor: pointer;
|
|
310
|
+
fill: none;
|
|
311
|
+
stroke: #8a93a6;
|
|
312
|
+
stroke-width: 1;
|
|
313
|
+
stroke-dasharray: 3 3;
|
|
314
|
+
stroke-linejoin: round;
|
|
315
|
+
opacity: 0.4;
|
|
316
|
+
pointer-events: stroke;
|
|
317
|
+
transition:
|
|
318
|
+
stroke 0.15s,
|
|
319
|
+
stroke-width 0.15s,
|
|
320
|
+
opacity 0.15s;
|
|
321
|
+
}
|
|
322
|
+
.face-ghost:hover {
|
|
323
|
+
opacity: 0.85;
|
|
324
|
+
stroke: var(--md-sys-color-primary, #e15c5c);
|
|
325
|
+
}
|
|
326
|
+
.face-ghost.selected {
|
|
327
|
+
stroke: var(--md-sys-color-primary, #e15c5c);
|
|
328
|
+
stroke-width: 2;
|
|
329
|
+
opacity: 1;
|
|
330
|
+
}
|
|
331
|
+
.face-ghost.invisible {
|
|
332
|
+
opacity: 0.2;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.face-label {
|
|
336
|
+
position: absolute;
|
|
337
|
+
display: inline-flex;
|
|
338
|
+
align-items: center;
|
|
339
|
+
gap: 4px;
|
|
340
|
+
padding: 2px 6px 2px 4px;
|
|
341
|
+
font: 600 10px Arial, sans-serif;
|
|
342
|
+
background: var(--md-sys-color-surface, #fff);
|
|
343
|
+
border: 1px solid var(--md-sys-color-outline-variant, #d8dde6);
|
|
344
|
+
border-radius: 10px;
|
|
345
|
+
cursor: pointer;
|
|
346
|
+
user-select: none;
|
|
347
|
+
transform: translate(-50%, -50%);
|
|
348
|
+
white-space: nowrap;
|
|
349
|
+
transition:
|
|
350
|
+
border-color 0.15s,
|
|
351
|
+
background 0.15s,
|
|
352
|
+
color 0.15s;
|
|
353
|
+
text-transform: capitalize;
|
|
354
|
+
}
|
|
355
|
+
.face-label:hover {
|
|
356
|
+
border-color: var(--md-sys-color-primary, #e15c5c);
|
|
357
|
+
}
|
|
358
|
+
.face-label.selected {
|
|
359
|
+
border-color: var(--md-sys-color-primary, #e15c5c);
|
|
360
|
+
background: var(--md-sys-color-primary-container, #fde7e7);
|
|
361
|
+
color: var(--md-sys-color-on-primary-container, #b91c1c);
|
|
362
|
+
}
|
|
363
|
+
.face-label .swatch {
|
|
364
|
+
width: 12px;
|
|
365
|
+
height: 12px;
|
|
366
|
+
border-radius: 2px;
|
|
367
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
368
|
+
flex: none;
|
|
369
|
+
}
|
|
370
|
+
.face-label .swatch[data-empty] {
|
|
371
|
+
background: repeating-linear-gradient(45deg, #fff, #fff 2px, #ccc 2px, #ccc 4px);
|
|
372
|
+
}
|
|
373
|
+
.face-label .eye {
|
|
374
|
+
font-size: 9px;
|
|
375
|
+
opacity: 0.55;
|
|
376
|
+
margin-left: 1px;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.face-detail {
|
|
380
|
+
border-top: 1px dashed var(--md-sys-color-outline-variant, #d8dde6);
|
|
381
|
+
padding-top: 10px;
|
|
382
|
+
margin-top: 4px;
|
|
383
|
+
}
|
|
384
|
+
.face-detail-title {
|
|
385
|
+
display: flex;
|
|
386
|
+
justify-content: space-between;
|
|
387
|
+
align-items: baseline;
|
|
388
|
+
font-weight: 600;
|
|
389
|
+
font-size: 11px;
|
|
390
|
+
color: var(--md-sys-color-primary, #e15c5c);
|
|
391
|
+
text-transform: uppercase;
|
|
392
|
+
letter-spacing: 0.5px;
|
|
393
|
+
margin-bottom: 8px;
|
|
394
|
+
}
|
|
395
|
+
.face-detail-title small {
|
|
396
|
+
font-weight: 400;
|
|
397
|
+
text-transform: none;
|
|
398
|
+
letter-spacing: 0;
|
|
399
|
+
color: var(--md-sys-color-on-secondary-container, #8a93a6);
|
|
400
|
+
font: 10px monospace;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.row {
|
|
404
|
+
display: grid;
|
|
405
|
+
grid-template-columns: 60px 1fr;
|
|
406
|
+
gap: 8px;
|
|
407
|
+
align-items: center;
|
|
408
|
+
margin-bottom: 6px;
|
|
409
|
+
}
|
|
410
|
+
.row > label {
|
|
411
|
+
text-align: right;
|
|
412
|
+
font-size: 11px;
|
|
413
|
+
color: var(--md-sys-color-on-secondary-container, #6b7280);
|
|
414
|
+
}
|
|
415
|
+
.row .ctl {
|
|
416
|
+
display: flex;
|
|
417
|
+
align-items: center;
|
|
418
|
+
gap: 6px;
|
|
419
|
+
}
|
|
420
|
+
.ctl input[type='range'] {
|
|
421
|
+
flex: 1;
|
|
422
|
+
accent-color: var(--md-sys-color-primary, #e15c5c);
|
|
423
|
+
}
|
|
424
|
+
.ctl input[type='checkbox'] {
|
|
425
|
+
accent-color: var(--md-sys-color-primary, #e15c5c);
|
|
426
|
+
}
|
|
427
|
+
.alpha-readout {
|
|
428
|
+
width: 30px;
|
|
429
|
+
text-align: right;
|
|
430
|
+
font: 11px monospace;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.row select,
|
|
434
|
+
.row .mirror-toggle {
|
|
435
|
+
font: 10px Arial, sans-serif;
|
|
436
|
+
padding: 5px 6px;
|
|
437
|
+
border: 1px solid var(--md-sys-color-outline-variant, #d8dde6);
|
|
438
|
+
border-radius: 4px;
|
|
439
|
+
background: var(--md-sys-color-surface, #fff);
|
|
440
|
+
color: inherit;
|
|
441
|
+
cursor: pointer;
|
|
442
|
+
}
|
|
443
|
+
.row select {
|
|
444
|
+
flex: 1;
|
|
445
|
+
outline: none;
|
|
446
|
+
}
|
|
447
|
+
.row select:hover,
|
|
448
|
+
.row .mirror-toggle:hover {
|
|
449
|
+
border-color: var(--md-sys-color-primary, #e15c5c);
|
|
450
|
+
color: var(--md-sys-color-primary, #e15c5c);
|
|
451
|
+
}
|
|
452
|
+
.row .mirror-toggle {
|
|
453
|
+
display: inline-flex;
|
|
454
|
+
align-items: center;
|
|
455
|
+
gap: 4px;
|
|
456
|
+
}
|
|
457
|
+
.row .mirror-toggle input[type='checkbox'] {
|
|
458
|
+
margin: 0;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.fill-row {
|
|
462
|
+
margin-bottom: 6px;
|
|
463
|
+
}
|
|
464
|
+
restful-input-fill-style {
|
|
465
|
+
font: 12px Arial, sans-serif;
|
|
466
|
+
display: block;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.actions {
|
|
470
|
+
margin-top: 8px;
|
|
471
|
+
display: flex;
|
|
472
|
+
gap: 6px;
|
|
473
|
+
}
|
|
474
|
+
.actions button {
|
|
475
|
+
flex: 1;
|
|
476
|
+
font: 10px Arial, sans-serif;
|
|
477
|
+
padding: 5px 6px;
|
|
478
|
+
border: 1px solid var(--md-sys-color-outline-variant, #d8dde6);
|
|
479
|
+
border-radius: 4px;
|
|
480
|
+
background: var(--md-sys-color-surface, #fff);
|
|
481
|
+
color: inherit;
|
|
482
|
+
cursor: pointer;
|
|
483
|
+
}
|
|
484
|
+
.actions button:hover {
|
|
485
|
+
border-color: var(--md-sys-color-primary, #e15c5c);
|
|
486
|
+
color: var(--md-sys-color-primary, #e15c5c);
|
|
487
|
+
}
|
|
488
|
+
`;
|
|
489
|
+
__decorate([
|
|
490
|
+
property({ type: Object })
|
|
491
|
+
], RestfulInputBackdropFaces.prototype, "value", void 0);
|
|
492
|
+
__decorate([
|
|
493
|
+
state()
|
|
494
|
+
], RestfulInputBackdropFaces.prototype, "_selected", void 0);
|
|
495
|
+
RestfulInputBackdropFaces = __decorate([
|
|
496
|
+
customElement('restful-input-backdrop-faces')
|
|
497
|
+
], RestfulInputBackdropFaces);
|
|
498
|
+
export { RestfulInputBackdropFaces };
|
|
499
|
+
let RestfulPropertyEditorBackdropFaces = class RestfulPropertyEditorBackdropFaces extends OxPropertyEditor {
|
|
500
|
+
editorTemplate(value, spec) {
|
|
501
|
+
const { fullwidth = true } = spec.editor || {};
|
|
502
|
+
return html `
|
|
503
|
+
<restful-input-backdrop-faces
|
|
504
|
+
id="editor"
|
|
505
|
+
.value=${value}
|
|
506
|
+
?fullwidth=${fullwidth}
|
|
507
|
+
?disabled=${this.disabled}
|
|
508
|
+
></restful-input-backdrop-faces>
|
|
509
|
+
`;
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
RestfulPropertyEditorBackdropFaces.styles = [
|
|
513
|
+
...OxPropertyEditor.styles,
|
|
514
|
+
css `
|
|
515
|
+
restful-input-backdrop-faces#editor {
|
|
516
|
+
font: 12px Arial, sans-serif;
|
|
517
|
+
}
|
|
518
|
+
`
|
|
519
|
+
];
|
|
520
|
+
RestfulPropertyEditorBackdropFaces = __decorate([
|
|
521
|
+
customElement('restful-property-editor-backdrop-faces')
|
|
522
|
+
], RestfulPropertyEditorBackdropFaces);
|
|
523
|
+
export { RestfulPropertyEditorBackdropFaces };
|
|
524
|
+
//# sourceMappingURL=restful-property-editor-backdrop-faces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restful-property-editor-backdrop-faces.js","sourceRoot":"","sources":["../../../src/component/restful-property-editor-backdrop-faces.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n *\n * fmsim-restful 환경에서는 GraphQL/attachment 의존이 있는 ox-input-fill-style 대신\n * restful-input-fill-style 을 사용해야 한다. ox-property-editor-backdrop-faces 와\n * 동일한 cube-picker UI 를 유지하되 fillStyle 에디터만 restful 버전으로 교체.\n *\n * 양쪽 동기화 시 주의: ox-property-editor-backdrop-faces.ts (operato/property-editor)\n * 변경 시 이 파일도 함께 업데이트.\n */\n\nimport './restful-input-fill-style.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html, LitElement, nothing, type TemplateResult } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { OxPropertyEditor } from '@operato/property-editor'\nimport type { PropertySpec } from '@operato/property-editor'\n\ntype FaceName = 'east' | 'west' | 'north' | 'south' | 'ceiling' | 'floor'\nconst OPPOSITE: Record<FaceName, FaceName> = {\n east: 'west',\n west: 'east',\n north: 'south',\n south: 'north',\n ceiling: 'floor',\n floor: 'ceiling'\n}\nconst AXIS_LABEL: Record<FaceName, string> = {\n east: '+X',\n west: '−X',\n north: '−Z',\n south: '+Z',\n ceiling: '+Y',\n floor: '−Y'\n}\n\ninterface FaceState {\n fillStyle?: any\n visible?: boolean\n alpha?: number\n rotation?: 0 | 90 | 180 | 270\n mirror?: boolean\n}\ntype FacesValue = Partial<Record<FaceName, FaceState>>\n\nconst DEFAULT_FACES: Record<FaceName, FaceState> = {\n east: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },\n west: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },\n north: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },\n south: { fillStyle: '#dde2e8', visible: true, alpha: 0.35, rotation: 0, mirror: false },\n ceiling: { fillStyle: '#e8e8ec', visible: true, alpha: 1.0, rotation: 0, mirror: false },\n floor: { fillStyle: '#9c9c9c', visible: true, alpha: 1.0, rotation: 0, mirror: false }\n}\n\n@customElement('restful-input-backdrop-faces')\nexport class RestfulInputBackdropFaces extends LitElement {\n @property({ type: Object }) value: FacesValue = {}\n @state() private _selected: FaceName = 'ceiling'\n\n static styles = css`\n :host {\n display: block;\n font: 12px Arial, sans-serif;\n }\n\n .cube-picker {\n position: relative;\n width: 100%;\n max-width: 260px;\n height: 160px;\n margin: 0 auto 8px;\n }\n .cube-picker svg {\n display: block;\n width: 100%;\n height: 100%;\n overflow: visible;\n }\n\n .face-poly {\n cursor: pointer;\n stroke: #3a3f4a;\n stroke-width: 1;\n stroke-linejoin: round;\n transition:\n filter 0.15s,\n stroke 0.15s,\n stroke-width 0.15s;\n }\n .face-poly:hover {\n filter: brightness(1.15);\n }\n .face-poly.selected {\n stroke: var(--md-sys-color-primary, #e15c5c);\n stroke-width: 2.5;\n }\n .face-poly.hidden-face {\n stroke-dasharray: 3 2;\n opacity: 0.4;\n }\n\n .face-ghost {\n cursor: pointer;\n fill: none;\n stroke: #8a93a6;\n stroke-width: 1;\n stroke-dasharray: 3 3;\n stroke-linejoin: round;\n opacity: 0.4;\n pointer-events: stroke;\n transition:\n stroke 0.15s,\n stroke-width 0.15s,\n opacity 0.15s;\n }\n .face-ghost:hover {\n opacity: 0.85;\n stroke: var(--md-sys-color-primary, #e15c5c);\n }\n .face-ghost.selected {\n stroke: var(--md-sys-color-primary, #e15c5c);\n stroke-width: 2;\n opacity: 1;\n }\n .face-ghost.invisible {\n opacity: 0.2;\n }\n\n .face-label {\n position: absolute;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px 2px 4px;\n font: 600 10px Arial, sans-serif;\n background: var(--md-sys-color-surface, #fff);\n border: 1px solid var(--md-sys-color-outline-variant, #d8dde6);\n border-radius: 10px;\n cursor: pointer;\n user-select: none;\n transform: translate(-50%, -50%);\n white-space: nowrap;\n transition:\n border-color 0.15s,\n background 0.15s,\n color 0.15s;\n text-transform: capitalize;\n }\n .face-label:hover {\n border-color: var(--md-sys-color-primary, #e15c5c);\n }\n .face-label.selected {\n border-color: var(--md-sys-color-primary, #e15c5c);\n background: var(--md-sys-color-primary-container, #fde7e7);\n color: var(--md-sys-color-on-primary-container, #b91c1c);\n }\n .face-label .swatch {\n width: 12px;\n height: 12px;\n border-radius: 2px;\n border: 1px solid rgba(0, 0, 0, 0.15);\n flex: none;\n }\n .face-label .swatch[data-empty] {\n background: repeating-linear-gradient(45deg, #fff, #fff 2px, #ccc 2px, #ccc 4px);\n }\n .face-label .eye {\n font-size: 9px;\n opacity: 0.55;\n margin-left: 1px;\n }\n\n .face-detail {\n border-top: 1px dashed var(--md-sys-color-outline-variant, #d8dde6);\n padding-top: 10px;\n margin-top: 4px;\n }\n .face-detail-title {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n font-weight: 600;\n font-size: 11px;\n color: var(--md-sys-color-primary, #e15c5c);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n }\n .face-detail-title small {\n font-weight: 400;\n text-transform: none;\n letter-spacing: 0;\n color: var(--md-sys-color-on-secondary-container, #8a93a6);\n font: 10px monospace;\n }\n\n .row {\n display: grid;\n grid-template-columns: 60px 1fr;\n gap: 8px;\n align-items: center;\n margin-bottom: 6px;\n }\n .row > label {\n text-align: right;\n font-size: 11px;\n color: var(--md-sys-color-on-secondary-container, #6b7280);\n }\n .row .ctl {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .ctl input[type='range'] {\n flex: 1;\n accent-color: var(--md-sys-color-primary, #e15c5c);\n }\n .ctl input[type='checkbox'] {\n accent-color: var(--md-sys-color-primary, #e15c5c);\n }\n .alpha-readout {\n width: 30px;\n text-align: right;\n font: 11px monospace;\n }\n\n .row select,\n .row .mirror-toggle {\n font: 10px Arial, sans-serif;\n padding: 5px 6px;\n border: 1px solid var(--md-sys-color-outline-variant, #d8dde6);\n border-radius: 4px;\n background: var(--md-sys-color-surface, #fff);\n color: inherit;\n cursor: pointer;\n }\n .row select {\n flex: 1;\n outline: none;\n }\n .row select:hover,\n .row .mirror-toggle:hover {\n border-color: var(--md-sys-color-primary, #e15c5c);\n color: var(--md-sys-color-primary, #e15c5c);\n }\n .row .mirror-toggle {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n }\n .row .mirror-toggle input[type='checkbox'] {\n margin: 0;\n }\n\n .fill-row {\n margin-bottom: 6px;\n }\n restful-input-fill-style {\n font: 12px Arial, sans-serif;\n display: block;\n }\n\n .actions {\n margin-top: 8px;\n display: flex;\n gap: 6px;\n }\n .actions button {\n flex: 1;\n font: 10px Arial, sans-serif;\n padding: 5px 6px;\n border: 1px solid var(--md-sys-color-outline-variant, #d8dde6);\n border-radius: 4px;\n background: var(--md-sys-color-surface, #fff);\n color: inherit;\n cursor: pointer;\n }\n .actions button:hover {\n border-color: var(--md-sys-color-primary, #e15c5c);\n color: var(--md-sys-color-primary, #e15c5c);\n }\n `\n\n private _face(name: FaceName): FaceState {\n return { ...DEFAULT_FACES[name], ...(this.value?.[name] ?? {}) }\n }\n\n private _swatchColor(name: FaceName): string | undefined {\n const fs = this._face(name).fillStyle\n if (typeof fs === 'string' && fs && fs !== 'transparent') return fs\n if (fs && typeof fs === 'object') {\n if (fs.type === 'gradient' && Array.isArray(fs.colorStops) && fs.colorStops[0]?.color) {\n return fs.colorStops[0].color\n }\n if (fs.color) return fs.color\n }\n return undefined\n }\n\n private _select(name: FaceName) {\n this._selected = name\n }\n\n private _commit(next: FacesValue) {\n this.value = next\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n }\n\n private _patchFace(name: FaceName, patch: Partial<FaceState>) {\n const next: FacesValue = { ...(this.value || {}) }\n next[name] = { ...this._face(name), ...patch }\n this._commit(next)\n }\n\n private _onFillStyleChange(e: Event) {\n e.stopPropagation()\n const target = e.target as { value?: any }\n this._patchFace(this._selected, { fillStyle: target.value })\n }\n\n private _onVisibleChange(e: Event) {\n e.stopPropagation()\n const target = e.target as HTMLInputElement\n this._patchFace(this._selected, { visible: target.checked })\n }\n\n private _onAlphaChange(e: Event) {\n e.stopPropagation()\n const target = e.target as HTMLInputElement\n const v = parseFloat(target.value)\n const alpha = Number.isFinite(v) ? Math.max(0, Math.min(1, v)) : 1\n this._patchFace(this._selected, { alpha })\n }\n\n private _onRotationChange(e: Event) {\n e.stopPropagation()\n const target = e.target as HTMLSelectElement\n const n = parseInt(target.value, 10)\n const rotation: 0 | 90 | 180 | 270 = n === 90 || n === 180 || n === 270 ? n : 0\n this._patchFace(this._selected, { rotation })\n }\n\n private _onMirrorChange(e: Event) {\n e.stopPropagation()\n const target = e.target as HTMLInputElement\n this._patchFace(this._selected, { mirror: target.checked })\n }\n\n private _copyToOpposite() {\n const src = this._face(this._selected)\n const opposite = OPPOSITE[this._selected]\n const next: FacesValue = { ...(this.value || {}) }\n next[opposite] = { ...src }\n this._commit(next)\n }\n\n private _copyToAllWalls() {\n const src = this._face(this._selected)\n const next: FacesValue = { ...(this.value || {}) }\n for (const w of ['east', 'west', 'north', 'south'] as const) {\n next[w] = { ...src }\n }\n this._commit(next)\n }\n\n private _renderLabel(name: FaceName, x: number, y: number) {\n const f = this._face(name)\n const swatch = this._swatchColor(name)\n const selected = this._selected === name\n return html`\n <div\n class=\"face-label ${selected ? 'selected' : ''}\"\n style=\"left: ${x}px; top: ${y}px;\"\n @click=${() => this._select(name)}\n title=${`${name} (${AXIS_LABEL[name]})`}\n >\n <span\n class=\"swatch\"\n style=${swatch ? `background: ${swatch};` : ''}\n ?data-empty=${!swatch}\n ></span>\n <ox-i18n msgid=\"label.${name}\">${name}</ox-i18n>\n ${f.visible === false ? html`<span class=\"eye\" title=\"hidden\">⊘</span>` : nothing}\n </div>\n `\n }\n\n private _faceClass(name: FaceName): string {\n const cls = ['face-poly']\n if (this._selected === name) cls.push('selected')\n if (this._face(name).visible === false) cls.push('hidden-face')\n return cls.join(' ')\n }\n\n private _ghostClass(name: FaceName): string {\n const cls = ['face-ghost']\n if (this._selected === name) cls.push('selected')\n if (this._face(name).visible === false) cls.push('invisible')\n return cls.join(' ')\n }\n\n override render() {\n const sel = this._face(this._selected)\n return html`\n <div class=\"cube-picker\">\n <svg viewBox=\"0 0 288 160\" aria-label=\"Backdrop face picker\">\n <polygon\n class=${this._faceClass('ceiling')}\n points=\"90,69 170,69 198,41 118,41\"\n fill=\"${this._swatchColor('ceiling') ?? '#fff8e1'}\"\n @click=${() => this._select('ceiling')}\n />\n <polygon\n class=${this._faceClass('east')}\n points=\"170,125 198,97 198,41 170,69\"\n fill=\"${this._swatchColor('east') ?? '#ffcdd2'}\"\n @click=${() => this._select('east')}\n />\n <polygon\n class=${this._faceClass('south')}\n points=\"90,125 170,125 170,69 90,69\"\n fill=\"${this._swatchColor('south') ?? '#c8e6c9'}\"\n @click=${() => this._select('south')}\n />\n\n <polygon\n class=${this._ghostClass('north')}\n points=\"118,97 198,97 198,41 118,41\"\n @click=${() => this._select('north')}\n />\n <polygon\n class=${this._ghostClass('west')}\n points=\"118,97 90,125 90,69 118,41\"\n @click=${() => this._select('west')}\n />\n <polygon\n class=${this._ghostClass('floor')}\n points=\"118,97 198,97 170,125 90,125\"\n @click=${() => this._select('floor')}\n />\n </svg>\n\n ${this._renderLabel('ceiling', 144, 20)} ${this._renderLabel('floor', 144, 146)}\n ${this._renderLabel('east', 220, 83)} ${this._renderLabel('west', 38, 83)}\n ${this._renderLabel('north', 220, 51)} ${this._renderLabel('south', 38, 115)}\n </div>\n\n <div class=\"face-detail\">\n <div class=\"face-detail-title\">\n <span><ox-i18n msgid=\"label.${this._selected}\">${this._selected}</ox-i18n></span>\n <small>${AXIS_LABEL[this._selected]}</small>\n </div>\n\n <div class=\"row\">\n <label><ox-i18n msgid=\"label.visible\">visible</ox-i18n></label>\n <div class=\"ctl\">\n <input type=\"checkbox\" ?checked=${sel.visible !== false} @change=${this._onVisibleChange} />\n </div>\n </div>\n\n <div class=\"fill-row\">\n <restful-input-fill-style .value=${sel.fillStyle} @change=${this._onFillStyleChange}>\n </restful-input-fill-style>\n </div>\n\n <div class=\"row\">\n <label><ox-i18n msgid=\"label.alpha\">alpha</ox-i18n></label>\n <div class=\"ctl\">\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n .value=${String(sel.alpha ?? 1)}\n @input=${this._onAlphaChange}\n />\n <span class=\"alpha-readout\">${(sel.alpha ?? 1).toFixed(2)}</span>\n </div>\n </div>\n\n <div class=\"row\">\n <label><ox-i18n msgid=\"label.rotation\">rotation</ox-i18n></label>\n <div class=\"ctl\">\n <select .value=${String(sel.rotation ?? 0)} @change=${this._onRotationChange}>\n <option value=\"0\">0°</option>\n <option value=\"90\">90°</option>\n <option value=\"180\">180°</option>\n <option value=\"270\">270°</option>\n </select>\n <label class=\"mirror-toggle\">\n <input type=\"checkbox\" ?checked=${sel.mirror === true} @change=${this._onMirrorChange} />\n <ox-i18n msgid=\"label.mirror\">mirror</ox-i18n>\n </label>\n </div>\n </div>\n\n <div class=\"actions\">\n <button @click=${this._copyToOpposite} title=\"Copy current face to opposite\">\n ↔ <ox-i18n msgid=\"label.copy-to-opposite\">opposite</ox-i18n>\n </button>\n <button @click=${this._copyToAllWalls} title=\"Copy current face to all 4 walls\">\n <ox-i18n msgid=\"label.copy-to-walls\">all walls</ox-i18n>\n </button>\n </div>\n </div>\n `\n }\n}\n\n@customElement('restful-property-editor-backdrop-faces')\nexport class RestfulPropertyEditorBackdropFaces extends OxPropertyEditor {\n static styles = [\n ...OxPropertyEditor.styles,\n css`\n restful-input-backdrop-faces#editor {\n font: 12px Arial, sans-serif;\n }\n `\n ]\n\n override editorTemplate(value: any, spec: PropertySpec): TemplateResult {\n const { fullwidth = true } = spec.editor || {}\n return html`\n <restful-input-backdrop-faces\n id=\"editor\"\n .value=${value}\n ?fullwidth=${fullwidth}\n ?disabled=${this.disabled}\n ></restful-input-backdrop-faces>\n `\n }\n}\n"]}
|