mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-28 08:58:07 +00:00
Add Scalar input field
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
export * from "./text-field.element";
|
export * from "./text-field.element";
|
||||||
|
export * from "./scalar-field.element";
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
@use "sass:math";
|
||||||
|
|
||||||
|
:host {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
|
||||||
|
background: #0004;
|
||||||
|
border: 1px solid #FFF2;
|
||||||
|
color: #FFFC;
|
||||||
|
outline: none !important;
|
||||||
|
transition: {
|
||||||
|
property: background-color, border-color, color;
|
||||||
|
duration: 33.333ms;
|
||||||
|
timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
font: {
|
||||||
|
family: "Fira Sans", sans-serif;
|
||||||
|
size: math.div(15, 16) * 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(:focus-within) {
|
||||||
|
border-color: #FFF4;
|
||||||
|
background: #0006;
|
||||||
|
color: #FFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(:not(.editing)) {
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(:disabled) {
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
outline: none !important;
|
||||||
|
|
||||||
|
&:first-line {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
import { on } from "@storyteller/framework";
|
||||||
|
import { PropertyValues, html, unsafeCSS } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators.js";
|
||||||
|
import { createRef, ref } from "lit/directives/ref.js";
|
||||||
|
|
||||||
|
import { FormFieldBaseElement } from "./form-field-base.element";
|
||||||
|
|
||||||
|
import styles from "./scalar-field.element.scss?inline";
|
||||||
|
|
||||||
|
const VALID_INPUT_PATTERN = /[-+*\/.0-9 ]/;
|
||||||
|
|
||||||
|
// NOTE: This code was adapted from here:
|
||||||
|
// https://stackblitz.com/edit/angular-wfikuy?file=src%2Ffloat-input%2Ffloat-input.component.ts
|
||||||
|
@customElement("sts-scalar-field")
|
||||||
|
export class ScalarFieldElement extends FormFieldBaseElement {
|
||||||
|
static override styles = unsafeCSS(styles);
|
||||||
|
|
||||||
|
@property({ reflect: true })
|
||||||
|
override role = "slider";
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Number,
|
||||||
|
attribute: "aria-valuenow",
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Number,
|
||||||
|
attribute: "aria-valuemax",
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
max = Infinity;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Number,
|
||||||
|
attribute: "aria-valuemin",
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
min = -Infinity;
|
||||||
|
|
||||||
|
@property({ type: Number })
|
||||||
|
sensitivity = 0.01;
|
||||||
|
|
||||||
|
@property({
|
||||||
|
type: Number,
|
||||||
|
attribute: "tabindex",
|
||||||
|
reflect: true,
|
||||||
|
})
|
||||||
|
override tabIndex = 0;
|
||||||
|
|
||||||
|
@state() _editing = false;
|
||||||
|
|
||||||
|
#inputRef = createRef<HTMLSpanElement>();
|
||||||
|
#abortControllers = {
|
||||||
|
"pointermove": null as AbortController | null,
|
||||||
|
"pointerup": null as AbortController | null,
|
||||||
|
};
|
||||||
|
|
||||||
|
#fmtDecimal = new Intl.NumberFormat("en-US", {
|
||||||
|
style: "decimal",
|
||||||
|
minimumIntegerDigits: 1,
|
||||||
|
minimumFractionDigits: 1,
|
||||||
|
maximumFractionDigits: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
protected override update(changes: PropertyValues<this>): void {
|
||||||
|
if (changes.has("_editing"))
|
||||||
|
this.classList.toggle("editing", this._editing);
|
||||||
|
|
||||||
|
super.update(changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
override disconnectedCallback(): void {
|
||||||
|
this.#abortControllers.pointermove?.abort();
|
||||||
|
this.#abortControllers.pointerup?.abort();
|
||||||
|
super.disconnectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
@on("pointerdown")
|
||||||
|
onPointerDown(event: PointerEvent): void {
|
||||||
|
if (this._editing || event.button !== 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.requestPointerLock();
|
||||||
|
|
||||||
|
this.#abortControllers.pointermove?.abort();
|
||||||
|
this.#abortControllers.pointermove = new AbortController();
|
||||||
|
|
||||||
|
this.#abortControllers.pointerup?.abort();
|
||||||
|
this.#abortControllers.pointerup = new AbortController();
|
||||||
|
|
||||||
|
const pointerMoveAbortSignal = this.#abortControllers.pointermove.signal;
|
||||||
|
|
||||||
|
let totalMovement = 0;
|
||||||
|
|
||||||
|
this.addEventListener("pointermove", event => {
|
||||||
|
totalMovement += event.movementX;
|
||||||
|
this.#emitValue(this.value + event.movementX * this.sensitivity);
|
||||||
|
}, {
|
||||||
|
signal: pointerMoveAbortSignal,
|
||||||
|
});
|
||||||
|
|
||||||
|
pointerMoveAbortSignal.addEventListener("abort", () => {
|
||||||
|
document.exitPointerLock();
|
||||||
|
// If no actual dragging occurred between pointerdown and pointerup,
|
||||||
|
// treat this like a click
|
||||||
|
if (totalMovement === 0)
|
||||||
|
this.#activateDirectInput();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener("pointerup", () => {
|
||||||
|
this.#abortControllers.pointermove?.abort();
|
||||||
|
}, {
|
||||||
|
once: true,
|
||||||
|
signal: this.#abortControllers.pointerup.signal,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@on("focus")
|
||||||
|
onFocus(): void {
|
||||||
|
this.#activateDirectInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
onInputEnter(event: KeyboardEvent): void {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const input = this.#inputRef.value;
|
||||||
|
if (!input) return;
|
||||||
|
|
||||||
|
input.textContent = this.#fmtDecimal.format(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onInputChange(event: InputEvent): void {
|
||||||
|
try {
|
||||||
|
const input = this.#inputRef.value!;
|
||||||
|
const textContent = input.textContent?.trim() ?? "";
|
||||||
|
|
||||||
|
if (event.data && !VALID_INPUT_PATTERN.test(event.data)) {
|
||||||
|
input.textContent = this.value.toString(10);
|
||||||
|
} else {
|
||||||
|
const value = parseFloat(textContent);
|
||||||
|
this.#emitValue(value);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #activateDirectInput(): Promise<void> {
|
||||||
|
this._editing = true;
|
||||||
|
this.tabIndex = -1;
|
||||||
|
|
||||||
|
this.requestUpdate();
|
||||||
|
await this.updateComplete;
|
||||||
|
|
||||||
|
const input = this.#inputRef.value;
|
||||||
|
if (!input)
|
||||||
|
throw new Error("Expected input to be available in editing mode");
|
||||||
|
|
||||||
|
input.addEventListener("blur", () => {
|
||||||
|
this._editing = false;
|
||||||
|
this.tabIndex = 0;
|
||||||
|
}, {
|
||||||
|
once: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
input.textContent = this.#fmtDecimal.format(this.value);
|
||||||
|
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(input);
|
||||||
|
|
||||||
|
const sel = window.getSelection()!;
|
||||||
|
sel.removeAllRanges();
|
||||||
|
sel.addRange(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
#emitValue(value: number): void {
|
||||||
|
if (this.max != null)
|
||||||
|
value = Math.min(value, this.max);
|
||||||
|
|
||||||
|
if (this.min != null)
|
||||||
|
value = Math.max(value, this.min);
|
||||||
|
|
||||||
|
this.dispatchEvent(new CustomEvent("value-change", {
|
||||||
|
detail: value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override render = () => html`
|
||||||
|
${!this._editing ? html`
|
||||||
|
${this.#fmtDecimal.format(this.value)}
|
||||||
|
` : html`
|
||||||
|
<span ${ref(this.#inputRef)}
|
||||||
|
class="input"
|
||||||
|
part="input"
|
||||||
|
contenteditable
|
||||||
|
inputmode="numeric"
|
||||||
|
@input=${this.onInputChange}
|
||||||
|
@keydown=${(event: KeyboardEvent) => {
|
||||||
|
if (event.key === "Enter")
|
||||||
|
this.onInputEnter(event);
|
||||||
|
}}
|
||||||
|
></span>
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ import { v4 as uuid } from "uuid";
|
|||||||
|
|
||||||
import { StandardMaterial, type Rgba } from "./inspector.types";
|
import { StandardMaterial, type Rgba } from "./inspector.types";
|
||||||
|
|
||||||
|
import "@storyteller/studio-ui/forms/scalar-field";
|
||||||
|
|
||||||
import styles from "./material-inspector.element.scss?inline";
|
import styles from "./material-inspector.element.scss?inline";
|
||||||
|
|
||||||
@customElement("sts-material-inspector")
|
@customElement("sts-material-inspector")
|
||||||
@@ -47,15 +49,12 @@ export class MaterialInspectorElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateField(reflectPath: Exclude<keyof StandardMaterial, "base_color">) {
|
updateField(reflectPath: Exclude<keyof StandardMaterial, "base_color">) {
|
||||||
return ({ detail }: CustomEvent<string>) => {
|
return ({ detail: value }: CustomEvent<number>) => {
|
||||||
const value = parseFloat(detail);
|
studio.updateComponentField({
|
||||||
if (Number.isFinite(value) && !Number.isNaN(value)) {
|
component: "bevy_pbr::pbr_material::StandardMaterial",
|
||||||
studio.updateComponentField({
|
reflectPath,
|
||||||
component: "bevy_pbr::pbr_material::StandardMaterial",
|
value,
|
||||||
reflectPath,
|
});
|
||||||
value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,32 +81,32 @@ export class MaterialInspectorElement extends LitElement {
|
|||||||
<label for=${this.#roughnessId}>
|
<label for=${this.#roughnessId}>
|
||||||
Roughness
|
Roughness
|
||||||
</label>
|
</label>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
id=${this.#roughnessId}
|
id=${this.#roughnessId}
|
||||||
type="number"
|
.min=${0} .max=${1}
|
||||||
.value=${this.roughness.toString(10)}
|
.value=${this.roughness}
|
||||||
@value-change=${this.updateField("perceptual_roughness")}
|
@value-change=${this.updateField("perceptual_roughness")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
|
|
||||||
<label for=${this.#metallicId}>
|
<label for=${this.#metallicId}>
|
||||||
Metallic
|
Metallic
|
||||||
</label>
|
</label>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
id=${this.#metallicId}
|
id=${this.#metallicId}
|
||||||
type="number"
|
.min=${0} .max=${1}
|
||||||
.value=${this.metallic.toString(10)}
|
.value=${this.metallic}
|
||||||
@value-change=${this.updateField("metallic")}
|
@value-change=${this.updateField("metallic")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
|
|
||||||
<label for=${this.#reflectanceId}>
|
<label for=${this.#reflectanceId}>
|
||||||
Reflectance
|
Reflectance
|
||||||
</label>
|
</label>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
id=${this.#reflectanceId}
|
id=${this.#reflectanceId}
|
||||||
type="number"
|
.min=${0} .max=${1}
|
||||||
.value=${this.reflectance.toString(10)}
|
.value=${this.reflectance}
|
||||||
@value-change=${this.updateField("reflectance")}
|
@value-change=${this.updateField("reflectance")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,73 +18,25 @@ h4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fieldset {
|
.fieldset {
|
||||||
position: relative;
|
|
||||||
padding-block-start: math.div(14, 16) + 0.333rem !important;
|
|
||||||
|
|
||||||
legend {
|
|
||||||
position: absolute;
|
|
||||||
inset-block-start: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset, .fieldset {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0;
|
padding: 0 {
|
||||||
|
block-start: math.div(14, 16) + 0.333rem !important;
|
||||||
|
}
|
||||||
margin: 0;
|
margin: 0;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
border: none;
|
border: none;
|
||||||
|
|
||||||
legend {
|
legend {
|
||||||
|
position: absolute;
|
||||||
|
inset-block-start: 0;
|
||||||
|
margin-block-end: 0.333rem;
|
||||||
color: #FFF9;
|
color: #FFF9;
|
||||||
font-size: math.div(14, 16) * 1rem;
|
font-size: math.div(14, 16) * 1rem;
|
||||||
margin-block-end: 0.333rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
.input {
|
||||||
appearance: textfield;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
|
|
||||||
background: #0004;
|
|
||||||
border: 1px solid #FFF2;
|
|
||||||
color: #FFFC;
|
|
||||||
transition: {
|
|
||||||
property: background-color, border-color, color;
|
|
||||||
duration: 33.333ms;
|
|
||||||
timing-function: linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
font: {
|
|
||||||
family: "Fira Sans", sans-serif;
|
|
||||||
size: math.div(15, 16) * 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #FFF4;
|
|
||||||
background: #0006;
|
|
||||||
color: #FFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-outer-spin-button,
|
|
||||||
&::-webkit-inner-spin-button {
|
|
||||||
appearance: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sts-text-field::part(input) {
|
|
||||||
flex: unset;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&::-webkit-outer-spin-button,
|
|
||||||
&::-webkit-inner-spin-button {
|
|
||||||
appearance: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input, sts-text-field {
|
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
width: math.div(1, 3) * 100%;
|
width: math.div(1, 3) * 100%;
|
||||||
border-left-width: 4px;
|
border-left-width: 4px;
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import * as studio from "@storyteller/studio"
|
import * as studio from "@storyteller/studio"
|
||||||
import { LitElement, html, unsafeCSS } from "lit";
|
import { LitElement, html, unsafeCSS } from "lit";
|
||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
|
|
||||||
import { type Quat, type Vec3 } from "./inspector.types";
|
import { type Quat, type Vec3 } from "./inspector.types";
|
||||||
|
|
||||||
|
import "@storyteller/studio-ui/forms/scalar-field";
|
||||||
|
|
||||||
import styles from "./transform-inspector.element.scss?inline";
|
import styles from "./transform-inspector.element.scss?inline";
|
||||||
|
|
||||||
@customElement("sts-transform-inspector")
|
@customElement("sts-transform-inspector")
|
||||||
@@ -18,6 +22,10 @@ export class TransformInspectorElement extends LitElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
scale: Vec3 = { x: 1, y: 1, z: 1 };
|
scale: Vec3 = { x: 1, y: 1, z: 1 };
|
||||||
|
|
||||||
|
#positionLabelId = uuid();
|
||||||
|
#rotationLabelId = uuid();
|
||||||
|
#scaleLabelId = uuid();
|
||||||
|
|
||||||
updateField(reflectPath: `${"translation"|"rotation"|"scale"}.${"x"|"y"|"z"}`) {
|
updateField(reflectPath: `${"translation"|"rotation"|"scale"}.${"x"|"y"|"z"}`) {
|
||||||
return ({ detail }: CustomEvent<string>) => {
|
return ({ detail }: CustomEvent<string>) => {
|
||||||
const value = parseFloat(detail);
|
const value = parseFloat(detail);
|
||||||
@@ -33,61 +41,88 @@ export class TransformInspectorElement extends LitElement {
|
|||||||
|
|
||||||
protected override render = () => html`
|
protected override render = () => html`
|
||||||
<h4>Transform</h4>
|
<h4>Transform</h4>
|
||||||
<div class="fieldset" role="group">
|
<div
|
||||||
<legend>Position</legend>
|
class="fieldset"
|
||||||
<sts-text-field
|
role="group"
|
||||||
type="number"
|
aria-labelledby=${this.#positionLabelId}
|
||||||
.value=${this.translation.x.toFixed(3)}
|
>
|
||||||
|
<legend id=${this.#positionLabelId}>
|
||||||
|
Position
|
||||||
|
</legend>
|
||||||
|
<sts-scalar-field
|
||||||
|
class="input"
|
||||||
|
aria-label="X"
|
||||||
|
.value=${this.translation.x}
|
||||||
@value-change=${this.updateField("translation.x")}
|
@value-change=${this.updateField("translation.x")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
type="number"
|
class="input"
|
||||||
.value=${this.translation.y.toFixed(3)}
|
aria-label="Y"
|
||||||
|
.value=${this.translation.y}
|
||||||
@value-change=${this.updateField("translation.y")}
|
@value-change=${this.updateField("translation.y")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
type="number"
|
class="input"
|
||||||
.value=${this.translation.z.toFixed(3)}
|
aria-label="Z"
|
||||||
|
.value=${this.translation.z}
|
||||||
@value-change=${this.updateField("translation.z")}
|
@value-change=${this.updateField("translation.z")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="fieldset" role="group">
|
<div
|
||||||
<legend>Rotation</legend>
|
class="fieldset"
|
||||||
|
role="group"
|
||||||
|
aria-labelledby=${this.#rotationLabelId}
|
||||||
|
>
|
||||||
|
<legend id=${this.#rotationLabelId}>
|
||||||
|
Rotation
|
||||||
|
</legend>
|
||||||
<!-- TODO: This is not how quaternions work lol -->
|
<!-- TODO: This is not how quaternions work lol -->
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
type="number"
|
class="input"
|
||||||
.value=${this.rotation.x.toFixed(3)}
|
aria-label="X"
|
||||||
|
.value=${this.rotation.x}
|
||||||
@value-change=${this.updateField("rotation.x")}
|
@value-change=${this.updateField("rotation.x")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
type="number"
|
class="input"
|
||||||
.value=${this.rotation.y.toFixed(3)}
|
aria-label="Y"
|
||||||
|
.value=${this.rotation.y}
|
||||||
@value-change=${this.updateField("rotation.y")}
|
@value-change=${this.updateField("rotation.y")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
type="number"
|
class="input"
|
||||||
.value=${this.rotation.z.toFixed(3)}
|
aria-label="Z"
|
||||||
|
.value=${this.rotation.z}
|
||||||
@value-change=${this.updateField("rotation.z")}
|
@value-change=${this.updateField("rotation.z")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
<!-- <input type="number" value=${this.rotation.w.toFixed(3)} /> -->
|
<!-- <input type="number" value=${this.rotation.w.toFixed(3)} /> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="fieldset" role="group">
|
<div
|
||||||
<legend>Scale</legend>
|
class="fieldset"
|
||||||
<sts-text-field
|
role="group"
|
||||||
type="number"
|
aria-labelledby=${this.#scaleLabelId}
|
||||||
.value=${this.scale.x.toFixed(3)}
|
>
|
||||||
|
<legend id=${this.#scaleLabelId}>
|
||||||
|
Scale
|
||||||
|
</legend>
|
||||||
|
<sts-scalar-field
|
||||||
|
class="input"
|
||||||
|
aria-label="X"
|
||||||
|
.value=${this.scale.x}
|
||||||
@value-change=${this.updateField("scale.x")}
|
@value-change=${this.updateField("scale.x")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
type="number"
|
class="input"
|
||||||
.value=${this.scale.y.toFixed(3)}
|
aria-label="Y"
|
||||||
|
.value=${this.scale.y}
|
||||||
@value-change=${this.updateField("scale.y")}
|
@value-change=${this.updateField("scale.y")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
<sts-text-field
|
<sts-scalar-field
|
||||||
type="number"
|
class="input"
|
||||||
.value=${this.scale.z.toFixed(3)}
|
aria-label="Z"
|
||||||
|
.value=${this.scale.z}
|
||||||
@value-change=${this.updateField("scale.z")}
|
@value-change=${this.updateField("scale.z")}
|
||||||
></sts-text-field>
|
></sts-scalar-field>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"@storyteller/studio-ui/toolbar": ["studio-ui/src/lib/toolbar.element.ts"],
|
"@storyteller/studio-ui/toolbar": ["studio-ui/src/lib/toolbar.element.ts"],
|
||||||
"@storyteller/studio-ui/tree": ["studio-ui/src/lib/tree.element.ts"],
|
"@storyteller/studio-ui/tree": ["studio-ui/src/lib/tree.element.ts"],
|
||||||
"@storyteller/studio-ui/forms/text-field": ["studio-ui/src/lib/forms/text-field.element.ts"],
|
"@storyteller/studio-ui/forms/text-field": ["studio-ui/src/lib/forms/text-field.element.ts"],
|
||||||
|
"@storyteller/studio-ui/forms/scalar-field": ["studio-ui/src/lib/forms/scalar-field.element.ts"],
|
||||||
"@storyteller/studio-web": ["studio-web/src/index.ts"],
|
"@storyteller/studio-web": ["studio-web/src/index.ts"],
|
||||||
"@storyteller/studio-web/add-to-scene-menu": ["studio-web/src/lib/add-to-scene-menu.element.ts"],
|
"@storyteller/studio-web/add-to-scene-menu": ["studio-web/src/lib/add-to-scene-menu.element.ts"],
|
||||||
"@storyteller/studio-web/canvas-provider": ["studio-web/src/lib/canvas-provider.element.ts"],
|
"@storyteller/studio-web/canvas-provider": ["studio-web/src/lib/canvas-provider.element.ts"],
|
||||||
|
|||||||
Reference in New Issue
Block a user