diff --git a/source/Component/AttrInput/AttrInput.scss b/source/Component/AttrInput/AttrInput.scss index 3aebe35..ce1cd82 100644 --- a/source/Component/AttrInput/AttrInput.scss +++ b/source/Component/AttrInput/AttrInput.scss @@ -4,51 +4,70 @@ div.attr-input { width: 100%; display: flex; min-height: 24px; - padding: 8px 0; + padding: 5px 0; div.input-intro { width: 50%; height: 100%; - max-width: 180px; + max-width: 220px; display: flex; align-items: center; + padding-right: 5px; + box-sizing: border-box; } - div.input-content { - width: 50%; - height: 100%; - max-width: 180px; - box-sizing: border-box; - border-radius: 3px; - overflow: hidden; - display: flex; - justify-content: space-between; - align-items: center; - min-height: 24px; + div.root-content { + width: 50%; + height: 100%; + max-width: 180px; - input { - padding: 0 5px; - width: 100%; - height: 100%; - border: none; - outline:none; - }; + div.input-content { + box-sizing: border-box; + border: 1px solid transparent; + border-radius: 3px; + overflow: hidden; + display: flex; + justify-content: space-between; + align-items: center; + min-height: 24px; + + input { + width: 100%; + height: 100%; + border: none; + outline:none; + }; + + input:focus { + border: none; + } + + div.button-left, div.button-right { + min-height: 24px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + vertical-align: middle; + cursor: pointer; + user-select: none; + padding: 0 3px; + } + } + + div.input-content.error { + border: 1px solid $lt-red; + } - input:focus { - border: none; - } + div.input-content.focus { + border: 1px solid $lt-blue; + } - div.button-left, div.button-right { - height: 100%; - display: flex; - justify-content: center; - align-items: center; - vertical-align: middle; - cursor: pointer; - user-select: none; - padding: 0 3px; - } - } + div.err-message { + color: $lt-red; + padding-top: 5px; + } + } } div.dark.attr-input { diff --git a/source/Component/AttrInput/AttrInput.tsx b/source/Component/AttrInput/AttrInput.tsx index dd273b4..633bc06 100644 --- a/source/Component/AttrInput/AttrInput.tsx +++ b/source/Component/AttrInput/AttrInput.tsx @@ -2,35 +2,143 @@ import { Component, ReactNode } from "react"; import { FontLevel, Theme } from "@Component/Theme/Theme"; import "./AttrInput.scss"; import { Icon } from "@fluentui/react"; +import { Localization, AllI18nKeys } from "@Component/Localization/Localization"; interface IAttrInputProps { + keyI18n: AllI18nKeys; + infoI18n?: AllI18nKeys; + value?: number | string; isNumber?: boolean; + maxLength?: number; + max?: number; + min?: number; + step?: number; + valueChange?: (value: this["isNumber"] extends true ? number : string) => any; } -class AttrInput extends Component { +interface AttrInputState { + error: ReactNode; + value: string; +} + +class AttrInput extends Component { + + public constructor(props: IAttrInputProps) { + super(props); + const value = props.value ?? props.isNumber ? "0" : ""; + this.state = { + error: this.check(value), + value: value + } + } + + private check(value: string): ReactNode { + + // 长度校验 + const maxLength = this.props.maxLength ?? 32; + if (value.length > maxLength) { + return + } + + if (this.props.isNumber) { + const praseNumber = (value as any) / 1; + + // 数字校验 + if (isNaN(praseNumber)) { + return + } + + // 最大值校验 + if (this.props.max !== undefined && praseNumber > this.props.max) { + return + } + + // 最小值校验 + if (this.props.min !== undefined && praseNumber < this.props.min) { + return + } + + } + return undefined; + } + + private handelValueChange = () => { + if (!this.state.error && this.props.valueChange) { + this.props.valueChange(this.state.value); + } + } + + private changeValue = (direction: number) => { + if (this.state.error) { + return; + } else { + let newVal = (this.state.value as any / 1) + (this.props.step ?? 1) * direction; + + // 最大值校验 + if (this.props.max !== undefined && newVal > this.props.max) { + newVal = this.props.max; + } + + // 最小值校验 + if (this.props.min !== undefined && newVal < this.props.min) { + newVal = this.props.min; + } + + this.setState( + { value: newVal.toString() }, + () => this.handelValueChange() + ); + } + } + public render(): ReactNode { return -
- Input -
-
- { - this.props.isNumber ?
- -
: null - } - - { - this.props.isNumber ?
- -
: null - } -
-
+ className="attr-input" + fontLevel={FontLevel.normal} + > +
+ +
+
+
+ { + this.props.isNumber ?
this.changeValue(-1)} + > + +
: null + } + { + this.setState({ + error: this.check(e.target.value), + value: e.target.value + }, () => this.handelValueChange()); + }} + > + { + this.props.isNumber ?
this.changeValue(1)} + > + +
: null + } +
+ { +
+ {this.state.error} +
+ } +
+ } } diff --git a/source/Component/Container/Container.scss b/source/Component/Container/Container.scss index 99442d6..a2d4287 100644 --- a/source/Component/Container/Container.scss +++ b/source/Component/Container/Container.scss @@ -27,7 +27,7 @@ div.app-container { } div:hover { - background-color: blue; + background-color: $lt-blue; } } @@ -83,7 +83,7 @@ div.app-container { } div.app-tab-header-item.active { - border: .8px solid blue; + border: .8px solid $lt-blue; transition: none; } @@ -141,7 +141,7 @@ div.app-container { } div.app-panel-root.active { - border: .8px solid blue !important; + border: .8px solid $lt-blue !important; } } diff --git a/source/Component/Theme/Theme.scss b/source/Component/Theme/Theme.scss index 3f24727..8069a6d 100644 --- a/source/Component/Theme/Theme.scss +++ b/source/Component/Theme/Theme.scss @@ -1,5 +1,8 @@ @import "@fluentui/react/dist/sass/References"; +$lt-blue: rgb(81, 79, 235); +$lt-red: rgb(240, 94, 94); + $lt-font-size-normal: 13px; $lt-font-size-lvl3: $ms-font-size-16; $lt-font-size-lvl2: $ms-font-size-18; diff --git a/source/Localization/EN-US.ts b/source/Localization/EN-US.ts index fda2eff..dc506d9 100644 --- a/source/Localization/EN-US.ts +++ b/source/Localization/EN-US.ts @@ -19,6 +19,10 @@ const EN_US = { "Command.Bar.Add.Tag.Info": "Add label object", "Command.Bar.Camera.Info": "Renderer settings", "Command.Bar.Setting.Info": "Global Settings", + "Input.Error.Not.Number": "Please key in numbers", + "Input.Error.Max": "Enter value must be less than {num}", + "Input.Error.Min": "Enter value must be greater than {num}", + "Input.Error.Length": "The length of the input content must be less than {num}", "Object.List.New.Group": "Group object {id}", "Object.List.New.Range": "Range object {id}", "Object.List.No.Data": "There are no objects in the model, click the button to create it", @@ -30,6 +34,9 @@ const EN_US = { "Panel.Info.Object.List.View": "Edit View All Object Properties", "Panel.Title.Range.Details.View": "Range attributes", "Panel.Info.Range.Details.View": "Edit View Range attributes", - + "Common.Attr.Key.Display.Name": "Display name", + "Common.Attr.Key.Position.X": "Position X", + "Common.Attr.Key.Position.Y": "Position Y", + "Common.Attr.Key.Position.Z": "Position Z", } export default EN_US; \ No newline at end of file diff --git a/source/Localization/ZH-CN.ts b/source/Localization/ZH-CN.ts index c986442..7e6f645 100644 --- a/source/Localization/ZH-CN.ts +++ b/source/Localization/ZH-CN.ts @@ -19,6 +19,10 @@ const ZH_CN = { "Command.Bar.Add.Tag.Info": "添加标签对象", "Command.Bar.Camera.Info": "渲染器设置", "Command.Bar.Setting.Info": "全局设置", + "Input.Error.Not.Number": "请输入数字", + "Input.Error.Max": "输入数值须小于 {number}", + "Input.Error.Min": "输入数值须大于 {number}", + "Input.Error.Length": "输入内容长度须小于 {number}", "Object.List.New.Group": "组对象 {id}", "Object.List.New.Range": "范围对象 {id}", "Object.List.No.Data": "模型中没有任何对象,点击按钮以创建", @@ -30,5 +34,9 @@ const ZH_CN = { "Panel.Info.Object.List.View": "编辑查看全部对象属性", "Panel.Title.Range.Details.View": "范围属性", "Panel.Info.Range.Details.View": "编辑查看范围属性", + "Common.Attr.Key.Display.Name": "显示名称", + "Common.Attr.Key.Position.X": "X 坐标", + "Common.Attr.Key.Position.Y": "Y 坐标", + "Common.Attr.Key.Position.Z": "Z 坐标", } export default ZH_CN; \ No newline at end of file diff --git a/source/Panel/RangeDetails/RangeDetails.tsx b/source/Panel/RangeDetails/RangeDetails.tsx index 0e456db..52cf4b7 100644 --- a/source/Panel/RangeDetails/RangeDetails.tsx +++ b/source/Panel/RangeDetails/RangeDetails.tsx @@ -5,8 +5,10 @@ import "./RangeDetails.scss"; class RangeDetails extends Component { public render(): ReactNode { return
- - + + + +
} }