From 5a2a335784aab581cda90448193e48f687df6b15 Mon Sep 17 00:00:00 2001 From: Will Martin Date: Thu, 11 Nov 2021 12:18:38 -0500 Subject: [PATCH] fix(all): Ionic components that use child Ionic components are now correctly defined (#24191) resolves #23571, #24116, #24129 Co-authored-by: Liam DeBeasi --- core/package-lock.json | 35 +++++++++++++---- core/package.json | 2 +- .../picker-column-internal.tsx | 4 +- .../picker-internal-interfaces.ts | 2 +- .../picker-internal/picker-internal.tsx | 22 +++++------ core/src/components/select/readme.md | 23 +++++++++++ core/src/components/select/select.tsx | 10 +++++ core/src/utils/overlays.ts | 39 +++++++++++++------ core/stencil.config.ts | 1 + 9 files changed, 104 insertions(+), 34 deletions(-) diff --git a/core/package-lock.json b/core/package-lock.json index 33c07a66e0e..dba1e4f08c6 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -9,7 +9,7 @@ "version": "6.0.0-rc.2", "license": "MIT", "dependencies": { - "@stencil/core": "~2.10.0", + "@stencil/core": "~2.11.0-0", "ionicons": "^6.0.0", "tslib": "^2.1.0" }, @@ -1364,9 +1364,10 @@ "dev": true }, "node_modules/@stencil/core": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.10.0.tgz", - "integrity": "sha512-15rWMTPQ/sp0lSV82HVCXkIya3QLN+uBl7pqK4JnTrp4HiLrzLmNbWjbvgCs55gw0lULbCIGbRIEsFz+Pe/Q+A==", + "version": "2.11.0-0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.11.0-0.tgz", + "integrity": "sha512-ZJlambyk3s5Xzqd5yfzwvD7adEIHpfv89yOd210XsMhonXOLHK2k7XpFluGYUrv69HDgosu2TjFxQxhyVSS0Vg==", + "license": "MIT", "bin": { "stencil": "bin/stencil" }, @@ -5556,6 +5557,19 @@ "@stencil/core": "~2.10.0" } }, + "node_modules/ionicons/node_modules/@stencil/core": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.10.0.tgz", + "integrity": "sha512-15rWMTPQ/sp0lSV82HVCXkIya3QLN+uBl7pqK4JnTrp4HiLrzLmNbWjbvgCs55gw0lULbCIGbRIEsFz+Pe/Q+A==", + "license": "MIT", + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=12.10.0", + "npm": ">=6.0.0" + } + }, "node_modules/ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", @@ -15029,9 +15043,9 @@ "dev": true }, "@stencil/core": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.10.0.tgz", - "integrity": "sha512-15rWMTPQ/sp0lSV82HVCXkIya3QLN+uBl7pqK4JnTrp4HiLrzLmNbWjbvgCs55gw0lULbCIGbRIEsFz+Pe/Q+A==" + "version": "2.11.0-0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.11.0-0.tgz", + "integrity": "sha512-ZJlambyk3s5Xzqd5yfzwvD7adEIHpfv89yOd210XsMhonXOLHK2k7XpFluGYUrv69HDgosu2TjFxQxhyVSS0Vg==" }, "@stencil/react-output-target": { "version": "0.1.0", @@ -18412,6 +18426,13 @@ "integrity": "sha512-p83W1T8jZUlllHAjuIWaDQbI36OYqdrwcf8MhYbKW7+9rjGlCMP9+5OaR0W7tl0QfM004uAiy/zkc7HTpDNKgA==", "requires": { "@stencil/core": "~2.10.0" + }, + "dependencies": { + "@stencil/core": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.10.0.tgz", + "integrity": "sha512-15rWMTPQ/sp0lSV82HVCXkIya3QLN+uBl7pqK4JnTrp4HiLrzLmNbWjbvgCs55gw0lULbCIGbRIEsFz+Pe/Q+A==" + } } }, "ip-regex": { diff --git a/core/package.json b/core/package.json index db134db041f..6c06bfa2403 100644 --- a/core/package.json +++ b/core/package.json @@ -31,7 +31,7 @@ "loader/" ], "dependencies": { - "@stencil/core": "~2.10.0", + "@stencil/core": "~2.11.0-0", "ionicons": "^6.0.0", "tslib": "^2.1.0" }, diff --git a/core/src/components/picker-column-internal/picker-column-internal.tsx b/core/src/components/picker-column-internal/picker-column-internal.tsx index 7af3fb56edc..4168a765f5e 100644 --- a/core/src/components/picker-column-internal/picker-column-internal.tsx +++ b/core/src/components/picker-column-internal/picker-column-internal.tsx @@ -133,7 +133,7 @@ export class PickerColumnInternal implements ComponentInterface { private inputModeChange = (ev: PickerInternalCustomEvent) => { if (!this.numericInput) { return; } - const { inputMode, inputModeColumn } = ev.detail; + const { useInputMode, inputModeColumn } = ev.detail; /** * If inputModeColumn is undefined then this means @@ -141,7 +141,7 @@ export class PickerColumnInternal implements ComponentInterface { */ const isColumnActive = inputModeColumn === undefined || inputModeColumn === this.el; - if (!inputMode || !isColumnActive) { + if (!useInputMode || !isColumnActive) { this.isActive = false; return; } diff --git a/core/src/components/picker-internal/picker-internal-interfaces.ts b/core/src/components/picker-internal/picker-internal-interfaces.ts index bc4efa70afe..30e24a90ccb 100644 --- a/core/src/components/picker-internal/picker-internal-interfaces.ts +++ b/core/src/components/picker-internal/picker-internal-interfaces.ts @@ -1,5 +1,5 @@ export interface PickerInternalChangeEventDetail { - inputMode: boolean; + useInputMode: boolean; inputModeColumn?: HTMLIonPickerColumnInternalElement; } diff --git a/core/src/components/picker-internal/picker-internal.tsx b/core/src/components/picker-internal/picker-internal.tsx index 77f81e22fcd..b544ddd117a 100644 --- a/core/src/components/picker-internal/picker-internal.tsx +++ b/core/src/components/picker-internal/picker-internal.tsx @@ -18,7 +18,7 @@ import { PickerInternalChangeEventDetail } from './picker-internal-interfaces'; }) export class PickerInternal implements ComponentInterface { private inputEl?: HTMLInputElement; - private inputMode = false; + private useInputMode = false; private inputModeColumn?: HTMLIonPickerColumnInternalElement; private highlightEl?: HTMLElement; private actionOnClick?: () => void; @@ -131,7 +131,7 @@ export class PickerInternal implements ComponentInterface { * runs and runs the actionOnClick callback. */ private onPointerDown = (ev: PointerEvent) => { - const { inputMode, inputModeColumn, el } = this; + const { useInputMode, inputModeColumn, el } = this; if (this.isInHighlightBounds(ev)) { /** * If we were already in @@ -140,7 +140,7 @@ export class PickerInternal implements ComponentInterface { * should switch to input mode for * that specific column. */ - if (inputMode) { + if (useInputMode) { /** * If we tapped a picker column * then we should either switch to input @@ -225,7 +225,7 @@ export class PickerInternal implements ComponentInterface { * are eligible for text entry. * (i.e. hour and minute columns) */ - this.inputMode = true; + this.useInputMode = true; this.inputModeColumn = columnEl; /** @@ -253,10 +253,10 @@ export class PickerInternal implements ComponentInterface { } private exitInputMode = () => { - const { inputEl, inputMode } = this; - if (!inputMode || !inputEl) { return; } + const { inputEl, useInputMode } = this; + if (!useInputMode || !inputEl) { return; } - this.inputMode = false; + this.useInputMode = false; this.inputModeColumn = undefined; inputEl.blur(); inputEl.value = ''; @@ -457,8 +457,8 @@ export class PickerInternal implements ComponentInterface { * to select */ private onInputChange = () => { - const { inputMode, inputEl, inputModeColumn } = this; - if (!inputMode || !inputEl) { return; } + const { useInputMode, inputEl, inputModeColumn } = this; + if (!useInputMode || !inputEl) { return; } if (inputModeColumn) { this.selectSingleColumn(); @@ -473,10 +473,10 @@ export class PickerInternal implements ComponentInterface { * or not their column is "active" for text input. */ private emitInputModeChange = () => { - const { inputMode, inputModeColumn } = this; + const { useInputMode, inputModeColumn } = this; this.ionInputModeChange.emit({ - inputMode, + useInputMode, inputModeColumn }); } diff --git a/core/src/components/select/readme.md b/core/src/components/select/readme.md index 618b6e57a54..03f7259eb93 100644 --- a/core/src/components/select/readme.md +++ b/core/src/components/select/readme.md @@ -1428,6 +1428,29 @@ Type: `Promise` | `--placeholder-opacity` | Opacity of the select placeholder text | +## Dependencies + +### Depends on + +- ion-select-popover + +### Graph +```mermaid +graph TD; + ion-select --> ion-select-popover + ion-select-popover --> ion-item + ion-select-popover --> ion-checkbox + ion-select-popover --> ion-label + ion-select-popover --> ion-radio-group + ion-select-popover --> ion-radio + ion-select-popover --> ion-list + ion-select-popover --> ion-list-header + ion-item --> ion-icon + ion-item --> ion-ripple-effect + ion-item --> ion-note + style ion-select fill:#f9f,stroke:#333,stroke-width:4px +``` + ---------------------------------------------- *Built with [StencilJS](https://stenciljs.com/)* diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx index 990c2a99db3..dadcd457078 100644 --- a/core/src/components/select/select.tsx +++ b/core/src/components/select/select.tsx @@ -360,6 +360,16 @@ export class Select implements ComponentInterface { options: this.createPopoverOptions(this.childOpts, value) } }; + + /** + * Workaround for Stencil to autodefine ion-select-popover. + */ + // tslint:disable-next-line + if (false) { + // @ts-ignore + document.createElement('ion-select-popover'); + } + return popoverController.create(popoverOpts); } diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 050a2ecc898..925fa8bf1b8 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -1,3 +1,10 @@ +import { ActionSheet } from '../components/action-sheet/action-sheet'; +import { Alert } from '../components/alert/alert'; +import { Loading } from '../components/loading/loading'; +import { Modal } from '../components/modal/modal'; +import { Picker } from '../components/picker/picker'; +import { Popover } from '../components/popover/popover'; +import { Toast } from '../components/toast/toast'; import { config } from '../global/config'; import { getIonMode } from '../global/ionic-global'; import { ActionSheetOptions, AlertOptions, Animation, AnimationBuilder, BackButtonEvent, HTMLIonOverlayElement, IonicConfig, LoadingOptions, ModalOptions, OverlayInterface, PickerOptions, PopoverOptions, ToastOptions } from '../interface'; @@ -9,10 +16,10 @@ let lastId = 0; export const activeAnimations = new WeakMap(); -const createController = (tagName: string) => { +const createController = (tagName: string, customElement?: any) => { return { create(options: Opts): Promise { - return createOverlay(tagName, options) as any; + return createOverlay(tagName, options, customElement) as any; }, dismiss(data?: any, role?: string, id?: string) { return dismissOverlay(document, data, role, tagName, id); @@ -23,13 +30,13 @@ const createController = (tagName: str }; }; -export const alertController = /*@__PURE__*/createController('ion-alert'); -export const actionSheetController = /*@__PURE__*/createController('ion-action-sheet'); -export const loadingController = /*@__PURE__*/createController('ion-loading'); -export const modalController = /*@__PURE__*/createController('ion-modal'); -export const pickerController = /*@__PURE__*/createController('ion-picker'); -export const popoverController = /*@__PURE__*/createController('ion-popover'); -export const toastController = /*@__PURE__*/createController('ion-toast'); +export const alertController = /*@__PURE__*/createController('ion-alert', Alert); +export const actionSheetController = /*@__PURE__*/createController('ion-action-sheet', ActionSheet); +export const loadingController = /*@__PURE__*/createController('ion-loading', Loading); +export const modalController = /*@__PURE__*/createController('ion-modal', Modal); +export const pickerController = /*@__PURE__*/createController('ion-picker', Picker); +export const popoverController = /*@__PURE__*/createController('ion-popover', Popover); +export const toastController = /*@__PURE__*/createController('ion-toast', Toast); export const prepareOverlay = (el: T) => { /* tslint:disable-next-line */ @@ -43,10 +50,18 @@ export const prepareOverlay = (el: T) => { } }; -export const createOverlay = (tagName: string, opts: object | undefined): Promise => { +export const createOverlay = (tagName: string, opts: object | undefined, customElement?: any): Promise => { /* tslint:disable-next-line */ - if (typeof customElements !== 'undefined') { - return customElements.whenDefined(tagName).then(() => { + if (typeof window.customElements !== 'undefined') { + if ( + typeof (window as any) !== 'undefined' && + window.customElements && + !window.customElements.get(tagName) + ) { + window.customElements.define(tagName, customElement); + } + + return window.customElements.whenDefined(tagName).then(() => { const element = document.createElement(tagName) as HTMLIonOverlayElement; element.classList.add('overlay-hidden'); diff --git a/core/stencil.config.ts b/core/stencil.config.ts index 3afca17281d..d6ea5b3c22b 100644 --- a/core/stencil.config.ts +++ b/core/stencil.config.ts @@ -157,6 +157,7 @@ export const config: Config = { { type: 'dist-custom-elements', dir: 'components', + autoDefineCustomElements: true, copy: [{ src: '../scripts/custom-elements', dest: 'components',