mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-23 05:58:26 +08:00
feat(radio): add helperText and errorText properties
This commit is contained in:
@ -1323,6 +1323,8 @@ ion-radio,shadow
|
|||||||
ion-radio,prop,alignment,"center" | "start" | undefined,undefined,false,false
|
ion-radio,prop,alignment,"center" | "start" | undefined,undefined,false,false
|
||||||
ion-radio,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
ion-radio,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
|
||||||
ion-radio,prop,disabled,boolean,false,false,false
|
ion-radio,prop,disabled,boolean,false,false,false
|
||||||
|
ion-radio,prop,errorText,string | undefined,undefined,false,false
|
||||||
|
ion-radio,prop,helperText,string | undefined,undefined,false,false
|
||||||
ion-radio,prop,justify,"end" | "space-between" | "start" | undefined,undefined,false,false
|
ion-radio,prop,justify,"end" | "space-between" | "start" | undefined,undefined,false,false
|
||||||
ion-radio,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',false,false
|
ion-radio,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',false,false
|
||||||
ion-radio,prop,mode,"ios" | "md",undefined,false,false
|
ion-radio,prop,mode,"ios" | "md",undefined,false,false
|
||||||
@ -1339,8 +1341,11 @@ ion-radio,css-prop,--color-checked,md
|
|||||||
ion-radio,css-prop,--inner-border-radius,ios
|
ion-radio,css-prop,--inner-border-radius,ios
|
||||||
ion-radio,css-prop,--inner-border-radius,md
|
ion-radio,css-prop,--inner-border-radius,md
|
||||||
ion-radio,part,container
|
ion-radio,part,container
|
||||||
|
ion-radio,part,error-text
|
||||||
|
ion-radio,part,helper-text
|
||||||
ion-radio,part,label
|
ion-radio,part,label
|
||||||
ion-radio,part,mark
|
ion-radio,part,mark
|
||||||
|
ion-radio,part,supporting-text
|
||||||
|
|
||||||
ion-radio-group,none
|
ion-radio-group,none
|
||||||
ion-radio-group,prop,allowEmptySelection,boolean,false,false,false
|
ion-radio-group,prop,allowEmptySelection,boolean,false,false,false
|
||||||
|
16
core/src/components.d.ts
vendored
16
core/src/components.d.ts
vendored
@ -2267,6 +2267,14 @@ export namespace Components {
|
|||||||
* If `true`, the user cannot interact with the radio.
|
* If `true`, the user cannot interact with the radio.
|
||||||
*/
|
*/
|
||||||
"disabled": boolean;
|
"disabled": boolean;
|
||||||
|
/**
|
||||||
|
* Text that is placed under the radio and displayed when an error is detected.
|
||||||
|
*/
|
||||||
|
"errorText"?: string;
|
||||||
|
/**
|
||||||
|
* Text that is placed under the radio and displayed when no error is detected.
|
||||||
|
*/
|
||||||
|
"helperText"?: string;
|
||||||
/**
|
/**
|
||||||
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements. Setting this property will change the radio `display` to `block`.
|
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements. Setting this property will change the radio `display` to `block`.
|
||||||
*/
|
*/
|
||||||
@ -7017,6 +7025,14 @@ declare namespace LocalJSX {
|
|||||||
* If `true`, the user cannot interact with the radio.
|
* If `true`, the user cannot interact with the radio.
|
||||||
*/
|
*/
|
||||||
"disabled"?: boolean;
|
"disabled"?: boolean;
|
||||||
|
/**
|
||||||
|
* Text that is placed under the radio and displayed when an error is detected.
|
||||||
|
*/
|
||||||
|
"errorText"?: string;
|
||||||
|
/**
|
||||||
|
* Text that is placed under the radio and displayed when no error is detected.
|
||||||
|
*/
|
||||||
|
"helperText"?: string;
|
||||||
/**
|
/**
|
||||||
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements. Setting this property will change the radio `display` to `block`.
|
* How to pack the label and radio within a line. `"start"`: The label and radio will appear on the left in LTR and on the right in RTL. `"end"`: The label and radio will appear on the right in LTR and on the left in RTL. `"space-between"`: The label and radio will appear on opposite ends of the line with space between the two elements. Setting this property will change the radio `display` to `block`.
|
||||||
*/
|
*/
|
||||||
|
@ -140,6 +140,53 @@ input {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Radio Bottom Content
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
|
.radio-bottom {
|
||||||
|
@include padding(5px, null, null, null);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
font-size: dynamic-font(12px);
|
||||||
|
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.radio-label-placement-stacked) .radio-bottom {
|
||||||
|
font-size: dynamic-font(16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Radio Hint Text
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error text should only be shown when .ion-invalid is
|
||||||
|
* present on the checkbox. Otherwise the helper text should
|
||||||
|
* be shown.
|
||||||
|
*/
|
||||||
|
.radio-bottom .error-text {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
color: ion-color(danger, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-bottom .helper-text {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
color: $text-color-step-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.ion-touched.ion-invalid) .radio-bottom .error-text {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host(.ion-touched.ion-invalid) .radio-bottom .helper-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
// Radio Label Placement - Start
|
// Radio Label Placement - Start
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
@ -213,6 +260,8 @@ input {
|
|||||||
*/
|
*/
|
||||||
:host(.radio-label-placement-stacked) .radio-wrapper {
|
:host(.radio-label-placement-stacked) .radio-wrapper {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host(.radio-label-placement-stacked) .label-text-wrapper {
|
:host(.radio-label-placement-stacked) .label-text-wrapper {
|
||||||
|
@ -15,6 +15,9 @@ import type { Color } from '../../interface';
|
|||||||
* @part container - The container for the radio mark.
|
* @part container - The container for the radio mark.
|
||||||
* @part label - The label text describing the radio.
|
* @part label - The label text describing the radio.
|
||||||
* @part mark - The checkmark or dot used to indicate the checked state.
|
* @part mark - The checkmark or dot used to indicate the checked state.
|
||||||
|
* @part supporting-text - Supporting text displayed beneath the radio label.
|
||||||
|
* @part helper-text - Supporting text displayed beneath the radio label when the radio is valid.
|
||||||
|
* @part error-text - Supporting text displayed beneath the radio label when the radio is invalid and touched.
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-radio',
|
tag: 'ion-radio',
|
||||||
@ -26,6 +29,8 @@ import type { Color } from '../../interface';
|
|||||||
})
|
})
|
||||||
export class Radio implements ComponentInterface {
|
export class Radio implements ComponentInterface {
|
||||||
private inputId = `ion-rb-${radioButtonIds++}`;
|
private inputId = `ion-rb-${radioButtonIds++}`;
|
||||||
|
private helperTextId = `${this.inputId}-helper-text`;
|
||||||
|
private errorTextId = `${this.inputId}-error-text`;
|
||||||
private radioGroup: HTMLIonRadioGroupElement | null = null;
|
private radioGroup: HTMLIonRadioGroupElement | null = null;
|
||||||
|
|
||||||
@Element() el!: HTMLIonRadioElement;
|
@Element() el!: HTMLIonRadioElement;
|
||||||
@ -58,6 +63,16 @@ export class Radio implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
@Prop() disabled = false;
|
@Prop() disabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text that is placed under the radio and displayed when an error is detected.
|
||||||
|
*/
|
||||||
|
@Prop() errorText?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text that is placed under the radio and displayed when no error is detected.
|
||||||
|
*/
|
||||||
|
@Prop() helperText?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the value of the radio.
|
* the value of the radio.
|
||||||
*/
|
*/
|
||||||
@ -212,6 +227,48 @@ export class Radio implements ComponentInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getHintTextID(): string | undefined {
|
||||||
|
const { el, helperText, errorText, helperTextId, errorTextId } = this;
|
||||||
|
|
||||||
|
if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
|
||||||
|
return errorTextId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (helperText) {
|
||||||
|
return helperTextId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for rendering helper text and error text.
|
||||||
|
* This element should only be rendered if hint text is set.
|
||||||
|
*/
|
||||||
|
private renderHintText() {
|
||||||
|
const { helperText, errorText, helperTextId, errorTextId } = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* undefined and empty string values should
|
||||||
|
* be treated as not having helper/error text.
|
||||||
|
*/
|
||||||
|
const hasHintText = !!helperText || !!errorText;
|
||||||
|
if (!hasHintText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="radio-bottom">
|
||||||
|
<div id={helperTextId} class="helper-text" part="supporting-text helper-text">
|
||||||
|
{helperText}
|
||||||
|
</div>
|
||||||
|
<div id={errorTextId} class="error-text" part="supporting-text error-text">
|
||||||
|
{errorText}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { checked, disabled, color, el, justify, labelPlacement, hasLabel, buttonTabindex, alignment } = this;
|
const { checked, disabled, color, el, justify, labelPlacement, hasLabel, buttonTabindex, alignment } = this;
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
@ -237,6 +294,8 @@ export class Radio implements ComponentInterface {
|
|||||||
role="radio"
|
role="radio"
|
||||||
aria-checked={checked ? 'true' : 'false'}
|
aria-checked={checked ? 'true' : 'false'}
|
||||||
aria-disabled={disabled ? 'true' : null}
|
aria-disabled={disabled ? 'true' : null}
|
||||||
|
aria-describedby={this.getHintTextID()}
|
||||||
|
aria-invalid={this.getHintTextID() === this.errorTextId}
|
||||||
tabindex={buttonTabindex}
|
tabindex={buttonTabindex}
|
||||||
>
|
>
|
||||||
<label class="radio-wrapper">
|
<label class="radio-wrapper">
|
||||||
@ -248,6 +307,7 @@ export class Radio implements ComponentInterface {
|
|||||||
part="label"
|
part="label"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
{this.renderHintText()}
|
||||||
</div>
|
</div>
|
||||||
<div class="native-wrapper">{this.renderRadioControl()}</div>
|
<div class="native-wrapper">{this.renderRadioControl()}</div>
|
||||||
</label>
|
</label>
|
||||||
|
@ -1607,14 +1607,14 @@ export declare interface IonProgressBar extends Components.IonProgressBar {}
|
|||||||
|
|
||||||
|
|
||||||
@ProxyCmp({
|
@ProxyCmp({
|
||||||
inputs: ['alignment', 'color', 'disabled', 'justify', 'labelPlacement', 'mode', 'name', 'value']
|
inputs: ['alignment', 'color', 'disabled', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'value']
|
||||||
})
|
})
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-radio',
|
selector: 'ion-radio',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: '<ng-content></ng-content>',
|
template: '<ng-content></ng-content>',
|
||||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||||
inputs: ['alignment', 'color', 'disabled', 'justify', 'labelPlacement', 'mode', 'name', 'value'],
|
inputs: ['alignment', 'color', 'disabled', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'value'],
|
||||||
})
|
})
|
||||||
export class IonRadio {
|
export class IonRadio {
|
||||||
protected el: HTMLElement;
|
protected el: HTMLElement;
|
||||||
|
@ -1614,14 +1614,14 @@ export declare interface IonProgressBar extends Components.IonProgressBar {}
|
|||||||
|
|
||||||
@ProxyCmp({
|
@ProxyCmp({
|
||||||
defineCustomElementFn: defineIonRadio,
|
defineCustomElementFn: defineIonRadio,
|
||||||
inputs: ['alignment', 'color', 'disabled', 'justify', 'labelPlacement', 'mode', 'name', 'value']
|
inputs: ['alignment', 'color', 'disabled', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'value']
|
||||||
})
|
})
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-radio',
|
selector: 'ion-radio',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
template: '<ng-content></ng-content>',
|
template: '<ng-content></ng-content>',
|
||||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||||
inputs: ['alignment', 'color', 'disabled', 'justify', 'labelPlacement', 'mode', 'name', 'value'],
|
inputs: ['alignment', 'color', 'disabled', 'errorText', 'helperText', 'justify', 'labelPlacement', 'mode', 'name', 'value'],
|
||||||
standalone: true
|
standalone: true
|
||||||
})
|
})
|
||||||
export class IonRadio {
|
export class IonRadio {
|
||||||
|
@ -612,6 +612,8 @@ export const IonRadio = /*@__PURE__*/ defineContainer<JSX.IonRadio, JSX.IonRadio
|
|||||||
'color',
|
'color',
|
||||||
'name',
|
'name',
|
||||||
'disabled',
|
'disabled',
|
||||||
|
'errorText',
|
||||||
|
'helperText',
|
||||||
'value',
|
'value',
|
||||||
'labelPlacement',
|
'labelPlacement',
|
||||||
'justify',
|
'justify',
|
||||||
|
Reference in New Issue
Block a user