-
Notifications
You must be signed in to change notification settings - Fork 80
feat(text-area): add support for minLength
#10970
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
base: dev
Are you sure you want to change the base?
Changes from 4 commits
7e7a588
d0bd9b4
dc0b7ed
42ba789
40ed428
079d1dd
246993c
6b4d1f4
6608343
7a490d3
ac7be20
8da4580
2bcdf3d
42b7b79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
{ | ||
"invalid": "Invalid", | ||
"tooLong": "The current character length is {currentLength}, which exceeds the maximum character length of {maxLength}." | ||
"tooLong": "The current character length is {currentLength}, which exceeds the maximum character length of {maxLength}.", | ||
"tooShort": "The current character length is {currentLength}, which does not reach the min character length of {minLength}." | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
{ | ||
"invalid": "Invalid", | ||
"tooLong": "The current character length is {currentLength}, which exceeds the maximum character length of {maxLength}." | ||
"tooLong": "The current character length is {currentLength}, which exceeds the maximum character length of {maxLength}.", | ||
"tooShort": "The current character length is {currentLength}, which does not reach the min character length of {minLength}." | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
export interface CharacterLengthObj { | ||
currentLength: string; | ||
maxLength: string; | ||
minLength: string; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -161,7 +161,7 @@ export class TextArea | |
@property() label: string; | ||
|
||
/** | ||
* Specifies the maximum number of characters allowed. | ||
* Specifies the maximum number of characters allowed. Must be greater than or equal to the value of `minlength`, if present and valid. | ||
Elijbet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* @mdn [maxlength](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#attr-maxlength) | ||
*/ | ||
|
@@ -178,7 +178,7 @@ export class TextArea | |
messages = useT9n<typeof T9nStrings>({ blocking: true }); | ||
|
||
/** | ||
* Specifies the minimum number of characters allowed. | ||
* Specifies the minimum number of characters allowed. Must be less than or equal to the value of `maxlength`, if present and valid. | ||
* | ||
* @mdn [minlength](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#attr-minlength) | ||
*/ | ||
|
@@ -361,8 +361,9 @@ export class TextArea | |
private getLocalizedCharacterLength(): CharacterLengthObj { | ||
const currentLength = this.value ? this.value.length.toString() : "0"; | ||
const maxLength = this.maxLength.toString(); | ||
const minLength = this.minLength.toString(); | ||
if (this.numberingSystem === "latn") { | ||
return { currentLength, maxLength }; | ||
return { currentLength, maxLength, minLength }; | ||
} | ||
|
||
numberStringFormatter.numberFormatOptions = { | ||
|
@@ -374,13 +375,17 @@ export class TextArea | |
return { | ||
currentLength: numberStringFormatter.localize(currentLength), | ||
maxLength: numberStringFormatter.localize(maxLength), | ||
minLength: numberStringFormatter.localize(minLength), | ||
}; | ||
} | ||
|
||
syncHiddenFormInput(input: HTMLInputElement): void { | ||
input.setCustomValidity(""); | ||
if (this.isCharacterLimitExceeded()) { | ||
input.setCustomValidity(this.replacePlaceholdersInMessages()); | ||
if (this.isCharacterOverMaxLimit()) { | ||
input.setCustomValidity(this.replacePlaceholdersInLongMessages()); | ||
} | ||
if (this.isCharacterUnderMinLimit()) { | ||
Elijbet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
input.setCustomValidity(this.replacePlaceholdersInShortMessages()); | ||
} | ||
|
||
syncHiddenFormInput("textarea", this, input); | ||
|
@@ -426,34 +431,50 @@ export class TextArea | |
}; | ||
} | ||
|
||
private replacePlaceholdersInMessages(): string { | ||
private replacePlaceholdersInLongMessages(): string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: can we use a different name here to be more meaningful.
|
||
return this.messages.tooLong | ||
.replace("{maxLength}", this.localizedCharacterLengthObj.maxLength) | ||
.replace("{currentLength}", this.localizedCharacterLengthObj.currentLength); | ||
.replace("{currentLength}", this.localizedCharacterLengthObj.currentLength) | ||
.replace("{maxLength}", this.localizedCharacterLengthObj.maxLength); | ||
} | ||
|
||
private replacePlaceholdersInShortMessages(): string { | ||
Elijbet marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: can we use a different name here to be more meaningful. replaceMinLengthPlaceHolderMessage( ) or getMinLengthMessage( ). |
||
return this.messages.tooShort | ||
.replace("{currentLength}", this.localizedCharacterLengthObj.currentLength) | ||
.replace("{minLength}", this.localizedCharacterLengthObj.minLength); | ||
} | ||
|
||
private isCharacterLimitExceeded(): boolean { | ||
private isCharacterOverMaxLimit(): boolean { | ||
return this.value?.length > this.maxLength; | ||
} | ||
|
||
private isCharacterUnderMinLimit(): boolean { | ||
return this.value?.length < this.minLength; | ||
} | ||
|
||
// #endregion | ||
|
||
// #region Rendering | ||
|
||
override render(): JsxNode { | ||
const hasFooter = this.startSlotHasElements || this.endSlotHasElements || !!this.maxLength; | ||
const hasFooter = | ||
this.startSlotHasElements || this.endSlotHasElements || !!this.maxLength || !!this.minLength; | ||
return ( | ||
<InteractiveContainer disabled={this.disabled}> | ||
<textarea | ||
aria-describedby={this.guid} | ||
aria-errormessage={IDS.validationMessage} | ||
ariaInvalid={this.status === "invalid" || this.isCharacterLimitExceeded()} | ||
ariaInvalid={ | ||
this.status === "invalid" || | ||
this.isCharacterOverMaxLimit() || | ||
this.isCharacterUnderMinLimit() | ||
} | ||
ariaLabel={getLabelText(this)} | ||
autofocus={this.el.autofocus} | ||
class={{ | ||
[CSS.textArea]: true, | ||
[CSS.readOnly]: this.readOnly, | ||
[CSS.textAreaInvalid]: this.isCharacterLimitExceeded(), | ||
[CSS.textAreaInvalid]: | ||
this.isCharacterOverMaxLimit() || this.isCharacterUnderMinLimit(), | ||
Elijbet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[CSS.footerSlotted]: this.endSlotHasElements && this.startSlotHasElements, | ||
[CSS.textAreaOnly]: !hasFooter, | ||
}} | ||
|
@@ -504,9 +525,14 @@ export class TextArea | |
{this.renderCharacterLimit()} | ||
</footer> | ||
<HiddenFormInputSlot component={this} /> | ||
{this.isCharacterLimitExceeded() && ( | ||
{this.isCharacterOverMaxLimit() && ( | ||
<span ariaLive="polite" class={CSS.assistiveText} id={this.guid}> | ||
{this.replacePlaceholdersInMessages()} | ||
{this.replacePlaceholdersInLongMessages()} | ||
</span> | ||
)} | ||
{this.isCharacterUnderMinLimit() && ( | ||
<span ariaLive="polite" class={CSS.assistiveText} id={this.guid}> | ||
{this.replacePlaceholdersInShortMessages()} | ||
</span> | ||
)} | ||
{this.validationMessage && this.status === "invalid" ? ( | ||
|
@@ -527,7 +553,12 @@ export class TextArea | |
this.localizedCharacterLengthObj = this.getLocalizedCharacterLength(); | ||
return ( | ||
<span class={CSS.characterLimit}> | ||
<span class={{ [CSS.characterOverLimit]: this.isCharacterLimitExceeded() }}> | ||
<span | ||
class={{ | ||
[CSS.characterPastLimit]: | ||
this.isCharacterOverMaxLimit() || this.isCharacterUnderMinLimit(), | ||
}} | ||
> | ||
{this.localizedCharacterLengthObj.currentLength} | ||
</span> | ||
{"/"} | ||
|
Uh oh!
There was an error while loading. Please reload this page.