From 68afc49e9ed27acffb0b765b7be6b03e8574850d Mon Sep 17 00:00:00 2001
From: Liam DeBeasi
Date: Mon, 21 Sep 2020 15:39:09 -0400
Subject: [PATCH 01/22] perf(segment): improve scrolling performance on ios
when using segment (#22110)
resolves #22095
---
core/src/components/segment-button/segment-button.ios.scss | 4 +---
core/src/components/segment-button/segment-button.scss | 6 ++----
core/src/components/segment/segment.tsx | 2 +-
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/core/src/components/segment-button/segment-button.ios.scss b/core/src/components/segment-button/segment-button.ios.scss
index 57f4da6f29..2624c3d296 100644
--- a/core/src/components/segment-button/segment-button.ios.scss
+++ b/core/src/components/segment-button/segment-button.ios.scss
@@ -38,7 +38,7 @@
min-height: #{$segment-button-ios-min-height};
// Necessary for the z-index to work properly
- transform: translate3d(0, 0, 0);
+ transform: translate(0, 0);
font-size: #{$segment-button-ios-font-size};
@@ -62,8 +62,6 @@
content: "";
opacity: 1;
-
- will-change: opacity;
}
:host(:first-of-type)::before {
diff --git a/core/src/components/segment-button/segment-button.scss b/core/src/components/segment-button/segment-button.scss
index 2c6d1a1ef2..e9c492c055 100644
--- a/core/src/components/segment-button/segment-button.scss
+++ b/core/src/components/segment-button/segment-button.scss
@@ -81,7 +81,7 @@
@include text-inherit();
@include margin(var(--margin-top), var(--margin-end), var(--margin-bottom), var(--margin-start));
@include padding(var(--padding-top), var(--padding-end), var(--padding-bottom), var(--padding-start));
- @include transform(translate3d(0,0,0));
+ @include transform(translate(0,0));
display: flex;
position: relative;
@@ -270,8 +270,6 @@ ion-ripple-effect {
box-sizing: border-box;
- will-change: transform, opacity;
-
pointer-events: none;
}
@@ -306,4 +304,4 @@ ion-ripple-effect {
.segment-button-indicator-animated {
transition: none;
}
-}
\ No newline at end of file
+}
diff --git a/core/src/components/segment/segment.tsx b/core/src/components/segment/segment.tsx
index 21ab3d034b..17b1e0d47d 100644
--- a/core/src/components/segment/segment.tsx
+++ b/core/src/components/segment/segment.tsx
@@ -244,7 +244,7 @@ export class Segment implements ComponentInterface {
// Scale the indicator width to match the previous indicator width
// and translate it on top of the previous indicator
- const transform = `translate3d(${xPosition}px, 0, 0) scaleX(${widthDelta})`;
+ const transform = `translate(${xPosition}px, 0) scaleX(${widthDelta})`;
writeTask(() => {
// Remove the transition before positioning on top of the previous indicator
From a24a041064fd9ce6ca161d3522083d50e585e9dd Mon Sep 17 00:00:00 2001
From: Liam DeBeasi
Date: Tue, 22 Sep 2020 14:04:39 -0400
Subject: [PATCH 02/22] fix(picker-column): add cancelable check to avoid
intervention error in chrome (#22140)
resolves #22137
---
core/src/components/picker-column/picker-column.tsx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/core/src/components/picker-column/picker-column.tsx b/core/src/components/picker-column/picker-column.tsx
index f884d4205e..82202a3c1f 100644
--- a/core/src/components/picker-column/picker-column.tsx
+++ b/core/src/components/picker-column/picker-column.tsx
@@ -250,7 +250,9 @@ export class PickerColumnCmp implements ComponentInterface {
// We have to prevent default in order to block scrolling under the picker
// but we DO NOT have to stop propagation, since we still want
// some "click" events to capture
- detail.event.preventDefault();
+ if (detail.event.cancelable) {
+ detail.event.preventDefault();
+ }
detail.event.stopPropagation();
hapticSelectionStart();
@@ -272,7 +274,9 @@ export class PickerColumnCmp implements ComponentInterface {
}
private onMove(detail: GestureDetail) {
- detail.event.preventDefault();
+ if (detail.event.cancelable) {
+ detail.event.preventDefault();
+ }
detail.event.stopPropagation();
// update the scroll position relative to pointer start position
From ca338864bf1fe90bd90a01316f74acd7faa00bc7 Mon Sep 17 00:00:00 2001
From: Nelson Martell
Date: Wed, 23 Sep 2020 16:58:01 -0500
Subject: [PATCH 03/22] docs(reorder-group): add type to the event param
(#22157)
Improve Angular example by adding missing (`any`) typehint of the event
---
core/src/components/reorder-group/readme.md | 6 ++++--
core/src/components/reorder-group/usage/angular.md | 6 ++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/core/src/components/reorder-group/readme.md b/core/src/components/reorder-group/readme.md
index e03b854193..5905c1f810 100644
--- a/core/src/components/reorder-group/readme.md
+++ b/core/src/components/reorder-group/readme.md
@@ -88,6 +88,7 @@ The `detail` property of the `ionItemReorder` event includes all of the relevant
```javascript
import { Component, ViewChild } from '@angular/core';
import { IonReorderGroup } from '@ionic/angular';
+import { ItemReorderEventDetail } from '@ionic/core';
@Component({
selector: 'reorder-group-example',
@@ -99,7 +100,7 @@ export class ReorderGroupExample {
constructor() {}
- doReorder(ev: any) {
+ doReorder(ev: CustomEvent) {
// The `from` and `to` properties contain the index of the item
// when the drag started and ended, respectively
console.log('Dragged from index', ev.detail.from, 'to', ev.detail.to);
@@ -121,6 +122,7 @@ export class ReorderGroupExample {
```javascript
import { Component, ViewChild } from '@angular/core';
import { IonReorderGroup } from '@ionic/angular';
+import { ItemReorderEventDetail } from '@ionic/core';
@Component({
selector: 'reorder-group-example',
@@ -134,7 +136,7 @@ export class ReorderGroupExample {
constructor() {}
- doReorder(ev: any) {
+ doReorder(ev: CustomEvent) {
// Before complete is called with the items they will remain in the
// order before the drag
console.log('Before complete', this.items);
diff --git a/core/src/components/reorder-group/usage/angular.md b/core/src/components/reorder-group/usage/angular.md
index 43111202e6..f5773e44fd 100644
--- a/core/src/components/reorder-group/usage/angular.md
+++ b/core/src/components/reorder-group/usage/angular.md
@@ -72,6 +72,7 @@
```javascript
import { Component, ViewChild } from '@angular/core';
import { IonReorderGroup } from '@ionic/angular';
+import { ItemReorderEventDetail } from '@ionic/core';
@Component({
selector: 'reorder-group-example',
@@ -83,7 +84,7 @@ export class ReorderGroupExample {
constructor() {}
- doReorder(ev: any) {
+ doReorder(ev: CustomEvent) {
// The `from` and `to` properties contain the index of the item
// when the drag started and ended, respectively
console.log('Dragged from index', ev.detail.from, 'to', ev.detail.to);
@@ -105,6 +106,7 @@ export class ReorderGroupExample {
```javascript
import { Component, ViewChild } from '@angular/core';
import { IonReorderGroup } from '@ionic/angular';
+import { ItemReorderEventDetail } from '@ionic/core';
@Component({
selector: 'reorder-group-example',
@@ -118,7 +120,7 @@ export class ReorderGroupExample {
constructor() {}
- doReorder(ev: any) {
+ doReorder(ev: CustomEvent) {
// Before complete is called with the items they will remain in the
// order before the drag
console.log('Before complete', this.items);
From ea0e0499e24865faad3d11f50f7037645f6cdcc8 Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Thu, 24 Sep 2020 14:33:27 -0400
Subject: [PATCH 04/22] fix(radio): update to follow accessibility guidelines
outlined by wai-aria (#22113)
This also fixes the Select "popover" interface as it is made up of radio buttons
WAI-ARIA Guidelines:
- Tab and Shift + Tab: Move focus into and out of the radio group. When focus moves into a radio group :
- If a radio button is checked, focus is set on the checked button.
- If none of the radio buttons are checked, focus is set on the first radio button in the group.
- Space: checks the focused radio button if it is not already checked.
- Right Arrow and Down Arrow: move focus to the next radio button in the group, uncheck the previously focused button, and check the newly focused button. If focus is on the last button, focus moves to the first button.
- Left Arrow and Up Arrow: move focus to the previous radio button in the group, uncheck the previously focused button, and check the newly focused button. If focus is on the first button, focus moves to the last button.
Closes #21743
---
core/src/components.d.ts | 2 +
.../components/radio-group/radio-group.tsx | 72 ++++++++++++++++++-
core/src/components/radio/radio.tsx | 28 +++++++-
.../components/radio/test/basic/index.html | 28 ++++++++
core/src/utils/overlays.ts | 2 +-
5 files changed, 127 insertions(+), 5 deletions(-)
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index 6c378ebb70..2aa816ffa0 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -1703,6 +1703,8 @@ export namespace Components {
* The name of the control, which is submitted with the form data.
*/
"name": string;
+ "setButtonTabindex": (value: number) => Promise;
+ "setFocus": () => Promise;
/**
* the value of the radio.
*/
diff --git a/core/src/components/radio-group/radio-group.tsx b/core/src/components/radio-group/radio-group.tsx
index c4e58a79f1..5c86b3d5b4 100644
--- a/core/src/components/radio-group/radio-group.tsx
+++ b/core/src/components/radio-group/radio-group.tsx
@@ -1,4 +1,4 @@
-import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop, Watch, h } from '@stencil/core';
+import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Listen, Prop, Watch, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { RadioGroupChangeEventDetail } from '../../interface';
@@ -30,6 +30,8 @@ export class RadioGroup implements ComponentInterface {
@Watch('value')
valueChanged(value: any | undefined) {
+ this.setRadioTabindex(value);
+
this.ionChange.emit({ value });
}
@@ -38,6 +40,31 @@ export class RadioGroup implements ComponentInterface {
*/
@Event() ionChange!: EventEmitter;
+ componentDidLoad() {
+ this.setRadioTabindex(this.value);
+ }
+
+ private setRadioTabindex = (value: any | undefined) => {
+ const radios = this.getRadios();
+
+ // Get the first radio that is not disabled and the checked one
+ const first = radios.find(radio => !radio.disabled);
+ const checked = radios.find(radio => (radio.value === value && !radio.disabled));
+
+ if (!first && !checked) {
+ return;
+ }
+
+ // If an enabled checked radio exists, set it to be the focusable radio
+ // otherwise we default to focus the first radio
+ const focusable = checked || first;
+
+ for (const radio of radios) {
+ const tabindex = radio === focusable ? 0 : -1;
+ radio.setButtonTabindex(tabindex);
+ }
+ }
+
async connectedCallback() {
// Get the list header if it exists and set the id
// this is used to set aria-labelledby
@@ -51,6 +78,10 @@ export class RadioGroup implements ComponentInterface {
}
}
+ private getRadios(): HTMLIonRadioElement[] {
+ return Array.from(this.el.querySelectorAll('ion-radio'));
+ }
+
private onClick = (ev: Event) => {
const selectedRadio = ev.target && (ev.target as HTMLElement).closest('ion-radio');
if (selectedRadio) {
@@ -64,6 +95,45 @@ export class RadioGroup implements ComponentInterface {
}
}
+ @Listen('keydown', { target: 'document' })
+ onKeydown(ev: any) {
+ if (ev.target && !this.el.contains(ev.target)) {
+ return;
+ }
+
+ // Get all radios inside of the radio group and then
+ // filter out disabled radios since we need to skip those
+ const radios = Array.from(this.el.querySelectorAll('ion-radio')).filter(radio => !radio.disabled);
+
+ // Only move the radio if the current focus is in the radio group
+ if (ev.target && radios.includes(ev.target)) {
+ const index = radios.findIndex(radio => radio === ev.target);
+
+ let next;
+
+ // If hitting arrow down or arrow right, move to the next radio
+ // If we're on the last radio, move to the first radio
+ if (['ArrowDown', 'ArrowRight'].includes(ev.key)) {
+ next = (index === radios.length - 1)
+ ? radios[0]
+ : radios[index + 1];
+ }
+
+ // If hitting arrow up or arrow left, move to the previous radio
+ // If we're on the first radio, move to the last radio
+ if (['ArrowUp', 'ArrowLeft'].includes(ev.key)) {
+ next = (index === 0)
+ ? radios[radios.length - 1]
+ : radios[index - 1]
+ }
+
+ if (next && radios.includes(next)) {
+ next.setFocus();
+ this.value = next.value;
+ }
+ }
+ }
+
render() {
return (
;
+ /** @internal */
+ @Method()
+ async setFocus() {
+ if (this.buttonEl) {
+ this.buttonEl.focus();
+ }
+ }
+
+ /** @internal */
+ @Method()
+ async setButtonTabindex(value: number) {
+ this.buttonTabindex = value;
+ }
+
connectedCallback() {
if (this.value === undefined) {
this.value = this.inputId;
@@ -117,7 +137,7 @@ export class Radio implements ComponentInterface {
}
render() {
- const { inputId, disabled, checked, color, el } = this;
+ const { inputId, disabled, checked, color, el, buttonTabindex } = this;
const mode = getIonMode(this);
const labelId = inputId + '-lbl';
const label = findItemLabel(el);
@@ -142,10 +162,12 @@ export class Radio implements ComponentInterface {
diff --git a/core/src/components/radio/test/basic/index.html b/core/src/components/radio/test/basic/index.html
index 412d88283a..74dcf63a26 100644
--- a/core/src/components/radio/test/basic/index.html
+++ b/core/src/components/radio/test/basic/index.html
@@ -20,6 +20,26 @@
+
+
+
+ Pizza Toppings (Unchecked Group)
+
+
+ Pepperoni
+
+
+
+
+ Sausage
+
+
+
+
+ Pineapple
+
+
+
@@ -77,6 +97,10 @@
+
+ Custom (Group w/ allow empty)
+
+
Custom
@@ -84,6 +108,10 @@
+
+ Part (Group w/ allow empty)
+
+
Radio ::part
diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts
index 85847e6372..2346a4693a 100644
--- a/core/src/utils/overlays.ts
+++ b/core/src/utils/overlays.ts
@@ -63,7 +63,7 @@ export const createOverlay = (tagName: string,
return Promise.resolve() as any;
};
-const focusableQueryString = '[tabindex]:not([tabindex^="-"]), input:not([type=hidden]), textarea, button, select, .ion-focusable';
+const focusableQueryString = '[tabindex]:not([tabindex^="-"]), input:not([type=hidden]):not([tabindex^="-"]), textarea:not([tabindex^="-"]), button:not([tabindex^="-"]), select:not([tabindex^="-"]), .ion-focusable:not([tabindex^="-"])';
const innerFocusableQueryString = 'input:not([type=hidden]), textarea, button, select';
const focusFirstDescendant = (ref: Element, overlay: HTMLIonOverlayElement) => {
From baafe08927b7b858170496605781e6fa682e0147 Mon Sep 17 00:00:00 2001
From: archzaiko
Date: Thu, 24 Sep 2020 21:43:32 +0300
Subject: [PATCH 05/22] fix(reorder): allow click event propagation when
reorder group is disabled (#21947)
Allow interactive components (e.g ``) inside of an `` tag in a disabled `` to fire click events / have their state changed.
fixes #21017
---
.../reorder-group/test/basic/index.html | 18 ++++++++++++++++++
core/src/components/reorder/reorder.tsx | 12 ++++++++++--
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/core/src/components/reorder-group/test/basic/index.html b/core/src/components/reorder-group/test/basic/index.html
index 1f9aaa8311..36f1017e17 100644
--- a/core/src/components/reorder-group/test/basic/index.html
+++ b/core/src/components/reorder-group/test/basic/index.html
@@ -115,6 +115,24 @@
+
+
+
+ Item 11 (the whole item can be dragged)
+
+
+
+
+
+
+
+
+ Item 12 (the whole item can be dragged)
+
+
+
+
+
diff --git a/core/src/components/reorder/reorder.tsx b/core/src/components/reorder/reorder.tsx
index 18b4d997ba..a013f20aa5 100644
--- a/core/src/components/reorder/reorder.tsx
+++ b/core/src/components/reorder/reorder.tsx
@@ -1,4 +1,4 @@
-import { Component, ComponentInterface, Host, Listen, h } from '@stencil/core';
+import { Component, ComponentInterface, Element, Host, Listen, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
@@ -14,11 +14,19 @@ import { getIonMode } from '../../global/ionic-global';
shadow: true
})
export class Reorder implements ComponentInterface {
+ @Element() el!: HTMLIonReorderElement;
@Listen('click', { capture: true })
onClick(ev: Event) {
+ const reorderGroup = this.el.closest('ion-reorder-group');
+
ev.preventDefault();
- ev.stopImmediatePropagation();
+
+ // Only stop event propagation if the reorder is inside of an enabled
+ // reorder group. This allows interaction with clickable children components.
+ if (!reorderGroup || !reorderGroup.disabled) {
+ ev.stopImmediatePropagation();
+ }
}
render() {
From 1526bdfb492c1fa8d71f8a1af8cd97abd9e62642 Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Thu, 24 Sep 2020 14:48:52 -0400
Subject: [PATCH 06/22] fix(segment): do not allow text selection on desktop
(#22158)
---
core/src/components/segment/segment.scss | 2 ++
1 file changed, 2 insertions(+)
diff --git a/core/src/components/segment/segment.scss b/core/src/components/segment/segment.scss
index 47b231a05a..42bb468692 100644
--- a/core/src/components/segment/segment.scss
+++ b/core/src/components/segment/segment.scss
@@ -27,6 +27,8 @@
text-align: center;
contain: paint;
+
+ user-select: none;
}
From e9b2cc8453f5e1c45d44397df738f60ea5b32efd Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Thu, 24 Sep 2020 17:09:54 -0400
Subject: [PATCH 07/22] fix(alert): update to follow accessibility guidelines
outlined by wai-aria (#22159)
This also fixes the Select "alert" interface as it uses this component
WAI-ARIA Guidelines:
- Tab and Shift + Tab: Move focus into and out of the radio group. When focus moves into a radio group :
- If a radio button is checked, focus is set on the checked button.
- If none of the radio buttons are checked, focus is set on the first radio button in the group.
- Space: checks the focused radio button if it is not already checked.
- Right Arrow and Down Arrow: move focus to the next radio button in the group, uncheck the previously focused button, and check the newly focused button. If focus is on the last button, focus moves to the first button.
- Left Arrow and Up Arrow: move focus to the previous radio button in the group, uncheck the previously focused button, and check the newly focused button. If focus is on the first button, focus moves to the last button.
closes #21744
---
core/src/components/alert/alert-interface.ts | 1 +
core/src/components/alert/alert.tsx | 74 +++++++++++++++++--
.../components/alert/test/basic/index.html | 10 +--
3 files changed, 75 insertions(+), 10 deletions(-)
diff --git a/core/src/components/alert/alert-interface.ts b/core/src/components/alert/alert-interface.ts
index 5704b35e45..898ca322e8 100644
--- a/core/src/components/alert/alert-interface.ts
+++ b/core/src/components/alert/alert-interface.ts
@@ -36,6 +36,7 @@ export interface AlertInput {
max?: string | number;
cssClass?: string | string[];
attributes?: AlertInputAttributes | AlertTextareaAttributes;
+ tabindex?: number;
}
export interface AlertTextareaAttributes extends JSXBase.TextareaHTMLAttributes {}
diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx
index 42fbca8098..89e1468477 100644
--- a/core/src/components/alert/alert.tsx
+++ b/core/src/components/alert/alert.tsx
@@ -1,4 +1,4 @@
-import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Method, Prop, Watch, forceUpdate, h } from '@stencil/core';
+import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Listen, Method, Prop, Watch, forceUpdate, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { AlertButton, AlertInput, AlertInputAttributes, AlertTextareaAttributes, AnimationBuilder, CssClassMap, OverlayEventDetail, OverlayInterface } from '../../interface';
@@ -130,6 +130,59 @@ export class Alert implements ComponentInterface, OverlayInterface {
*/
@Event({ eventName: 'ionAlertDidDismiss' }) didDismiss!: EventEmitter;
+ @Listen('keydown', { target: 'document' })
+ onKeydown(ev: any) {
+ const inputTypes = new Set(this.processedInputs.map(i => i.type));
+
+ // The only inputs we want to navigate between using arrow keys are the radios
+ // ignore the keydown event if it is not on a radio button
+ if (
+ !inputTypes.has('radio')
+ || (ev.target && !this.el.contains(ev.target))
+ || ev.target.classList.contains('alert-button'))
+ {
+ return;
+ }
+
+ // Get all radios inside of the radio group and then
+ // filter out disabled radios since we need to skip those
+ const query = this.el.querySelectorAll('.alert-radio') as NodeListOf;
+ const radios = Array.from(query).filter(radio => !radio.disabled);
+
+ // The focused radio is the one that shares the same id as
+ // the event target
+ const index = radios.findIndex(radio => radio.id === ev.target.id);
+
+ // We need to know what the next radio element should
+ // be in order to change the focus
+ let nextEl: HTMLButtonElement | undefined;
+
+ // If hitting arrow down or arrow right, move to the next radio
+ // If we're on the last radio, move to the first radio
+ if (['ArrowDown', 'ArrowRight'].includes(ev.key)) {
+ nextEl = (index === radios.length - 1)
+ ? radios[0]
+ : radios[index + 1];
+ }
+
+ // If hitting arrow up or arrow left, move to the previous radio
+ // If we're on the first radio, move to the last radio
+ if (['ArrowUp', 'ArrowLeft'].includes(ev.key)) {
+ nextEl = (index === 0)
+ ? radios[radios.length - 1]
+ : radios[index - 1]
+ }
+
+ if (nextEl && radios.includes(nextEl)) {
+ const nextProcessed = this.processedInputs.find(input => input.id === nextEl?.id);
+
+ if (nextProcessed) {
+ this.rbClick(nextProcessed);
+ nextEl.focus();
+ }
+ }
+ }
+
@Watch('buttons')
buttonsChanged() {
const buttons = this.buttons;
@@ -144,12 +197,21 @@ export class Alert implements ComponentInterface, OverlayInterface {
inputsChanged() {
const inputs = this.inputs;
+ // Get the first input that is not disabled and the checked one
+ // If an enabled checked input exists, set it to be the focusable input
+ // otherwise we default to focus the first input
+ // This will only be used when the input is type radio
+ const first = inputs.find(input => !input.disabled);
+ const checked = inputs.find(input => input.checked && !input.disabled);
+ const focusable = checked || first;
+
// An alert can be created with several different inputs. Radios,
// checkboxes and inputs are all accepted, but they cannot be mixed.
const inputTypes = new Set(inputs.map(i => i.type));
if (inputTypes.has('checkbox') && inputTypes.has('radio')) {
console.warn(`Alert cannot mix input types: ${(Array.from(inputTypes.values()).join('/'))}. Please see alert docs for more info.`);
}
+
this.inputType = inputTypes.values().next().value;
this.processedInputs = inputs.map((i, index) => ({
type: i.type || 'text',
@@ -165,6 +227,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
max: i.max,
cssClass: i.cssClass || '',
attributes: i.attributes || {},
+ tabindex: (i.type === 'radio' && i !== focusable) ? -1 : 0
}) as AlertInput);
}
@@ -241,6 +304,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
private rbClick(selectedInput: AlertInput) {
for (const input of this.processedInputs) {
input.checked = input === selectedInput;
+ input.tabindex = input === selectedInput ? 0 : -1;
}
this.activeId = selectedInput.id;
safeCall(selectedInput.handler, selectedInput);
@@ -333,7 +397,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
aria-checked={`${i.checked}`}
id={i.id}
disabled={i.disabled}
- tabIndex={0}
+ tabIndex={i.tabindex}
role="checkbox"
class={{
...getClassMap(i.cssClass),
@@ -373,7 +437,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
aria-checked={`${i.checked}`}
disabled={i.disabled}
id={i.id}
- tabIndex={0}
+ tabIndex={i.tabindex}
class={{
...getClassMap(i.cssClass),
'alert-radio-button': true,
@@ -411,7 +475,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
placeholder={i.placeholder}
value={i.value}
id={i.id}
- tabIndex={0}
+ tabIndex={i.tabindex}
{...i.attributes as AlertTextareaAttributes}
disabled={i.attributes?.disabled ?? i.disabled}
class={inputClass(i)}
@@ -432,7 +496,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
max={i.max}
value={i.value}
id={i.id}
- tabIndex={0}
+ tabIndex={i.tabindex}
{...i.attributes as AlertInputAttributes}
disabled={i.attributes?.disabled ?? i.disabled}
class={inputClass(i)}
diff --git a/core/src/components/alert/test/basic/index.html b/core/src/components/alert/test/basic/index.html
index a7d4847b91..df7afb9a31 100644
--- a/core/src/components/alert/test/basic/index.html
+++ b/core/src/components/alert/test/basic/index.html
@@ -206,7 +206,6 @@
type: 'radio',
label: 'Radio 1',
value: 'value1',
- checked: true
},
{
type: 'radio',
@@ -216,7 +215,8 @@
{
type: 'radio',
label: 'Radio 3',
- value: 'value3'
+ value: 'value3',
+ checked: true
},
{
type: 'radio',
@@ -241,12 +241,12 @@
role: 'cancel',
cssClass: 'secondary',
handler: () => {
- console.log('Confirm Cancel')
+ console.log('Confirm Cancel');
}
}, {
text: 'Ok',
- handler: () => {
- console.log('Confirm Ok')
+ handler: (ev) => {
+ console.log('Confirm Ok', ev);
}
}
]
From cc45ad815c002c5d890f2e105c546b4c3b3a58c0 Mon Sep 17 00:00:00 2001
From: Liam DeBeasi
Date: Thu, 24 Sep 2020 18:07:25 -0400
Subject: [PATCH 08/22] fix(overlays): return focus to presenting element after
dismissal (#22167)
resolves #21768
---
.../src/components/datetime/test/basic/e2e.ts | 2 --
core/src/components/modal/test/basic/e2e.ts | 33 ++++++++++++++---
core/src/utils/overlays.ts | 36 +++++++++++++++++++
3 files changed, 65 insertions(+), 6 deletions(-)
diff --git a/core/src/components/datetime/test/basic/e2e.ts b/core/src/components/datetime/test/basic/e2e.ts
index b9a902dd94..7a3ea3347d 100644
--- a/core/src/components/datetime/test/basic/e2e.ts
+++ b/core/src/components/datetime/test/basic/e2e.ts
@@ -7,14 +7,12 @@ const getActiveElementText = async (page) => {
test('datetime/picker: focus trap', async () => {
const page = await newE2EPage({ url: '/src/components/datetime/test/basic?ionic:_testing=true' });
-
await page.click('#datetime-part');
await page.waitForSelector('#datetime-part');
let datetime = await page.find('ion-datetime');
expect(datetime).not.toBe(null);
- await datetime.waitForVisible();
// TODO fix
await page.waitFor(100);
diff --git a/core/src/components/modal/test/basic/e2e.ts b/core/src/components/modal/test/basic/e2e.ts
index ff10d74118..06ce04f06b 100644
--- a/core/src/components/modal/test/basic/e2e.ts
+++ b/core/src/components/modal/test/basic/e2e.ts
@@ -9,17 +9,15 @@ const getActiveElementText = async (page) => {
test('modal: focus trap', async () => {
const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
+ const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#basic-modal');
await page.waitForSelector('#basic-modal');
let modal = await page.find('ion-modal');
-
expect(modal).not.toBe(null);
- await modal.waitForVisible();
- // TODO fix
- await page.waitFor(50);
+ await ionModalDidPresent.next();
await page.keyboard.press('Tab');
@@ -39,6 +37,33 @@ test('modal: focus trap', async () => {
expect(activeElementTextThree).toEqual('Dismiss Modal');
});
+test('modal: return focus', async () => {
+ const page = await newE2EPage({ url: '/src/components/modal/test/basic?ionic:_testing=true' });
+ const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss');
+ const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
+
+ await page.click('#basic-modal');
+ await page.waitForSelector('#basic-modal');
+
+ let modal = await page.find('ion-modal');
+ expect(modal).not.toBe(null);
+
+ await ionModalDidPresent.next()
+
+ await Promise.all([
+ await modal.callMethod('dismiss'),
+ await ionModalDidDismiss.next(),
+ await modal.waitForNotVisible(),
+ ]);
+
+ modal = await page.find('ion-modal');
+ expect(modal).toBeNull();
+
+ const activeElement = await page.evaluateHandle(() => document.activeElement);
+ const id = await activeElement.evaluate((node) => node.id);
+ expect(id).toEqual('basic-modal');
+});
+
test('modal: basic', async () => {
await testModal(DIRECTORY, '#basic-modal');
});
diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts
index 2346a4693a..d66301085e 100644
--- a/core/src/utils/overlays.ts
+++ b/core/src/utils/overlays.ts
@@ -260,11 +260,47 @@ export const present = async (
overlay.didPresent.emit();
}
+ /**
+ * When an overlay that steals focus
+ * is dismissed, focus should be returned
+ * to the element that was focused
+ * prior to the overlay opening. Toast
+ * does not steal focus and is excluded
+ * from returning focus as a result.
+ */
+ if (overlay.el.tagName !== 'ION-TOAST') {
+ focusPreviousElementOnDismiss(overlay.el);
+ }
+
if (overlay.keyboardClose) {
overlay.el.focus();
}
};
+/**
+ * When an overlay component is dismissed,
+ * focus should be returned to the element
+ * that presented the overlay. Otherwise
+ * focus will be set on the body which
+ * means that people using screen readers
+ * or tabbing will need to re-navigate
+ * to where they were before they
+ * opened the overlay.
+ */
+const focusPreviousElementOnDismiss = async (overlayEl: any) => {
+ let previousElement = document.activeElement as HTMLElement | null;
+ if (!previousElement) { return; }
+
+ const shadowRoot = previousElement && previousElement.shadowRoot;
+ if (shadowRoot) {
+ // If there are no inner focusable elements, just focus the host element.
+ previousElement = shadowRoot.querySelector(innerFocusableQueryString) || previousElement;
+ }
+
+ await overlayEl.onDidDismiss();
+ previousElement.focus();
+}
+
export const dismiss = async (
overlay: OverlayInterface,
data: any | undefined,
From aeda33d8ae579a47fd3dcb3b8293eb198b9a9a72 Mon Sep 17 00:00:00 2001
From: Liam DeBeasi
Date: Fri, 25 Sep 2020 10:27:27 -0400
Subject: [PATCH 09/22] docs(vue): add revised overlay examples (#22173)
---
core/src/components/action-sheet/readme.md | 82 +++++++++++++++++--
core/src/components/action-sheet/usage/vue.md | 82 +++++++++++++++++--
core/src/components/alert/readme.md | 34 ++++++++
core/src/components/alert/usage/vue.md | 34 ++++++++
core/src/components/loading/readme.md | 34 ++++++++
core/src/components/loading/usage/vue.md | 34 ++++++++
core/src/components/modal/readme.md | 31 +++++++
core/src/components/modal/usage/vue.md | 31 +++++++
core/src/components/popover/readme.md | 36 ++++++++
core/src/components/popover/usage/vue.md | 36 ++++++++
core/src/components/toast/readme.md | 30 +++++++
core/src/components/toast/usage/vue.md | 30 +++++++
12 files changed, 484 insertions(+), 10 deletions(-)
diff --git a/core/src/components/action-sheet/readme.md b/core/src/components/action-sheet/readme.md
index 4a70de38e3..83690632c5 100644
--- a/core/src/components/action-sheet/readme.md
+++ b/core/src/components/action-sheet/readme.md
@@ -286,6 +286,7 @@ export class ActionSheetExample {
```
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Action Sheet
+
+
+
+
+
+```
+
## Properties
diff --git a/core/src/components/action-sheet/usage/vue.md b/core/src/components/action-sheet/usage/vue.md
index b2e3658ecf..8e9d4169e5 100644
--- a/core/src/components/action-sheet/usage/vue.md
+++ b/core/src/components/action-sheet/usage/vue.md
@@ -6,6 +6,7 @@
```
+
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Action Sheet
+
+
+
+
+
+```
diff --git a/core/src/components/alert/readme.md b/core/src/components/alert/readme.md
index 5ed7034655..ab7fa95b9b 100644
--- a/core/src/components/alert/readme.md
+++ b/core/src/components/alert/readme.md
@@ -1419,6 +1419,40 @@ export default defineComponent({
```
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Alert
+
+
+
+
+
+```
+
## Properties
diff --git a/core/src/components/alert/usage/vue.md b/core/src/components/alert/usage/vue.md
index cf90273088..c1cb7990cf 100644
--- a/core/src/components/alert/usage/vue.md
+++ b/core/src/components/alert/usage/vue.md
@@ -263,3 +263,37 @@ export default defineComponent({
});
```
+
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Alert
+
+
+
+
+
+```
diff --git a/core/src/components/loading/readme.md b/core/src/components/loading/readme.md
index 622ea29f6b..84f29b9a4d 100644
--- a/core/src/components/loading/readme.md
+++ b/core/src/components/loading/readme.md
@@ -265,6 +265,40 @@ export default defineComponent({
```
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Loading
+
+
+
+
+
+```
+
## Properties
diff --git a/core/src/components/loading/usage/vue.md b/core/src/components/loading/usage/vue.md
index 266a3326b4..8d92512536 100644
--- a/core/src/components/loading/usage/vue.md
+++ b/core/src/components/loading/usage/vue.md
@@ -52,3 +52,37 @@ export default defineComponent({
});
```
+
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Loading
+
+
+
+
+
+```
diff --git a/core/src/components/modal/readme.md b/core/src/components/modal/readme.md
index 6d3771b35a..c007e0bc42 100644
--- a/core/src/components/modal/readme.md
+++ b/core/src/components/modal/readme.md
@@ -646,6 +646,37 @@ export default {
```
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Modal
+
+
+
+
+
+
+```
+
## Properties
diff --git a/core/src/components/modal/usage/vue.md b/core/src/components/modal/usage/vue.md
index 8f9233315b..cc10f78bb7 100644
--- a/core/src/components/modal/usage/vue.md
+++ b/core/src/components/modal/usage/vue.md
@@ -67,3 +67,34 @@ export default {
}
```
+
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Modal
+
+
+
+
+
+
+```
diff --git a/core/src/components/popover/readme.md b/core/src/components/popover/readme.md
index b4c493fede..9222a14629 100644
--- a/core/src/components/popover/readme.md
+++ b/core/src/components/popover/readme.md
@@ -224,6 +224,42 @@ export default {
```
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Popover
+
+
+
+
+
+
+```
+
## Properties
diff --git a/core/src/components/popover/usage/vue.md b/core/src/components/popover/usage/vue.md
index a46dc65d37..c83f6b6d58 100644
--- a/core/src/components/popover/usage/vue.md
+++ b/core/src/components/popover/usage/vue.md
@@ -46,3 +46,39 @@ export default {
}
```
+
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Popover
+
+
+
+
+
+
+```
diff --git a/core/src/components/toast/readme.md b/core/src/components/toast/readme.md
index e60e5cabea..f29b1c03d8 100644
--- a/core/src/components/toast/readme.md
+++ b/core/src/components/toast/readme.md
@@ -271,6 +271,36 @@ export default {
```
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Toast
+
+
+
+
+
+```
+
## Properties
diff --git a/core/src/components/toast/usage/vue.md b/core/src/components/toast/usage/vue.md
index f0c5134151..9d8bea3ee2 100644
--- a/core/src/components/toast/usage/vue.md
+++ b/core/src/components/toast/usage/vue.md
@@ -51,3 +51,33 @@ export default {
}
```
+
+Developers can also use this component directly in their template:
+
+```html
+
+ Show Toast
+
+
+
+
+
+```
From 5e341643d4c18d964cfb4baf1a974901fd60f46c Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Fri, 25 Sep 2020 10:43:25 -0400
Subject: [PATCH 10/22] 5.3.4
---
CHANGELOG.md | 25 ++++++++++++++++++++---
angular/package-lock.json | 8 ++++----
angular/package.json | 4 ++--
core/package-lock.json | 2 +-
core/package.json | 2 +-
docs/package.json | 2 +-
packages/angular-server/package-lock.json | 8 ++++----
packages/angular-server/package.json | 4 ++--
packages/react-router/package.json | 10 ++++-----
packages/react/package.json | 4 ++--
10 files changed, 44 insertions(+), 25 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5717554304..fdefc1e966 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,22 @@
+## [5.3.4](https://github.com/ionic-team/ionic/compare/v5.3.3...v5.3.4) (2020-09-25)
+
+
+### Bug Fixes
+
+* **alert:** follow accessibility guidelines outlined by wai-aria ([#22159](https://github.com/ionic-team/ionic/issues/22159)) ([e9b2cc8](https://github.com/ionic-team/ionic/commit/e9b2cc8453f5e1c45d44397df738f60ea5b32efd)), closes [#21744](https://github.com/ionic-team/ionic/issues/21744)
+* **overlays:** return focus to presenting element after dismissal ([#22167](https://github.com/ionic-team/ionic/issues/22167)) ([cc45ad8](https://github.com/ionic-team/ionic/commit/cc45ad815c002c5d890f2e105c546b4c3b3a58c0)), closes [#21768](https://github.com/ionic-team/ionic/issues/21768)
+* **picker-column:** add cancelable check to avoid intervention error in chrome ([#22140](https://github.com/ionic-team/ionic/issues/22140)) ([a24a041](https://github.com/ionic-team/ionic/commit/a24a041064fd9ce6ca161d3522083d50e585e9dd)), closes [#22137](https://github.com/ionic-team/ionic/issues/22137)
+* **radio:** follow accessibility guidelines outlined by wai-aria ([#22113](https://github.com/ionic-team/ionic/issues/22113)) ([ea0e049](https://github.com/ionic-team/ionic/commit/ea0e0499e24865faad3d11f50f7037645f6cdcc8)), closes [#21743](https://github.com/ionic-team/ionic/issues/21743)
+* **reorder:** allow click event propagation when reorder group is disabled ([#21947](https://github.com/ionic-team/ionic/issues/21947)) ([baafe08](https://github.com/ionic-team/ionic/commit/baafe08927b7b858170496605781e6fa682e0147)), closes [#21017](https://github.com/ionic-team/ionic/issues/21017)
+* **segment:** do not allow text selection on desktop ([#22158](https://github.com/ionic-team/ionic/issues/22158)) ([1526bdf](https://github.com/ionic-team/ionic/commit/1526bdfb492c1fa8d71f8a1af8cd97abd9e62642))
+
+
+### Performance Improvements
+
+* **segment:** improve scrolling performance on ios when using segment ([#22110](https://github.com/ionic-team/ionic/issues/22110)) ([68afc49](https://github.com/ionic-team/ionic/commit/68afc49e9ed27acffb0b765b7be6b03e8574850d)), closes [#22095](https://github.com/ionic-team/ionic/issues/22095)
+
+
+
## [5.3.3](https://github.com/ionic-team/ionic/compare/v5.3.2...v5.3.3) (2020-09-17)
@@ -60,7 +79,7 @@
* **card:** expose global card css variables ([#21756](https://github.com/ionic-team/ionic/issues/21756)) ([096eef4](https://github.com/ionic-team/ionic/commit/096eef4a79c2d05c37eb224466c6d7d512d2be20)), closes [#21694](https://github.com/ionic-team/ionic/issues/21694)
* **input:** accept datetime-local, month, and week type values ([#21758](https://github.com/ionic-team/ionic/issues/21758)) ([fa93dff](https://github.com/ionic-team/ionic/commit/fa93dffdb4f350e8db8acc7f06b06761974eea8e)), closes [#21757](https://github.com/ionic-team/ionic/issues/21757)
* **input, textarea:** expose native events for ionBlur and ionFocus ([#21777](https://github.com/ionic-team/ionic/issues/21777)) ([a625c83](https://github.com/ionic-team/ionic/commit/a625c837a60abc07ad71c696196a89f1a25a4c27)), closes [#17363](https://github.com/ionic-team/ionic/issues/17363)
-* **react:** add custom history to IonReactRouter ([#21775](https://github.com/ionic-team/ionic/issues/21775)) ([d4a5fbd](https://github.com/ionic-team/ionic/commit/d4a5fbd955e8ecccba8b77491943d81fdf5a5ef4)), closes [#20297](https://github.com/ionic-team/ionic/issues/20297)
+* **react:** add custom history to IonReactRouter ([#21775](https://github.com/ionic-team/ionic/issues/21775)) ([d4a5fbd](https://github.com/ionic-team/ionic/commit/d4a5fbd955e8ecccba8b77491943d81fdf5a5ef4)), closes [#20297](https://github.com/ionic-team/ionic/issues/20297)
* **react:** add new react router ([#21693](https://github.com/ionic-team/ionic/issues/21693)) ([c171ccb](https://github.com/ionic-team/ionic/commit/c171ccbd37c1ee4b4934758a3a759170ff357cb2))
* **router:** add navigation hooks ([#21709](https://github.com/ionic-team/ionic/issues/21709)) ([77464ef](https://github.com/ionic-team/ionic/commit/77464ef21aaaa5afa7a02e5417f3ec295b240601))
* **segment-button, toast:** expose additional shadow parts ([#21532](https://github.com/ionic-team/ionic/issues/21532)) ([a5e4669](https://github.com/ionic-team/ionic/commit/a5e4669c4bcbcb2cdd605ed17c35e42438bd5596))
@@ -341,9 +360,9 @@
* **modal:** presenting multiple card-style modals now adds border radius properly ([#20476](https://github.com/ionic-team/ionic/issues/20476)) ([abf594a](https://github.com/ionic-team/ionic/commit/abf594aa611562a76e3baecfa38456d41a1410f3)), closes [#20475](https://github.com/ionic-team/ionic/issues/20475)
* **modal:** prevent card style modal styles from being overridden ([#20470](https://github.com/ionic-team/ionic/issues/20470)) ([86ab77a](https://github.com/ionic-team/ionic/commit/86ab77a6e2cb124510c244110fc78a4bc0654cd1)), closes [#20469](https://github.com/ionic-team/ionic/issues/20469)
* **react:** do a better job matching up route to sync ([#20446](https://github.com/ionic-team/ionic/issues/20446)) ([c0aadd6](https://github.com/ionic-team/ionic/commit/c0aadd60077e5ba379959d93006e3a9c1418263c)), closes [#20363](https://github.com/ionic-team/ionic/issues/20363)
-* **react:** do not remove pages when navigating between tabs ([#20431](https://github.com/ionic-team/ionic/issues/20431)) ([b6fbe98](https://github.com/ionic-team/ionic/commit/b6fbe98812fbab5ef9e0723802605c0711581dd2)), closes [#20398](https://github.com/ionic-team/ionic/issues/20398)
+* **react:** do not remove pages when navigating between tabs ([#20431](https://github.com/ionic-team/ionic/issues/20431)) ([b6fbe98](https://github.com/ionic-team/ionic/commit/b6fbe98812fbab5ef9e0723802605c0711581dd2)), closes [#20398](https://github.com/ionic-team/ionic/issues/20398)
* **react:** icons with MD set should work in browser ([#20463](https://github.com/ionic-team/ionic/issues/20463)) ([82670fe](https://github.com/ionic-team/ionic/commit/82670fe4d0592451cbc243b3008beb3f8f483c30))
-* **react:** update paths of tab buttons when href changes in ion buttons ([#20480](https://github.com/ionic-team/ionic/issues/20480)) ([45d03ba](https://github.com/ionic-team/ionic/commit/45d03baf981d0e10eb1fe689908532adef2ba31d)), closes [#20321](https://github.com/ionic-team/ionic/issues/20321)
+* **react:** update paths of tab buttons when href changes in ion buttons ([#20480](https://github.com/ionic-team/ionic/issues/20480)) ([45d03ba](https://github.com/ionic-team/ionic/commit/45d03baf981d0e10eb1fe689908532adef2ba31d)), closes [#20321](https://github.com/ionic-team/ionic/issues/20321)
* **searchbar:** properly align placeholder ([#20460](https://github.com/ionic-team/ionic/issues/20460)) ([4d6e15a](https://github.com/ionic-team/ionic/commit/4d6e15ab18fc894c3826b89362163256adc227f4)), closes [#20456](https://github.com/ionic-team/ionic/issues/20456)
* **segment:** border radius applies to indicator on ios ([#20541](https://github.com/ionic-team/ionic/issues/20541)) ([9b5854d](https://github.com/ionic-team/ionic/commit/9b5854d79712356f8a3772442c0cc412db09d5e0)), closes [#20539](https://github.com/ionic-team/ionic/issues/20539)
* **segment:** do not show ripple effect if disabled via config ([#20542](https://github.com/ionic-team/ionic/issues/20542)) ([7a461c5](https://github.com/ionic-team/ionic/commit/7a461c59c5d9a23de0bcdd53397f452d17251fd6)), closes [#20533](https://github.com/ionic-team/ionic/issues/20533)
diff --git a/angular/package-lock.json b/angular/package-lock.json
index 1f3d9478d3..791aa20a4a 100644
--- a/angular/package-lock.json
+++ b/angular/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
- "version": "5.3.3",
+ "version": "5.3.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -147,9 +147,9 @@
}
},
"@ionic/core": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.3.2.tgz",
- "integrity": "sha512-s/SDnS993fnZ3d6EzOlURHBbc2aI2/WsZSsCLgnJz3G+KUO4hY/2RQvdmtl0FZpDHMSyehG6tRgFFXvnFSI9CQ==",
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.3.3.tgz",
+ "integrity": "sha512-vXZQAPdLM0XimXJ+8pSQijIYliD+WiBQy3zkRG5czXsVkhCdwd095XgZ7pcdmWDstUKxtB1BzxJgKntjJw0Tdg==",
"requires": {
"ionicons": "^5.1.2",
"tslib": "^1.10.0"
diff --git a/angular/package.json b/angular/package.json
index 6112c65a53..1163f7445e 100644
--- a/angular/package.json
+++ b/angular/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
- "version": "5.3.3",
+ "version": "5.3.4",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -42,7 +42,7 @@
"validate": "npm i && npm run lint && npm run test && npm run build"
},
"dependencies": {
- "@ionic/core": "5.3.3",
+ "@ionic/core": "5.3.4",
"tslib": "^1.9.3"
},
"peerDependencies": {
diff --git a/core/package-lock.json b/core/package-lock.json
index 5ae444efe1..ebc527f622 100644
--- a/core/package-lock.json
+++ b/core/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
- "version": "5.3.3",
+ "version": "5.3.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/core/package.json b/core/package.json
index d08e0dca28..b1a73eb384 100644
--- a/core/package.json
+++ b/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
- "version": "5.3.3",
+ "version": "5.3.4",
"description": "Base components for Ionic",
"keywords": [
"ionic",
diff --git a/docs/package.json b/docs/package.json
index f501a9fda1..3b2a18ef2d 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/docs",
- "version": "5.3.3",
+ "version": "5.3.4",
"description": "Pre-packaged API documentation for the Ionic docs.",
"main": "core.json",
"types": "core.d.ts",
diff --git a/packages/angular-server/package-lock.json b/packages/angular-server/package-lock.json
index 51ef0c4898..bebee8f675 100644
--- a/packages/angular-server/package-lock.json
+++ b/packages/angular-server/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/angular-server",
- "version": "5.3.3",
+ "version": "5.3.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -99,9 +99,9 @@
}
},
"@ionic/core": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.3.2.tgz",
- "integrity": "sha512-s/SDnS993fnZ3d6EzOlURHBbc2aI2/WsZSsCLgnJz3G+KUO4hY/2RQvdmtl0FZpDHMSyehG6tRgFFXvnFSI9CQ==",
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.3.3.tgz",
+ "integrity": "sha512-vXZQAPdLM0XimXJ+8pSQijIYliD+WiBQy3zkRG5czXsVkhCdwd095XgZ7pcdmWDstUKxtB1BzxJgKntjJw0Tdg==",
"dev": true,
"requires": {
"ionicons": "^5.1.2",
diff --git a/packages/angular-server/package.json b/packages/angular-server/package.json
index fe4d466e22..c2a5607350 100644
--- a/packages/angular-server/package.json
+++ b/packages/angular-server/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/angular-server",
- "version": "5.3.3",
+ "version": "5.3.4",
"description": "Angular SSR Module for Ionic",
"keywords": [
"ionic",
@@ -49,7 +49,7 @@
"@angular/core": "8.2.13",
"@angular/platform-browser": "8.2.13",
"@angular/platform-server": "8.2.13",
- "@ionic/core": "5.3.3",
+ "@ionic/core": "5.3.4",
"ng-packagr": "5.7.1",
"tslint": "^5.12.1",
"tslint-ionic-rules": "0.0.21",
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index 5c9b838900..2418b3b360 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/react-router",
- "version": "5.3.3",
+ "version": "5.3.4",
"description": "React Router wrapper for @ionic/react",
"keywords": [
"ionic",
@@ -39,16 +39,16 @@
"tslib": "*"
},
"peerDependencies": {
- "@ionic/core": "5.3.3",
- "@ionic/react": "5.3.3",
+ "@ionic/core": "5.3.4",
+ "@ionic/react": "5.3.4",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1"
},
"devDependencies": {
- "@ionic/core": "5.3.3",
- "@ionic/react": "5.3.3",
+ "@ionic/core": "5.3.4",
+ "@ionic/react": "5.3.4",
"@rollup/plugin-node-resolve": "^8.1.0",
"@testing-library/jest-dom": "^5.11.0",
"@testing-library/react": "^10.4.9",
diff --git a/packages/react/package.json b/packages/react/package.json
index bd66b3a54d..bde00f7b43 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/react",
- "version": "5.3.3",
+ "version": "5.3.4",
"description": "React specific wrapper for @ionic/core",
"keywords": [
"ionic",
@@ -39,7 +39,7 @@
"css/"
],
"dependencies": {
- "@ionic/core": "5.3.3",
+ "@ionic/core": "5.3.4",
"ionicons": "^5.1.2",
"tslib": "*"
},
From 1832be059736a5c2cc5b78b8be36d82bc08cbce4 Mon Sep 17 00:00:00 2001
From: Liam DeBeasi
Date: Tue, 29 Sep 2020 10:00:59 -0400
Subject: [PATCH 11/22] docs(modal): fix props on vue example (#22201)
---
core/src/components/modal/readme.md | 7 +------
core/src/components/modal/usage/vue.md | 7 +------
2 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/core/src/components/modal/readme.md b/core/src/components/modal/readme.md
index c007e0bc42..7df06e6982 100644
--- a/core/src/components/modal/readme.md
+++ b/core/src/components/modal/readme.md
@@ -631,12 +631,7 @@ export default {
component: Modal,
cssClass: 'my-custom-class',
componentProps: {
- data: {
- content: 'New Content',
- },
- propsData: {
- title: 'New title',
- },
+ title: 'New Title'
},
})
return modal.present();
diff --git a/core/src/components/modal/usage/vue.md b/core/src/components/modal/usage/vue.md
index cc10f78bb7..429086a808 100644
--- a/core/src/components/modal/usage/vue.md
+++ b/core/src/components/modal/usage/vue.md
@@ -53,12 +53,7 @@ export default {
component: Modal,
cssClass: 'my-custom-class',
componentProps: {
- data: {
- content: 'New Content',
- },
- propsData: {
- title: 'New title',
- },
+ title: 'New Title'
},
})
return modal.present();
From f81d18c6f9f1bce056afda1cac4cf6d6ace0a7ca Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Tue, 29 Sep 2020 16:32:21 -0400
Subject: [PATCH 12/22] fix(datetime): remove the automatic switching from am
to pm (#22207)
fixes #18924 fixes #22171 fixes #22199
---
core/src/components/datetime/datetime-util.ts | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/core/src/components/datetime/datetime-util.ts b/core/src/components/datetime/datetime-util.ts
index 466c863e60..12581428a1 100644
--- a/core/src/components/datetime/datetime-util.ts
+++ b/core/src/components/datetime/datetime-util.ts
@@ -326,24 +326,6 @@ export const updateDate = (existingData: DatetimeData, newData: any, displayTime
// newData is from the datetime picker's selected values
// update the existing datetimeValue with the new values
if (newData.ampm !== undefined && newData.hour !== undefined) {
- // If the date we came from exists, we need to change the meridiem value when
- // going to and from 12
- if (existingData.ampm !== undefined && existingData.hour !== undefined) {
- // If the existing meridiem is am, we want to switch to pm if it is either
- // A) coming from 0 (12 am)
- // B) going to 12 (12 pm)
- if (existingData.ampm === 'am' && (existingData.hour === 0 || newData.hour.value === 12)) {
- newData.ampm.value = 'pm';
- }
-
- // If the existing meridiem is pm, we want to switch to am if it is either
- // A) coming from 12 (12 pm)
- // B) going to 12 (12 am)
- if (existingData.ampm === 'pm' && (existingData.hour === 12 || newData.hour.value === 12)) {
- newData.ampm.value = 'am';
- }
- }
-
// change the value of the hour based on whether or not it is am or pm
// if the meridiem is pm and equal to 12, it remains 12
// otherwise we add 12 to the hour value
From a8fbb34844e245060d1863a30fc2ffd89ea5b053 Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Wed, 30 Sep 2020 18:10:25 -0400
Subject: [PATCH 13/22] chore(github): add pull request labeler for packages
(#22219)
---
.github/ionic-issue-bot.yml | 16 ----------------
.github/labeler.yml | 21 +++++++++++++++++++++
.github/workflows/label.yml | 19 +++++++++++++++++++
3 files changed, 40 insertions(+), 16 deletions(-)
create mode 100644 .github/labeler.yml
create mode 100644 .github/workflows/label.yml
diff --git a/.github/ionic-issue-bot.yml b/.github/ionic-issue-bot.yml
index d3f7cbef25..9bf011ce4d 100644
--- a/.github/ionic-issue-bot.yml
+++ b/.github/ionic-issue-bot.yml
@@ -130,22 +130,6 @@ noReproduction:
lock: true
dryRun: false
-labelPullRequest:
- labels:
- - label: "package: angular"
- branch: master
- path: ^angular
- - label: "package: core"
- branch: master
- path: ^core
- - label: "package: react"
- branch: master
- path: ^react
- - label: "package: vue"
- branch: master
- path: ^vue
- dryRun: false
-
wrongRepo:
repos:
- label: "ionitron: capacitor"
diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 0000000000..c39479e679
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,21 @@
+# This is used with the label workflow which
+# will triage pull requests and apply a label based on the
+# paths that are modified in the pull request.
+#
+# For more information, see:
+# https://github.com/actions/labeler
+
+'package: core':
+ - core/**/*
+
+'package: angular':
+ - angular/**/*
+ - packages/angular-*/**/*
+
+'package: react':
+ - packages/react/**/*
+ - packages/react-*/**/*
+
+'package: vue':
+ - packages/vue/**/*
+ - packages/vue-*/**/*
diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml
new file mode 100644
index 0000000000..0241c7fa5b
--- /dev/null
+++ b/.github/workflows/label.yml
@@ -0,0 +1,19 @@
+# This workflow will triage pull requests and apply a label based on the
+# paths that are modified in the pull request.
+#
+# To use this workflow, you will need to set up a .github/labeler.yml
+# file with configuration. For more information, see:
+# https://github.com/actions/labeler
+
+name: "Pull Request Labeler"
+on:
+- pull_request_target
+
+jobs:
+ triage:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/labeler@main
+ with:
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ sync-labels: true
From 18fb8855e0c45fe65843b33811812c51c74de90f Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Thu, 1 Oct 2020 13:06:13 -0400
Subject: [PATCH 14/22] fix(datetime): do not set ampm when the column doesn't
exist (#22220)
fixes #22149
---
.../components/datetime/datetime-util.spec.ts | 8 ++---
core/src/components/datetime/datetime-util.ts | 11 +++++--
.../components/datetime/test/basic/index.html | 9 ++++--
.../components/datetime/test/datetime.spec.ts | 32 +++++++++++++++++++
4 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/core/src/components/datetime/datetime-util.spec.ts b/core/src/components/datetime/datetime-util.spec.ts
index db6dfd25ff..589b1b0bc9 100644
--- a/core/src/components/datetime/datetime-util.spec.ts
+++ b/core/src/components/datetime/datetime-util.spec.ts
@@ -220,7 +220,7 @@ describe('datetime-util', () => {
"second": undefined,
"tzOffset": 0,
"year": 1000,
- "ampm": "am"
+ "ampm": undefined
});
});
@@ -235,7 +235,7 @@ describe('datetime-util', () => {
"second": undefined,
"tzOffset": 0,
"year": undefined,
- "ampm": "pm"
+ "ampm": undefined
});
});
@@ -250,7 +250,7 @@ describe('datetime-util', () => {
"second": 20,
"tzOffset": 0,
"year": 1994,
- "ampm": "pm"
+ "ampm": undefined
});
});
@@ -265,7 +265,7 @@ describe('datetime-util', () => {
"second": undefined,
"tzOffset": 0,
"year": 2018,
- "ampm": "am"
+ "ampm": undefined
});
});
diff --git a/core/src/components/datetime/datetime-util.ts b/core/src/components/datetime/datetime-util.ts
index 12581428a1..bce769f58e 100644
--- a/core/src/components/datetime/datetime-util.ts
+++ b/core/src/components/datetime/datetime-util.ts
@@ -3,10 +3,16 @@
* Defaults to the current date if
* no date given
*/
-export const getDateValue = (date: DatetimeData, format: string): number => {
+export const getDateValue = (date: DatetimeData, format: string): number | string => {
const getValue = getValueFromFormat(date, format);
- if (getValue !== undefined) { return getValue; }
+ if (getValue !== undefined) {
+ if (format === FORMAT_A || format === FORMAT_a) {
+ date.ampm = getValue;
+ }
+
+ return getValue;
+ }
const defaultDate = parseDate(new Date().toISOString());
return getValueFromFormat((defaultDate as DatetimeData), format);
@@ -238,7 +244,6 @@ export const parseDate = (val: string | undefined | null): DatetimeData | undefi
second: parse[6],
millisecond: parse[7],
tzOffset,
- ampm: parse[4] >= 12 ? 'pm' : 'am'
};
};
diff --git a/core/src/components/datetime/test/basic/index.html b/core/src/components/datetime/test/basic/index.html
index 9f3deabfe5..8d627ee78c 100644
--- a/core/src/components/datetime/test/basic/index.html
+++ b/core/src/components/datetime/test/basic/index.html
@@ -113,8 +113,8 @@
- HH:mm
-
+ HH:mm A
+
@@ -127,6 +127,11 @@
+
+ h:mm A
+
+
+
hh:mm A (15 min steps)
diff --git a/core/src/components/datetime/test/datetime.spec.ts b/core/src/components/datetime/test/datetime.spec.ts
index 3f55504a37..84a2ce49c3 100644
--- a/core/src/components/datetime/test/datetime.spec.ts
+++ b/core/src/components/datetime/test/datetime.spec.ts
@@ -30,6 +30,38 @@ describe('Datetime', () => {
expect(monthvalue).toEqual(date.getMonth() + 1);
expect(yearValue).toEqual(date.getFullYear());
});
+
+ it('it should return the date value for a given time', () => {
+ const dateTimeData: DatetimeData = {
+ hour: 2,
+ minute: 23,
+ tzOffset: 0
+ };
+
+ const hourValue = getDateValue(dateTimeData, 'hh');
+ const minuteValue = getDateValue(dateTimeData, 'mm');
+ const ampmValue = getDateValue(dateTimeData, 'A');
+
+ expect(hourValue).toEqual(2);
+ expect(minuteValue).toEqual(23);
+ expect(ampmValue).toEqual("am");
+ });
+
+ it('it should return the date value for a given time after 12', () => {
+ const dateTimeData: DatetimeData = {
+ hour: 16,
+ minute: 47,
+ tzOffset: 0
+ };
+
+ const hourValue = getDateValue(dateTimeData, 'hh');
+ const minuteValue = getDateValue(dateTimeData, 'mm');
+ const ampmValue = getDateValue(dateTimeData, 'a');
+
+ expect(hourValue).toEqual(4);
+ expect(minuteValue).toEqual(47);
+ expect(ampmValue).toEqual("pm");
+ });
});
describe('getDateTime()', () => {
From f42c688f4630e3dc5d10b947e7f2bee9d5967d8c Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Thu, 1 Oct 2020 18:54:19 -0400
Subject: [PATCH 15/22] fix(item): properly align datetime and select without
labels and with fixed labels (#22221)
fixes #18773 fixes #18761 fixes #18779
---
core/src/components/item/item.ios.scss | 9 ++
core/src/components/item/item.md.scss | 10 +-
core/src/components/item/item.scss | 14 +-
.../src/components/item/test/alignment/e2e.ts | 19 +++
.../components/item/test/alignment/index.html | 135 ++++++++++++++++++
core/src/components/label/label.md.scss | 4 -
core/src/components/select/select.md.scss | 4 +
7 files changed, 189 insertions(+), 6 deletions(-)
create mode 100644 core/src/components/item/test/alignment/e2e.ts
create mode 100644 core/src/components/item/test/alignment/index.html
diff --git a/core/src/components/item/item.ios.scss b/core/src/components/item/item.ios.scss
index 87235cbddf..30f2c00062 100644
--- a/core/src/components/item/item.ios.scss
+++ b/core/src/components/item/item.ios.scss
@@ -204,6 +204,15 @@
}
+// iOS Fixed Labels
+// --------------------------------------------------
+
+:host(.item-label-fixed) ::slotted(ion-select),
+:host(.item-label-fixed) ::slotted(ion-datetime) {
+ --padding-start: 0;
+}
+
+
// FROM TEXTAREA
// iOS Stacked & Floating Textarea
// --------------------------------------------------
diff --git a/core/src/components/item/item.md.scss b/core/src/components/item/item.md.scss
index 643001a9bb..cfe05fdb7b 100644
--- a/core/src/components/item/item.md.scss
+++ b/core/src/components/item/item.md.scss
@@ -212,7 +212,6 @@
}
-
// Material Design Floating/Stacked Label
// --------------------------------------------------
@@ -222,6 +221,15 @@
}
+// Material Design Fixed Labels
+// --------------------------------------------------
+
+:host(.item-label-fixed) ::slotted(ion-select),
+:host(.item-label-fixed) ::slotted(ion-datetime) {
+ --padding-start: 8px;
+}
+
+
// Material Design Toggle/Radio Item
// --------------------------------------------------
diff --git a/core/src/components/item/item.scss b/core/src/components/item/item.scss
index ecbfcae447..882cce3023 100644
--- a/core/src/components/item/item.scss
+++ b/core/src/components/item/item.scss
@@ -407,8 +407,16 @@ button, a {
// Item Select
// --------------------------------------------------
+:host(:not(.item-label)) ::slotted(ion-select) {
+ --padding-start: 0;
+
+ max-width: none;
+}
+
:host(.item-label-stacked) ::slotted(ion-select),
:host(.item-label-floating) ::slotted(ion-select) {
+ --padding-top: 8px;
+ --padding-bottom: 8px;
--padding-start: 0;
align-self: stretch;
@@ -422,6 +430,10 @@ button, a {
// Item Datetime
// --------------------------------------------------
+:host(:not(.item-label)) ::slotted(ion-datetime) {
+ --padding-start: 0;
+}
+
:host(.item-label-stacked) ::slotted(ion-datetime),
:host(.item-label-floating) ::slotted(ion-datetime) {
--padding-start: 0;
@@ -463,4 +475,4 @@ button, a {
ion-ripple-effect {
color: var(--ripple-color);
-}
\ No newline at end of file
+}
diff --git a/core/src/components/item/test/alignment/e2e.ts b/core/src/components/item/test/alignment/e2e.ts
new file mode 100644
index 0000000000..2b3633538d
--- /dev/null
+++ b/core/src/components/item/test/alignment/e2e.ts
@@ -0,0 +1,19 @@
+import { newE2EPage } from '@stencil/core/testing';
+
+test('item: alignment', async () => {
+ const page = await newE2EPage({
+ url: '/src/components/item/test/alignment?ionic:_testing=true'
+ });
+
+ const compare = await page.compareScreenshot();
+ expect(compare).toMatchScreenshot();
+});
+
+test('item: alignment-rtl', async () => {
+ const page = await newE2EPage({
+ url: '/src/components/item/test/alignment?ionic:_testing=true&rtl=true'
+ });
+
+ const compare = await page.compareScreenshot();
+ expect(compare).toMatchScreenshot();
+});
diff --git a/core/src/components/item/test/alignment/index.html b/core/src/components/item/test/alignment/index.html
new file mode 100644
index 0000000000..0fe63d492e
--- /dev/null
+++ b/core/src/components/item/test/alignment/index.html
@@ -0,0 +1,135 @@
+
+
+
+
+
+ Item - Alignment
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Item - Alignment
+
+
+
+
+
+ Leading Icons
+
+
+
+
+
+
+
+
+
+
+
+ Madison, WI
+ Atlanta, GA
+
+
+
+
+
+ Default Labels
+
+ Time
+
+
+
+ From
+
+
+
+ Destination
+
+ Madison, WI
+ Atlanta, GA
+
+
+
+
+
+ Fixed Labels
+
+ Time
+
+
+
+ From
+
+
+
+ Destination
+
+ Madison, WI
+ Atlanta, GA
+
+
+
+
+
+ Floating Labels
+
+ Time
+
+
+
+ From
+
+
+
+ Destination
+
+ Madison, WI
+ Atlanta, GA
+
+
+
+
+
+ Stacked Labels
+
+ Time
+
+
+
+ From
+
+
+
+ Destination
+
+ Madison, WI
+ Atlanta, GA
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/components/label/label.md.scss b/core/src/components/label/label.md.scss
index d1739c80f4..4bdb56c259 100644
--- a/core/src/components/label/label.md.scss
+++ b/core/src/components/label/label.md.scss
@@ -38,10 +38,6 @@
@include margin(0, 0, 0, 0);
}
-:host-context(.item-select).label-floating {
- @include transform(translate3d(0, 130%, 0));
-}
-
:host-context(.item-has-focus).label-floating,
:host-context(.item-has-placeholder).label-floating,
:host-context(.item-has-value).label-floating {
diff --git a/core/src/components/select/select.md.scss b/core/src/components/select/select.md.scss
index 5f087e47aa..cd12859302 100644
--- a/core/src/components/select/select.md.scss
+++ b/core/src/components/select/select.md.scss
@@ -15,3 +15,7 @@
width: 19px;
height: 19px;
}
+
+:host-context(.item-label-floating) .select-icon {
+ @include transform(translate3d(0, -9px, 0));
+}
From 2373ff0d3923754190eefac24a35259ee29cbf2b Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Thu, 1 Oct 2020 19:04:18 -0400
Subject: [PATCH 16/22] docs(popover): add the popover-example-page to core and
event to react (#22231)
closes ionic-team/ionic-docs#1517
---
core/src/components/popover/readme.md | 38 +++++++++++++++++--
.../components/popover/usage/javascript.md | 22 +++++++++++
core/src/components/popover/usage/react.md | 18 ++++++---
3 files changed, 69 insertions(+), 9 deletions(-)
diff --git a/core/src/components/popover/readme.md b/core/src/components/popover/readme.md
index 9222a14629..b8fbd9b1b1 100644
--- a/core/src/components/popover/readme.md
+++ b/core/src/components/popover/readme.md
@@ -76,6 +76,28 @@ In Angular, the CSS of a specific page is scoped only to elements of that page.
### Javascript
```javascript
+class PopoverExamplePage extends HTMLElement {
+ constructor() {
+ super();
+ }
+
+ connectedCallback() {
+ this.innerHTML = `
+
+
+ Ionic
+ Item 0
+ Item 1
+ Item 2
+ Item 3
+
+
+ `;
+ }
+}
+
+customElements.define('popover-example-page', PopoverExamplePage);
+
function presentPopover(ev) {
const popover = Object.assign(document.createElement('ion-popover'), {
component: 'popover-example-page',
@@ -96,18 +118,26 @@ import React, { useState } from 'react';
import { IonPopover, IonButton } from '@ionic/react';
export const PopoverExample: React.FC = () => {
- const [showPopover, setShowPopover] = useState(false);
+ const [popoverState, setShowPopover] = useState({ showPopover: false, event: undefined });
return (
<>
setShowPopover(false)}
+ event={popoverState.event}
+ isOpen={popoverState.showPopover}
+ onDidDismiss={() => setShowPopover({ showPopover: false, event: undefined })}
>
This is popover content
- setShowPopover(true)}>Show Popover
+ {
+ e.persist();
+ setShowPopover({ showPopover: true, event: e })
+ }}
+ >
+ Show Popover
+
>
);
};
diff --git a/core/src/components/popover/usage/javascript.md b/core/src/components/popover/usage/javascript.md
index 548a236399..6141a1ec94 100644
--- a/core/src/components/popover/usage/javascript.md
+++ b/core/src/components/popover/usage/javascript.md
@@ -1,4 +1,26 @@
```javascript
+class PopoverExamplePage extends HTMLElement {
+ constructor() {
+ super();
+ }
+
+ connectedCallback() {
+ this.innerHTML = `
+
+
+ Ionic
+ Item 0
+ Item 1
+ Item 2
+ Item 3
+
+
+ `;
+ }
+}
+
+customElements.define('popover-example-page', PopoverExamplePage);
+
function presentPopover(ev) {
const popover = Object.assign(document.createElement('ion-popover'), {
component: 'popover-example-page',
diff --git a/core/src/components/popover/usage/react.md b/core/src/components/popover/usage/react.md
index 9cde980381..f55b109f52 100644
--- a/core/src/components/popover/usage/react.md
+++ b/core/src/components/popover/usage/react.md
@@ -3,19 +3,27 @@ import React, { useState } from 'react';
import { IonPopover, IonButton } from '@ionic/react';
export const PopoverExample: React.FC = () => {
- const [showPopover, setShowPopover] = useState(false);
+ const [popoverState, setShowPopover] = useState({ showPopover: false, event: undefined });
return (
<>
setShowPopover(false)}
+ event={popoverState.event}
+ isOpen={popoverState.showPopover}
+ onDidDismiss={() => setShowPopover({ showPopover: false, event: undefined })}
>
This is popover content
- setShowPopover(true)}>Show Popover
+ {
+ e.persist();
+ setShowPopover({ showPopover: true, event: e })
+ }}
+ >
+ Show Popover
+
>
);
};
-```
\ No newline at end of file
+```
From 66b4d11545a91e7d155c36eed736e70d15054ebf Mon Sep 17 00:00:00 2001
From: Jeremy Forsythe
Date: Fri, 2 Oct 2020 11:28:52 -0400
Subject: [PATCH 17/22] docs(select): fix objects as values angular usage
(#22143)
Fix the Objects as Values documentation to add the necessary value
property to the template, simplify the compare function, and add an
interface for type checking.
Add an Objects as Values with Multiple Selection documentation section
to show the difference with the compare function which needs to
determine if an object is in the array of selected objects
This fixes an issue noted in the forums at https://forum.ionicframework.com/t/ionic-5-ion-select-objects-as-values-not-working/191807/2
---
core/src/components/select/readme.md | 80 ++++++++++++++++++--
core/src/components/select/usage/angular.md | 82 +++++++++++++++++++--
2 files changed, 151 insertions(+), 11 deletions(-)
diff --git a/core/src/components/select/readme.md b/core/src/components/select/readme.md
index 8d8825a3de..d1888ff1dd 100644
--- a/core/src/components/select/readme.md
+++ b/core/src/components/select/readme.md
@@ -209,7 +209,7 @@ However, the Select Option does set a class for easier styling and allows for th
Users
- {{user.first + ' ' + user.last}}
+ {{user.first + ' ' + user.last}}
@@ -218,13 +218,19 @@ However, the Select Option does set a class for easier styling and allows for th
```typescript
import { Component } from '@angular/core';
+interface User {
+ id: number;
+ first: string;
+ last: string;
+}
+
@Component({
selector: 'select-example',
templateUrl: 'select-example.html',
styleUrls: ['./select-example.css'],
})
export class SelectExample {
- users: any[] = [
+ users: User[] = [
{
id: 1,
first: 'Alice',
@@ -242,11 +248,75 @@ export class SelectExample {
}
];
- compareWithFn = (o1, o2) => {
+ compareWith(o1: User, o2: User) {
return o1 && o2 ? o1.id === o2.id : o1 === o2;
- };
+ }
+}
+```
- compareWith = compareWithFn;
+### Objects as Values with Multiple Selection
+
+```html
+
+
+
+ Objects as Values (compareWith)
+
+
+
+
+ Users
+
+ {{user.first + ' ' + user.last}}
+
+
+
+```
+
+```typescript
+import { Component } from '@angular/core';
+
+interface User {
+ id: number;
+ first: string;
+ last: string;
+}
+
+@Component({
+ selector: 'select-example',
+ templateUrl: 'select-example.html',
+ styleUrls: ['./select-example.css'],
+})
+export class SelectExample {
+ users: User[] = [
+ {
+ id: 1,
+ first: 'Alice',
+ last: 'Smith',
+ },
+ {
+ id: 2,
+ first: 'Bob',
+ last: 'Davis',
+ },
+ {
+ id: 3,
+ first: 'Charlie',
+ last: 'Rosenburg',
+ }
+ ];
+
+ compareWith(o1: User, o2: User | User[]) {
+ if (!o1 || !o2) {
+ return o1 === o2;
+ }
+
+ if (Array.isArray(o2)) {
+ return o2.some((u: User) => u.id === o1.id);
+ }
+
+ return o1.id === o2.id;
+ }
}
```
diff --git a/core/src/components/select/usage/angular.md b/core/src/components/select/usage/angular.md
index bff14eda67..0bfd985904 100644
--- a/core/src/components/select/usage/angular.md
+++ b/core/src/components/select/usage/angular.md
@@ -80,7 +80,7 @@
Users
- {{user.first + ' ' + user.last}}
+ {{user.first + ' ' + user.last}}
@@ -89,13 +89,19 @@
```typescript
import { Component } from '@angular/core';
+interface User {
+ id: number;
+ first: string;
+ last: string;
+}
+
@Component({
selector: 'select-example',
templateUrl: 'select-example.html',
styleUrls: ['./select-example.css'],
})
export class SelectExample {
- users: any[] = [
+ users: User[] = [
{
id: 1,
first: 'Alice',
@@ -113,11 +119,75 @@ export class SelectExample {
}
];
- compareWithFn = (o1, o2) => {
+ compareWith(o1: User, o2: User) {
return o1 && o2 ? o1.id === o2.id : o1 === o2;
- };
+ }
+}
+```
- compareWith = compareWithFn;
+### Objects as Values with Multiple Selection
+
+```html
+
+
+
+ Objects as Values (compareWith)
+
+
+
+
+ Users
+
+ {{user.first + ' ' + user.last}}
+
+
+
+```
+
+```typescript
+import { Component } from '@angular/core';
+
+interface User {
+ id: number;
+ first: string;
+ last: string;
+}
+
+@Component({
+ selector: 'select-example',
+ templateUrl: 'select-example.html',
+ styleUrls: ['./select-example.css'],
+})
+export class SelectExample {
+ users: User[] = [
+ {
+ id: 1,
+ first: 'Alice',
+ last: 'Smith',
+ },
+ {
+ id: 2,
+ first: 'Bob',
+ last: 'Davis',
+ },
+ {
+ id: 3,
+ first: 'Charlie',
+ last: 'Rosenburg',
+ }
+ ];
+
+ compareWith(o1: User, o2: User | User[]) {
+ if (!o1 || !o2) {
+ return o1 === o2;
+ }
+
+ if (Array.isArray(o2)) {
+ return o2.some((u: User) => u.id === o1.id);
+ }
+
+ return o1.id === o2.id;
+ }
}
```
@@ -198,4 +268,4 @@ export class SelectExample {
subHeader: 'Select your favorite color'
};
}
-```
\ No newline at end of file
+```
From 1878c8e7e01c02f06bdc5f1562af0d45531539cf Mon Sep 17 00:00:00 2001
From: Brandy Carney
Date: Tue, 6 Oct 2020 17:33:35 -0400
Subject: [PATCH 18/22] fix(select): do not close popover or set value when
switching with arrow keys (#22210)
fixes #22179
---
core/src/components/radio-group/radio-group.tsx | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/core/src/components/radio-group/radio-group.tsx b/core/src/components/radio-group/radio-group.tsx
index 5c86b3d5b4..17e2980662 100644
--- a/core/src/components/radio-group/radio-group.tsx
+++ b/core/src/components/radio-group/radio-group.tsx
@@ -97,6 +97,8 @@ export class RadioGroup implements ComponentInterface {
@Listen('keydown', { target: 'document' })
onKeydown(ev: any) {
+ const inSelectPopover = !!this.el.closest('ion-select-popover');
+
if (ev.target && !this.el.contains(ev.target)) {
return;
}
@@ -129,7 +131,10 @@ export class RadioGroup implements ComponentInterface {
if (next && radios.includes(next)) {
next.setFocus();
- this.value = next.value;
+
+ if (!inSelectPopover) {
+ this.value = next.value;
+ }
}
}
}
From c454c84ef46322143467600334a0263d4e7df6cb Mon Sep 17 00:00:00 2001
From: Matthias Max
Date: Wed, 7 Oct 2020 00:40:29 +0200
Subject: [PATCH 19/22] fix(button): allow any element type to use the
"icon-only" slot (#22168)
---
core/src/components/button/button.tsx | 2 +-
.../components/button/test/icon/index.html | 37 ++++++++++---------
2 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx
index 64fa387d5d..ba10f9db2b 100644
--- a/core/src/components/button/button.tsx
+++ b/core/src/components/button/button.tsx
@@ -137,7 +137,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
}
private get hasIconOnly() {
- return !!this.el.querySelector('ion-icon[slot="icon-only"]');
+ return !!this.el.querySelector('[slot="icon-only"]');
}
private get rippleType() {
diff --git a/core/src/components/button/test/icon/index.html b/core/src/components/button/test/icon/index.html
index deb5afdf52..535d62aed1 100644
--- a/core/src/components/button/test/icon/index.html
+++ b/core/src/components/button/test/icon/index.html
@@ -17,6 +17,14 @@
Button - Icon
+
+
+
+
+
+
+
+
@@ -26,8 +34,6 @@
Left Icon
-
-
Left Icon
@@ -38,8 +44,6 @@
Right Icon
-
-
Right Icon
@@ -49,8 +53,6 @@
-
-
@@ -60,8 +62,6 @@
Left, Large
-
-
Left, Large
@@ -72,8 +72,6 @@
Right, Large
-
-
Right, Large
@@ -83,8 +81,6 @@
-
-
@@ -94,8 +90,6 @@
Left, Small
-
-
Left, Small
@@ -106,8 +100,6 @@
Right, Small
-
-
Right, Small
@@ -117,8 +109,6 @@
-
-
@@ -128,4 +118,15 @@