mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
refactor(checkbox): use native input type=checkbox
This commit is contained in:
1
packages/core/src/components.d.ts
vendored
1
packages/core/src/components.d.ts
vendored
@ -594,6 +594,7 @@ declare global {
|
|||||||
|
|
||||||
color?: string,
|
color?: string,
|
||||||
mode?: 'ios' | 'md',
|
mode?: 'ios' | 'md',
|
||||||
|
name?: string,
|
||||||
checked?: boolean,
|
checked?: boolean,
|
||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
value?: string
|
value?: string
|
||||||
|
@ -123,6 +123,27 @@ $checkbox-ios-item-end-margin-start: 0 !default;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// iOS Checkbox Keyboard Focus
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
.checkbox-key .checkbox-icon::after {
|
||||||
|
position: absolute;
|
||||||
|
top: -9px;
|
||||||
|
left: -9px;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
|
||||||
|
background: #86A8DF;
|
||||||
|
opacity: .3;
|
||||||
|
|
||||||
|
border-radius: 50%;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// iOS Checkbox Within An Item
|
// iOS Checkbox Within An Item
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
|
@ -142,6 +142,27 @@ $checkbox-md-item-end-margin-start: 0 !default;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Material Design Checkbox Keyboard Focus
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
.checkbox-key .checkbox-icon::after {
|
||||||
|
position: absolute;
|
||||||
|
top: -12px;
|
||||||
|
left: -12px;
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
|
||||||
|
background: #86A8DF;
|
||||||
|
opacity: .3;
|
||||||
|
|
||||||
|
border-radius: 50%;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Material Design Checkbox Within An Item
|
// Material Design Checkbox Within An Item
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ ion-checkbox {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-cover {
|
ion-checkbox input {
|
||||||
@include position(0, null, null, 0);
|
@include position(0, null, null, 0);
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -19,4 +19,8 @@ ion-checkbox {
|
|||||||
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BlurEvent, CheckboxInput, CheckedInputChangeEvent, FocusEvent, StyleEvent } from '../../utils/input-interfaces';
|
import { BlurEvent, CheckboxInput, CheckedInputChangeEvent, FocusEvent, StyleEvent } from '../../utils/input-interfaces';
|
||||||
import { Component, CssClassMap, Event, EventEmitter, Listen, Prop, PropDidChange } from '@stencil/core';
|
import { Component, CssClassMap, Event, EventEmitter, Prop, PropDidChange, State } from '@stencil/core';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -13,10 +13,46 @@ import { Component, CssClassMap, Event, EventEmitter, Listen, Prop, PropDidChang
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
export class Checkbox implements CheckboxInput {
|
export class Checkbox implements CheckboxInput {
|
||||||
private checkboxId: string;
|
private didLoad: boolean;
|
||||||
private labelId: string;
|
private inputId: string;
|
||||||
|
private nativeInput: HTMLInputElement;
|
||||||
private styleTmr: any;
|
private styleTmr: any;
|
||||||
|
|
||||||
|
@State() keyFocus: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {string} The color to use from your Sass `$colors` map.
|
||||||
|
* Default options are: `"primary"`, `"secondary"`, `"danger"`, `"light"`, and `"dark"`.
|
||||||
|
* For more information, see [Theming your App](/docs/theming/theming-your-app).
|
||||||
|
*/
|
||||||
|
@Prop() color: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {string} The mode determines which platform styles to use.
|
||||||
|
* Possible values are: `"ios"` or `"md"`.
|
||||||
|
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
|
||||||
|
*/
|
||||||
|
@Prop() mode: 'ios' | 'md';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Prop() name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {boolean} If true, the checkbox is selected. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
@Prop({ mutable: true }) checked = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @input {boolean} If true, the user cannot interact with the checkbox. Default false.
|
||||||
|
*/
|
||||||
|
@Prop() disabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {string} the value of the checkbox.
|
||||||
|
*/
|
||||||
|
@Prop({ mutable: true }) value: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {Event} Emitted when the checked property has changed.
|
* @output {Event} Emitted when the checked property has changed.
|
||||||
*/
|
*/
|
||||||
@ -37,55 +73,51 @@ export class Checkbox implements CheckboxInput {
|
|||||||
*/
|
*/
|
||||||
@Event() ionStyle: EventEmitter<StyleEvent>;
|
@Event() ionStyle: EventEmitter<StyleEvent>;
|
||||||
|
|
||||||
/**
|
|
||||||
* @input {string} The color to use from your Sass `$colors` map.
|
|
||||||
* Default options are: `"primary"`, `"secondary"`, `"danger"`, `"light"`, and `"dark"`.
|
|
||||||
* For more information, see [Theming your App](/docs/theming/theming-your-app).
|
|
||||||
*/
|
|
||||||
@Prop() color: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @input {string} The mode determines which platform styles to use.
|
|
||||||
* Possible values are: `"ios"` or `"md"`.
|
|
||||||
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
|
|
||||||
*/
|
|
||||||
@Prop() mode: 'ios' | 'md';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @input {boolean} If true, the checkbox is selected. Defaults to `false`.
|
|
||||||
*/
|
|
||||||
@Prop({ mutable: true }) checked: boolean = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @input {boolean} If true, the user cannot interact with the checkbox. Default false.
|
|
||||||
*/
|
|
||||||
@Prop() disabled: boolean = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @input {string} the value of the checkbox.
|
|
||||||
*/
|
|
||||||
@Prop({ mutable: true }) value: string;
|
|
||||||
|
|
||||||
|
|
||||||
componentWillLoad() {
|
componentWillLoad() {
|
||||||
|
this.inputId = 'ion-cb-' + (checkboxIds++);
|
||||||
|
if (this.value === undefined) {
|
||||||
|
this.value = this.inputId;
|
||||||
|
}
|
||||||
this.emitStyle();
|
this.emitStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidLoad() {
|
||||||
|
this.nativeInput.checked = this.checked;
|
||||||
|
this.didLoad = true;
|
||||||
|
|
||||||
|
const parentItem = this.nativeInput.closest('ion-item');
|
||||||
|
if (parentItem) {
|
||||||
|
const itemLabel = parentItem.querySelector('ion-label');
|
||||||
|
if (itemLabel) {
|
||||||
|
itemLabel.id = this.inputId + '-lbl';
|
||||||
|
this.nativeInput.setAttribute('aria-labelledby', itemLabel.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PropDidChange('checked')
|
@PropDidChange('checked')
|
||||||
checkedChanged(isChecked: boolean) {
|
checkedChanged(isChecked: boolean) {
|
||||||
this.ionChange.emit({
|
if (this.nativeInput.checked !== isChecked) {
|
||||||
checked: isChecked,
|
// keep the checked value and native input `nync
|
||||||
value: this.value
|
this.nativeInput.checked = isChecked;
|
||||||
});
|
}
|
||||||
|
if (this.didLoad) {
|
||||||
|
this.ionChange.emit({
|
||||||
|
checked: isChecked,
|
||||||
|
value: this.value
|
||||||
|
});
|
||||||
|
}
|
||||||
this.emitStyle();
|
this.emitStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PropDidChange('disabled')
|
@PropDidChange('disabled')
|
||||||
disabledChanged() {
|
disabledChanged(isDisabled: boolean) {
|
||||||
|
this.nativeInput.disabled = isDisabled;
|
||||||
this.emitStyle();
|
this.emitStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
private emitStyle() {
|
emitStyle() {
|
||||||
clearTimeout(this.styleTmr);
|
clearTimeout(this.styleTmr);
|
||||||
|
|
||||||
this.styleTmr = setTimeout(() => {
|
this.styleTmr = setTimeout(() => {
|
||||||
@ -96,22 +128,29 @@ export class Checkbox implements CheckboxInput {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listen('keydown.space')
|
onChange() {
|
||||||
onSpace(ev: KeyboardEvent) {
|
this.checked = !this.checked;
|
||||||
this.toggle();
|
|
||||||
ev.stopPropagation();
|
|
||||||
ev.preventDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle() {
|
onKeyUp() {
|
||||||
this.checked = !this.checked;
|
this.keyFocus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocus() {
|
||||||
|
this.ionFocus.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur() {
|
||||||
|
this.keyFocus = false;
|
||||||
|
this.ionBlur.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
hostData() {
|
hostData() {
|
||||||
return {
|
return {
|
||||||
class: {
|
class: {
|
||||||
'checkbox-checked': this.checked,
|
'checkbox-checked': this.checked,
|
||||||
'checkbox-disabled': this.disabled
|
'checkbox-disabled': this.disabled,
|
||||||
|
'checkbox-key': this.keyFocus
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -126,16 +165,19 @@ export class Checkbox implements CheckboxInput {
|
|||||||
<div class={checkboxClasses}>
|
<div class={checkboxClasses}>
|
||||||
<div class='checkbox-inner'></div>
|
<div class='checkbox-inner'></div>
|
||||||
</div>,
|
</div>,
|
||||||
<button
|
<input
|
||||||
class='checkbox-cover'
|
type='checkbox'
|
||||||
onClick={() => this.toggle()}
|
onChange={this.onChange.bind(this)}
|
||||||
id={this.checkboxId}
|
onFocus={this.onFocus.bind(this)}
|
||||||
aria-checked={this.checked ? 'true' : false}
|
onBlur={this.onBlur.bind(this)}
|
||||||
aria-disabled={this.disabled ? 'true' : false}
|
onKeyUp={this.onKeyUp.bind(this)}
|
||||||
aria-labelledby={this.labelId}
|
id={this.inputId}
|
||||||
role='checkbox'
|
name={this.name}
|
||||||
tabIndex={0}
|
value={this.value}
|
||||||
/>
|
disabled={this.disabled}
|
||||||
|
ref={r => this.nativeInput = (r as any)}/>
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let checkboxIds = 0;
|
||||||
|
@ -10,50 +10,22 @@ Placed in an `ion-item` or used as a stand-alone checkbox.
|
|||||||
|
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Pepperoni</ion-label>
|
<ion-label>Pepperoni</ion-label>
|
||||||
<ion-checkbox [(ngModel)]="pepperoni"></ion-checkbox>
|
<ion-checkbox value="pepperoni" checked></ion-checkbox>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Sausage</ion-label>
|
<ion-label>Sausage</ion-label>
|
||||||
<ion-checkbox [(ngModel)]="sausage" disabled="true"></ion-checkbox>
|
<ion-checkbox value="sausage" disabled></ion-checkbox>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Mushrooms</ion-label>
|
<ion-label>Mushrooms</ion-label>
|
||||||
<ion-checkbox [(ngModel)]="mushrooms"></ion-checkbox>
|
<ion-checkbox value="mushrooms"></ion-checkbox>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
</ion-list>
|
</ion-list>
|
||||||
```
|
```
|
||||||
|
|
||||||
@advanced
|
|
||||||
|
|
||||||
```html
|
|
||||||
|
|
||||||
<!-- Call function when state changes -->
|
|
||||||
<ion-list>
|
|
||||||
|
|
||||||
<ion-item>
|
|
||||||
<ion-label>Cucumber</ion-label>
|
|
||||||
<ion-checkbox [(ngModel)]="cucumber" (ionChange)="updateCucumber()"></ion-checkbox>
|
|
||||||
</ion-item>
|
|
||||||
|
|
||||||
</ion-list>
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
@Component({
|
|
||||||
templateUrl: 'main.html'
|
|
||||||
})
|
|
||||||
class SaladPage {
|
|
||||||
cucumber: boolean;
|
|
||||||
|
|
||||||
updateCucumber() {
|
|
||||||
console.log('Cucumbers new state:' + this.cucumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
|
|
||||||
|
@ -40,6 +40,10 @@
|
|||||||
<ion-label>Dark</ion-label>
|
<ion-label>Dark</ion-label>
|
||||||
<ion-checkbox color="dark" checked></ion-checkbox>
|
<ion-checkbox color="dark" checked></ion-checkbox>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>Unchecked by Default</ion-label>
|
||||||
|
<ion-checkbox></ion-checkbox>
|
||||||
|
</ion-item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>Disabled</ion-label>
|
<ion-label>Disabled</ion-label>
|
||||||
<ion-checkbox disabled></ion-checkbox>
|
<ion-checkbox disabled></ion-checkbox>
|
||||||
|
Reference in New Issue
Block a user