From 5ad4bbe5ba3d95c0f569c98c93e055ea254adca2 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Tue, 7 Jul 2020 08:33:13 -0400 Subject: [PATCH] Fix checked states --- docs/components/radio.md | 9 +++-- src/components.d.ts | 6 ++-- src/components/checkbox/checkbox.tsx | 19 +++++------ src/components/radio/radio.scss | 2 +- src/components/radio/radio.tsx | 50 +++++++++++++++++++++++----- src/components/switch/switch.tsx | 20 +++++------ 6 files changed, 69 insertions(+), 37 deletions(-) diff --git a/docs/components/radio.md b/docs/components/radio.md index 1f8ae27a3..5b80bd3ad 100644 --- a/docs/components/radio.md +++ b/docs/components/radio.md @@ -7,9 +7,12 @@ Radios... Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ```html preview -Default
-Checked
-Disabled
+Default 1
+Default 2
+Default 3
+Default 4
+Checked
+Disabled
``` [component-metadata:sl-radio] diff --git a/src/components.d.ts b/src/components.d.ts index 64fd48fa9..a8254da11 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -1170,7 +1170,7 @@ declare namespace LocalJSX { */ "onSlBlur"?: (event: CustomEvent) => void; /** - * Emitted when the control's state changes. + * Emitted when the control's checked state changes. */ "onSlChange"?: (event: CustomEvent) => void; /** @@ -1619,7 +1619,7 @@ declare namespace LocalJSX { */ "onSlBlur"?: (event: CustomEvent) => void; /** - * Emitted when the control's state changes. + * Emitted when the control's checked state changes. */ "onSlChange"?: (event: CustomEvent) => void; /** @@ -1751,7 +1751,7 @@ declare namespace LocalJSX { */ "onSlBlur"?: (event: CustomEvent) => void; /** - * Emitted when the control's state changes. + * Emitted when the control's checked state changes. */ "onSlChange"?: (event: CustomEvent) => void; /** diff --git a/src/components/checkbox/checkbox.tsx b/src/components/checkbox/checkbox.tsx index e7efde94b..6ef4541db 100644 --- a/src/components/checkbox/checkbox.tsx +++ b/src/components/checkbox/checkbox.tsx @@ -46,15 +46,18 @@ export class Checkbox { /** Emitted when the control loses focus. */ @Event() slBlur: EventEmitter; - /** Emitted when the control's state changes. */ + /** Emitted when the control's checked state changes. */ @Event() slChange: EventEmitter; /** Emitted when the control gains focus. */ @Event() slFocus: EventEmitter; + @Watch('checked') @Watch('indeterminate') - handleIndeterminateChange() { + handleCheckedChange() { + this.input.checked = this.checked; this.input.indeterminate = this.indeterminate; + this.slChange.emit(); } componentDidLoad() { @@ -73,15 +76,9 @@ export class Checkbox { this.input.blur(); } - handleClick(event: MouseEvent) { - const slChange = this.slChange.emit(); - - if (slChange.defaultPrevented) { - event.preventDefault(); - } else { - this.checked = this.input.checked; - this.indeterminate = this.input.indeterminate; - } + handleClick() { + this.checked = this.input.checked; + this.indeterminate = this.input.indeterminate; } handleBlur() { diff --git a/src/components/radio/radio.scss b/src/components/radio/radio.scss index 08ff1a188..fdb30b3ce 100644 --- a/src/components/radio/radio.scss +++ b/src/components/radio/radio.scss @@ -43,7 +43,7 @@ input[type='radio'] { position: absolute; - opacity: 1; + opacity: 0; padding: 0; margin: 0; pointer-events: none; diff --git a/src/components/radio/radio.tsx b/src/components/radio/radio.tsx index b28f5264c..d4ee0afcd 100644 --- a/src/components/radio/radio.tsx +++ b/src/components/radio/radio.tsx @@ -1,4 +1,4 @@ -import { Component, Element, Event, EventEmitter, Method, Prop, State, h } from '@stencil/core'; +import { Component, Element, Event, EventEmitter, Method, Prop, State, Watch, h } from '@stencil/core'; let id = 0; @@ -19,6 +19,7 @@ export class Radio { this.handleClick = this.handleClick.bind(this); this.handleBlur = this.handleBlur.bind(this); this.handleFocus = this.handleFocus.bind(this); + this.handleKeyDown = this.handleKeyDown.bind(this); this.handleMouseDown = this.handleMouseDown.bind(this); } @@ -42,10 +43,19 @@ export class Radio { /** Set to true to draw the radio in a checked state. */ @Prop({ mutable: true }) checked = false; + @Watch('checked') + handleCheckedChange() { + if (this.checked) { + this.getSiblingRadios().map(radio => (radio.checked = false)); + } + this.input.checked = this.checked; + this.slChange.emit(); + } + /** Emitted when the control loses focus. */ @Event() slBlur: EventEmitter; - /** Emitted when the control's state changes. */ + /** Emitted when the control's checked state changes. */ @Event() slChange: EventEmitter; /** Emitted when the control gains focus. */ @@ -63,14 +73,19 @@ export class Radio { this.input.blur(); } - handleClick(event: MouseEvent) { - const slChange = this.slChange.emit(); + getAllRadios() { + const form = this.host.closest('sl-form, form') || document.body; + return [...form.querySelectorAll('sl-radio')].filter( + (radio: HTMLSlRadioElement) => radio.name === this.name + ) as HTMLSlRadioElement[]; + } - if (slChange.defaultPrevented) { - event.preventDefault(); - } else { - this.checked = this.input.checked; - } + getSiblingRadios() { + return this.getAllRadios().filter(radio => radio !== this.host) as HTMLSlRadioElement[]; + } + + handleClick() { + this.checked = this.input.checked; } handleBlur() { @@ -83,6 +98,22 @@ export class Radio { this.slFocus.emit(); } + handleKeyDown(event: KeyboardEvent) { + if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) { + const radios = this.getAllRadios().filter(radio => !radio.disabled); + const incr = ['ArrowUp', 'ArrowLeft'].includes(event.key) ? -1 : 1; + let index = radios.indexOf(this.host) + incr; + if (index < 0) index = radios.length - 1; + if (index > radios.length - 1) index = 0; + + this.getAllRadios().map(radio => (radio.checked = false)); + radios[index].setFocus(); + radios[index].checked = true; + + event.preventDefault(); + } + } + handleMouseDown(event: MouseEvent) { // Prevent clicks on the label from briefly blurring the input event.preventDefault(); @@ -100,6 +131,7 @@ export class Radio { 'radio--disabled': this.disabled, 'radio--focused': this.hasFocus }} + onKeyDown={this.handleKeyDown} onMouseDown={this.handleMouseDown} > diff --git a/src/components/switch/switch.tsx b/src/components/switch/switch.tsx index 6a3a488df..9d91b3a1c 100644 --- a/src/components/switch/switch.tsx +++ b/src/components/switch/switch.tsx @@ -1,4 +1,4 @@ -import { Component, Event, EventEmitter, Method, Prop, State, h } from '@stencil/core'; +import { Component, Event, EventEmitter, Method, Prop, State, Watch, h } from '@stencil/core'; let id = 0; @@ -42,10 +42,16 @@ export class Switch { /** Set to true to draw the switch in a checked state. */ @Prop({ mutable: true }) checked = false; + @Watch('checked') + handleCheckedChange() { + this.input.checked = this.checked; + this.slChange.emit(); + } + /** Emitted when the control loses focus. */ @Event() slBlur: EventEmitter; - /** Emitted when the control's state changes. */ + /** Emitted when the control's checked state changes. */ @Event() slChange: EventEmitter; /** Emitted when the control gains focus. */ @@ -63,14 +69,8 @@ export class Switch { this.input.blur(); } - handleClick(event: MouseEvent) { - const slChange = this.slChange.emit(); - - if (slChange.defaultPrevented) { - event.preventDefault(); - } else { - this.checked = this.input.checked; - } + handleClick() { + this.checked = this.input.checked; } handleBlur() {