diff --git a/packages/core/src/components.d.ts b/packages/core/src/components.d.ts index 8704692fbd..58058f2bc3 100644 --- a/packages/core/src/components.d.ts +++ b/packages/core/src/components.d.ts @@ -594,6 +594,7 @@ declare global { color?: string, mode?: 'ios' | 'md', + name?: string, checked?: boolean, disabled?: boolean, value?: string diff --git a/packages/core/src/components/checkbox/checkbox.ios.scss b/packages/core/src/components/checkbox/checkbox.ios.scss index 8ff04187b4..ef95d4cd96 100644 --- a/packages/core/src/components/checkbox/checkbox.ios.scss +++ b/packages/core/src/components/checkbox/checkbox.ios.scss @@ -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 // ----------------------------------------- diff --git a/packages/core/src/components/checkbox/checkbox.md.scss b/packages/core/src/components/checkbox/checkbox.md.scss index 6e85fb250a..a4e0b24fd4 100644 --- a/packages/core/src/components/checkbox/checkbox.md.scss +++ b/packages/core/src/components/checkbox/checkbox.md.scss @@ -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 // ----------------------------------------- diff --git a/packages/core/src/components/checkbox/checkbox.scss b/packages/core/src/components/checkbox/checkbox.scss index 5f377baa4b..4d81627698 100644 --- a/packages/core/src/components/checkbox/checkbox.scss +++ b/packages/core/src/components/checkbox/checkbox.scss @@ -9,7 +9,7 @@ ion-checkbox { display: inline-block; } -.checkbox-cover { +ion-checkbox input { @include position(0, null, null, 0); position: absolute; @@ -19,4 +19,8 @@ ion-checkbox { background: transparent; cursor: pointer; + + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } diff --git a/packages/core/src/components/checkbox/checkbox.tsx b/packages/core/src/components/checkbox/checkbox.tsx index 18fbe2f2d6..270ef88ee3 100644 --- a/packages/core/src/components/checkbox/checkbox.tsx +++ b/packages/core/src/components/checkbox/checkbox.tsx @@ -1,5 +1,5 @@ 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({ @@ -13,10 +13,46 @@ import { Component, CssClassMap, Event, EventEmitter, Listen, Prop, PropDidChang } }) export class Checkbox implements CheckboxInput { - private checkboxId: string; - private labelId: string; + private didLoad: boolean; + private inputId: string; + private nativeInput: HTMLInputElement; 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. */ @@ -37,55 +73,51 @@ export class Checkbox implements CheckboxInput { */ @Event() ionStyle: EventEmitter; - /** - * @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() { + this.inputId = 'ion-cb-' + (checkboxIds++); + if (this.value === undefined) { + this.value = this.inputId; + } 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') checkedChanged(isChecked: boolean) { - this.ionChange.emit({ - checked: isChecked, - value: this.value - }); + if (this.nativeInput.checked !== isChecked) { + // keep the checked value and native input `nync + this.nativeInput.checked = isChecked; + } + if (this.didLoad) { + this.ionChange.emit({ + checked: isChecked, + value: this.value + }); + } this.emitStyle(); } @PropDidChange('disabled') - disabledChanged() { + disabledChanged(isDisabled: boolean) { + this.nativeInput.disabled = isDisabled; this.emitStyle(); } - private emitStyle() { + emitStyle() { clearTimeout(this.styleTmr); this.styleTmr = setTimeout(() => { @@ -96,22 +128,29 @@ export class Checkbox implements CheckboxInput { }); } - @Listen('keydown.space') - onSpace(ev: KeyboardEvent) { - this.toggle(); - ev.stopPropagation(); - ev.preventDefault(); + onChange() { + this.checked = !this.checked; } - toggle() { - this.checked = !this.checked; + onKeyUp() { + this.keyFocus = true; + } + + onFocus() { + this.ionFocus.emit(); + } + + onBlur() { + this.keyFocus = false; + this.ionBlur.emit(); } hostData() { return { class: { '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 {
, -