Compare commits
	
		
			No commits in common. "d1ffc85df484372a3e7e7af8201b25e2c742fb76" and "2c329e9d17494536ca924547177936e91c0e78e1" have entirely different histories.
		
	
	
		
			d1ffc85df4
			...
			2c329e9d17
		
	
		
| @ -1,25 +1,49 @@ | |||||||
| @import "../Theme/Theme.scss"; | @import "../Theme/Theme.scss"; | ||||||
| 
 | 
 | ||||||
| $line-min-height: 24px; | $line-min-height: 26px; | ||||||
| 
 | 
 | ||||||
| div.attr-input-root { | div.attr-input { | ||||||
|  | 	width: 100%; | ||||||
|  | 	display: flex; | ||||||
|  | 	min-height: $line-min-height; | ||||||
|  | 	padding: 5px 0; | ||||||
|  | 
 | ||||||
|  | 	div.input-intro { | ||||||
|  | 		width: 50%; | ||||||
|  | 		height: 100%; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  | 		max-width: 220px; | ||||||
|  | 		display: flex; | ||||||
|  | 		align-items: center; | ||||||
|  |         padding-right: 5px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     div.root-content { | ||||||
|  |         width: 50%; | ||||||
|  |         height: 100%; | ||||||
|  |         max-width: 180px; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  | 
 | ||||||
|  |         div.input-content { | ||||||
|  |             box-sizing: border-box; | ||||||
|  |             border: 1px solid transparent; | ||||||
|  |             border-radius: 3px; | ||||||
|  |             overflow: hidden; | ||||||
|             display: flex; |             display: flex; | ||||||
|             justify-content: space-between; |             justify-content: space-between; | ||||||
|             align-items: center; |             align-items: center; | ||||||
|  |             height: $line-min-height; | ||||||
|      |      | ||||||
|             input { |             input { | ||||||
|         display: block; |  | ||||||
|                 width: 100%; |                 width: 100%; | ||||||
|                 height: 100%; |                 height: 100%; | ||||||
|                 border: none; |                 border: none; | ||||||
|         outline: none; |                 outline:none; | ||||||
|         background-color: transparent; |  | ||||||
|         min-height: $line-min-height; |  | ||||||
|             }; |             }; | ||||||
|      |      | ||||||
|             input:focus { |             input:focus { | ||||||
|                 border: none; |                 border: none; | ||||||
|         background-color: transparent; |  | ||||||
|             } |             } | ||||||
|      |      | ||||||
|             div.button-left, div.button-right { |             div.button-left, div.button-right { | ||||||
| @ -33,27 +57,64 @@ div.attr-input-root { | |||||||
|                 user-select: none; |                 user-select: none; | ||||||
|                 padding: 0 3px; |                 padding: 0 3px; | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |      | ||||||
|  |         div.input-content.error { | ||||||
|  |             border: 1px solid $lt-red; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         div.input-content.focus { | ||||||
|  |             border: 1px solid $lt-blue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         div.err-message { | ||||||
|  |             color: $lt-red; | ||||||
|  |             padding-top: 5px; | ||||||
|  |             min-height: $line-min-height; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         div.error-view { | ||||||
|  |             border-radius: 3px; | ||||||
|  |             overflow: hidden; | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             height: $line-min-height; | ||||||
|  |             text-overflow: ellipsis; | ||||||
|  |             word-wrap: none; | ||||||
|  |             word-break: keep-all; | ||||||
|  |             white-space: nowrap; | ||||||
|  |             cursor:not-allowed; | ||||||
|  | 
 | ||||||
|  |             span { | ||||||
|  |                 padding-left: 8px; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| div.dark.text-field-root { | div.dark.attr-input { | ||||||
| 
 | 
 | ||||||
| 	input { | 	div.input-content, div.error-view, | ||||||
|  | 	div.input-content input { | ||||||
| 		background-color: $lt-bg-color-lvl3-dark; | 		background-color: $lt-bg-color-lvl3-dark; | ||||||
| 		color: $lt-font-color-normal-dark; | 		color: $lt-font-color-normal-dark; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |     div.error-view:hover, | ||||||
| 	div.button-left:hover, div.button-right:hover { | 	div.button-left:hover, div.button-right:hover { | ||||||
| 		background-color: $lt-bg-color-lvl2-dark; | 		background-color: $lt-bg-color-lvl2-dark; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| div.light.text-field-root { | div.light.attr-input { | ||||||
| 
 | 
 | ||||||
| 	input { | 	div.input-content, div.error-view, | ||||||
|  | 	div.input-content input { | ||||||
| 		background-color: $lt-bg-color-lvl3-light; | 		background-color: $lt-bg-color-lvl3-light; | ||||||
| 		color: $lt-font-color-normal-light; | 		color: $lt-font-color-normal-light; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |     div.error-view:hover, | ||||||
| 	div.button-left:hover, div.button-right:hover { | 	div.button-left:hover, div.button-right:hover { | ||||||
| 		background-color: $lt-bg-color-lvl2-light; | 		background-color: $lt-bg-color-lvl2-light; | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -1,12 +1,14 @@ | |||||||
| import { Component, ReactNode } from "react"; | import { Component, ReactNode } from "react"; | ||||||
|  | import { FontLevel, Theme } from "@Component/Theme/Theme"; | ||||||
|  | import "./AttrInput.scss"; | ||||||
| import { Icon } from "@fluentui/react"; | import { Icon } from "@fluentui/react"; | ||||||
| import { Localization, AllI18nKeys } from "@Component/Localization/Localization"; | import { Localization, AllI18nKeys } from "@Component/Localization/Localization"; | ||||||
| import { ObjectID } from "@Model/Renderer"; | import { ObjectID } from "@Model/Renderer"; | ||||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; |  | ||||||
| import "./AttrInput.scss"; |  | ||||||
| 
 | 
 | ||||||
| interface IAttrInputProps extends ITextFieldProps { | interface IAttrInputProps { | ||||||
|     id?: ObjectID; |     id?: ObjectID; | ||||||
|  |     keyI18n: AllI18nKeys; | ||||||
|  |     infoI18n?: AllI18nKeys; | ||||||
|     value?: number | string; |     value?: number | string; | ||||||
| 	isNumber?: boolean; | 	isNumber?: boolean; | ||||||
|     maxLength?: number; |     maxLength?: number; | ||||||
| @ -14,14 +16,15 @@ interface IAttrInputProps extends ITextFieldProps { | |||||||
|     max?: number; |     max?: number; | ||||||
|     min?: number; |     min?: number; | ||||||
|     step?: number; |     step?: number; | ||||||
|  |     disable?: boolean; | ||||||
|  |     disableI18n?: AllI18nKeys; | ||||||
|     valueChange?: (value: this["isNumber"] extends true ? number : string) => any; |     valueChange?: (value: this["isNumber"] extends true ? number : string) => any; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class AttrInput extends Component<IAttrInputProps> { | class AttrInput extends Component<IAttrInputProps> { | ||||||
| 
 | 
 | ||||||
|     private value: string = ""; |     private value: string = ""; | ||||||
|     private error?: AllI18nKeys; |     private error: ReactNode; | ||||||
|     private errorOption?: Record<string, string>; |  | ||||||
|     private numberTestReg = [/\.0*$/, /\.\d*[1-9]+0+$/]; |     private numberTestReg = [/\.0*$/, /\.\d*[1-9]+0+$/]; | ||||||
| 
 | 
 | ||||||
|     private numberTester(value: string) { |     private numberTester(value: string) { | ||||||
| @ -30,21 +33,17 @@ class AttrInput extends Component<IAttrInputProps> { | |||||||
|             this.numberTestReg[1].test(value); |             this.numberTestReg[1].test(value); | ||||||
|     }  |     }  | ||||||
| 
 | 
 | ||||||
|     private check(value: string): AllI18nKeys | undefined { |     private check(value: string): ReactNode { | ||||||
| 
 | 
 | ||||||
|         // 长度校验
 |         // 长度校验
 | ||||||
|         const maxLength = this.props.maxLength ?? 32; |         const maxLength = this.props.maxLength ?? 32; | ||||||
|         if (value.length > maxLength) { |         if (value.length > maxLength) { | ||||||
|             this.error = "Input.Error.Length"; |             return <Localization i18nKey="Input.Error.Length" options={{ num: maxLength.toString() }} /> | ||||||
|             this.errorOption = { num: maxLength.toString() }; |  | ||||||
|             return this.error; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const minLength = this.props.minLength ?? 1; |         const minLength = this.props.minLength ?? 1; | ||||||
|         if (value.length < minLength) { |         if (value.length < minLength) { | ||||||
|             this.error = "Input.Error.Length.Less"; |             return <Localization i18nKey="Input.Error.Length.Less" options={{ num: minLength.toString() }} /> | ||||||
|             this.errorOption = { num: minLength.toString() }; |  | ||||||
|             return this.error; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this.props.isNumber) { |         if (this.props.isNumber) { | ||||||
| @ -52,22 +51,17 @@ class AttrInput extends Component<IAttrInputProps> { | |||||||
| 
 | 
 | ||||||
|             // 数字校验
 |             // 数字校验
 | ||||||
|             if (this.numberTester(value)) { |             if (this.numberTester(value)) { | ||||||
|                 this.error = "Input.Error.Not.Number"; |                 return <Localization i18nKey="Input.Error.Not.Number" /> | ||||||
|                 return this.error; |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // 最大值校验
 |             // 最大值校验
 | ||||||
|             if (this.props.max !== undefined && praseNumber > this.props.max) { |             if (this.props.max !== undefined && praseNumber > this.props.max) { | ||||||
|                 this.error = "Input.Error.Max"; |                 return <Localization i18nKey="Input.Error.Max" options={{ num: this.props.max.toString() }} /> | ||||||
|                 this.errorOption = { num: this.props.max.toString() }; |  | ||||||
|                 return this.error; |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // 最小值校验
 |             // 最小值校验
 | ||||||
|             if (this.props.min !== undefined && praseNumber < this.props.min) { |             if (this.props.min !== undefined && praseNumber < this.props.min) { | ||||||
|                 this.error = "Input.Error.Min"; |                 return <Localization i18nKey="Input.Error.Min" options={{ num: this.props.min.toString() }} /> | ||||||
|                 this.errorOption = { num: this.props.min.toString() }; |  | ||||||
|                 return this.error; |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
| @ -108,6 +102,7 @@ class AttrInput extends Component<IAttrInputProps> { | |||||||
| 
 | 
 | ||||||
|     private renderInput() { |     private renderInput() { | ||||||
|         return <> |         return <> | ||||||
|  |             <div className={"input-content" + (this.error ? ` error` : "")}> | ||||||
|                 { |                 { | ||||||
|                     this.props.isNumber ? <div |                     this.props.isNumber ? <div | ||||||
|                         className="button-left" |                         className="button-left" | ||||||
| @ -136,6 +131,13 @@ class AttrInput extends Component<IAttrInputProps> { | |||||||
|                         <Icon iconName="ChevronRight"></Icon> |                         <Icon iconName="ChevronRight"></Icon> | ||||||
|                     </div> : null |                     </div> : null | ||||||
|                 } |                 } | ||||||
|  |             </div> | ||||||
|  |             {  | ||||||
|  |                 this.error ?  | ||||||
|  |                     <div className="err-message"> | ||||||
|  |                         {this.error} | ||||||
|  |                     </div> : null | ||||||
|  |             } | ||||||
|         </> |         </> | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -164,19 +166,33 @@ class AttrInput extends Component<IAttrInputProps> { | |||||||
|         this.error = this.check(value.toString()); |         this.error = this.check(value.toString()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private renderErrorInput() { | ||||||
|  |         return <div className="error-view"> | ||||||
|  |             { | ||||||
|  |                 this.props.disableI18n ?  | ||||||
|  |                 <Localization i18nKey={this.props.disableI18n}/> : | ||||||
|  |                 <span>{this.props.value}</span> | ||||||
|  |             } | ||||||
|  |         </div> | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 	public render(): ReactNode { | 	public render(): ReactNode { | ||||||
| 
 | 
 | ||||||
| 		return <TextField | 		return <Theme | ||||||
|             {...this.props} |             className="attr-input" | ||||||
|             className="attr-input-root" |             fontLevel={FontLevel.normal} | ||||||
|             customHoverStyle |  | ||||||
|             errorI18n={this.error} |  | ||||||
|             errorI18nOption={this.errorOption} |  | ||||||
|         > |         > | ||||||
|  |             <div className="input-intro"> | ||||||
|  |                 <Localization i18nKey={this.props.keyI18n}/> | ||||||
|  |             </div> | ||||||
|  |             <div className="root-content"> | ||||||
|                 { |                 { | ||||||
|  |                     this.props.disable ?  | ||||||
|  |                         this.renderErrorInput() : | ||||||
|                         this.renderInput() |                         this.renderInput() | ||||||
|                 } |                 } | ||||||
|         </TextField>; |             </div> | ||||||
|  |         </Theme> | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,32 @@ | |||||||
| $line-min-height: 24px; | @import "../Theme/Theme.scss"; | ||||||
| 
 | 
 | ||||||
| div.color-input { | $line-min-height: 26px; | ||||||
|  | 
 | ||||||
|  | div.color-input-root { | ||||||
|  | 	width: 100%; | ||||||
|  | 	display: flex; | ||||||
|  | 	min-height: $line-min-height; | ||||||
|  | 	padding: 5px 0; | ||||||
|  | 
 | ||||||
|  |     div.input-intro { | ||||||
|  | 		width: 50%; | ||||||
|  | 		height: 100%; | ||||||
|  | 		max-width: 220px; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  | 		display: flex; | ||||||
|  | 		align-items: center; | ||||||
|  |         padding-right: 5px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     div.root-content { | ||||||
|  |         width: 50%; | ||||||
|  |         height: 100%; | ||||||
|  |         max-width: 180px; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  |         border-radius: 3px; | ||||||
|  |         overflow: hidden; | ||||||
|  |         display: flex; | ||||||
| 
 | 
 | ||||||
|         div.color-view { |         div.color-view { | ||||||
|             width: $line-min-height; |             width: $line-min-height; | ||||||
| @ -27,6 +53,37 @@ div.color-input { | |||||||
|                 padding-left: 1px; |                 padding-left: 1px; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         div.error-box { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             padding-left: 8px; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div.dark.color-input-root { | ||||||
|  | 
 | ||||||
|  | 	div.root-content { | ||||||
|  | 		background-color: $lt-bg-color-lvl3-dark; | ||||||
|  | 		color: $lt-font-color-normal-dark; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	div.root-content:hover { | ||||||
|  | 		background-color: $lt-bg-color-lvl2-dark; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div.light.color-input-root { | ||||||
|  | 
 | ||||||
|  | 	div.root-content { | ||||||
|  | 		background-color: $lt-bg-color-lvl3-light; | ||||||
|  | 		color: $lt-font-color-normal-light; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	div.root-content:hover { | ||||||
|  | 		background-color: $lt-bg-color-lvl2-light; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| div.color-picker-root { | div.color-picker-root { | ||||||
|  | |||||||
| @ -1,11 +1,16 @@ | |||||||
| import { Component, createRef, ReactNode } from "react"; | import { Component, createRef, ReactNode } from "react"; | ||||||
| import { TextField, ITextFieldProps } from "@Component/TextField/TextField"; | import { FontLevel, Theme } from "@Component/Theme/Theme"; | ||||||
| import { Callout, ColorPicker, DirectionalHint } from "@fluentui/react"; | import { Callout, ColorPicker, DirectionalHint } from "@fluentui/react"; | ||||||
|  | import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||||
| import "./ColorInput.scss"; | import "./ColorInput.scss"; | ||||||
| 
 | 
 | ||||||
| interface IColorInputProps extends ITextFieldProps { | interface IColorInputProps { | ||||||
|  |     keyI18n: AllI18nKeys; | ||||||
|  |     infoI18n?: AllI18nKeys; | ||||||
|     value?: number[]; |     value?: number[]; | ||||||
|     normal?: boolean; |     normal?: boolean; | ||||||
|  |     disable?: boolean; | ||||||
|  |     disableI18n?: AllI18nKeys; | ||||||
|     valueChange?: (color: number[]) => any; |     valueChange?: (color: number[]) => any; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -60,6 +65,16 @@ class ColorInput extends Component<IColorInputProps, IColorInputState> { | |||||||
|         </Callout> |         </Callout> | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private renderErrorInput() { | ||||||
|  |         return <div className="error-box"> | ||||||
|  |             { | ||||||
|  |                 this.props.disableI18n ?  | ||||||
|  |                 <Localization i18nKey={this.props.disableI18n}/> : | ||||||
|  |                 <span>{this.props.value}</span> | ||||||
|  |             } | ||||||
|  |         </div>; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private renderColorInput() { |     private renderColorInput() { | ||||||
|         return <> |         return <> | ||||||
|             <div className="color-view"> |             <div className="color-view"> | ||||||
| @ -89,21 +104,29 @@ class ColorInput extends Component<IColorInputProps, IColorInputState> { | |||||||
| 
 | 
 | ||||||
|     public render(): ReactNode { |     public render(): ReactNode { | ||||||
|         return <> |         return <> | ||||||
|             <TextField |             <Theme className="color-input-root" fontLevel={FontLevel.normal}> | ||||||
|                 {...this.props} |                 <div className="input-intro"> | ||||||
|                 className="color-input" |                     <Localization i18nKey={this.props.keyI18n}/> | ||||||
|                 keyI18n={this.props.keyI18n} |                 </div> | ||||||
|                 targetRef={this.pickerTarget} |                 <div | ||||||
|  |                     className="root-content" | ||||||
|  |                     ref={this.pickerTarget} | ||||||
|  |                     style={{ | ||||||
|  |                         cursor: this.props.disable ? "not-allowed" : "pointer" | ||||||
|  |                     }} | ||||||
|                     onClick={() => { |                     onClick={() => { | ||||||
|                         this.setState({ |                         this.setState({ | ||||||
|                         isPickerVisible: !this.props.disableI18n |                             isPickerVisible: !this.props.disable | ||||||
|                         }) |                         }) | ||||||
|                     }} |                     }} | ||||||
|                 > |                 > | ||||||
|                 { this.renderColorInput() } |                     { this.props.disable ? null : this.renderColorInput() } | ||||||
|             </TextField> |                     { this.props.disable ? this.renderErrorInput() : null } | ||||||
|  |                 </div> | ||||||
|  |             </Theme> | ||||||
|  | 
 | ||||||
|             {this.state.isPickerVisible ?  this.renderPicker(): null} |             {this.state.isPickerVisible ?  this.renderPicker(): null} | ||||||
|         </>; |         </> | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,14 +1,38 @@ | |||||||
| @import "../Theme/Theme.scss"; | @import "../Theme/Theme.scss"; | ||||||
| 
 | 
 | ||||||
| $line-min-height: 24px; | $line-min-height: 26px; | ||||||
| 
 | 
 | ||||||
| div.combo-input { | div.combo-input-root { | ||||||
|  | 	width: 100%; | ||||||
|  | 	display: flex; | ||||||
|  | 	min-height: $line-min-height; | ||||||
|  | 	padding: 5px 0; | ||||||
|  | 
 | ||||||
|  |     div.input-intro { | ||||||
|  | 		width: 50%; | ||||||
|  | 		height: 100%; | ||||||
|  | 		max-width: 220px; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  | 		display: flex; | ||||||
|  | 		align-items: center; | ||||||
|  |         padding-right: 5px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     div.root-content { | ||||||
|  |         width: 50%; | ||||||
|  |         height: 100%; | ||||||
|  |         max-width: 180px; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  |         border-radius: 3px; | ||||||
|  |         overflow: hidden; | ||||||
|  |         display: flex; | ||||||
|  |         cursor: pointer; | ||||||
| 
 | 
 | ||||||
|         div.value-view { |         div.value-view { | ||||||
|             width: 100%; |             width: 100%; | ||||||
|             height: 100%; |             height: 100%; | ||||||
|             min-height: $line-min-height; |             min-height: $line-min-height; | ||||||
|         max-width: calc( 100% - 32px ); |  | ||||||
|             display: flex; |             display: flex; | ||||||
|             align-items: center; |             align-items: center; | ||||||
|             padding-left: 8px; |             padding-left: 8px; | ||||||
| @ -18,12 +42,7 @@ div.combo-input { | |||||||
|             overflow: hidden; |             overflow: hidden; | ||||||
| 
 | 
 | ||||||
|             span { |             span { | ||||||
|             word-break: keep-all; |  | ||||||
|             overflow: hidden; |  | ||||||
|             white-space: nowrap; |  | ||||||
|             text-overflow: ellipsis; |  | ||||||
|                 display: block; |                 display: block; | ||||||
|             max-width: 100%; |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -35,4 +54,34 @@ div.combo-input { | |||||||
|             justify-content: center; |             justify-content: center; | ||||||
|             align-items: center; |             align-items: center; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div.dark.combo-input-root { | ||||||
|  | 
 | ||||||
|  | 	div.root-content { | ||||||
|  | 		background-color: $lt-bg-color-lvl3-dark; | ||||||
|  | 		color: $lt-font-color-normal-dark; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	div.root-content:hover { | ||||||
|  | 		background-color: $lt-bg-color-lvl2-dark; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div.light.combo-input-root { | ||||||
|  | 
 | ||||||
|  | 	div.root-content { | ||||||
|  | 		background-color: $lt-bg-color-lvl3-light; | ||||||
|  | 		color: $lt-font-color-normal-light; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	div.root-content:hover { | ||||||
|  | 		background-color: $lt-bg-color-lvl2-light; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | div.combo-picker-root { | ||||||
|  |     width: 300px; | ||||||
|  |     height: 340px; | ||||||
| } | } | ||||||
| @ -1,10 +1,13 @@ | |||||||
| import { Component, createRef, ReactNode } from "react"; | import { Component, createRef, ReactNode } from "react"; | ||||||
|  | import { FontLevel, Theme } from "@Component/Theme/Theme"; | ||||||
| import { PickerList, IDisplayItem } from "../PickerList/PickerList"; | import { PickerList, IDisplayItem } from "../PickerList/PickerList"; | ||||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; | import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||||
| import { Icon } from "@fluentui/react"; | import { Icon } from "@fluentui/react"; | ||||||
| import { Localization } from "@Component/Localization/Localization"; |  | ||||||
| import "./ComboInput.scss"; | import "./ComboInput.scss"; | ||||||
| interface IComboInputProps extends ITextFieldProps { | 
 | ||||||
|  | interface IComboInputProps { | ||||||
|  |     keyI18n: AllI18nKeys; | ||||||
|  |     infoI18n?: AllI18nKeys; | ||||||
|     allOption?: IDisplayItem[]; |     allOption?: IDisplayItem[]; | ||||||
|     value?: IDisplayItem; |     value?: IDisplayItem; | ||||||
|     valueChange?: (value: IDisplayItem) => any; |     valueChange?: (value: IDisplayItem) => any; | ||||||
| @ -50,11 +53,13 @@ class ComboInput extends Component<IComboInputProps, IComboInputState> { | |||||||
| 
 | 
 | ||||||
|     public render(): ReactNode { |     public render(): ReactNode { | ||||||
|         return <> |         return <> | ||||||
|             <TextField |             <Theme className="combo-input-root" fontLevel={FontLevel.normal}> | ||||||
|                 {...this.props} |                 <div className="input-intro"> | ||||||
|                 targetRef={this.pickerTarget} |                     <Localization i18nKey={this.props.keyI18n}/> | ||||||
|                 className="combo-input" |                 </div> | ||||||
|                 keyI18n={this.props.keyI18n} |                 <div | ||||||
|  |                     className="root-content" | ||||||
|  |                     ref={this.pickerTarget} | ||||||
|                     onClick={() => { |                     onClick={() => { | ||||||
|                         this.setState({ |                         this.setState({ | ||||||
|                             isPickerVisible: true |                             isPickerVisible: true | ||||||
| @ -71,7 +76,8 @@ class ComboInput extends Component<IComboInputProps, IComboInputState> { | |||||||
|                     <div className="list-button"> |                     <div className="list-button"> | ||||||
|                         <Icon iconName="ChevronDownMed"/> |                         <Icon iconName="ChevronDownMed"/> | ||||||
|                     </div> |                     </div> | ||||||
|             </TextField> |                 </div> | ||||||
|  |             </Theme> | ||||||
| 
 | 
 | ||||||
|             {this.state.isPickerVisible ?  this.renderPicker(): null} |             {this.state.isPickerVisible ?  this.renderPicker(): null} | ||||||
|         </> |         </> | ||||||
|  | |||||||
| @ -2,6 +2,31 @@ | |||||||
| 
 | 
 | ||||||
| $line-min-height: 26px; | $line-min-height: 26px; | ||||||
| 
 | 
 | ||||||
| div.label-picker { | div.label-picker-root { | ||||||
|  | 	width: 100%; | ||||||
|  | 	display: flex; | ||||||
|  | 	flex-wrap: wrap; | ||||||
| 	min-height: $line-min-height; | 	min-height: $line-min-height; | ||||||
|  | 	padding: 5px 0; | ||||||
|  | 
 | ||||||
|  |     div.input-intro { | ||||||
|  | 		width: 50%; | ||||||
|  | 		height: 100%; | ||||||
|  | 		min-height: $line-min-height; | ||||||
|  | 		max-width: 220px; | ||||||
|  | 		display: flex; | ||||||
|  | 		align-items: center; | ||||||
|  |         padding-right: 5px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     div.root-content { | ||||||
|  |         width: 50%; | ||||||
|  |         height: 100%; | ||||||
|  |         max-width: 180px; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  |         border-radius: 3px; | ||||||
|  |         overflow: hidden; | ||||||
|  |         display: flex; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| @ -1,12 +1,14 @@ | |||||||
|  | import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||||
| import { PickerList } from "../PickerList/PickerList"; | import { PickerList } from "../PickerList/PickerList"; | ||||||
| import { Label } from "@Model/Label"; | import { Label } from "@Model/Label"; | ||||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; |  | ||||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | ||||||
| import { Component, ReactNode, createRef } from "react"; | import { Component, ReactNode, createRef } from "react"; | ||||||
| import { LabelList } from "../LabelList/LabelList"; | import { LabelList } from "../LabelList/LabelList"; | ||||||
| import "./LabelPicker.scss" | import "./LabelPicker.scss" | ||||||
| 
 | 
 | ||||||
| interface ILabelPickerProps extends ITextFieldProps { | interface ILabelPickerProps { | ||||||
|  | 	keyI18n: AllI18nKeys; | ||||||
|  |     infoI18n?: AllI18nKeys; | ||||||
| 	labels: Label[]; | 	labels: Label[]; | ||||||
| 	labelAdd?: (label: Label) => any; | 	labelAdd?: (label: Label) => any; | ||||||
| 	labelDelete?: (label: Label) => any; | 	labelDelete?: (label: Label) => any; | ||||||
| @ -45,8 +47,28 @@ class LabelPicker extends Component<ILabelPickerProps & IMixinStatusProps, ILabe | |||||||
| 		return res; | 		return res; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|     private renderPicker() { | 	public render(): ReactNode { | ||||||
|         return <PickerList | 		return <div | ||||||
|  | 			className="label-picker-root" | ||||||
|  | 		> | ||||||
|  | 			<div className="input-intro"> | ||||||
|  | 				<Localization i18nKey={this.props.keyI18n}/> | ||||||
|  | 			</div> | ||||||
|  | 			<div className="root-content"> | ||||||
|  | 				<LabelList | ||||||
|  | 					addRef={this.addButtonRef} | ||||||
|  | 					labels={this.props.labels} | ||||||
|  | 					minHeight={26} | ||||||
|  | 					deleteLabel={(label) => { | ||||||
|  | 						this.props.labelDelete ? this.props.labelDelete(label) : 0; | ||||||
|  | 					}} | ||||||
|  | 					addLabel={() => { | ||||||
|  | 						this.setState({ | ||||||
|  | 							isPickerVisible: true | ||||||
|  | 						}); | ||||||
|  | 					}} | ||||||
|  | 				/> | ||||||
|  | 				{this.state.isPickerVisible ? <PickerList | ||||||
|                     noData="Common.Attr.Key.Label.Picker.Nodata" |                     noData="Common.Attr.Key.Label.Picker.Nodata" | ||||||
| 					objectList={this.getOtherLabel()} | 					objectList={this.getOtherLabel()} | ||||||
| 					dismiss={() => { | 					dismiss={() => { | ||||||
| @ -63,32 +85,9 @@ class LabelPicker extends Component<ILabelPickerProps & IMixinStatusProps, ILabe | |||||||
| 						}); | 						}); | ||||||
| 					}} | 					}} | ||||||
| 					target={this.addButtonRef} | 					target={this.addButtonRef} | ||||||
|         />; | 				/> : null} | ||||||
|     } | 			</div> | ||||||
| 
 | 		</div> | ||||||
| 	public render(): ReactNode { |  | ||||||
| 		return <TextField |  | ||||||
|             {...this.props} |  | ||||||
|             className="label-picker" |  | ||||||
|             customHoverStyle |  | ||||||
|             customStyle |  | ||||||
|             keyI18n={this.props.keyI18n} |  | ||||||
|         > |  | ||||||
|             <LabelList |  | ||||||
|                 addRef={this.addButtonRef} |  | ||||||
|                 labels={this.props.labels} |  | ||||||
|                 minHeight={26} |  | ||||||
|                 deleteLabel={(label) => { |  | ||||||
|                     this.props.labelDelete ? this.props.labelDelete(label) : 0; |  | ||||||
|                 }} |  | ||||||
|                 addLabel={() => { |  | ||||||
|                     this.setState({ |  | ||||||
|                         isPickerVisible: true |  | ||||||
|                     }); |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
|             {this.state.isPickerVisible ? this.renderPicker(): null} |  | ||||||
|         </TextField>; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,57 +0,0 @@ | |||||||
| @import "../Theme/Theme.scss"; |  | ||||||
| 
 |  | ||||||
| $line-min-height: 24px; |  | ||||||
| 
 |  | ||||||
| div.object-picker { |  | ||||||
| 
 |  | ||||||
|     div.list-color { |  | ||||||
|         width: 3px; |  | ||||||
|         height: $line-min-height; |  | ||||||
|         border-radius: 1000px; |  | ||||||
|         flex-shrink: 0; |  | ||||||
|         display: flex; |  | ||||||
|         justify-content: center; |  | ||||||
|         align-items: center; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     div.value-view { |  | ||||||
|         flex-shrink: 1; |  | ||||||
|         width: 100%; |  | ||||||
|         height: 100%; |  | ||||||
|         max-width: calc( 100% - 51px ); |  | ||||||
|         min-height: $line-min-height; |  | ||||||
|         display: flex; |  | ||||||
|         align-items: center; |  | ||||||
| 
 |  | ||||||
|         span { |  | ||||||
|             word-break: keep-all; |  | ||||||
|             overflow: hidden; |  | ||||||
|             white-space: nowrap; |  | ||||||
|             text-overflow: ellipsis; |  | ||||||
|             display: block; |  | ||||||
|             max-width: 100%; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     div.list-button { |  | ||||||
|         width: $line-min-height; |  | ||||||
|         height: $line-min-height; |  | ||||||
|         flex-shrink: 0; |  | ||||||
|         display: flex; |  | ||||||
|         justify-content: center; |  | ||||||
|         align-items: center; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     div.list-empty { |  | ||||||
|         width: $line-min-height; |  | ||||||
|         height: $line-min-height; |  | ||||||
|         flex-shrink: 0; |  | ||||||
|         display: flex; |  | ||||||
|         justify-content: center; |  | ||||||
|         align-items: center; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     div.list-empty:hover { |  | ||||||
|         color: $lt-red; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,169 +1,12 @@ | |||||||
| import { Component, createRef, ReactNode } from "react"; | import { Component, ReactNode } from "react"; | ||||||
| import { Label } from "@Model/Label"; |  | ||||||
| import { Group } from "@Model/Group"; |  | ||||||
| import { Range } from "@Model/Range"; |  | ||||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; |  | ||||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; |  | ||||||
| import { PickerList, IDisplayItem, getObjectDisplayInfo, IDisplayInfo } from "../PickerList/PickerList"; |  | ||||||
| import { Localization } from "@Component/Localization/Localization"; |  | ||||||
| import { Icon } from "@fluentui/react"; |  | ||||||
| import { CtrlObject } from "@Model/CtrlObject"; |  | ||||||
| import "./ObjectPicker.scss"; |  | ||||||
| 
 | 
 | ||||||
| type IObjectType = Label | Group | Range | CtrlObject; | interface IObjectPickerProps {} | ||||||
| 
 | 
 | ||||||
| interface IObjectPickerProps extends ITextFieldProps { | class ObjectPicker extends Component<IObjectPickerProps> { | ||||||
|     type: Array<"L" | "G" | "R">; |  | ||||||
|     value?: IObjectType; |  | ||||||
|     valueChange?: (value: IObjectType) => any; |  | ||||||
|     cleanValue?: () => any; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface IObjectPickerState { |  | ||||||
|     isPickerVisible: boolean; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @useStatusWithEvent("objectChange", "labelChange") |  | ||||||
| class ObjectPicker extends Component<IObjectPickerProps & IMixinStatusProps, IObjectPickerState> { |  | ||||||
| 
 |  | ||||||
|     private getAllOption() { |  | ||||||
|         let option: Array<IObjectType> = []; |  | ||||||
|         if (this.props.status) { |  | ||||||
| 
 |  | ||||||
|             for (let i = 0; i < this.props.type.length; i++) { |  | ||||||
| 
 |  | ||||||
|                 if (this.props.type[i] === "L") { |  | ||||||
|                     for (let j = 0; j < this.props.status.model.labelPool.length; j++) { |  | ||||||
|                         option.push(this.props.status.model.labelPool[j]); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if (this.props.type[i] === "R") { |  | ||||||
|                     for (let j = 0; j < this.props.status.model.objectPool.length; j++) { |  | ||||||
|                         if (this.props.status.model.objectPool[j] instanceof Range) { |  | ||||||
|                             option.push(this.props.status.model.objectPool[j]); |  | ||||||
|                         } |  | ||||||
|                     }     |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if (this.props.type[i] === "G") { |  | ||||||
|                     for (let j = 0; j < this.props.status.model.objectPool.length; j++) { |  | ||||||
|                         if (this.props.status.model.objectPool[j] instanceof Group) { |  | ||||||
|                             option.push(this.props.status.model.objectPool[j]); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return option; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private isClean: boolean = false; |  | ||||||
| 
 |  | ||||||
|     public constructor(props: IObjectPickerProps) { |  | ||||||
|         super(props); |  | ||||||
|         this.state = { |  | ||||||
|             isPickerVisible: false |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private pickerTarget = createRef<HTMLDivElement>(); |  | ||||||
| 
 |  | ||||||
|     private renderPicker() { |  | ||||||
|         return <PickerList |  | ||||||
|             noData="Object.Picker.List.No.Data" |  | ||||||
|             target={this.pickerTarget} |  | ||||||
|             objectList={this.getAllOption()} |  | ||||||
|             clickObjectItems={((item) => { |  | ||||||
|                 if (this.props.valueChange) { |  | ||||||
|                     this.props.valueChange(item); |  | ||||||
|                 } |  | ||||||
|                 this.setState({ |  | ||||||
|                     isPickerVisible: false |  | ||||||
|                 }) |  | ||||||
|             })} |  | ||||||
|             dismiss={() => { |  | ||||||
|                 this.setState({ |  | ||||||
|                     isPickerVisible: false |  | ||||||
|                 }) |  | ||||||
|             }} |  | ||||||
|         /> |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
| 	public render(): ReactNode { | 	public render(): ReactNode { | ||||||
| 
 | 		return <div></div> | ||||||
|         let disPlayInfo: IDisplayInfo; |  | ||||||
|         let isDelete: boolean = false; |  | ||||||
| 
 |  | ||||||
|         if (this.props.value) { |  | ||||||
|             disPlayInfo = getObjectDisplayInfo(this.props.value); |  | ||||||
|             isDelete = this.props.value.isDeleted(); |  | ||||||
|         } else { |  | ||||||
|             disPlayInfo = { |  | ||||||
|                 name: "", |  | ||||||
|                 icon: "Label", |  | ||||||
|                 color: "rgba(0,0,0,0)" |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return <> |  | ||||||
|             <TextField |  | ||||||
|                 {...this.props} |  | ||||||
|                 className="object-picker" |  | ||||||
|                 keyI18n={this.props.keyI18n} |  | ||||||
|                 targetRef={this.pickerTarget} |  | ||||||
|                 onClick={() => { |  | ||||||
|                     if (this.isClean) { |  | ||||||
|                         this.isClean = false; |  | ||||||
|                     } else { |  | ||||||
|                         this.setState({ |  | ||||||
|                             isPickerVisible: true |  | ||||||
|                         }) |  | ||||||
|                     } |  | ||||||
|                 }} |  | ||||||
|             > |  | ||||||
|                 <div |  | ||||||
|                     className="list-color" |  | ||||||
|                     style={{ |  | ||||||
|                             backgroundColor: disPlayInfo.color |  | ||||||
|                     }} |  | ||||||
|                 /> |  | ||||||
|                 <div className="list-button"> |  | ||||||
|                     <Icon iconName={disPlayInfo.icon}/> |  | ||||||
|                 </div> |  | ||||||
|                 <div |  | ||||||
|                     className="value-view" |  | ||||||
|                     style={{ |  | ||||||
|                         textDecoration: isDelete ? "line-through" : undefined, |  | ||||||
|                         opacity: isDelete ? ".6" : undefined |  | ||||||
|                     }} |  | ||||||
|                 > |  | ||||||
|                     {    |  | ||||||
|                         disPlayInfo.name ?  |  | ||||||
|                             <span>{disPlayInfo.name}</span> : |  | ||||||
|                             <Localization i18nKey="Input.Error.Select"/> |  | ||||||
|                     } |  | ||||||
|                 </div> |  | ||||||
|                 <div |  | ||||||
|                     className="list-empty" |  | ||||||
|                     onClick={() => { |  | ||||||
|                         if (this.props.cleanValue && disPlayInfo.name) { |  | ||||||
|                             this.isClean = true; |  | ||||||
|                             this.props.cleanValue(); |  | ||||||
|                         } |  | ||||||
|                     }} |  | ||||||
|                 > |  | ||||||
|                     {    |  | ||||||
|                         disPlayInfo.name ?  |  | ||||||
|                             <Icon iconName="delete"/> : |  | ||||||
|                             null |  | ||||||
|                     } |  | ||||||
|                 </div> |  | ||||||
|             </TextField> |  | ||||||
| 
 |  | ||||||
|             {this.state.isPickerVisible ?  this.renderPicker(): null} |  | ||||||
|         </> |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export { ObjectPicker, IDisplayItem }; | export { ObjectPicker } | ||||||
| @ -1,13 +1,12 @@ | |||||||
| div.picker-list-root { | div.picker-list-root { | ||||||
| 	min-width: 200px; | 	max-width: 200px; | ||||||
| 	height: 100%; | 	height: 100%; | ||||||
| 	padding: 0px; | 	padding: 0px; | ||||||
| 	margin: 0px; | 	margin: 0px; | ||||||
| 	overflow-y: auto; | 	overflow-y: auto; | ||||||
| 
 | 
 | ||||||
| 	div.picker-list-item { | 	div.picker-list-item { | ||||||
| 		min-width: 200px; | 		width: 200px; | ||||||
| 		padding-right: 10px; |  | ||||||
| 		height: 36px; | 		height: 36px; | ||||||
| 		display: flex; | 		display: flex; | ||||||
| 		justify-content: center; | 		justify-content: center; | ||||||
| @ -38,7 +37,6 @@ div.picker-list-root { | |||||||
| 
 | 
 | ||||||
| 		div.list-item-name { | 		div.list-item-name { | ||||||
| 			width: 100%; | 			width: 100%; | ||||||
| 			white-space: nowrap; |  | ||||||
|             box-sizing: border-box; |             box-sizing: border-box; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -7,15 +7,26 @@ import { Range } from "@Model/Range"; | |||||||
| import { Component, ReactNode, RefObject } from "react"; | import { Component, ReactNode, RefObject } from "react"; | ||||||
| import "./PickerList.scss"; | import "./PickerList.scss"; | ||||||
| 
 | 
 | ||||||
| type IDisplayInfo = Record<"color" | "icon" | "name", string>; | type IPickerListItem = CtrlObject | Label; | ||||||
| type IPickerListItem = CtrlObject | Label | Range | Group; |  | ||||||
| type IDisplayItem = { | type IDisplayItem = { | ||||||
|     nameKey: AllI18nKeys; |     nameKey: AllI18nKeys; | ||||||
|     key: string; |     key: string; | ||||||
| 	mark?: boolean; | 	mark?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getObjectDisplayInfo(item: IPickerListItem): IDisplayInfo { | interface IPickerListProps { | ||||||
|  |     displayItems?: IDisplayItem[]; | ||||||
|  | 	objectList?: IPickerListItem[]; | ||||||
|  | 	target?: RefObject<any>; | ||||||
|  |     noData?: AllI18nKeys; | ||||||
|  | 	dismiss?: () => any; | ||||||
|  | 	clickObjectItems?: (item: IPickerListItem) => any; | ||||||
|  |     clickDisplayItems?: (item: IDisplayItem) => any; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class PickerList extends Component<IPickerListProps> { | ||||||
|  | 
 | ||||||
|  | 	private renderItem(item: IPickerListItem) { | ||||||
| 
 | 
 | ||||||
| 		let color: number[] = []; | 		let color: number[] = []; | ||||||
| 		let icon: string = "tag"; | 		let icon: string = "tag"; | ||||||
| @ -39,28 +50,6 @@ function getObjectDisplayInfo(item: IPickerListItem): IDisplayInfo { | |||||||
| 			name = item.name; | 			name = item.name; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	return { |  | ||||||
| 		color: `rgb(${color[0]},${color[1]},${color[2]})`, |  | ||||||
| 		icon: icon, |  | ||||||
| 		name: name |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| interface IPickerListProps { |  | ||||||
|     displayItems?: IDisplayItem[]; |  | ||||||
| 	objectList?: IPickerListItem[]; |  | ||||||
| 	target?: RefObject<any>; |  | ||||||
|     noData?: AllI18nKeys; |  | ||||||
| 	dismiss?: () => any; |  | ||||||
| 	clickObjectItems?: (item: IPickerListItem) => any; |  | ||||||
|     clickDisplayItems?: (item: IDisplayItem) => any; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class PickerList extends Component<IPickerListProps> { |  | ||||||
| 
 |  | ||||||
| 	private renderItem(item: IPickerListItem) { |  | ||||||
| 		const displayInfo = getObjectDisplayInfo(item); |  | ||||||
| 
 |  | ||||||
| 		return <div | 		return <div | ||||||
| 			className="picker-list-item" | 			className="picker-list-item" | ||||||
| 			key={item.id} | 			key={item.id} | ||||||
| @ -72,14 +61,14 @@ class PickerList extends Component<IPickerListProps> { | |||||||
| 		> | 		> | ||||||
| 			<div className="list-item-color" | 			<div className="list-item-color" | ||||||
| 				style={{ | 				style={{ | ||||||
| 					backgroundColor: displayInfo.color | 					backgroundColor: `rgb(${color[0]},${color[1]},${color[2]})` | ||||||
| 				}} | 				}} | ||||||
| 			></div> | 			></div> | ||||||
| 			<div className="list-item-icon"> | 			<div className="list-item-icon"> | ||||||
| 				<Icon iconName={displayInfo.icon}/> | 				<Icon iconName={icon}/> | ||||||
| 			</div> | 			</div> | ||||||
| 			<div className="list-item-name"> | 			<div className="list-item-name"> | ||||||
| 				{displayInfo.name} | 				{name} | ||||||
| 			</div> | 			</div> | ||||||
| 		</div>; | 		</div>; | ||||||
| 	} | 	} | ||||||
| @ -135,4 +124,4 @@ class PickerList extends Component<IPickerListProps> { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export { PickerList, IDisplayItem, IDisplayInfo, getObjectDisplayInfo } | export { PickerList, IDisplayItem } | ||||||
| @ -1,84 +0,0 @@ | |||||||
| @import "../Theme/Theme.scss"; |  | ||||||
| 
 |  | ||||||
| $line-min-height: 26px; |  | ||||||
| 
 |  | ||||||
| div.text-field-root { |  | ||||||
|     min-height: $line-min-height; |  | ||||||
| 	width: 100%; |  | ||||||
| 	display: flex; |  | ||||||
| 	padding: 5px 0; |  | ||||||
| 
 |  | ||||||
|     div.text-field-intro { |  | ||||||
|         min-height: $line-min-height; |  | ||||||
| 		width: 50%; |  | ||||||
| 		height: 100%; |  | ||||||
| 		max-width: 220px; |  | ||||||
| 		display: flex; |  | ||||||
| 		align-items: center; |  | ||||||
|         padding-right: 5px; |  | ||||||
|         box-sizing: border-box; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|     div.text-field-container { |  | ||||||
|         min-height: $line-min-height; |  | ||||||
|         width: 50%; |  | ||||||
|         height: 100%; |  | ||||||
|         max-width: 180px; |  | ||||||
| 
 |  | ||||||
|         div.text-field-content { |  | ||||||
|             min-height: $line-min-height; |  | ||||||
|             width: 100%; |  | ||||||
|             height: 100%; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         div.text-field-content-styled { |  | ||||||
|             box-sizing: border-box; |  | ||||||
|             border: 1px solid transparent; |  | ||||||
|             border-radius: 3px; |  | ||||||
|             overflow: hidden; |  | ||||||
|             display: flex; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         div.text-field-content-disable { |  | ||||||
|             align-items: center; |  | ||||||
|              |  | ||||||
|             span { |  | ||||||
|                 display: block; |  | ||||||
|                 padding-left: 8px; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         div.text-field-content-error { |  | ||||||
|             border: 1px solid $lt-red; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         div.text-field-error-message { |  | ||||||
|             padding-top: 5px; |  | ||||||
|             color: $lt-red; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| div.dark.text-field-root { |  | ||||||
| 
 |  | ||||||
| 	div.text-field-content-styled { |  | ||||||
| 		background-color: $lt-bg-color-lvl3-dark; |  | ||||||
| 		color: $lt-font-color-normal-dark; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	div.text-field-content-hover-styled:hover { |  | ||||||
| 		background-color: $lt-bg-color-lvl2-dark; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| div.light.text-field-root { |  | ||||||
| 
 |  | ||||||
| 	div.text-field-content-styled { |  | ||||||
| 		background-color: $lt-bg-color-lvl3-light; |  | ||||||
| 		color: $lt-font-color-normal-light; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	div.text-field-content-hover-styled:hover { |  | ||||||
| 		background-color: $lt-bg-color-lvl2-light; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -1,104 +0,0 @@ | |||||||
| import { Component, ReactNode, RefObject } from "react"; |  | ||||||
| import { FontLevel, Theme } from "@Component/Theme/Theme"; |  | ||||||
| import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; |  | ||||||
| import "./TextField.scss"; |  | ||||||
| 
 |  | ||||||
| interface ITextFieldProps { |  | ||||||
|     className?: string; |  | ||||||
|     keyI18n: AllI18nKeys; |  | ||||||
|     infoI18n?: AllI18nKeys; |  | ||||||
|     disableI18n?: AllI18nKeys; |  | ||||||
|     disableI18nOption?: Record<string, string>; |  | ||||||
|     errorI18n?: AllI18nKeys; |  | ||||||
|     errorI18nOption?: Record<string, string>; |  | ||||||
|     targetRef?: RefObject<HTMLDivElement>; |  | ||||||
|     customStyle?: boolean; |  | ||||||
|     customHoverStyle?: boolean; |  | ||||||
|     onClick?: () => any; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class TextField extends Component<ITextFieldProps> { |  | ||||||
| 
 |  | ||||||
|     private renderInput() { |  | ||||||
| 
 |  | ||||||
|         const classList: string[] = ["text-field-content"]; |  | ||||||
|         if (this.props.className) { |  | ||||||
|             classList.push(this.props.className); |  | ||||||
|         } |  | ||||||
|         if (!this.props.customStyle) { |  | ||||||
|             classList.push("text-field-content-styled"); |  | ||||||
|         } |  | ||||||
|         if (!this.props.customHoverStyle) { |  | ||||||
|             classList.push("text-field-content-hover-styled"); |  | ||||||
|         } |  | ||||||
|         if (this.props.errorI18n) { |  | ||||||
|             classList.push("text-field-content-error"); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return <div |  | ||||||
|             className={classList.join(" ")} |  | ||||||
|             ref={this.props.targetRef} |  | ||||||
|             style={{ cursor: "pointer" }} |  | ||||||
|             onClick={this.props.onClick} |  | ||||||
|         > |  | ||||||
|             { this.props.children } |  | ||||||
|         </div> |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private renderDisable() { |  | ||||||
|         return <div |  | ||||||
|             className={ |  | ||||||
|                 `${ |  | ||||||
|                     "text-field-content" |  | ||||||
|                 } ${ |  | ||||||
|                     "text-field-content-styled" |  | ||||||
|                 } ${ |  | ||||||
|                     "text-field-content-hover-styled" |  | ||||||
|                 } ${ |  | ||||||
|                     "text-field-content-disable" |  | ||||||
|                 }` |  | ||||||
|             } |  | ||||||
|             ref={this.props.targetRef} |  | ||||||
|             style={{ cursor: "not-allowed" }} |  | ||||||
|             onClick={this.props.onClick} |  | ||||||
|         > |  | ||||||
|             <Localization |  | ||||||
|                 i18nKey={this.props.disableI18n ?? "Common.No.Unknown.Error"} |  | ||||||
|                 options={this.props.disableI18nOption} |  | ||||||
|             /> |  | ||||||
|         </div> |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private renderError() { |  | ||||||
|         return <div className="text-field-error-message"> |  | ||||||
|             <Localization |  | ||||||
|                 i18nKey={this.props.errorI18n ?? "Common.No.Unknown.Error"} |  | ||||||
|                 options={this.props.errorI18nOption} |  | ||||||
|             /> |  | ||||||
|         </div> |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public render(): ReactNode { |  | ||||||
|         return <> |  | ||||||
|             <Theme className="text-field-root" fontLevel={FontLevel.normal}> |  | ||||||
|                 <div className="text-field-intro"> |  | ||||||
|                     <Localization i18nKey={this.props.keyI18n}/> |  | ||||||
|                 </div> |  | ||||||
|                 <div className="text-field-container"> |  | ||||||
|                     { |  | ||||||
|                         this.props.disableI18n ?  |  | ||||||
|                             this.renderDisable() : |  | ||||||
|                             this.renderInput() |  | ||||||
|                     } |  | ||||||
|                     { |  | ||||||
|                         this.props.errorI18n ? |  | ||||||
|                             this.renderError() : |  | ||||||
|                             undefined |  | ||||||
|                     } |  | ||||||
|                 </div> |  | ||||||
|             </Theme> |  | ||||||
|         </> |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export { TextField, ITextFieldProps }; |  | ||||||
| @ -3,6 +3,27 @@ | |||||||
| $line-min-height: 26px; | $line-min-height: 26px; | ||||||
| 
 | 
 | ||||||
| div.toggles-input { | div.toggles-input { | ||||||
|  | 	width: 100%; | ||||||
|  | 	display: flex; | ||||||
|  | 	min-height: $line-min-height; | ||||||
|  | 	padding: 5px 0; | ||||||
|  | 
 | ||||||
|  | 	div.toggles-intro { | ||||||
|  | 		width: 50%; | ||||||
|  | 		height: 100%; | ||||||
|  | 		max-width: 220px; | ||||||
|  |         min-height: $line-min-height; | ||||||
|  | 		display: flex; | ||||||
|  | 		align-items: center; | ||||||
|  |         padding-right: 5px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     div.toggles-content { | ||||||
|  |         width: 50%; | ||||||
|  |         height: 100%; | ||||||
|  |         max-width: 180px; | ||||||
|  |         min-height: $line-min-height; | ||||||
| 
 | 
 | ||||||
|         div.checkbox { |         div.checkbox { | ||||||
|             width: $line-min-height; |             width: $line-min-height; | ||||||
| @ -15,28 +36,29 @@ div.toggles-input { | |||||||
|             cursor: pointer; |             cursor: pointer; | ||||||
|             user-select: none; |             user-select: none; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| div.dark.text-field-root { | div.dark.toggles-input { | ||||||
| 
 | 
 | ||||||
|     div.toggles-input div.checkbox { |     div.toggles-content div.checkbox { | ||||||
|         background-color: $lt-bg-color-lvl3-dark; |         background-color: $lt-bg-color-lvl3-dark; | ||||||
| 		color: $lt-font-color-normal-dark; | 		color: $lt-font-color-normal-dark; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 	div.toggles-input div.checkbox:hover { | 	div.toggles-content div.checkbox:hover { | ||||||
| 		background-color: $lt-bg-color-lvl2-dark; | 		background-color: $lt-bg-color-lvl2-dark; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| div.light.text-field-root { | div.light.toggles-input { | ||||||
| 
 | 
 | ||||||
|     div.toggles-input div.checkbox { |     div.toggles-content div.checkbox { | ||||||
|         background-color: $lt-bg-color-lvl3-light; |         background-color: $lt-bg-color-lvl3-light; | ||||||
| 		color: $lt-font-color-normal-light; | 		color: $lt-font-color-normal-light; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 	div.toggles-input div.checkbox:hover { | 	div.toggles-content div.checkbox:hover { | ||||||
| 		background-color: $lt-bg-color-lvl2-light; | 		background-color: $lt-bg-color-lvl2-light; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -1,10 +1,14 @@ | |||||||
|  | import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||||
|  | import { Theme } from "@Component/Theme/Theme"; | ||||||
| import { Icon } from "@fluentui/react"; | import { Icon } from "@fluentui/react"; | ||||||
| import { Component, ReactNode } from "react"; | import { Component, ReactNode } from "react"; | ||||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; |  | ||||||
| import "./TogglesInput.scss"; | import "./TogglesInput.scss"; | ||||||
| 
 | 
 | ||||||
| interface ITogglesInputProps extends ITextFieldProps { | interface ITogglesInputProps { | ||||||
|  |     keyI18n: AllI18nKeys; | ||||||
|  |     infoI18n?: AllI18nKeys; | ||||||
|     value?: boolean; |     value?: boolean; | ||||||
|  |     disable?: boolean; | ||||||
|     onIconName?: string; |     onIconName?: string; | ||||||
|     offIconName?: string; |     offIconName?: string; | ||||||
|     valueChange?: (value: boolean) => any; |     valueChange?: (value: boolean) => any; | ||||||
| @ -12,20 +16,18 @@ interface ITogglesInputProps extends ITextFieldProps { | |||||||
| 
 | 
 | ||||||
| class TogglesInput extends Component<ITogglesInputProps> { | class TogglesInput extends Component<ITogglesInputProps> { | ||||||
|     public render(): ReactNode { |     public render(): ReactNode { | ||||||
|         return <TextField |         return <Theme className="toggles-input"> | ||||||
|             {...this.props} |             <div className="toggles-intro"> | ||||||
|             className="toggles-input" |                 <Localization i18nKey={this.props.keyI18n}/> | ||||||
|             keyI18n={this.props.keyI18n} |             </div> | ||||||
|             customHoverStyle |             <div className="toggles-content"> | ||||||
|             customStyle |  | ||||||
|         > |  | ||||||
|                 <div |                 <div | ||||||
|                     className="checkbox" |                     className="checkbox" | ||||||
|                     style={{ |                     style={{ | ||||||
|                     cursor: this.props.disableI18n ? "not-allowed" : "pointer" |                         cursor: this.props.disable ? "not-allowed" : "pointer" | ||||||
|                     }} |                     }} | ||||||
|                     onClick={(() => { |                     onClick={(() => { | ||||||
|                     if (this.props.disableI18n) { |                         if (this.props.disable) { | ||||||
|                             return; |                             return; | ||||||
|                         } |                         } | ||||||
|                         if (this.props.valueChange) { |                         if (this.props.valueChange) { | ||||||
| @ -43,9 +45,10 @@ class TogglesInput extends Component<ITogglesInputProps> { | |||||||
|                             display: this.props.value ? "inline-block" :  |                             display: this.props.value ? "inline-block" :  | ||||||
|                                 this.props.offIconName ? "inline-block" : "none" |                                 this.props.offIconName ? "inline-block" : "none" | ||||||
|                         }} |                         }} | ||||||
|                 /> |                     ></Icon> | ||||||
|                 </div>     |                 </div>     | ||||||
|         </TextField>; |             </div> | ||||||
|  |         </Theme> | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -24,12 +24,10 @@ const EN_US = { | |||||||
|     "Input.Error.Min": "Enter value must be greater 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}", |     "Input.Error.Length": "The length of the input content must be less than {num}", | ||||||
|     "Input.Error.Length.Less": "The length of the input content must be greater than {num}", |     "Input.Error.Length.Less": "The length of the input content must be greater than {num}", | ||||||
|     "Input.Error.Select": "Select object ...", |  | ||||||
|     "Object.List.New.Group": "Group object {id}", |     "Object.List.New.Group": "Group object {id}", | ||||||
|     "Object.List.New.Range": "Range object {id}", |     "Object.List.New.Range": "Range object {id}", | ||||||
|     "Object.List.New.Label": "Label {id}", |     "Object.List.New.Label": "Label {id}", | ||||||
|     "Object.List.No.Data": "There are no objects in the model, click the button to create it", |     "Object.List.No.Data": "There are no objects in the model, click the button to create it", | ||||||
|     "Object.Picker.List.No.Data": "There is no model in the model for this option", |  | ||||||
|     "Panel.Title.Notfound": "{id}", |     "Panel.Title.Notfound": "{id}", | ||||||
|     "Panel.Info.Notfound": "This panel with id {id} can not found!", |     "Panel.Info.Notfound": "This panel with id {id} can not found!", | ||||||
|     "Panel.Title.Render.View": "Live preview", |     "Panel.Title.Render.View": "Live preview", | ||||||
| @ -45,7 +43,6 @@ const EN_US = { | |||||||
|     "Panel.Title.Group.Details.View": "Group", |     "Panel.Title.Group.Details.View": "Group", | ||||||
|     "Panel.Info.Group.Details.View": "Edit view group attributes", |     "Panel.Info.Group.Details.View": "Edit view group attributes", | ||||||
|     "Common.No.Data": "No Data", |     "Common.No.Data": "No Data", | ||||||
|     "Common.No.Unknown.Error": "Unknown error", |  | ||||||
|     "Common.Attr.Title.Basic": "Basic properties", |     "Common.Attr.Title.Basic": "Basic properties", | ||||||
|     "Common.Attr.Title.Spatial": "Spatial property", |     "Common.Attr.Title.Spatial": "Spatial property", | ||||||
|     "Common.Attr.Title.Individual.Generation": "Individual generation", |     "Common.Attr.Title.Individual.Generation": "Individual generation", | ||||||
| @ -68,11 +65,6 @@ const EN_US = { | |||||||
|     "Common.Attr.Key.Generation.Mod": "Generation model", |     "Common.Attr.Key.Generation.Mod": "Generation model", | ||||||
|     "Common.Attr.Key.Generation.Mod.Point": "Point model", |     "Common.Attr.Key.Generation.Mod.Point": "Point model", | ||||||
|     "Common.Attr.Key.Generation.Mod.Range": "Range model", |     "Common.Attr.Key.Generation.Mod.Range": "Range model", | ||||||
|     "Common.Attr.Key.Generation.Use.Range": "Generation range", |  | ||||||
|     "Common.Attr.Key.Generation.Count": "Generation count", |  | ||||||
|     "Common.Attr.Key.Generation.Point.X": "Generation Point X", |  | ||||||
|     "Common.Attr.Key.Generation.Point.Y": "Generation Point Y", |  | ||||||
|     "Common.Attr.Key.Generation.Point.Z": "Generation Point Z", |  | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Not.Range": "Object is not a Range", |     "Panel.Info.Range.Details.Attr.Error.Not.Range": "Object is not a Range", | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Unspecified": "Unspecified range object", |     "Panel.Info.Range.Details.Attr.Error.Unspecified": "Unspecified range object", | ||||||
|     "Panel.Info.Group.Details.Attr.Error.Not.Group": "Object is not a Group", |     "Panel.Info.Group.Details.Attr.Error.Not.Group": "Object is not a Group", | ||||||
|  | |||||||
| @ -24,12 +24,10 @@ const ZH_CN = { | |||||||
|     "Input.Error.Min": "输入数值须大于 {number}", |     "Input.Error.Min": "输入数值须大于 {number}", | ||||||
|     "Input.Error.Length": "输入内容长度须小于 {number}", |     "Input.Error.Length": "输入内容长度须小于 {number}", | ||||||
|     "Input.Error.Length.Less": "输入内容长度须大于 {number}", |     "Input.Error.Length.Less": "输入内容长度须大于 {number}", | ||||||
|     "Input.Error.Select": "选择对象 ...", |  | ||||||
|     "Object.List.New.Group": "组对象 {id}", |     "Object.List.New.Group": "组对象 {id}", | ||||||
|     "Object.List.New.Range": "范围对象 {id}", |     "Object.List.New.Range": "范围对象 {id}", | ||||||
|     "Object.List.New.Label": "标签 {id}", |     "Object.List.New.Label": "标签 {id}", | ||||||
|     "Object.List.No.Data": "模型中没有任何对象,点击按钮以创建", |     "Object.List.No.Data": "模型中没有任何对象,点击按钮以创建", | ||||||
|     "Object.Picker.List.No.Data": "模型中没有合适此选项的模型", |  | ||||||
|     "Panel.Title.Notfound": "{id}", |     "Panel.Title.Notfound": "{id}", | ||||||
|     "Panel.Info.Notfound": "这个编号为 {id} 的面板无法找到!", |     "Panel.Info.Notfound": "这个编号为 {id} 的面板无法找到!", | ||||||
|     "Panel.Title.Render.View": "实时预览", |     "Panel.Title.Render.View": "实时预览", | ||||||
| @ -45,7 +43,6 @@ const ZH_CN = { | |||||||
|     "Panel.Title.Group.Details.View": "群", |     "Panel.Title.Group.Details.View": "群", | ||||||
|     "Panel.Info.Group.Details.View": "编辑查看群属性", |     "Panel.Info.Group.Details.View": "编辑查看群属性", | ||||||
|     "Common.No.Data": "暂无数据", |     "Common.No.Data": "暂无数据", | ||||||
|     "Common.No.Unknown.Error": "未知错误", |  | ||||||
|     "Common.Attr.Title.Basic": "基础属性", |     "Common.Attr.Title.Basic": "基础属性", | ||||||
|     "Common.Attr.Title.Spatial": "空间属性", |     "Common.Attr.Title.Spatial": "空间属性", | ||||||
|     "Common.Attr.Title.Individual.Generation": "个体生成", |     "Common.Attr.Title.Individual.Generation": "个体生成", | ||||||
| @ -68,11 +65,6 @@ const ZH_CN = { | |||||||
|     "Common.Attr.Key.Generation.Mod": "生成模式", |     "Common.Attr.Key.Generation.Mod": "生成模式", | ||||||
|     "Common.Attr.Key.Generation.Mod.Point": "点生成", |     "Common.Attr.Key.Generation.Mod.Point": "点生成", | ||||||
|     "Common.Attr.Key.Generation.Mod.Range": "范围生成", |     "Common.Attr.Key.Generation.Mod.Range": "范围生成", | ||||||
|     "Common.Attr.Key.Generation.Use.Range": "生成范围", |  | ||||||
|     "Common.Attr.Key.Generation.Count": "生成个数", |  | ||||||
|     "Common.Attr.Key.Generation.Point.X": "生成位置 X 坐标", |  | ||||||
|     "Common.Attr.Key.Generation.Point.Y": "生成位置 Y 坐标", |  | ||||||
|     "Common.Attr.Key.Generation.Point.Z": "生成位置 Z 坐标", |  | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Not.Range": "对象不是一个范围", |     "Panel.Info.Range.Details.Attr.Error.Not.Range": "对象不是一个范围", | ||||||
|     "Panel.Info.Range.Details.Attr.Error.Unspecified": "未指定范围对象", |     "Panel.Info.Range.Details.Attr.Error.Unspecified": "未指定范围对象", | ||||||
|     "Panel.Info.Group.Details.Attr.Error.Not.Group": "对象不是一个群", |     "Panel.Info.Group.Details.Attr.Error.Not.Group": "对象不是一个群", | ||||||
|  | |||||||
| @ -52,31 +52,6 @@ class CtrlObject extends LabelObject { | |||||||
|     public delete() { |     public delete() { | ||||||
|         this.model.deleteObject([this]); |         this.model.deleteObject([this]); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 判断是否为相同对象 |  | ||||||
|      */ |  | ||||||
|     public equal(obj: CtrlObject): boolean { |  | ||||||
|         return this === obj || this.id === obj.id; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 删除标记 |  | ||||||
|      */ |  | ||||||
|     private deleteFlag: boolean = false; |  | ||||||
| 
 |  | ||||||
|      /** |  | ||||||
|       * 是否被删除 |  | ||||||
|       */ |  | ||||||
|     public isDeleted(): boolean { |  | ||||||
|         if (this.deleteFlag) return true; |  | ||||||
|         for (let i = 0; i < this.model.objectPool.length; i++) { |  | ||||||
|             if (this.model.objectPool[i].equal(this)) return false; |  | ||||||
|         } |  | ||||||
|         this.deleteFlag = true; |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default CtrlObject; | export default CtrlObject; | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { Individual } from "./Individual"; | import { Individual } from "./Individual"; | ||||||
| import { CtrlObject } from "./CtrlObject"; | import { CtrlObject } from "./CtrlObject"; | ||||||
| import type { Behavior } from "./Behavior";  | import type { Behavior } from "./Behavior";  | ||||||
| import type { Label } from "./Label"; | import type { Model } from "./Model"; | ||||||
| 
 | 
 | ||||||
| enum GenMod { | enum GenMod { | ||||||
|     Point = "p", |     Point = "p", | ||||||
| @ -23,21 +23,6 @@ class Group extends CtrlObject { | |||||||
|      */ |      */ | ||||||
|     public genMethod: GenMod = GenMod.Point; |     public genMethod: GenMod = GenMod.Point; | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * 生成位置坐标 |  | ||||||
|      */ |  | ||||||
|     public genPoint: number[] = [0, 0, 0]; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 生成范围 |  | ||||||
|      */ |  | ||||||
|     public genRange?: CtrlObject | Label; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 生成个数 |  | ||||||
|      */ |  | ||||||
|     public genCount?: number = 0; |  | ||||||
| 
 |  | ||||||
| 	/** | 	/** | ||||||
| 	 * 创建个体 | 	 * 创建个体 | ||||||
|      * @param count 创建数量 |      * @param count 创建数量 | ||||||
|  | |||||||
| @ -44,20 +44,13 @@ class Label { | |||||||
|         return this === label || this.id === label.id; |         return this === label || this.id === label.id; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * 删除标记 |  | ||||||
|      */ |  | ||||||
|     private deleteFlag: boolean = false; |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 是否被删除 |      * 是否被删除 | ||||||
|      */ |      */ | ||||||
|     public isDeleted(): boolean { |     public isDeleted(): boolean { | ||||||
|         if (this.deleteFlag) return true; |  | ||||||
|         for (let i = 0; i < this.model.labelPool.length; i++) { |         for (let i = 0; i < this.model.labelPool.length; i++) { | ||||||
|             if (this.model.labelPool[i].equal(this)) return false; |             if (this.model.labelPool[i].equal(this)) return false; | ||||||
|         } |         } | ||||||
|         this.deleteFlag = true; |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -90,31 +90,6 @@ class Model extends Emitter<ModelEvent> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * 通过标签获取指定类型的对象 |  | ||||||
|      * @param label 标签 |  | ||||||
|      * @param type 筛选类型 |  | ||||||
|      */ |  | ||||||
|     public getObjectByLabel( |  | ||||||
|         label: Label, type?:  |  | ||||||
|             (new (...p: any) => Range) |  |  | ||||||
|             (new (...p: any) => Group) |  | ||||||
|     ): CtrlObject[] { |  | ||||||
|         const res: CtrlObject[] = []; |  | ||||||
|         for (let i = 0; i < this.objectPool.length; i++) { |  | ||||||
|             if (this.objectPool[i].hasLabel(label)) { |  | ||||||
|                 if (type) { |  | ||||||
|                     if (this.objectPool[i] instanceof type) { |  | ||||||
|                         res.push(this.objectPool[i]); |  | ||||||
|                     } |  | ||||||
|                 } else { |  | ||||||
|                     res.push(this.objectPool[i]); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return res; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * 添加组 |      * 添加组 | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -9,7 +9,6 @@ import { LabelPicker } from "@Component/LabelPicker/LabelPicker"; | |||||||
| import { Group, GenMod } from "@Model/Group"; | import { Group, GenMod } from "@Model/Group"; | ||||||
| import { AllI18nKeys } from "@Component/Localization/Localization"; | import { AllI18nKeys } from "@Component/Localization/Localization"; | ||||||
| import { ComboInput, IDisplayItem } from "@Component/ComboInput/ComboInput"; | import { ComboInput, IDisplayItem } from "@Component/ComboInput/ComboInput"; | ||||||
| import { ObjectPicker } from "@Component/ObjectPicker/ObjectPicker"; |  | ||||||
| import "./GroupDetails.scss"; | import "./GroupDetails.scss"; | ||||||
| 
 | 
 | ||||||
| interface IGroupDetailsProps {} | interface IGroupDetailsProps {} | ||||||
| @ -26,33 +25,58 @@ const allOption: IDisplayItem[] = [ | |||||||
| @useStatusWithEvent("groupAttrChange", "groupLabelChange", "focusObjectChange") | @useStatusWithEvent("groupAttrChange", "groupLabelChange", "focusObjectChange") | ||||||
| class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> { | class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> { | ||||||
| 
 | 
 | ||||||
|  | 	private renderAttrInput( | ||||||
|  |         id: ObjectID, key: AllI18nKeys, val: string | number | undefined, | ||||||
|  |         change: (val: string, status: Status) => any, | ||||||
|  |         step?: number, max?: number, min?: number | ||||||
|  |     ) { | ||||||
|  |         const handelFunc = (e: string) => { | ||||||
|  |             if (this.props.status) { | ||||||
|  |                 change(e, this.props.status); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (step) { | ||||||
|  |             return <AttrInput | ||||||
|  |                 id={id} isNumber={true} step={step} keyI18n={key} | ||||||
|  |                 value={val} max={max} min={min} | ||||||
|  |                 valueChange={handelFunc} | ||||||
|  |             /> | ||||||
|  |         } else { | ||||||
|  |             return <AttrInput | ||||||
|  |                 id={id} keyI18n={key} value={val} | ||||||
|  |                 valueChange={handelFunc} | ||||||
|  |             /> | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 	private renderFrom(group: Group) { | 	private renderFrom(group: Group) { | ||||||
| 		return <> | 		return <> | ||||||
| 
 | 
 | ||||||
| 			<Message i18nKey="Common.Attr.Title.Basic" isTitle first/> | 			<Message i18nKey="Common.Attr.Title.Basic" isTitle first/> | ||||||
| 
 | 
 | ||||||
|             <AttrInput | 			{this.renderAttrInput( | ||||||
|                 id={group.id} keyI18n="Common.Attr.Key.Display.Name" value={group.displayName} |                 group.id, "Common.Attr.Key.Display.Name", group.displayName, | ||||||
|                 valueChange={(val) => { |                 (val, status) => { | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "displayName", val); |                     status.changeGroupAttrib(group.id, "displayName", val); | ||||||
|                 }} |                 } | ||||||
|             /> |             )} | ||||||
| 
 | 
 | ||||||
|             <ColorInput |             <ColorInput | ||||||
|                 keyI18n="Common.Attr.Key.Color" |                 keyI18n="Common.Attr.Key.Color" | ||||||
|                 value={group.color} normal |                 value={group.color} normal | ||||||
|                 valueChange={(color) => { |                 valueChange={(color) => { | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "color", color); |                     if (this.props.status) { | ||||||
|  |                         this.props.status.changeGroupAttrib(group.id, "color", color); | ||||||
|  |                     } | ||||||
|                 }} |                 }} | ||||||
|             /> |             /> | ||||||
| 
 | 
 | ||||||
|             <AttrInput |             {this.renderAttrInput( | ||||||
|                 id={group.id} isNumber={true} step={10} keyI18n="Common.Attr.Key.Size" |                 group.id, "Common.Attr.Key.Size", group.size, | ||||||
|                 value={group.size} min={0} |                 (val, status) => { | ||||||
|                 valueChange={(val) => { |                     status.changeGroupAttrib(group.id, "size", (val as any) / 1); | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "size", (val as any) / 1); |                 }, 10, undefined, 0 | ||||||
|                 }} |             )} | ||||||
|             /> |  | ||||||
| 
 | 
 | ||||||
|             <LabelPicker |             <LabelPicker | ||||||
|                 keyI18n="Common.Attr.Key.Label" |                 keyI18n="Common.Attr.Key.Label" | ||||||
| @ -113,74 +137,6 @@ class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> { | |||||||
|                     } |                     } | ||||||
|                 }} |                 }} | ||||||
|             /> |             /> | ||||||
| 
 |  | ||||||
|             <AttrInput |  | ||||||
|                 id={group.id} isNumber={true} step={1} keyI18n="Common.Attr.Key.Generation.Count" |  | ||||||
|                 value={group.genCount} min={0} max={1000} |  | ||||||
|                 valueChange={(val) => { |  | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "genCount", (val as any) / 1); |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
| 
 |  | ||||||
|             {group.genMethod === GenMod.Point ? this.renderPointGenOption(group) : null} |  | ||||||
| 
 |  | ||||||
|             {group.genMethod === GenMod.Range ? this.renderRangeGenOption(group) : null} |  | ||||||
| 
 |  | ||||||
|             <TogglesInput |  | ||||||
| 				keyI18n="Common.Attr.Key.Generation" |  | ||||||
| 				onIconName="BuildDefinition" offIconName="BuildDefinition" |  | ||||||
| 				valueChange={() => { |  | ||||||
| 					console.log("gen"); |  | ||||||
| 				}} |  | ||||||
| 			/> |  | ||||||
| 
 |  | ||||||
| 		</> |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
|     private renderPointGenOption(group: Group) { |  | ||||||
|         return <> |  | ||||||
|             <AttrInput |  | ||||||
|                 id={group.id} isNumber={true} step={0.1} keyI18n="Common.Attr.Key.Generation.Point.X" |  | ||||||
|                 value={group.genPoint[0] ?? 0} |  | ||||||
|                 valueChange={(val) => { |  | ||||||
|                     group.genPoint[0] = (val as any) / 1; |  | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "genPoint", group.genPoint); |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
| 
 |  | ||||||
|             <AttrInput |  | ||||||
|                 id={group.id} isNumber={true} step={0.1} keyI18n="Common.Attr.Key.Generation.Point.Y" |  | ||||||
|                 value={group.genPoint[1] ?? 0} |  | ||||||
|                 valueChange={(val) => { |  | ||||||
|                     group.genPoint[1] = (val as any) / 1; |  | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "genPoint", group.genPoint); |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
| 
 |  | ||||||
|             <AttrInput |  | ||||||
|                 id={group.id} isNumber={true} step={0.1} keyI18n="Common.Attr.Key.Generation.Point.Z" |  | ||||||
|                 value={group.genPoint[2] ?? 0} |  | ||||||
|                 valueChange={(val) => { |  | ||||||
|                     group.genPoint[2] = (val as any) / 1; |  | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "genPoint", group.genPoint); |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
|         </> |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private renderRangeGenOption(group: Group) { |  | ||||||
|         return <> |  | ||||||
|             <ObjectPicker |  | ||||||
|                 keyI18n="Common.Attr.Key.Generation.Use.Range" |  | ||||||
|                 type={["L", "R"]} |  | ||||||
|                 value={group.genRange} |  | ||||||
|                 valueChange={(value) => { |  | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "genRange", value); |  | ||||||
|                 }} |  | ||||||
|                 cleanValue={() => { |  | ||||||
|                     this.props.status?.changeGroupAttrib(group.id, "genRange", undefined); |  | ||||||
|                 }} |  | ||||||
|             /> |  | ||||||
| 		</> | 		</> | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user