Skip to content

feat(textarea): support readonly and allowInputOverMax props #3474

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 3 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/textarea/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,20 @@ isComponent: true

{{ maxcharacter }}

允许超出最大字符个数

{{ allowInputOverMax }}

### 组件状态

禁用多行文本框

{{ disabled }}

多行文本框只读

{{ readonly }}

### 自定义组件样式

标签外置输入框
Expand Down Expand Up @@ -81,13 +89,15 @@ cursor | Number | -1 | 指定 focus 时的光标位置 | N
cursor-spacing | Number | 0 | 指定光标与键盘的距离。取textarea距离底部的距离和cursor-spacing指定的距离的最小值作为光标与键盘的距离 | N
disable-default-padding | Boolean | false | 是否去掉 iOS 下的默认内边距 | N
disabled | Boolean | undefined | 是否禁用文本框 | N
readonly | Boolean | undefined | 是否只读 | N
fixed | Boolean | false | 如果 textarea 是在一个 `position:fixed` 的区域,需要显式指定属性 fixed 为 true | N
focus | Boolean | false | 自动聚焦 | N
hold-keyboard | Boolean | false | focus时,点击页面的时候不收起键盘 | N
indicator | Boolean | false | 显示文本计数器,如 0/140。当 `maxlength < 0 && maxcharacter < 0` 成立时, indicator无效 | N
label | String / Slot | - | 左侧文本。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
maxcharacter | Number | - | 用户最多可以输入的字符个数,一个中文汉字表示两个字符长度 | N
maxlength | Number | -1 | 用户最多可以输入的字符个数,值为 -1 的时候不限制最大长度 | N
allowInputOverMax | Boolean | false | 是否允许超出最大字符数限制,默认不允许 | N
placeholder | String | undefined | 占位符 | N
placeholder-style | String | - | 指定 placeholder 的样式,目前仅支持 color ,font-size和font-weight | N
selection-end | Number | -1 | 光标结束位置,自动聚集时有效,需与 selection-start 搭配使用 | N
Expand Down
13 changes: 12 additions & 1 deletion src/textarea/__test__/demo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@
import path from 'path';
import simulate from 'miniprogram-simulate';

const mapper = ['autosize', 'base', 'card', 'custom', 'disabled', 'label', 'maxcharacter', 'maxlength'];
const mapper = [
'allowInputOverMax',
'autosize',
'base',
'card',
'custom',
'disabled',
'label',
'maxcharacter',
'maxlength',
'readonly',
];

describe('Textarea', () => {
mapper.forEach((demoName) => {
Expand Down
48 changes: 48 additions & 0 deletions src/textarea/__test__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,54 @@ describe('textarea', () => {
await simulate.sleep(0);
expect(component.instance.data.count).toBe(10);
});

it(': allowInputOverMax', async () => {
const handleChange = jest.fn();
const id = simulate.load({
template: `<t-textarea
class="base"
maxcharacter="{{maxcharacter}}"
allowInputOverMax
value="{{value}}"
bind:change="handleChange"
>
</t-textarea>`,
data: {
maxcharacter: 10,
value: 'tdesign',
},
methods: {
handleChange,
},
usingComponents: {
't-textarea': textarea,
},
});
const comp = simulate.render(id);
comp.attach(document.createElement('parent-wrapper'));
const component = comp.querySelector('.base');
expect(component.instance.data.count).toBe(7);

const $textarea = comp.querySelector('.base >>> .t-textarea__wrapper-inner');

$textarea.dispatchEvent('input', { detail: { value: 'tdesign123' } });
await simulate.sleep(0);
expect(handleChange).toHaveBeenCalledTimes(1);
expect(component.instance.data.count).toBe(10);

$textarea.dispatchEvent('input', { detail: { value: 'textarea用于多行文本信息输入' } });
await simulate.sleep(0);
expect(handleChange).toHaveBeenCalledTimes(2);
expect(component.instance.data.count).toBe(28);
expect(handleChange.mock.calls[1][0].detail).toStrictEqual({
value: 'textarea用于多行文本信息输入',
cursor: undefined,
});

$textarea.dispatchEvent('textarea', { detail: { value: 'textarea用于567' } });
await simulate.sleep(0);
expect(component.instance.data.count).toBe(15);
});
});

describe('slots', () => {
Expand Down
1 change: 1 addition & 0 deletions src/textarea/_example/allowInputOverMax/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Component({});
6 changes: 6 additions & 0 deletions src/textarea/_example/allowInputOverMax/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-textarea": "tdesign-miniprogram/textarea/textarea"
}
}
9 changes: 9 additions & 0 deletions src/textarea/_example/allowInputOverMax/index.wxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<t-textarea
t-class="external-class"
label="标签文字"
placeholder="允许输入超出最大字符个数限制"
maxlength="20"
allowInputOverMax
disableDefaultPadding="{{true}}"
indicator
/>
3 changes: 3 additions & 0 deletions src/textarea/_example/allowInputOverMax/index.wxss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.external-class {
height: 324rpx;
}
1 change: 1 addition & 0 deletions src/textarea/_example/readonly/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Component({});
6 changes: 6 additions & 0 deletions src/textarea/_example/readonly/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-textarea": "tdesign-miniprogram/textarea/textarea"
}
}
1 change: 1 addition & 0 deletions src/textarea/_example/readonly/index.wxml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<t-textarea t-class="external-class" label="标签文字" placeholder="请输入文字" value="只读模式" readonly />
3 changes: 3 additions & 0 deletions src/textarea/_example/readonly/index.wxss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.external-class {
height: 256rpx;
}
2 changes: 2 additions & 0 deletions src/textarea/_example/textarea.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
"label": "./label",
"autosize": "./autosize",
"disabled": "./disabled",
"readonly": "./readonly",
"maxcharacter": "./maxcharacter",
"maxlength": "./maxlength",
"allow-input-over-max": "./allowInputOverMax",
"card": "./card",
"custom": "./custom"
}
Expand Down
6 changes: 6 additions & 0 deletions src/textarea/_example/textarea.wxml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@
<t-demo>
<maxcharacter />
</t-demo>
<t-demo desc="允许输入超出最大字符个数限制">
<allow-input-over-max />
</t-demo>
<t-demo title="02 组件状态" desc="禁用状态">
<disabled />
</t-demo>
<t-demo desc="只读状态">
<readonly />
</t-demo>
<t-demo title="03 组件样式" desc="卡片样式">
<card />
</t-demo>
Expand Down
10 changes: 10 additions & 0 deletions src/textarea/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ const props: TdTextareaProps = {
type: null,
value: undefined,
},
/** 是否只读状态 */
readonly: {
type: null,
value: undefined,
},
/** 如果 textarea 是在一个 `position:fixed` 的区域,需要显式指定属性 fixed 为 true */
fixed: {
type: Boolean,
Expand Down Expand Up @@ -89,6 +94,11 @@ const props: TdTextareaProps = {
type: Number,
value: -1,
},
/** 是否允许超出最大字符数限制,默认不允许 */
allowInputOverMax: {
type: Boolean,
value: false,
},
/** 占位符 */
placeholder: {
type: String,
Expand Down
5 changes: 3 additions & 2 deletions src/textarea/textarea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,15 @@ export default class Textarea extends SuperComponent {
},

calculateValue(value, maxcharacter, maxlength) {
if (maxcharacter > 0 && !Number.isNaN(maxcharacter)) {
const { allowInputOverMax } = this.properties;
if (!allowInputOverMax && maxcharacter > 0 && !Number.isNaN(maxcharacter)) {
const { length, characters } = getCharacterLength('maxcharacter', value, maxcharacter);
return {
value: characters,
count: length,
};
}
if (maxlength > 0 && !Number.isNaN(maxlength)) {
if (!allowInputOverMax && maxlength > 0 && !Number.isNaN(maxlength)) {
const { length, characters } = getCharacterLength('maxlength', value, maxlength);
return {
value: characters,
Expand Down
4 changes: 2 additions & 2 deletions src/textarea/textarea.wxml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<textarea
class="{{classPrefix}}__wrapper-inner {{disabled? prefix + '-is-disabled' : ''}} {{prefix}}-class-textarea"
style="{{this.textareaStyle(autosize)}}"
maxlength="{{maxlength}}"
disabled="{{disabled}}"
maxlength="{{!allowInputOverMax && maxlength}}"
disabled="{{disabled || readonly}}"
placeholder="{{placeholder}}"
placeholder-class="{{classPrefix}}__placeholder"
placeholder-style="{{placeholderStyle}}"
Expand Down
14 changes: 14 additions & 0 deletions src/textarea/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ export interface TdTextareaProps {
type: BooleanConstructor;
value?: boolean;
};
/**
* 只读状态
*/
readonly?: {
type: BooleanConstructor;
value?: boolean;
};
/**
* 如果 textarea 是在一个 `position:fixed` 的区域,需要显式指定属性 fixed 为 true
* @default false
Expand Down Expand Up @@ -138,6 +145,13 @@ export interface TdTextareaProps {
type: NumberConstructor;
value?: number;
};
/**
* 是否允许超出最大字符数限制
*/
allowInputOverMax?: {
type: BooleanConstructor;
value?: boolean;
};
/**
* 占位符
*/
Expand Down
Loading