Compare commits
	
		
			5 Commits
		
	
	
		
			901913a4de
			...
			a25c8dd789
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a25c8dd789 | |||
| 0e79c09691 | |||
| 469ebd2ac9 | |||
| 66102a9936 | |||
| d07a20d8fe | 
| @ -1,120 +1,59 @@ | ||||
| @import "../Theme/Theme.scss"; | ||||
| 
 | ||||
| $line-min-height: 26px; | ||||
| $line-min-height: 24px; | ||||
| 
 | ||||
| div.attr-input { | ||||
| 	width: 100%; | ||||
| 	display: flex; | ||||
| 	min-height: $line-min-height; | ||||
| 	padding: 5px 0; | ||||
| div.attr-input-root { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
| 
 | ||||
| 	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%; | ||||
|     input { | ||||
|         display: block; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         max-width: 180px; | ||||
|         border: none; | ||||
|         outline: none; | ||||
|         background-color: transparent; | ||||
|         min-height: $line-min-height; | ||||
|     }; | ||||
| 
 | ||||
|         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; | ||||
|             height: $line-min-height; | ||||
|      | ||||
|             input { | ||||
|                 width: 100%; | ||||
|                 height: 100%; | ||||
|                 border: none; | ||||
|                 outline:none; | ||||
|             }; | ||||
|      | ||||
|             input:focus { | ||||
|                 border: none; | ||||
|             } | ||||
|      | ||||
|             div.button-left, div.button-right { | ||||
|                 min-height: $line-min-height; | ||||
|                 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; | ||||
|         background-color: transparent; | ||||
|     } | ||||
| 
 | ||||
|         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.button-left, div.button-right { | ||||
|         min-height: $line-min-height; | ||||
|         height: 100%; | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|         vertical-align: middle; | ||||
|         cursor: pointer; | ||||
|         user-select: none; | ||||
|         padding: 0 3px; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| div.dark.attr-input { | ||||
| div.dark.text-field-root { | ||||
| 
 | ||||
| 	div.input-content, div.error-view, | ||||
| 	div.input-content input { | ||||
| 	input { | ||||
| 		background-color: $lt-bg-color-lvl3-dark; | ||||
| 		color: $lt-font-color-normal-dark; | ||||
| 	} | ||||
| 
 | ||||
|     div.error-view:hover, | ||||
| 	div.button-left:hover, div.button-right:hover { | ||||
| 		background-color: $lt-bg-color-lvl2-dark; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| div.light.attr-input { | ||||
| div.light.text-field-root { | ||||
| 
 | ||||
| 	div.input-content, div.error-view, | ||||
| 	div.input-content input { | ||||
| 	input { | ||||
| 		background-color: $lt-bg-color-lvl3-light; | ||||
| 		color: $lt-font-color-normal-light; | ||||
| 	} | ||||
| 
 | ||||
|     div.error-view:hover, | ||||
| 	div.button-left:hover, div.button-right:hover { | ||||
| 		background-color: $lt-bg-color-lvl2-light; | ||||
| 	} | ||||
|  | ||||
| @ -1,14 +1,12 @@ | ||||
| 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"; | ||||
| import { ObjectID } from "@Model/Renderer"; | ||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; | ||||
| import "./AttrInput.scss"; | ||||
| 
 | ||||
| interface IAttrInputProps { | ||||
| interface IAttrInputProps extends ITextFieldProps { | ||||
|     id?: ObjectID; | ||||
|     keyI18n: AllI18nKeys; | ||||
|     infoI18n?: AllI18nKeys; | ||||
|     value?: number | string; | ||||
| 	isNumber?: boolean; | ||||
|     maxLength?: number; | ||||
| @ -16,15 +14,14 @@ interface IAttrInputProps { | ||||
|     max?: number; | ||||
|     min?: number; | ||||
|     step?: number; | ||||
|     disable?: boolean; | ||||
|     disableI18n?: AllI18nKeys; | ||||
|     valueChange?: (value: this["isNumber"] extends true ? number : string) => any; | ||||
| } | ||||
| 
 | ||||
| class AttrInput extends Component<IAttrInputProps> { | ||||
| 
 | ||||
|     private value: string = ""; | ||||
|     private error: ReactNode; | ||||
|     private error?: AllI18nKeys; | ||||
|     private errorOption?: Record<string, string>; | ||||
|     private numberTestReg = [/\.0*$/, /\.\d*[1-9]+0+$/]; | ||||
| 
 | ||||
|     private numberTester(value: string) { | ||||
| @ -33,17 +30,21 @@ class AttrInput extends Component<IAttrInputProps> { | ||||
|             this.numberTestReg[1].test(value); | ||||
|     }  | ||||
| 
 | ||||
|     private check(value: string): ReactNode { | ||||
|     private check(value: string): AllI18nKeys | undefined { | ||||
| 
 | ||||
|         // 长度校验
 | ||||
|         const maxLength = this.props.maxLength ?? 32; | ||||
|         if (value.length > maxLength) { | ||||
|             return <Localization i18nKey="Input.Error.Length" options={{ num: maxLength.toString() }} /> | ||||
|             this.error = "Input.Error.Length"; | ||||
|             this.errorOption = { num: maxLength.toString() }; | ||||
|             return this.error; | ||||
|         } | ||||
| 
 | ||||
|         const minLength = this.props.minLength ?? 1; | ||||
|         if (value.length < minLength) { | ||||
|             return <Localization i18nKey="Input.Error.Length.Less" options={{ num: minLength.toString() }} /> | ||||
|             this.error = "Input.Error.Length.Less"; | ||||
|             this.errorOption = { num: minLength.toString() }; | ||||
|             return this.error; | ||||
|         } | ||||
| 
 | ||||
|         if (this.props.isNumber) { | ||||
| @ -51,17 +52,22 @@ class AttrInput extends Component<IAttrInputProps> { | ||||
| 
 | ||||
|             // 数字校验
 | ||||
|             if (this.numberTester(value)) { | ||||
|                 return <Localization i18nKey="Input.Error.Not.Number" /> | ||||
|                 this.error = "Input.Error.Not.Number"; | ||||
|                 return this.error; | ||||
|             } | ||||
| 
 | ||||
|             // 最大值校验
 | ||||
|             if (this.props.max !== undefined && praseNumber > this.props.max) { | ||||
|                 return <Localization i18nKey="Input.Error.Max" options={{ num: this.props.max.toString() }} /> | ||||
|                 this.error = "Input.Error.Max"; | ||||
|                 this.errorOption = { num: this.props.max.toString() }; | ||||
|                 return this.error; | ||||
|             } | ||||
| 
 | ||||
|             // 最小值校验
 | ||||
|             if (this.props.min !== undefined && praseNumber < this.props.min) { | ||||
|                 return <Localization i18nKey="Input.Error.Min" options={{ num: this.props.min.toString() }} /> | ||||
|                 this.error = "Input.Error.Min"; | ||||
|                 this.errorOption = { num: this.props.min.toString() }; | ||||
|                 return this.error; | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| @ -102,41 +108,33 @@ class AttrInput extends Component<IAttrInputProps> { | ||||
| 
 | ||||
|     private renderInput() { | ||||
|         return <> | ||||
|             <div className={"input-content" + (this.error ? ` error` : "")}> | ||||
|                 { | ||||
|                     this.props.isNumber ? <div | ||||
|                         className="button-left" | ||||
|                         onClick={() => this.changeValue(-1)} | ||||
|                     > | ||||
|                         <Icon iconName="ChevronLeft"></Icon> | ||||
|                     </div> : null | ||||
|                 } | ||||
|                 <input | ||||
|                     className="input" | ||||
|                     value={this.value} | ||||
|                     style={{ | ||||
|                         padding: this.props.isNumber ? "0 3px" : "0 8px" | ||||
|                     }} | ||||
|                     onChange={(e) => { | ||||
|                         this.value = e.target.value; | ||||
|                         this.error = this.check(e.target.value); | ||||
|                         this.handelValueChange(); | ||||
|                     }} | ||||
|                 ></input> | ||||
|                 { | ||||
|                     this.props.isNumber ? <div | ||||
|                         className="button-right" | ||||
|                         onClick={() => this.changeValue(1)} | ||||
|                     > | ||||
|                         <Icon iconName="ChevronRight"></Icon> | ||||
|                     </div> : null | ||||
|                 } | ||||
|             </div> | ||||
|             {  | ||||
|                 this.error ?  | ||||
|                     <div className="err-message"> | ||||
|                         {this.error} | ||||
|                     </div> : null | ||||
|             { | ||||
|                 this.props.isNumber ? <div | ||||
|                     className="button-left" | ||||
|                     onClick={() => this.changeValue(-1)} | ||||
|                 > | ||||
|                     <Icon iconName="ChevronLeft"></Icon> | ||||
|                 </div> : null | ||||
|             } | ||||
|             <input | ||||
|                 className="input" | ||||
|                 value={this.value} | ||||
|                 style={{ | ||||
|                     padding: this.props.isNumber ? "0 3px" : "0 8px" | ||||
|                 }} | ||||
|                 onChange={(e) => { | ||||
|                     this.value = e.target.value; | ||||
|                     this.error = this.check(e.target.value); | ||||
|                     this.handelValueChange(); | ||||
|                 }} | ||||
|             ></input> | ||||
|             { | ||||
|                 this.props.isNumber ? <div | ||||
|                     className="button-right" | ||||
|                     onClick={() => this.changeValue(1)} | ||||
|                 > | ||||
|                     <Icon iconName="ChevronRight"></Icon> | ||||
|                 </div> : null | ||||
|             } | ||||
|         </> | ||||
|     } | ||||
| @ -166,33 +164,19 @@ class AttrInput extends Component<IAttrInputProps> { | ||||
|         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 { | ||||
| 
 | ||||
| 		return <Theme | ||||
|             className="attr-input" | ||||
|             fontLevel={FontLevel.normal} | ||||
| 		return <TextField | ||||
|             {...this.props} | ||||
|             className="attr-input-root" | ||||
|             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() | ||||
|                 } | ||||
|             </div> | ||||
|         </Theme> | ||||
|             { | ||||
|                 this.renderInput() | ||||
|             } | ||||
|         </TextField>; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,89 +1,32 @@ | ||||
| @import "../Theme/Theme.scss"; | ||||
| $line-min-height: 24px; | ||||
| 
 | ||||
| $line-min-height: 26px; | ||||
| div.color-input { | ||||
| 
 | ||||
| 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; | ||||
|     div.color-view { | ||||
|         width: $line-min-height; | ||||
|         max-width: $line-min-height; | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
| 
 | ||||
|         div.color-view { | ||||
|             width: $line-min-height; | ||||
|             max-width: $line-min-height; | ||||
|             display: flex; | ||||
|             justify-content: center; | ||||
|             align-items: center; | ||||
| 
 | ||||
|             div.color-box { | ||||
|                 width: 12px; | ||||
|                 height: 12px; | ||||
|                 border-radius: 3px; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         div.value-view { | ||||
|             width: 100%; | ||||
|             height: 100%; | ||||
|             min-height: $line-min-height; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
| 
 | ||||
|             div.text-box { | ||||
|                 padding-left: 1px; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         div.error-box { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             padding-left: 8px; | ||||
|         div.color-box { | ||||
|             width: 12px; | ||||
|             height: 12px; | ||||
|             border-radius: 3px; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| div.dark.color-input-root { | ||||
|     div.value-view { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         min-height: $line-min-height; | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
| 
 | ||||
| 	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.text-box { | ||||
|             padding-left: 1px; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| div.color-picker-root { | ||||
|  | ||||
| @ -1,16 +1,11 @@ | ||||
| import { Component, createRef, ReactNode } from "react"; | ||||
| import { FontLevel, Theme } from "@Component/Theme/Theme"; | ||||
| import { TextField, ITextFieldProps } from "@Component/TextField/TextField"; | ||||
| import { Callout, ColorPicker, DirectionalHint } from "@fluentui/react"; | ||||
| import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||
| import "./ColorInput.scss"; | ||||
| 
 | ||||
| interface IColorInputProps { | ||||
|     keyI18n: AllI18nKeys; | ||||
|     infoI18n?: AllI18nKeys; | ||||
| interface IColorInputProps extends ITextFieldProps { | ||||
|     value?: number[]; | ||||
|     normal?: boolean; | ||||
|     disable?: boolean; | ||||
|     disableI18n?: AllI18nKeys; | ||||
|     valueChange?: (color: number[]) => any; | ||||
| } | ||||
| 
 | ||||
| @ -65,16 +60,6 @@ class ColorInput extends Component<IColorInputProps, IColorInputState> { | ||||
|         </Callout> | ||||
|     } | ||||
| 
 | ||||
|     private renderErrorInput() { | ||||
|         return <div className="error-box"> | ||||
|             { | ||||
|                 this.props.disableI18n ?  | ||||
|                 <Localization i18nKey={this.props.disableI18n}/> : | ||||
|                 <span>{this.props.value}</span> | ||||
|             } | ||||
|         </div>; | ||||
|     } | ||||
| 
 | ||||
|     private renderColorInput() { | ||||
|         return <> | ||||
|             <div className="color-view"> | ||||
| @ -104,29 +89,21 @@ class ColorInput extends Component<IColorInputProps, IColorInputState> { | ||||
| 
 | ||||
|     public render(): ReactNode { | ||||
|         return <> | ||||
|             <Theme className="color-input-root" fontLevel={FontLevel.normal}> | ||||
|                 <div className="input-intro"> | ||||
|                     <Localization i18nKey={this.props.keyI18n}/> | ||||
|                 </div> | ||||
|                 <div | ||||
|                     className="root-content" | ||||
|                     ref={this.pickerTarget} | ||||
|                     style={{ | ||||
|                         cursor: this.props.disable ? "not-allowed" : "pointer" | ||||
|                     }} | ||||
|                     onClick={() => { | ||||
|                         this.setState({ | ||||
|                             isPickerVisible: !this.props.disable | ||||
|                         }) | ||||
|                     }} | ||||
|                 > | ||||
|                     { this.props.disable ? null : this.renderColorInput() } | ||||
|                     { this.props.disable ? this.renderErrorInput() : null } | ||||
|                 </div> | ||||
|             </Theme> | ||||
| 
 | ||||
|             <TextField | ||||
|                 {...this.props} | ||||
|                 className="color-input" | ||||
|                 keyI18n={this.props.keyI18n} | ||||
|                 targetRef={this.pickerTarget} | ||||
|                 onClick={() => { | ||||
|                     this.setState({ | ||||
|                         isPickerVisible: !this.props.disableI18n | ||||
|                     }) | ||||
|                 }} | ||||
|             > | ||||
|                 { this.renderColorInput() } | ||||
|             </TextField> | ||||
|             {this.state.isPickerVisible ?  this.renderPicker(): null} | ||||
|         </> | ||||
|         </>; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,87 +1,32 @@ | ||||
| @import "../Theme/Theme.scss"; | ||||
| 
 | ||||
| $line-min-height: 26px; | ||||
| $line-min-height: 24px; | ||||
| 
 | ||||
| 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%; | ||||
| div.combo-input { | ||||
| 	 | ||||
|     div.value-view { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         max-width: 180px; | ||||
|         min-height: $line-min-height; | ||||
|         border-radius: 3px; | ||||
|         overflow: hidden; | ||||
|         display: flex; | ||||
|         cursor: pointer; | ||||
|         align-items: center; | ||||
|         padding-left: 8px; | ||||
|         white-space: nowrap; | ||||
|         word-break: keep-all; | ||||
|         text-overflow: ellipsis; | ||||
|         overflow: hidden; | ||||
| 
 | ||||
|         div.value-view { | ||||
|             width: 100%; | ||||
|             height: 100%; | ||||
|             min-height: $line-min-height; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             padding-left: 8px; | ||||
|             white-space: nowrap; | ||||
|             word-break: keep-all; | ||||
|             text-overflow: ellipsis; | ||||
|             overflow: hidden; | ||||
| 
 | ||||
|             span { | ||||
|                 display: block; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         div.list-button { | ||||
|             width: $line-min-height; | ||||
|             height: $line-min-height; | ||||
|             flex-shrink: 0; | ||||
|             display: flex; | ||||
|             justify-content: center; | ||||
|             align-items: center; | ||||
|         span { | ||||
|             display: block; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|     div.list-button { | ||||
|         width: $line-min-height; | ||||
|         height: $line-min-height; | ||||
|         flex-shrink: 0; | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|     } | ||||
| } | ||||
| @ -1,13 +1,10 @@ | ||||
| import { Component, createRef, ReactNode } from "react"; | ||||
| import { FontLevel, Theme } from "@Component/Theme/Theme"; | ||||
| import { PickerList, IDisplayItem } from "../PickerList/PickerList"; | ||||
| import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; | ||||
| import { Icon } from "@fluentui/react"; | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import "./ComboInput.scss"; | ||||
| 
 | ||||
| interface IComboInputProps { | ||||
|     keyI18n: AllI18nKeys; | ||||
|     infoI18n?: AllI18nKeys; | ||||
| interface IComboInputProps extends ITextFieldProps { | ||||
|     allOption?: IDisplayItem[]; | ||||
|     value?: IDisplayItem; | ||||
|     valueChange?: (value: IDisplayItem) => any; | ||||
| @ -53,31 +50,28 @@ class ComboInput extends Component<IComboInputProps, IComboInputState> { | ||||
| 
 | ||||
|     public render(): ReactNode { | ||||
|         return <> | ||||
|             <Theme className="combo-input-root" fontLevel={FontLevel.normal}> | ||||
|                 <div className="input-intro"> | ||||
|                     <Localization i18nKey={this.props.keyI18n}/> | ||||
|             <TextField | ||||
|                 {...this.props} | ||||
|                 targetRef={this.pickerTarget} | ||||
|                 className="combo-input" | ||||
|                 keyI18n={this.props.keyI18n} | ||||
|                 onClick={() => { | ||||
|                     this.setState({ | ||||
|                         isPickerVisible: true | ||||
|                     }) | ||||
|                 }} | ||||
|             > | ||||
|                 <div className="value-view"> | ||||
|                     { | ||||
|                         this.props.value ?  | ||||
|                         <Localization i18nKey={this.props.value.nameKey}/> : | ||||
|                         null | ||||
|                     } | ||||
|                 </div> | ||||
|                 <div | ||||
|                     className="root-content" | ||||
|                     ref={this.pickerTarget} | ||||
|                     onClick={() => { | ||||
|                         this.setState({ | ||||
|                             isPickerVisible: true | ||||
|                         }) | ||||
|                     }} | ||||
|                 > | ||||
|                     <div className="value-view"> | ||||
|                         { | ||||
|                             this.props.value ?  | ||||
|                             <Localization i18nKey={this.props.value.nameKey}/> : | ||||
|                             null | ||||
|                         } | ||||
|                     </div> | ||||
|                     <div className="list-button"> | ||||
|                         <Icon iconName="ChevronDownMed"/> | ||||
|                     </div> | ||||
|                 <div className="list-button"> | ||||
|                     <Icon iconName="ChevronDownMed"/> | ||||
|                 </div> | ||||
|             </Theme> | ||||
|             </TextField> | ||||
| 
 | ||||
|             {this.state.isPickerVisible ?  this.renderPicker(): null} | ||||
|         </> | ||||
|  | ||||
| @ -2,31 +2,6 @@ | ||||
| 
 | ||||
| $line-min-height: 26px; | ||||
| 
 | ||||
| div.label-picker-root { | ||||
| 	width: 100%; | ||||
| 	display: flex; | ||||
| 	flex-wrap: wrap; | ||||
| 	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; | ||||
| 	} | ||||
| div.label-picker { | ||||
|     min-height: $line-min-height; | ||||
| } | ||||
| @ -1,14 +1,12 @@ | ||||
| import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||
| import { PickerList } from "../PickerList/PickerList"; | ||||
| import { Label } from "@Model/Label"; | ||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; | ||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | ||||
| import { Component, ReactNode, createRef } from "react"; | ||||
| import { LabelList } from "../LabelList/LabelList"; | ||||
| import "./LabelPicker.scss" | ||||
| 
 | ||||
| interface ILabelPickerProps { | ||||
| 	keyI18n: AllI18nKeys; | ||||
|     infoI18n?: AllI18nKeys; | ||||
| interface ILabelPickerProps extends ITextFieldProps { | ||||
| 	labels: Label[]; | ||||
| 	labelAdd?: (label: Label) => any; | ||||
| 	labelDelete?: (label: Label) => any; | ||||
| @ -47,47 +45,50 @@ class LabelPicker extends Component<ILabelPickerProps & IMixinStatusProps, ILabe | ||||
| 		return res; | ||||
| 	} | ||||
| 
 | ||||
|     private renderPicker() { | ||||
|         return <PickerList | ||||
|             noData="Common.Attr.Key.Label.Picker.Nodata" | ||||
|             objectList={this.getOtherLabel()} | ||||
|             dismiss={() => { | ||||
|                 this.setState({ | ||||
|                     isPickerVisible: false | ||||
|                 }); | ||||
|             }} | ||||
|             clickObjectItems={(label) => { | ||||
|                 if (label instanceof Label && this.props.labelAdd) { | ||||
|                     this.props.labelAdd(label) | ||||
|                 } | ||||
|                 this.setState({ | ||||
|                     isPickerVisible: false | ||||
|                 }); | ||||
|             }} | ||||
|             target={this.addButtonRef} | ||||
|         />; | ||||
|     } | ||||
| 
 | ||||
| 	public render(): ReactNode { | ||||
| 		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" | ||||
| 					objectList={this.getOtherLabel()} | ||||
| 					dismiss={() => { | ||||
| 						this.setState({ | ||||
| 							isPickerVisible: false | ||||
| 						}); | ||||
| 					}} | ||||
| 					clickObjectItems={(label) => { | ||||
| 						if (label instanceof Label && this.props.labelAdd) { | ||||
| 							this.props.labelAdd(label) | ||||
| 						} | ||||
| 						this.setState({ | ||||
| 							isPickerVisible: false | ||||
| 						}); | ||||
| 					}} | ||||
| 					target={this.addButtonRef} | ||||
| 				/> : null} | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		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>; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										31
									
								
								source/Component/ObjectPicker/ObjectPicker.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								source/Component/ObjectPicker/ObjectPicker.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| @import "../Theme/Theme.scss"; | ||||
| 
 | ||||
| $line-min-height: 24px; | ||||
| 
 | ||||
| div.object-picker { | ||||
| 
 | ||||
|     div.value-view { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         min-height: $line-min-height; | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         white-space: nowrap; | ||||
|         word-break: keep-all; | ||||
|         text-overflow: ellipsis; | ||||
|         overflow: hidden; | ||||
| 
 | ||||
|         span { | ||||
|             display: block; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     div.list-button { | ||||
|         width: $line-min-height; | ||||
|         height: $line-min-height; | ||||
|         flex-shrink: 0; | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|     } | ||||
| } | ||||
| @ -1,12 +1,138 @@ | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { Component, createRef, 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 } from "../PickerList/PickerList"; | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import { Icon } from "@fluentui/react"; | ||||
| import CtrlObject from "@Model/CtrlObject"; | ||||
| import "./ObjectPicker.scss"; | ||||
| 
 | ||||
| interface IObjectPickerProps {} | ||||
| type IObjectType = Label | Group | Range | CtrlObject; | ||||
| 
 | ||||
| class ObjectPicker extends Component<IObjectPickerProps> { | ||||
| 
 | ||||
| 	public render(): ReactNode { | ||||
| 		return <div></div> | ||||
| 	} | ||||
| interface IObjectPickerProps extends ITextFieldProps { | ||||
|     type: Array<"L" | "G" | "R">; | ||||
|     value?: IObjectType; | ||||
|     valueChange?: (value: IObjectType) => any; | ||||
| } | ||||
| 
 | ||||
| export { ObjectPicker } | ||||
| 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; | ||||
|     } | ||||
| 
 | ||||
|     public constructor(props: IObjectPickerProps) { | ||||
|         super(props); | ||||
|         this.state = { | ||||
|             isPickerVisible: false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private pickerTarget = createRef<HTMLDivElement>(); | ||||
| 
 | ||||
|     private renderPicker() { | ||||
|         return <PickerList | ||||
|             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 { | ||||
| 
 | ||||
|         let name = ""; | ||||
|         let icon = "Label"; | ||||
|         if (this.props.value instanceof CtrlObject) { | ||||
|             name = this.props.value.displayName; | ||||
| 
 | ||||
|             if (this.props.value instanceof Range) { | ||||
|                 icon = "CubeShape" | ||||
|             } | ||||
| 
 | ||||
|             if (this.props.value instanceof Group) { | ||||
|                 icon = "WebAppBuilderFragment" | ||||
|             } | ||||
|         } | ||||
|         if (this.props.value instanceof Label) { | ||||
|             name = this.props.value.name; | ||||
|             icon = "tag"; | ||||
|         } | ||||
| 
 | ||||
|         return <> | ||||
|             <TextField | ||||
|                 {...this.props} | ||||
|                 className="object-picker" | ||||
|                 keyI18n={this.props.keyI18n} | ||||
|                 targetRef={this.pickerTarget} | ||||
|                 onClick={() => { | ||||
|                     this.setState({ | ||||
|                         isPickerVisible: true | ||||
|                     }) | ||||
|                 }} | ||||
|             > | ||||
|                 <div className="list-button"> | ||||
|                     <Icon iconName={icon}/> | ||||
|                 </div> | ||||
|                 <div className="value-view"> | ||||
|                     {    | ||||
|                         name ?  | ||||
|                             <span>{name}</span> : | ||||
|                             <Localization i18nKey="Input.Error.Select"/> | ||||
|                     } | ||||
|                 </div> | ||||
|             </TextField> | ||||
| 
 | ||||
|             {this.state.isPickerVisible ?  this.renderPicker(): null} | ||||
|         </> | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export { ObjectPicker, IDisplayItem }; | ||||
							
								
								
									
										84
									
								
								source/Component/TextField/TextField.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								source/Component/TextField/TextField.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| @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; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										104
									
								
								source/Component/TextField/TextField.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								source/Component/TextField/TextField.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| 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,62 +3,40 @@ | ||||
| $line-min-height: 26px; | ||||
| 
 | ||||
| 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 { | ||||
|             width: $line-min-height; | ||||
|             height: $line-min-height; | ||||
|             overflow: hidden; | ||||
|             border-radius: 3px; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             cursor: pointer; | ||||
|             user-select: none; | ||||
|         } | ||||
|     div.checkbox { | ||||
|         width: $line-min-height; | ||||
|         height: $line-min-height; | ||||
|         overflow: hidden; | ||||
|         border-radius: 3px; | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: center; | ||||
|         cursor: pointer; | ||||
|         user-select: none; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| div.dark.toggles-input { | ||||
| div.dark.text-field-root { | ||||
| 
 | ||||
|     div.toggles-content div.checkbox { | ||||
|     div.toggles-input div.checkbox { | ||||
|         background-color: $lt-bg-color-lvl3-dark; | ||||
| 		color: $lt-font-color-normal-dark; | ||||
|     } | ||||
| 
 | ||||
| 	div.toggles-content div.checkbox:hover { | ||||
| 	div.toggles-input div.checkbox:hover { | ||||
| 		background-color: $lt-bg-color-lvl2-dark; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| div.light.toggles-input { | ||||
| div.light.text-field-root { | ||||
| 
 | ||||
|     div.toggles-content div.checkbox { | ||||
|     div.toggles-input div.checkbox { | ||||
|         background-color: $lt-bg-color-lvl3-light; | ||||
| 		color: $lt-font-color-normal-light; | ||||
|     } | ||||
| 
 | ||||
| 	div.toggles-content div.checkbox:hover { | ||||
| 	div.toggles-input div.checkbox:hover { | ||||
| 		background-color: $lt-bg-color-lvl2-light; | ||||
| 	} | ||||
| } | ||||
| @ -1,14 +1,10 @@ | ||||
| import { AllI18nKeys, Localization } from "@Component/Localization/Localization"; | ||||
| import { Theme } from "@Component/Theme/Theme"; | ||||
| import { Icon } from "@fluentui/react"; | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { TextField, ITextFieldProps } from "../TextField/TextField"; | ||||
| import "./TogglesInput.scss"; | ||||
| 
 | ||||
| interface ITogglesInputProps { | ||||
|     keyI18n: AllI18nKeys; | ||||
|     infoI18n?: AllI18nKeys; | ||||
| interface ITogglesInputProps extends ITextFieldProps { | ||||
|     value?: boolean; | ||||
|     disable?: boolean; | ||||
|     onIconName?: string; | ||||
|     offIconName?: string; | ||||
|     valueChange?: (value: boolean) => any; | ||||
| @ -16,39 +12,40 @@ interface ITogglesInputProps { | ||||
| 
 | ||||
| class TogglesInput extends Component<ITogglesInputProps> { | ||||
|     public render(): ReactNode { | ||||
|         return <Theme className="toggles-input"> | ||||
|             <div className="toggles-intro"> | ||||
|                 <Localization i18nKey={this.props.keyI18n}/> | ||||
|             </div> | ||||
|             <div className="toggles-content"> | ||||
|                 <div | ||||
|                     className="checkbox" | ||||
|         return <TextField | ||||
|             {...this.props} | ||||
|             className="toggles-input" | ||||
|             keyI18n={this.props.keyI18n} | ||||
|             customHoverStyle | ||||
|             customStyle | ||||
|         > | ||||
|             <div | ||||
|                 className="checkbox" | ||||
|                 style={{ | ||||
|                     cursor: this.props.disableI18n ? "not-allowed" : "pointer" | ||||
|                 }} | ||||
|                 onClick={(() => { | ||||
|                     if (this.props.disableI18n) { | ||||
|                         return; | ||||
|                     } | ||||
|                     if (this.props.valueChange) { | ||||
|                         this.props.valueChange(!this.props.value); | ||||
|                     } | ||||
|                 })} | ||||
|             > | ||||
|                 <Icon | ||||
|                     iconName={ | ||||
|                         this.props.value ?  | ||||
|                             this.props.onIconName ?? "CheckMark" : | ||||
|                             this.props.offIconName ?? undefined | ||||
|                     } | ||||
|                     style={{ | ||||
|                         cursor: this.props.disable ? "not-allowed" : "pointer" | ||||
|                         display: this.props.value ? "inline-block" :  | ||||
|                             this.props.offIconName ? "inline-block" : "none" | ||||
|                     }} | ||||
|                     onClick={(() => { | ||||
|                         if (this.props.disable) { | ||||
|                             return; | ||||
|                         } | ||||
|                         if (this.props.valueChange) { | ||||
|                             this.props.valueChange(!this.props.value); | ||||
|                         } | ||||
|                     })} | ||||
|                 > | ||||
|                     <Icon | ||||
|                         iconName={ | ||||
|                             this.props.value ?  | ||||
|                                 this.props.onIconName ?? "CheckMark" : | ||||
|                                 this.props.offIconName ?? undefined | ||||
|                         } | ||||
|                         style={{ | ||||
|                             display: this.props.value ? "inline-block" :  | ||||
|                                 this.props.offIconName ? "inline-block" : "none" | ||||
|                         }} | ||||
|                     ></Icon> | ||||
|                 </div>     | ||||
|             </div> | ||||
|         </Theme> | ||||
|                 /> | ||||
|             </div>   | ||||
|         </TextField>; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -24,6 +24,7 @@ const EN_US = { | ||||
|     "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.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.Range": "Range object {id}", | ||||
|     "Object.List.New.Label": "Label {id}", | ||||
| @ -43,6 +44,7 @@ const EN_US = { | ||||
|     "Panel.Title.Group.Details.View": "Group", | ||||
|     "Panel.Info.Group.Details.View": "Edit view group attributes", | ||||
|     "Common.No.Data": "No Data", | ||||
|     "Common.No.Unknown.Error": "Unknown error", | ||||
|     "Common.Attr.Title.Basic": "Basic properties", | ||||
|     "Common.Attr.Title.Spatial": "Spatial property", | ||||
|     "Common.Attr.Title.Individual.Generation": "Individual generation", | ||||
| @ -65,6 +67,7 @@ const EN_US = { | ||||
|     "Common.Attr.Key.Generation.Mod": "Generation model", | ||||
|     "Common.Attr.Key.Generation.Mod.Point": "Point model", | ||||
|     "Common.Attr.Key.Generation.Mod.Range": "Range model", | ||||
|     "Common.Attr.Key.Generation.Use.Range": "Generation 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.Group.Details.Attr.Error.Not.Group": "Object is not a Group", | ||||
|  | ||||
| @ -24,6 +24,7 @@ const ZH_CN = { | ||||
|     "Input.Error.Min": "输入数值须大于 {number}", | ||||
|     "Input.Error.Length": "输入内容长度须小于 {number}", | ||||
|     "Input.Error.Length.Less": "输入内容长度须大于 {number}", | ||||
|     "Input.Error.Select": "选择对象 ...", | ||||
|     "Object.List.New.Group": "组对象 {id}", | ||||
|     "Object.List.New.Range": "范围对象 {id}", | ||||
|     "Object.List.New.Label": "标签 {id}", | ||||
| @ -43,6 +44,7 @@ const ZH_CN = { | ||||
|     "Panel.Title.Group.Details.View": "群", | ||||
|     "Panel.Info.Group.Details.View": "编辑查看群属性", | ||||
|     "Common.No.Data": "暂无数据", | ||||
|     "Common.No.Unknown.Error": "未知错误", | ||||
|     "Common.Attr.Title.Basic": "基础属性", | ||||
|     "Common.Attr.Title.Spatial": "空间属性", | ||||
|     "Common.Attr.Title.Individual.Generation": "个体生成", | ||||
| @ -65,6 +67,7 @@ const ZH_CN = { | ||||
|     "Common.Attr.Key.Generation.Mod": "生成模式", | ||||
|     "Common.Attr.Key.Generation.Mod.Point": "点生成", | ||||
|     "Common.Attr.Key.Generation.Mod.Range": "范围生成", | ||||
|     "Common.Attr.Key.Generation.Use.Range": "生成范围", | ||||
|     "Panel.Info.Range.Details.Attr.Error.Not.Range": "对象不是一个范围", | ||||
|     "Panel.Info.Range.Details.Attr.Error.Unspecified": "未指定范围对象", | ||||
|     "Panel.Info.Group.Details.Attr.Error.Not.Group": "对象不是一个群", | ||||
|  | ||||
| @ -90,6 +90,31 @@ 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,6 +9,7 @@ import { LabelPicker } from "@Component/LabelPicker/LabelPicker"; | ||||
| import { Group, GenMod } from "@Model/Group"; | ||||
| import { AllI18nKeys } from "@Component/Localization/Localization"; | ||||
| import { ComboInput, IDisplayItem } from "@Component/ComboInput/ComboInput"; | ||||
| import { ObjectPicker } from "@Component/ObjectPicker/ObjectPicker"; | ||||
| import "./GroupDetails.scss"; | ||||
| 
 | ||||
| interface IGroupDetailsProps {} | ||||
| @ -137,6 +138,11 @@ class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> { | ||||
|                     } | ||||
|                 }} | ||||
|             /> | ||||
| 
 | ||||
|             <ObjectPicker | ||||
|                 keyI18n="Common.Attr.Key.Generation.Use.Range" | ||||
|                 type={["L", "G", "R"]} | ||||
|             /> | ||||
| 		</> | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user