-
Notifications
You must be signed in to change notification settings - Fork 28
feat: textarea问题修复 #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| export * from './button'; | ||
| export * from './icon'; | ||
| export * from './textarea'; | ||
| export * from './space'; | ||
| export * from './switch'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| --- | ||
| title: Textarea 文本框 | ||
| description: 通过鼠标或键盘输入多行内容。 | ||
| isComponent: true | ||
| usage: { title: '', description: '' } | ||
| spline: base | ||
| --- | ||
|
|
||
| ### 基础使用 | ||
|
|
||
| 高度自适应 | ||
|
|
||
| {{ base }} | ||
|
|
||
| ### 自定义事件 | ||
|
|
||
| {{ event }} | ||
|
|
||
| ### 字数限制 | ||
|
|
||
| 支持中文和英文字符数限制 | ||
|
|
||
| {{ limit }} | ||
|
|
||
| ### 自定义状态 | ||
|
|
||
| 支持禁用、只读,和default/success/warning/error四种status状态 | ||
|
|
||
| {{ status }} | ||
|
|
||
|
|
||
|
|
||
|
|
||
| ## API | ||
|
|
||
| ### Textarea Props | ||
|
|
||
| 名称 | 类型 | 默认值 | 说明 | 必传 | ||
| -- | -- | -- | -- | -- | ||
| allowInputOverMax | Boolean | false | 超出`maxlength`或`maxcharacter`之后是否还允许输入 | N | ||
| autofocus | Boolean | false | 自动聚焦,拉起键盘 | N | ||
| autosize | Boolean/Object | false | 高度自动撑开。Object属性:`minRows:number,maxRows:number`。autosize = true 表示组件高度自动撑开,同时,依旧允许手动拖高度。如果设置了 autosize.maxRows 或者 autosize.minRows 则不允许手动调整高度 | N | ||
| disabled | Boolean | false | 是否禁用文本框 | N | ||
| label | TNode | - | 左侧文本 | N | ||
| maxcharacter | Number | - | 用户最多可以输入的字符个数,一个中文汉字表示两个字符长度 | N | ||
| maxlength | Number | - | 用户最多可以输入的字符个数 | N | ||
| name | String | - | 名称 | N | ||
| placeholder | String | '' | 占位符 | N | ||
| readonly | Boolean | false | 只读状态 | N | ||
| status | String | - | 文本框状态。可选项:`default/success/warning/error` | N | ||
| tips | TNode | - | 输入框下方提示文本 | N | ||
| value | String | - | 文本框值 | N | ||
| defaultValue | String | - | 文本框值,非受控属性 | N | ||
| onBlur | Function | | TS 类型:`(value: string, context: FocusEvent) => void`<br/>失去焦点时触发 | N | ||
| onFocus | Function | | TS 类型:`(value: string, context: FocusEvent) => void`<br/>获得焦点时触发 | N | ||
| onKeydown | Function | | TS 类型:`(value: string, context: KeyboardEvent) => void`<br/>键盘按下时触发 | N | ||
| onKeypress | Function | | TS 类型:`(value: string, context: KeyboardEvent) => void`<br/>按下字符键时触发 | N | ||
| onKeyup | Function | | TS 类型:`(value: string, context: KeyboardEvent) => void`<br/>释放键盘时触发 | N | ||
| onChange | Function | | TS 类型:`(value: string, context: Event) => void`<br/>输入内容变化时触发 | N | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import 'tdesign-web-components/textarea'; | ||
|
|
||
| export default function Textarea() { | ||
|
|
||
| return ( | ||
| <div style={{ gap: 16, display: 'flex', flexDirection: 'column' }}> | ||
| <t-textarea placeholder="请输入描述文案"></t-textarea> | ||
| <t-textarea placeholder="请输入文案,高度可自适应;autosize=true" autosize={true}></t-textarea> | ||
| <t-textarea placeholder="请输入文案,高度可自适应,最小3行,最大5行;autosize={minRows: 3, maxRows: 5}" autosize={{minRows: 3, maxRows: 5}}></t-textarea> | ||
| </div> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import 'tdesign-web-components/textarea'; | ||
|
|
||
| export default function Textarea() { | ||
| const value = ''; | ||
|
|
||
| const onBlur = (value, { e }) => { | ||
| console.log('onBlur: ', value, e); | ||
| }; | ||
|
|
||
| const onFocus = (value, { e }) => { | ||
| console.log('onFocus: ', value, e); | ||
| }; | ||
|
|
||
| const onKeyup = (value, { e }) => { | ||
| console.log('onKeyup', value, e); | ||
| }; | ||
|
|
||
| const onKeypress = (value, { e }) => { | ||
| console.log('onKeypress', value, e); | ||
| }; | ||
|
|
||
| const onKeydown = (value, { e }) => { | ||
| console.log('onKeydown', value, e); | ||
| }; | ||
| const onChange = (value, { e }) => { | ||
| console.log('onChange', value, e); | ||
| }; | ||
|
|
||
| return ( | ||
| <t-textarea | ||
| placeholder="请输入" | ||
| value={value} | ||
| onBlur={onBlur} | ||
| onFocus={onFocus} | ||
| onKeypress={onKeypress} | ||
| onKeydown={onKeydown} | ||
| onKeyup={onKeyup} | ||
| onChange={onChange} | ||
| ></t-textarea> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import 'tdesign-web-components/textarea'; | ||
| import 'tdesign-web-components/space'; | ||
|
|
||
| export default function Textarea() { | ||
| return ( | ||
| <t-space direction="vertical" style={{ gap: 16, display: 'flex', flexDirection: 'column' }}> | ||
| <t-textarea placeholder="请输入描述文案,文本长度最多20,maxlength=20" maxlength="20"></t-textarea> | ||
| <t-textarea | ||
| placeholder="请输入描述文案,最多20字符(一个汉字占两个字符长度),maxcharacter=20" | ||
| maxcharacter="20" | ||
| ></t-textarea> | ||
| </t-space> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import 'tdesign-web-components/textarea'; | ||
| import 'tdesign-web-components/space'; | ||
|
|
||
| export default function Textarea() { | ||
| return ( | ||
| <t-space direction="vertical" style={{ gap: 16, display: 'flex', flexDirection: 'column' }}> | ||
| <t-textarea placeholder="禁用状态" disabled="true"></t-textarea> | ||
| <t-textarea placeholder="只读状态" readonly="true"></t-textarea> | ||
| <t-textarea placeholder="普通状态" readonly="true" tips="这是普通文本提示"></t-textarea> | ||
| <t-textarea placeholder="成功状态" tips="校验通过文本提示" status="success"></t-textarea> | ||
| <t-textarea placeholder="警告状态" tips="校验不通过文本提示" status="warning"></t-textarea> | ||
| <t-textarea placeholder="错误状态" tips="校验存在严重问题文本提示" status="error"></t-textarea> | ||
| </t-space> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import './style/index.js'; | ||
|
|
||
| import _Textarea from './textarea'; | ||
|
|
||
| export type { TextareaProps } from './textarea'; | ||
| export const Textarea = _Textarea; | ||
| export default Textarea; | ||
|
|
||
| export * from './type'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { css, globalCSS } from 'omi'; | ||
|
|
||
| // 为了做主题切换 | ||
| import styles from '../../_common/style/web/components/textarea/_index.less'; | ||
|
|
||
| export const styleSheet = css` | ||
| ${styles} | ||
| `; | ||
|
|
||
| globalCSS(styleSheet); | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| import { bind, classNames, Component, createRef, tag } from 'omi'; | ||
|
|
||
| import calcTextareaHeight from '../_common/js/utils/calcTextareaHeight'; | ||
| import { getCharacterLength, limitUnicodeMaxLength } from '../_common/js/utils/helper'; | ||
| import { getClassPrefix } from '../_util/classname'; | ||
| import { TdTextareaProps } from './type'; | ||
|
|
||
| export type TextareaProps = TdTextareaProps; | ||
| @tag('t-textarea') | ||
| export default class Textarea extends Component<TdTextareaProps> { | ||
| static css = []; | ||
|
|
||
| constructor() { | ||
| super(); | ||
| this.props = { | ||
| allowInputOverMax: false, | ||
| autofocus: false, | ||
| autosize: false, | ||
| disabled: false, | ||
| readonly: false, | ||
| value: '', | ||
| ...this.props, | ||
| }; | ||
| } | ||
|
|
||
| value = ''; | ||
|
|
||
| isFocused = false; | ||
|
|
||
| eventPropsNames; | ||
|
|
||
| eventProps; | ||
|
|
||
| classPrefix = getClassPrefix(); | ||
|
|
||
| installed() { | ||
| const { value, disabled, ...otherProps } = this.props; | ||
| this.value = value; | ||
| this.eventPropsNames = Object.keys(otherProps).filter((key) => /^on[A-Z]/.test(key)); | ||
| this.eventProps = this.eventPropsNames.reduce((eventProps, key) => { | ||
| Object.assign(eventProps, { | ||
| [key]: (e) => { | ||
| if (disabled) return; | ||
| if (key === 'onFocus') { | ||
| this.isFocused = true; | ||
| this.update(); | ||
| } | ||
| if (key === 'onBlur') { | ||
| this.isFocused = false; | ||
| this.update(); | ||
| } | ||
| this.props[key](e.currentTarget.value, { e }); | ||
| e.stopPropagation(); | ||
| }, | ||
| }); | ||
| return eventProps; | ||
| }, {}); | ||
|
|
||
| this.update(); | ||
|
|
||
| const node = this.textArea.current; | ||
| this.value = node.value; | ||
| this.onInput(); | ||
| } | ||
|
|
||
| countCharacters(text: string) { | ||
| // 按照一个中文汉字等于一个字符长度计算 | ||
| const chineseCharacterRegex = /[\u4e00-\u9fa5]/g; | ||
| const chineseCharacters = text.match(chineseCharacterRegex) || []; | ||
| return text.length + chineseCharacters.length; | ||
| } | ||
|
|
||
| // textarea ref | ||
| textArea = createRef<any>(); | ||
|
|
||
| getTextareaStatus(status: string) { | ||
| return `${this.classPrefix}-is-${status || ''}`; | ||
| } | ||
|
|
||
| getTipsStyle(status: string) { | ||
| return `${this.classPrefix}-textarea__tips--${status}`; | ||
| } | ||
|
|
||
| getTextareaIsDisabled(disabled: boolean) { | ||
| return `${this.classPrefix}-is-${disabled ? 'disabled' : ''}`; | ||
| } | ||
|
|
||
| textareaClassPrefix = `${this.classPrefix}-textarea`; | ||
|
|
||
| cls() { | ||
| return classNames(`${this.textareaClassPrefix}__inner`, { | ||
| [`${this.classPrefix}-is-${this.props.status}`]: this.props.status, | ||
| [`${this.classPrefix}-is-disabled`]: this.props.disabled, | ||
| [`${this.classPrefix}-is-focused`]: this.isFocused, | ||
| [`${this.classPrefix}-resize-none`]: typeof this.props.autosize === 'object', | ||
| }); | ||
| } | ||
|
|
||
| setHeight(heightObj) { | ||
| const node = this.textArea.current; | ||
| const clacMinHeight = heightObj.minHeight; | ||
| const clacHeight = heightObj.height; | ||
| node.style.minHeight = clacMinHeight; | ||
| node.style.height = clacHeight; | ||
| } | ||
|
|
||
| @bind | ||
| onInput() { | ||
| const node = this.textArea.current; | ||
| const { autosize, maxcharacter } = this.props; | ||
| if (autosize === true) { | ||
| const heightObj = calcTextareaHeight(node); | ||
| this.setHeight(heightObj); | ||
| } else if (typeof autosize === 'object') { | ||
| const heightObj = calcTextareaHeight(node, autosize?.minRows, autosize?.maxRows); | ||
| this.setHeight(heightObj); | ||
| } | ||
| if (maxcharacter) { | ||
| const text = node.value; | ||
| const length = this.countCharacters(text); | ||
| if (length > maxcharacter) { | ||
| if (text[text.length - 1].match('/[\u4e00-\u9fa5]/g')) { | ||
| node.value = text.slice(0, maxcharacter - 1); | ||
| } else { | ||
| node.value = text.slice(0, maxcharacter); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| onChange(e) { | ||
| const { target } = e; | ||
| let val = (target as HTMLInputElement).value; | ||
| if (!this.props?.allowInputOverMax && !this.textArea.current) { | ||
| val = limitUnicodeMaxLength(val, this.props?.maxlength); | ||
| if (this.props?.maxcharacter && this.props?.maxcharacter >= 0) { | ||
| const stringInfo = getCharacterLength(val, this.props?.maxcharacter); | ||
| val = typeof stringInfo === 'object' && stringInfo.characters; | ||
| } | ||
| } | ||
| // setValue(val, { e }); | ||
| this.value = val; | ||
|
|
||
| this.props?.onChange(val, { e }); | ||
| this.update(); | ||
| } | ||
|
|
||
| render(props: TextareaProps) { | ||
| const { autofocus, placeholder, readonly, status, disabled, tips, maxlength, maxcharacter } = props; | ||
|
|
||
| return ( | ||
| <> | ||
| <div class={classNames(`${this.classPrefix}-textarea`)}> | ||
| <textarea | ||
| {...this.eventProps} | ||
| class={this.cls()} | ||
| value={this.value} | ||
| placeholder={placeholder} | ||
| readonly={readonly} | ||
| disabled={disabled} | ||
| autofocus={autofocus} | ||
| maxlength={maxlength} | ||
| maxcharacter={maxcharacter} | ||
| onChange={(e) => this.onChange(e)} | ||
| onInput={this.onInput} | ||
| ref={this.textArea} | ||
| ></textarea> | ||
| {tips && <div class={classNames(`${this.classPrefix}-tips`, this.getTipsStyle(status))}>{tips}</div>} | ||
| </div> | ||
| </> | ||
| ); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
测试