From 9918f4ab8cc08853822afb7abfe678e8f46c92b9 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 9 Apr 2026 09:30:31 -0700 Subject: [PATCH 1/9] feat(select): allow HTML within options --- core/api.txt | 11 +- core/src/components.d.ts | 1190 +++-------------- .../components/action-sheet/action-sheet.tsx | 6 +- core/src/components/alert/alert.tsx | 12 +- .../components/select-modal/select-modal.tsx | 9 +- .../select-option/select-option.tsx | 15 +- .../select-popover/select-popover.tsx | 9 +- core/src/components/select/select.common.scss | 8 + core/src/components/select/select.tsx | 108 +- .../components/select/test/basic/index.html | 95 +- 10 files changed, 407 insertions(+), 1056 deletions(-) diff --git a/core/api.txt b/core/api.txt index e4e1ca4d603..f2536a2a447 100644 --- a/core/api.txt +++ b/core/api.txt @@ -949,7 +949,7 @@ ion-infinite-scroll-content,prop,theme,"ios" | "md" | "ionic",undefined,false,fa ion-input,scoped ion-input,prop,autocapitalize,string,'off',false,false -ion-input,prop,autocomplete,"additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday" | "bday-day" | "bday-month" | "bday-year" | "cc-additional-name" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "email" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "impp" | "language" | "name" | "new-password" | "nickname" | "off" | "on" | "one-time-code" | "organization" | "organization-title" | "photo" | "postal-code" | "sex" | "street-address" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "transaction-amount" | "transaction-currency" | "url" | "username",'off',false,false +ion-input,prop,autocomplete,"name" | "url" | "off" | "on" | "additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday-day" | "bday-month" | "bday-year" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "new-password" | "one-time-code" | "organization" | "postal-code" | "street-address" | "transaction-amount" | "transaction-currency" | "username" | "email" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "nickname" | "organization-title" | "cc-additional-name" | "language" | "bday" | "sex" | "impp" | "photo",'off',false,false ion-input,prop,autocorrect,"off" | "on",'off',false,false ion-input,prop,autofocus,boolean,false,false,false ion-input,prop,clearInput,boolean,false,false,false @@ -1631,7 +1631,7 @@ ion-nav,prop,animated,boolean,true,false,false ion-nav,prop,animation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-nav,prop,mode,"ios" | "md",undefined,false,false ion-nav,prop,root,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false -ion-nav,prop,rootParams,T | undefined,undefined,false,false +ion-nav,prop,rootParams,undefined | { [key: string]: any; },undefined,false,false ion-nav,prop,swipeGesture,boolean | undefined,undefined,false,false ion-nav,prop,theme,"ios" | "md" | "ionic",undefined,false,false ion-nav,method,canGoBack,canGoBack(view?: ViewController) => Promise @@ -1653,7 +1653,7 @@ ion-nav,event,ionNavWillChange,void,false ion-nav-link,none ion-nav-link,prop,component,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false -ion-nav-link,prop,componentProps,T | undefined,undefined,false,false +ion-nav-link,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false ion-nav-link,prop,mode,"ios" | "md",undefined,false,false ion-nav-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-nav-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false @@ -1758,7 +1758,7 @@ ion-popover,prop,animated,boolean,true,false,false ion-popover,prop,arrow,boolean,true,false,false ion-popover,prop,backdropDismiss,boolean,true,false,false ion-popover,prop,component,Function | HTMLElement | null | string | undefined,undefined,false,false -ion-popover,prop,componentProps,T | undefined,undefined,false,false +ion-popover,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false ion-popover,prop,dismissOnSelect,boolean,false,false,false ion-popover,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-popover,prop,event,any,undefined,false,false @@ -2066,7 +2066,7 @@ ion-row,css-prop,--ion-grid-gap ion-searchbar,scoped ion-searchbar,prop,animated,boolean,false,false,false ion-searchbar,prop,autocapitalize,string,'off',false,false -ion-searchbar,prop,autocomplete,"additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday" | "bday-day" | "bday-month" | "bday-year" | "cc-additional-name" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "email" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "impp" | "language" | "name" | "new-password" | "nickname" | "off" | "on" | "one-time-code" | "organization" | "organization-title" | "photo" | "postal-code" | "sex" | "street-address" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "transaction-amount" | "transaction-currency" | "url" | "username",'off',false,false +ion-searchbar,prop,autocomplete,"name" | "url" | "off" | "on" | "additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday-day" | "bday-month" | "bday-year" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "new-password" | "one-time-code" | "organization" | "postal-code" | "street-address" | "transaction-amount" | "transaction-currency" | "username" | "email" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "nickname" | "organization-title" | "cc-additional-name" | "language" | "bday" | "sex" | "impp" | "photo",'off',false,false ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false ion-searchbar,prop,cancelButtonIcon,string | undefined,undefined,false,false ion-searchbar,prop,cancelButtonText,string,'Cancel',false,false @@ -2345,6 +2345,7 @@ ion-select-modal,prop,multiple,boolean | undefined,undefined,false,false ion-select-modal,prop,options,SelectModalOption[],[],false,false ion-select-option,shadow +ion-select-option,prop,description,string | undefined,undefined,false,false ion-select-option,prop,disabled,boolean,false,false,false ion-select-option,prop,mode,"ios" | "md",undefined,false,false ion-select-option,prop,theme,"ios" | "md" | "ionic",undefined,false,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index ecbdb7475c6..11810a6766a 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -3813,6 +3813,10 @@ export namespace Components { "options": SelectModalOption[]; } interface IonSelectOption { + /** + * Text that is placed underneath the option text to provide additional details about the option. + */ + "description"?: string; /** * If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons. * @default false @@ -6019,8 +6023,6 @@ declare global { } } declare namespace LocalJSX { - type OneOf = { [P in K]: PropT } & { [P in `attr:${K}` | `prop:${K}`]?: never } | { [P in `attr:${K}`]: AttrT } & { [P in K | `prop:${K}`]?: never } | { [P in `prop:${K}`]: PropT } & { [P in K | `attr:${K}`]?: never }; - interface IonAccordion { /** * If `true`, the accordion cannot be interacted with. @@ -7783,10 +7785,6 @@ declare namespace LocalJSX { * @default 'outline' */ "fill"?: 'outline' | 'solid'; - /** - * The `id` of a `
` element to associate this element with. - */ - "form"?: string; /** * A hint to the browser for which keyboard to display. Possible values: `"none"`, `"text"`, `"tel"`, `"url"`, `"email"`, `"numeric"`, `"decimal"`, and `"search"`. For numbers (type="number"): "numeric" For text (type="text"): "text" */ @@ -7800,10 +7798,6 @@ declare namespace LocalJSX { * The mode determines the platform behaviors of the component. */ "mode"?: "ios" | "md"; - /** - * The name of the element, used when submitting an HTML form. - */ - "name"?: string; /** * Emitted when the input group loses focus. */ @@ -9897,6 +9891,10 @@ declare namespace LocalJSX { "options"?: SelectModalOption[]; } interface IonSelectOption { + /** + * Text that is placed underneath the option text to provide additional details about the option. + */ + "description"?: string; /** * If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons. * @default false @@ -10232,10 +10230,6 @@ declare namespace LocalJSX { * The fill for the item. If `"solid"` the item will have a background. If `"outline"` the item will be transparent with a border. Only available when the theme is `"md"`. */ "fill"?: 'outline' | 'solid'; - /** - * The `id` of a `` element to associate this element with. - */ - "form"?: string; /** * Text that is placed under the textarea and displayed when no error is detected. */ @@ -10599,1003 +10593,209 @@ declare namespace LocalJSX { */ "titlePlacement"?: 'start' | 'center' | 'end'; } - - interface IonAccordionAttributes { - "value": string; - "disabled": boolean; - "readonly": boolean; - "toggleIcon": string; - "toggleIconSlot": 'start' | 'end'; - } - interface IonAccordionGroupAttributes { - "animated": boolean; - "multiple": boolean; - "value": string | string[] | null; - "disabled": boolean; - "readonly": boolean; - "expand": 'compact' | 'inset'; - "shape": 'soft' | 'round' | 'rectangular'; - } - interface IonActionSheetAttributes { - "overlayIndex": number; - "hasController": boolean; - "keyboardClose": boolean; - "cssClass": string | string[]; - "backdropDismiss": boolean; - "header": string; - "subHeader": string; - "translucent": boolean; - "animated": boolean; - "isOpen": boolean; - "trigger": string | undefined; - } - interface IonAlertAttributes { - "overlayIndex": number; - "hasController": boolean; - "keyboardClose": boolean; - "cssClass": string | string[]; - "header": string; - "subHeader": string; - "message": string | IonicSafeString; - "backdropDismiss": boolean; - "translucent": boolean; - "animated": boolean; - "isOpen": boolean; - "trigger": string | undefined; - } - interface IonAvatarAttributes { - "size": 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'; - "shape": 'soft' | 'round' | 'rectangular'; - "disabled": boolean; - } - interface IonBackButtonAttributes { - "color": Color; - "defaultHref": string; - "disabled": boolean; - "icon": string | null; - "text": string | null; - "type": 'submit' | 'reset' | 'button'; - } - interface IonBackdropAttributes { - "visible": boolean; - "tappable": boolean; - "stopPropagation": boolean; - } - interface IonBadgeAttributes { - "color": Color; - "hue": 'bold' | 'subtle'; - "shape": 'soft' | 'round | rectangular'; - "size": 'small' | 'medium' | 'large'; - "vertical": 'top' | 'bottom'; - } - interface IonBreadcrumbAttributes { - "collapsed": boolean; - "last": boolean; - "showCollapsedIndicator": boolean; - "color": Color; - "active": boolean; - "disabled": boolean; - "download": string | undefined; - "href": string | undefined; - "rel": string | undefined; - "separator": boolean | undefined; - "target": string | undefined; - "routerDirection": RouterDirection; - } - interface IonBreadcrumbsAttributes { - "color": Color; - "maxItems": number; - "itemsBeforeCollapse": number; - "itemsAfterCollapse": number; - } - interface IonButtonAttributes { - "color": Color; - "buttonType": string; - "disabled": boolean; - "expand": 'full' | 'block'; - "fill": 'clear' | 'outline' | 'solid' | 'default'; - "routerDirection": RouterDirection; - "download": string | undefined; - "href": string | undefined; - "rel": string | undefined; - "shape": 'soft' | 'round' | 'rectangular'; - "size": 'small' | 'default' | 'medium' | 'large'; - "strong": boolean; - "target": string | undefined; - "type": 'submit' | 'reset' | 'button'; - "form": string | HTMLFormElement; - } - interface IonButtonsAttributes { - "collapse": boolean; - } - interface IonCardAttributes { - "color": Color; - "button": boolean; - "type": 'submit' | 'reset' | 'button'; - "disabled": boolean; - "download": string | undefined; - "href": string | undefined; - "rel": string | undefined; - "routerDirection": RouterDirection; - "shape": 'soft' | 'round' | 'rectangular'; - "target": string | undefined; - } - interface IonCardHeaderAttributes { - "color": Color; - "translucent": boolean; - } - interface IonCardSubtitleAttributes { - "color": Color; - } - interface IonCardTitleAttributes { - "color": Color; - } - interface IonCheckboxAttributes { - "color": Color; - "name": string; - "checked": boolean; - "indeterminate": boolean; - "disabled": boolean; - "errorText": string; - "helperText": string; - "value": string; - "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; - "justify": 'start' | 'end' | 'space-between'; - "alignment": 'start' | 'center'; - "required": boolean; - "shape": 'soft' | 'rectangular'; - "size": 'small'; - } - interface IonChipAttributes { - "color": Color; - "outline": boolean; - "disabled": boolean; - "hue": 'bold' | 'subtle'; - "shape": 'soft' | 'round' | 'rectangular'; - "size": 'small' | 'large'; - } - interface IonColAttributes { - "offset": string; - "offsetXs": string; - "offsetSm": string; - "offsetMd": string; - "offsetLg": string; - "offsetXl": string; - "order": string; - "orderXs": string; - "orderSm": string; - "orderMd": string; - "orderLg": string; - "orderXl": string; - "pull": string; - "pullXs": string; - "pullSm": string; - "pullMd": string; - "pullLg": string; - "pullXl": string; - "push": string; - "pushXs": string; - "pushSm": string; - "pushMd": string; - "pushLg": string; - "pushXl": string; - "size": string; - "sizeXs": string; - "sizeSm": string; - "sizeMd": string; - "sizeLg": string; - "sizeXl": string; - } - interface IonContentAttributes { - "color": Color; - "fullscreen": boolean; - "fixedSlotPlacement": 'after' | 'before'; - "forceOverscroll": boolean; - "scrollX": boolean; - "scrollY": boolean; - "scrollEvents": boolean; - } - interface IonDatetimeAttributes { - "color": Color; - "name": string; - "disabled": boolean; - "readonly": boolean; - "showAdjacentDays": boolean; - "min": string; - "max": string; - "presentation": DatetimePresentation; - "cancelText": string; - "doneText": string; - "clearText": string; - "yearValues": string; - "monthValues": string; - "dayValues": string; - "hourValues": string; - "minuteValues": string; - "locale": string; - "firstDayOfWeek": number; - "multiple": boolean; - "value": string | string[] | null; - "showDefaultTitle": boolean; - "showDefaultButtons": boolean; - "showClearButton": boolean; - "showDefaultTimeLabel": boolean; - "hourCycle": DatetimeHourCycle; - "size": 'cover' | 'fixed'; - "preferWheel": boolean; - } - interface IonDatetimeButtonAttributes { - "color": Color; - "disabled": boolean; - "datetime": string; - } - interface IonDividerAttributes { - "spacing": 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge'; - "inset": boolean; - } - interface IonFabAttributes { - "horizontal": 'start' | 'end' | 'center'; - "vertical": 'top' | 'bottom' | 'center'; - "edge": boolean; - "activated": boolean; - } - interface IonFabButtonAttributes { - "color": Color; - "activated": boolean; - "disabled": boolean; - "download": string | undefined; - "href": string | undefined; - "rel": string | undefined; - "routerDirection": RouterDirection; - "target": string | undefined; - "show": boolean; - "translucent": boolean; - "type": 'submit' | 'reset' | 'button'; - "size": 'small'; - "closeIcon": string; - } - interface IonFabListAttributes { - "activated": boolean; - "side": 'start' | 'end' | 'top' | 'bottom'; - } - interface IonFooterAttributes { - "collapse": 'fade'; - "translucent": boolean; - } - interface IonGridAttributes { - "fixed": boolean; - } - interface IonHeaderAttributes { - "collapse": 'condense' | 'fade'; - "divider": boolean; - "translucent": boolean; - } - interface IonImgAttributes { - "alt": string; - "src": string; - } - interface IonInfiniteScrollAttributes { - "threshold": string; - "disabled": boolean; - "position": 'top' | 'bottom'; - "preserveRerenderScrollPosition": boolean; - } - interface IonInfiniteScrollContentAttributes { - "loadingSpinner": SpinnerTypes | null; - "loadingText": string | IonicSafeString; - } - interface IonInputAttributes { - "color": Color; - "autocapitalize": string; - "autocomplete": AutocompleteTypes; - "autocorrect": 'on' | 'off'; - "autofocus": boolean; - "clearInput": boolean; - "clearInputIcon": string; - "clearOnEdit": boolean; - "counter": boolean; - "debounce": number; - "disabled": boolean; - "enterkeyhint": 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'; - "errorText": string; - "fill": 'outline' | 'solid'; - "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; - "helperText": string; - "label": string; - "labelPlacement": 'start' | 'end' | 'floating' | 'stacked' | 'fixed'; - "max": string; - "maxlength": number; - "min": string; - "minlength": number; - "multiple": boolean; - "name": string; - "pattern": string; - "placeholder": string; - "readonly": boolean; - "required": boolean; - "shape": 'soft' | 'round' | 'rectangular'; - "spellcheck": boolean; - "step": string; - "size": 'medium' | 'large' | 'xlarge'; - "type": TextFieldTypes; - "value": string; - } - interface IonInputOtpAttributes { - "autocapitalize": string; - "color": Color; - "disabled": boolean; - "fill": 'outline' | 'solid'; - "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; - "length": number; - "pattern": string; - "readonly": boolean; - "separators": 'all' | string | number[]; - "shape": 'round' | 'rectangular' | 'soft'; - "size": 'small' | 'medium' | 'large'; - "type": 'text' | 'number'; - "value": string; - } - interface IonInputPasswordToggleAttributes { - "color": Color; - "showIcon": string; - "hideIcon": string; - "type": TextFieldTypes; - } - interface IonItemAttributes { - "color": Color; - "button": boolean; - "detail": boolean; - "detailIcon": string; - "disabled": boolean; - "download": string | undefined; - "href": string | undefined; - "rel": string | undefined; - "lines": 'full' | 'inset' | 'none'; - "routerDirection": RouterDirection; - "target": string | undefined; - "type": 'submit' | 'reset' | 'button'; - } - interface IonItemDividerAttributes { - "color": Color; - "sticky": boolean; - } - interface IonItemOptionAttributes { - "color": Color; - "disabled": boolean; - "download": string | undefined; - "expandable": boolean; - "href": string | undefined; - "hue": 'bold' | 'subtle'; - "rel": string | undefined; - "target": string | undefined; - "type": 'submit' | 'reset' | 'button'; - "shape": 'soft' | 'round' | 'rectangular'; - } - interface IonItemOptionsAttributes { - "side": Side; - } - interface IonItemSlidingAttributes { - "disabled": boolean; - } - interface IonLabelAttributes { - "color": Color; - "position": 'fixed' | 'stacked' | 'floating'; - } - interface IonListAttributes { - "lines": 'full' | 'inset' | 'none'; - "inset": boolean; - "shape": 'soft' | 'round' | 'rectangular'; - } - interface IonListHeaderAttributes { - "color": Color; - "lines": 'full' | 'inset' | 'none'; - } - interface IonLoadingAttributes { - "overlayIndex": number; - "hasController": boolean; - "keyboardClose": boolean; - "message": string | IonicSafeString; - "cssClass": string | string[]; - "duration": number; - "backdropDismiss": boolean; - "showBackdrop": boolean; - "spinner": SpinnerTypes | null; - "translucent": boolean; - "animated": boolean; - "isOpen": boolean; - "trigger": string | undefined; - } - interface IonMenuAttributes { - "contentId": string; - "menuId": string; - "type": MenuType; - "disabled": boolean; - "side": Side; - "swipeGesture": boolean; - "maxEdgeStart": number; - } - interface IonMenuButtonAttributes { - "color": Color; - "disabled": boolean; - "menu": string; - "autoHide": boolean; - "type": 'submit' | 'reset' | 'button'; - } - interface IonMenuToggleAttributes { - "menu": string; - "autoHide": boolean; - } - interface IonModalAttributes { - "hasController": boolean; - "overlayIndex": number; - "keyboardClose": boolean; - "expandToScroll": boolean; - "initialBreakpoint": number; - "backdropBreakpoint": number; - "handle": boolean; - "handleBehavior": ModalHandleBehavior; - "component": ComponentRef; - "cssClass": string | string[]; - "backdropDismiss": boolean; - "showBackdrop": boolean; - "animated": boolean; - "isOpen": boolean; - "trigger": string | undefined; - "keepContentsMounted": boolean; - "focusTrap": boolean; - "canDismiss": boolean | ((data?: any, role?: string) => Promise); - "shape": 'soft' | 'round' | 'rectangular'; - } - interface IonNavAttributes { - "swipeGesture": boolean; - "animated": boolean; - "root": NavComponent; - } - interface IonNavLinkAttributes { - "component": NavComponent; - "routerDirection": RouterDirection; - } - interface IonNoteAttributes { - "color": Color; - } - interface IonPickerColumnAttributes { - "disabled": boolean; - "value": string; - "color": Color; - "numericInput": boolean; - } - interface IonPickerColumnOptionAttributes { - "disabled": boolean; - "value": string; - "color": Color; - } - interface IonPickerLegacyAttributes { - "overlayIndex": number; - "hasController": boolean; - "keyboardClose": boolean; - "cssClass": string | string[]; - "duration": number; - "showBackdrop": boolean; - "backdropDismiss": boolean; - "animated": boolean; - "isOpen": boolean; - "trigger": string | undefined; - } - interface IonPopoverAttributes { - "hasController": boolean; - "overlayIndex": number; - "component": ComponentRef; - "keyboardClose": boolean; - "cssClass": string | string[]; - "backdropDismiss": boolean; - "event": string; - "showBackdrop": boolean; - "translucent": boolean; - "animated": boolean; - "triggerAction": TriggerAction; - "trigger": string | undefined; - "size": PopoverSize; - "dismissOnSelect": boolean; - "reference": PositionReference; - "side": PositionSide; - "alignment": PositionAlign; - "arrow": boolean; - "isOpen": boolean; - "keyboardEvents": boolean; - "focusTrap": boolean; - "keepContentsMounted": boolean; - } - interface IonProgressBarAttributes { - "type": 'determinate' | 'indeterminate'; - "reversed": boolean; - "value": number; - "buffer": number; - "color": Color; - "shape": 'round' | 'rectangular'; - } - interface IonRadioAttributes { - "color": Color; - "name": string; - "disabled": boolean; - "value": string; - "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; - "justify": 'start' | 'end' | 'space-between'; - "alignment": 'start' | 'center'; - } - interface IonRadioGroupAttributes { - "allowEmptySelection": boolean; - "compareWith": string | RadioGroupCompareFn | null; - "name": string; - "value": string; - "helperText": string; - "errorText": string; - } - interface IonRangeAttributes { - "color": Color; - "debounce": number; - "name": string; - "label": string; - "dualKnobs": boolean; - "min": number; - "max": number; - "pin": boolean; - "snaps": boolean; - "step": number; - "ticks": boolean; - "activeBarStart": number; - "disabled": boolean; - "value": RangeValue; - "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; - } - interface IonRefresherAttributes { - "pullMin": number; - "pullMax": number; - "closeDuration": string; - "snapbackDuration": string; - "pullFactor": number; - "disabled": boolean; - } - interface IonRefresherContentAttributes { - "pullingIcon": SpinnerTypes | string | null; - "pullingText": string | IonicSafeString; - "refreshingSpinner": SpinnerTypes | null; - "refreshingText": string | IonicSafeString; - } - interface IonReorderGroupAttributes { - "disabled": boolean; - } - interface IonRippleEffectAttributes { - "type": 'bounded' | 'unbounded'; - } - interface IonRouteAttributes { - "url": string; - "component": string; - } - interface IonRouteRedirectAttributes { - "from": string; - "to": string | undefined | null; - } - interface IonRouterAttributes { - "root": string; - "useHash": boolean; - } - interface IonRouterLinkAttributes { - "color": Color; - "href": string | undefined; - "rel": string | undefined; - "routerDirection": RouterDirection; - "target": string | undefined; - } - interface IonRouterOutletAttributes { - "mode": "ios" | "md"; - "animated": boolean; - } - interface IonSearchbarAttributes { - "color": Color; - "animated": boolean; - "autocapitalize": string; - "autocomplete": AutocompleteTypes; - "autocorrect": 'on' | 'off'; - "cancelButtonIcon": string; - "cancelButtonText": string; - "clearIcon": string; - "debounce": number; - "disabled": boolean; - "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; - "enterkeyhint": 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'; - "maxlength": number; - "minlength": number; - "name": string; - "placeholder": string; - "searchIcon": string; - "showCancelButton": 'never' | 'focus' | 'always'; - "showClearButton": 'never' | 'focus' | 'always'; - "spellcheck": boolean; - "type": 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url'; - "value": string | null; - "shape": 'soft' | 'round' | 'rectangular'; - "size": 'small' | 'medium' | 'large'; - } - interface IonSegmentAttributes { - "color": Color; - "disabled": boolean; - "scrollable": boolean; - "swipeGesture": boolean; - "value": string; - "selectOnFocus": boolean; - } - interface IonSegmentButtonAttributes { - "contentId": string; - "disabled": boolean; - "layout": SegmentButtonLayout; - "type": 'submit' | 'reset' | 'button'; - "value": string; - } - interface IonSegmentViewAttributes { - "disabled": boolean; - "swipeGesture": boolean; - } - interface IonSelectAttributes { - "cancelText": string; - "color": Color; - "compareWith": string | SelectCompareFn | null; - "disabled": boolean; - "fill": 'outline' | 'solid'; - "errorText": string; - "helperText": string; - "interface": SelectInterface; - "interfaceOptions": string; - "justify": 'start' | 'end' | 'space-between'; - "label": string; - "labelPlacement": 'start' | 'end' | 'floating' | 'stacked' | 'fixed'; - "multiple": boolean; - "name": string; - "okText": string; - "placeholder": string; - "selectedText": string | null; - "toggleIcon": string; - "expandedIcon": string; - "required": boolean; - "shape": 'soft' | 'round' | 'rectangular'; - "size": 'small' | 'medium' | 'large'; - "value": string; - } - interface IonSelectModalAttributes { - "header": string; - "cancelText": string; - "multiple": boolean; - } - interface IonSelectOptionAttributes { - "disabled": boolean; - "value": string; - } - interface IonSelectPopoverAttributes { - "header": string; - "subHeader": string; - "message": string; - "multiple": boolean; - } - interface IonSkeletonTextAttributes { - "animated": boolean; - } - interface IonSpinnerAttributes { - "color": Color; - "duration": number; - "name": SpinnerTypes; - "paused": boolean; - "size": 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'; - } - interface IonSplitPaneAttributes { - "contentId": string; - "disabled": boolean; - "when": string; - } - interface IonTabAttributes { - "active": boolean; - "tab": string; - "component": ComponentRef; - } - interface IonTabBarAttributes { - "color": Color; - "selectedTab": string; - "translucent": boolean; - "expand": 'compact' | 'full'; - "shape": 'soft' | 'round' | 'rectangular'; - } - interface IonTabButtonAttributes { - "disabled": boolean; - "download": string | undefined; - "href": string | undefined; - "rel": string | undefined; - "layout": TabButtonLayout; - "selected": boolean; - "shape": 'soft' | 'round' | 'rectangular'; - "tab": string; - "target": string | undefined; - } - interface IonTabsAttributes { - "useRouter": boolean; - } - interface IonTextAttributes { - "color": Color; - } - interface IonTextareaAttributes { - "color": Color; - "autocapitalize": string; - "autofocus": boolean; - "clearOnEdit": boolean; - "debounce": number; - "disabled": boolean; - "fill": 'outline' | 'solid'; - "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; - "enterkeyhint": 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'; - "maxlength": number; - "minlength": number; - "name": string; - "placeholder": string; - "readonly": boolean; - "required": boolean; - "spellcheck": boolean; - "cols": number; - "rows": number; - "wrap": 'hard' | 'soft' | 'off'; - "autoGrow": boolean; - "value": string | null; - "counter": boolean; - "errorText": string; - "helperText": string; - "label": string; - "labelPlacement": 'start' | 'end' | 'floating' | 'stacked' | 'fixed'; - "shape": 'soft' | 'round' | 'rectangular'; - "size": 'small' | 'medium' | 'large'; - } - interface IonTitleAttributes { - "color": Color; - "size": 'large' | 'small'; - } - interface IonToastAttributes { - "overlayIndex": number; - "hasController": boolean; - "color": Color; - "cssClass": string | string[]; - "duration": number; - "header": string; - "hue": 'bold' | 'subtle'; - "layout": ToastLayout; - "message": string | IonicSafeString; - "keyboardClose": boolean; - "position": ToastPosition; - "positionAnchor": HTMLElement | string; - "shape": 'soft' | 'round' | 'rectangular'; - "translucent": boolean; - "animated": boolean; - "icon": string; - "swipeGesture": ToastSwipeGestureDirection; - "isOpen": boolean; - "trigger": string | undefined; - } - interface IonToggleAttributes { - "color": Color; - "name": string; - "checked": boolean; - "disabled": boolean; - "errorText": string; - "helperText": string; - "value": string | null; - "enableOnOffLabels": boolean | undefined; - "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; - "justify": 'start' | 'end' | 'space-between'; - "alignment": 'start' | 'center'; - "required": boolean; - } - interface IonToolbarAttributes { - "color": Color; - "titlePlacement": 'start' | 'center' | 'end'; - } - interface IntrinsicElements { - "ion-accordion": Omit & { [K in keyof IonAccordion & keyof IonAccordionAttributes]?: IonAccordion[K] } & { [K in keyof IonAccordion & keyof IonAccordionAttributes as `attr:${K}`]?: IonAccordionAttributes[K] } & { [K in keyof IonAccordion & keyof IonAccordionAttributes as `prop:${K}`]?: IonAccordion[K] }; - "ion-accordion-group": Omit & { [K in keyof IonAccordionGroup & keyof IonAccordionGroupAttributes]?: IonAccordionGroup[K] } & { [K in keyof IonAccordionGroup & keyof IonAccordionGroupAttributes as `attr:${K}`]?: IonAccordionGroupAttributes[K] } & { [K in keyof IonAccordionGroup & keyof IonAccordionGroupAttributes as `prop:${K}`]?: IonAccordionGroup[K] }; - "ion-action-sheet": Omit & { [K in keyof IonActionSheet & keyof IonActionSheetAttributes]?: IonActionSheet[K] } & { [K in keyof IonActionSheet & keyof IonActionSheetAttributes as `attr:${K}`]?: IonActionSheetAttributes[K] } & { [K in keyof IonActionSheet & keyof IonActionSheetAttributes as `prop:${K}`]?: IonActionSheet[K] } & OneOf<"overlayIndex", IonActionSheet["overlayIndex"], IonActionSheetAttributes["overlayIndex"]>; - "ion-alert": Omit & { [K in keyof IonAlert & keyof IonAlertAttributes]?: IonAlert[K] } & { [K in keyof IonAlert & keyof IonAlertAttributes as `attr:${K}`]?: IonAlertAttributes[K] } & { [K in keyof IonAlert & keyof IonAlertAttributes as `prop:${K}`]?: IonAlert[K] } & OneOf<"overlayIndex", IonAlert["overlayIndex"], IonAlertAttributes["overlayIndex"]>; + "ion-accordion": IonAccordion; + "ion-accordion-group": IonAccordionGroup; + "ion-action-sheet": IonActionSheet; + "ion-alert": IonAlert; "ion-app": IonApp; - "ion-avatar": Omit & { [K in keyof IonAvatar & keyof IonAvatarAttributes]?: IonAvatar[K] } & { [K in keyof IonAvatar & keyof IonAvatarAttributes as `attr:${K}`]?: IonAvatarAttributes[K] } & { [K in keyof IonAvatar & keyof IonAvatarAttributes as `prop:${K}`]?: IonAvatar[K] }; - "ion-back-button": Omit & { [K in keyof IonBackButton & keyof IonBackButtonAttributes]?: IonBackButton[K] } & { [K in keyof IonBackButton & keyof IonBackButtonAttributes as `attr:${K}`]?: IonBackButtonAttributes[K] } & { [K in keyof IonBackButton & keyof IonBackButtonAttributes as `prop:${K}`]?: IonBackButton[K] }; - "ion-backdrop": Omit & { [K in keyof IonBackdrop & keyof IonBackdropAttributes]?: IonBackdrop[K] } & { [K in keyof IonBackdrop & keyof IonBackdropAttributes as `attr:${K}`]?: IonBackdropAttributes[K] } & { [K in keyof IonBackdrop & keyof IonBackdropAttributes as `prop:${K}`]?: IonBackdrop[K] }; - "ion-badge": Omit & { [K in keyof IonBadge & keyof IonBadgeAttributes]?: IonBadge[K] } & { [K in keyof IonBadge & keyof IonBadgeAttributes as `attr:${K}`]?: IonBadgeAttributes[K] } & { [K in keyof IonBadge & keyof IonBadgeAttributes as `prop:${K}`]?: IonBadge[K] }; - "ion-breadcrumb": Omit & { [K in keyof IonBreadcrumb & keyof IonBreadcrumbAttributes]?: IonBreadcrumb[K] } & { [K in keyof IonBreadcrumb & keyof IonBreadcrumbAttributes as `attr:${K}`]?: IonBreadcrumbAttributes[K] } & { [K in keyof IonBreadcrumb & keyof IonBreadcrumbAttributes as `prop:${K}`]?: IonBreadcrumb[K] } & OneOf<"last", IonBreadcrumb["last"], IonBreadcrumbAttributes["last"]> & OneOf<"showCollapsedIndicator", IonBreadcrumb["showCollapsedIndicator"], IonBreadcrumbAttributes["showCollapsedIndicator"]>; - "ion-breadcrumbs": Omit & { [K in keyof IonBreadcrumbs & keyof IonBreadcrumbsAttributes]?: IonBreadcrumbs[K] } & { [K in keyof IonBreadcrumbs & keyof IonBreadcrumbsAttributes as `attr:${K}`]?: IonBreadcrumbsAttributes[K] } & { [K in keyof IonBreadcrumbs & keyof IonBreadcrumbsAttributes as `prop:${K}`]?: IonBreadcrumbs[K] }; - "ion-button": Omit & { [K in keyof IonButton & keyof IonButtonAttributes]?: IonButton[K] } & { [K in keyof IonButton & keyof IonButtonAttributes as `attr:${K}`]?: IonButtonAttributes[K] } & { [K in keyof IonButton & keyof IonButtonAttributes as `prop:${K}`]?: IonButton[K] }; - "ion-buttons": Omit & { [K in keyof IonButtons & keyof IonButtonsAttributes]?: IonButtons[K] } & { [K in keyof IonButtons & keyof IonButtonsAttributes as `attr:${K}`]?: IonButtonsAttributes[K] } & { [K in keyof IonButtons & keyof IonButtonsAttributes as `prop:${K}`]?: IonButtons[K] }; - "ion-card": Omit & { [K in keyof IonCard & keyof IonCardAttributes]?: IonCard[K] } & { [K in keyof IonCard & keyof IonCardAttributes as `attr:${K}`]?: IonCardAttributes[K] } & { [K in keyof IonCard & keyof IonCardAttributes as `prop:${K}`]?: IonCard[K] }; + "ion-avatar": IonAvatar; + "ion-back-button": IonBackButton; + "ion-backdrop": IonBackdrop; + "ion-badge": IonBadge; + "ion-breadcrumb": IonBreadcrumb; + "ion-breadcrumbs": IonBreadcrumbs; + "ion-button": IonButton; + "ion-buttons": IonButtons; + "ion-card": IonCard; "ion-card-content": IonCardContent; - "ion-card-header": Omit & { [K in keyof IonCardHeader & keyof IonCardHeaderAttributes]?: IonCardHeader[K] } & { [K in keyof IonCardHeader & keyof IonCardHeaderAttributes as `attr:${K}`]?: IonCardHeaderAttributes[K] } & { [K in keyof IonCardHeader & keyof IonCardHeaderAttributes as `prop:${K}`]?: IonCardHeader[K] }; - "ion-card-subtitle": Omit & { [K in keyof IonCardSubtitle & keyof IonCardSubtitleAttributes]?: IonCardSubtitle[K] } & { [K in keyof IonCardSubtitle & keyof IonCardSubtitleAttributes as `attr:${K}`]?: IonCardSubtitleAttributes[K] } & { [K in keyof IonCardSubtitle & keyof IonCardSubtitleAttributes as `prop:${K}`]?: IonCardSubtitle[K] }; - "ion-card-title": Omit & { [K in keyof IonCardTitle & keyof IonCardTitleAttributes]?: IonCardTitle[K] } & { [K in keyof IonCardTitle & keyof IonCardTitleAttributes as `attr:${K}`]?: IonCardTitleAttributes[K] } & { [K in keyof IonCardTitle & keyof IonCardTitleAttributes as `prop:${K}`]?: IonCardTitle[K] }; - "ion-checkbox": Omit & { [K in keyof IonCheckbox & keyof IonCheckboxAttributes]?: IonCheckbox[K] } & { [K in keyof IonCheckbox & keyof IonCheckboxAttributes as `attr:${K}`]?: IonCheckboxAttributes[K] } & { [K in keyof IonCheckbox & keyof IonCheckboxAttributes as `prop:${K}`]?: IonCheckbox[K] }; - "ion-chip": Omit & { [K in keyof IonChip & keyof IonChipAttributes]?: IonChip[K] } & { [K in keyof IonChip & keyof IonChipAttributes as `attr:${K}`]?: IonChipAttributes[K] } & { [K in keyof IonChip & keyof IonChipAttributes as `prop:${K}`]?: IonChip[K] }; - "ion-col": Omit & { [K in keyof IonCol & keyof IonColAttributes]?: IonCol[K] } & { [K in keyof IonCol & keyof IonColAttributes as `attr:${K}`]?: IonColAttributes[K] } & { [K in keyof IonCol & keyof IonColAttributes as `prop:${K}`]?: IonCol[K] }; - "ion-content": Omit & { [K in keyof IonContent & keyof IonContentAttributes]?: IonContent[K] } & { [K in keyof IonContent & keyof IonContentAttributes as `attr:${K}`]?: IonContentAttributes[K] } & { [K in keyof IonContent & keyof IonContentAttributes as `prop:${K}`]?: IonContent[K] }; - "ion-datetime": Omit & { [K in keyof IonDatetime & keyof IonDatetimeAttributes]?: IonDatetime[K] } & { [K in keyof IonDatetime & keyof IonDatetimeAttributes as `attr:${K}`]?: IonDatetimeAttributes[K] } & { [K in keyof IonDatetime & keyof IonDatetimeAttributes as `prop:${K}`]?: IonDatetime[K] }; - "ion-datetime-button": Omit & { [K in keyof IonDatetimeButton & keyof IonDatetimeButtonAttributes]?: IonDatetimeButton[K] } & { [K in keyof IonDatetimeButton & keyof IonDatetimeButtonAttributes as `attr:${K}`]?: IonDatetimeButtonAttributes[K] } & { [K in keyof IonDatetimeButton & keyof IonDatetimeButtonAttributes as `prop:${K}`]?: IonDatetimeButton[K] }; - "ion-divider": Omit & { [K in keyof IonDivider & keyof IonDividerAttributes]?: IonDivider[K] } & { [K in keyof IonDivider & keyof IonDividerAttributes as `attr:${K}`]?: IonDividerAttributes[K] } & { [K in keyof IonDivider & keyof IonDividerAttributes as `prop:${K}`]?: IonDivider[K] }; - "ion-fab": Omit & { [K in keyof IonFab & keyof IonFabAttributes]?: IonFab[K] } & { [K in keyof IonFab & keyof IonFabAttributes as `attr:${K}`]?: IonFabAttributes[K] } & { [K in keyof IonFab & keyof IonFabAttributes as `prop:${K}`]?: IonFab[K] }; - "ion-fab-button": Omit & { [K in keyof IonFabButton & keyof IonFabButtonAttributes]?: IonFabButton[K] } & { [K in keyof IonFabButton & keyof IonFabButtonAttributes as `attr:${K}`]?: IonFabButtonAttributes[K] } & { [K in keyof IonFabButton & keyof IonFabButtonAttributes as `prop:${K}`]?: IonFabButton[K] }; - "ion-fab-list": Omit & { [K in keyof IonFabList & keyof IonFabListAttributes]?: IonFabList[K] } & { [K in keyof IonFabList & keyof IonFabListAttributes as `attr:${K}`]?: IonFabListAttributes[K] } & { [K in keyof IonFabList & keyof IonFabListAttributes as `prop:${K}`]?: IonFabList[K] }; - "ion-footer": Omit & { [K in keyof IonFooter & keyof IonFooterAttributes]?: IonFooter[K] } & { [K in keyof IonFooter & keyof IonFooterAttributes as `attr:${K}`]?: IonFooterAttributes[K] } & { [K in keyof IonFooter & keyof IonFooterAttributes as `prop:${K}`]?: IonFooter[K] }; - "ion-grid": Omit & { [K in keyof IonGrid & keyof IonGridAttributes]?: IonGrid[K] } & { [K in keyof IonGrid & keyof IonGridAttributes as `attr:${K}`]?: IonGridAttributes[K] } & { [K in keyof IonGrid & keyof IonGridAttributes as `prop:${K}`]?: IonGrid[K] }; - "ion-header": Omit & { [K in keyof IonHeader & keyof IonHeaderAttributes]?: IonHeader[K] } & { [K in keyof IonHeader & keyof IonHeaderAttributes as `attr:${K}`]?: IonHeaderAttributes[K] } & { [K in keyof IonHeader & keyof IonHeaderAttributes as `prop:${K}`]?: IonHeader[K] }; - "ion-img": Omit & { [K in keyof IonImg & keyof IonImgAttributes]?: IonImg[K] } & { [K in keyof IonImg & keyof IonImgAttributes as `attr:${K}`]?: IonImgAttributes[K] } & { [K in keyof IonImg & keyof IonImgAttributes as `prop:${K}`]?: IonImg[K] }; - "ion-infinite-scroll": Omit & { [K in keyof IonInfiniteScroll & keyof IonInfiniteScrollAttributes]?: IonInfiniteScroll[K] } & { [K in keyof IonInfiniteScroll & keyof IonInfiniteScrollAttributes as `attr:${K}`]?: IonInfiniteScrollAttributes[K] } & { [K in keyof IonInfiniteScroll & keyof IonInfiniteScrollAttributes as `prop:${K}`]?: IonInfiniteScroll[K] }; - "ion-infinite-scroll-content": Omit & { [K in keyof IonInfiniteScrollContent & keyof IonInfiniteScrollContentAttributes]?: IonInfiniteScrollContent[K] } & { [K in keyof IonInfiniteScrollContent & keyof IonInfiniteScrollContentAttributes as `attr:${K}`]?: IonInfiniteScrollContentAttributes[K] } & { [K in keyof IonInfiniteScrollContent & keyof IonInfiniteScrollContentAttributes as `prop:${K}`]?: IonInfiniteScrollContent[K] }; - "ion-input": Omit & { [K in keyof IonInput & keyof IonInputAttributes]?: IonInput[K] } & { [K in keyof IonInput & keyof IonInputAttributes as `attr:${K}`]?: IonInputAttributes[K] } & { [K in keyof IonInput & keyof IonInputAttributes as `prop:${K}`]?: IonInput[K] }; - "ion-input-otp": Omit & { [K in keyof IonInputOtp & keyof IonInputOtpAttributes]?: IonInputOtp[K] } & { [K in keyof IonInputOtp & keyof IonInputOtpAttributes as `attr:${K}`]?: IonInputOtpAttributes[K] } & { [K in keyof IonInputOtp & keyof IonInputOtpAttributes as `prop:${K}`]?: IonInputOtp[K] }; - "ion-input-password-toggle": Omit & { [K in keyof IonInputPasswordToggle & keyof IonInputPasswordToggleAttributes]?: IonInputPasswordToggle[K] } & { [K in keyof IonInputPasswordToggle & keyof IonInputPasswordToggleAttributes as `attr:${K}`]?: IonInputPasswordToggleAttributes[K] } & { [K in keyof IonInputPasswordToggle & keyof IonInputPasswordToggleAttributes as `prop:${K}`]?: IonInputPasswordToggle[K] }; - "ion-item": Omit & { [K in keyof IonItem & keyof IonItemAttributes]?: IonItem[K] } & { [K in keyof IonItem & keyof IonItemAttributes as `attr:${K}`]?: IonItemAttributes[K] } & { [K in keyof IonItem & keyof IonItemAttributes as `prop:${K}`]?: IonItem[K] }; - "ion-item-divider": Omit & { [K in keyof IonItemDivider & keyof IonItemDividerAttributes]?: IonItemDivider[K] } & { [K in keyof IonItemDivider & keyof IonItemDividerAttributes as `attr:${K}`]?: IonItemDividerAttributes[K] } & { [K in keyof IonItemDivider & keyof IonItemDividerAttributes as `prop:${K}`]?: IonItemDivider[K] }; + "ion-card-header": IonCardHeader; + "ion-card-subtitle": IonCardSubtitle; + "ion-card-title": IonCardTitle; + "ion-checkbox": IonCheckbox; + "ion-chip": IonChip; + "ion-col": IonCol; + "ion-content": IonContent; + "ion-datetime": IonDatetime; + "ion-datetime-button": IonDatetimeButton; + "ion-divider": IonDivider; + "ion-fab": IonFab; + "ion-fab-button": IonFabButton; + "ion-fab-list": IonFabList; + "ion-footer": IonFooter; + "ion-grid": IonGrid; + "ion-header": IonHeader; + "ion-img": IonImg; + "ion-infinite-scroll": IonInfiniteScroll; + "ion-infinite-scroll-content": IonInfiniteScrollContent; + "ion-input": IonInput; + "ion-input-otp": IonInputOtp; + "ion-input-password-toggle": IonInputPasswordToggle; + "ion-item": IonItem; + "ion-item-divider": IonItemDivider; "ion-item-group": IonItemGroup; - "ion-item-option": Omit & { [K in keyof IonItemOption & keyof IonItemOptionAttributes]?: IonItemOption[K] } & { [K in keyof IonItemOption & keyof IonItemOptionAttributes as `attr:${K}`]?: IonItemOptionAttributes[K] } & { [K in keyof IonItemOption & keyof IonItemOptionAttributes as `prop:${K}`]?: IonItemOption[K] }; - "ion-item-options": Omit & { [K in keyof IonItemOptions & keyof IonItemOptionsAttributes]?: IonItemOptions[K] } & { [K in keyof IonItemOptions & keyof IonItemOptionsAttributes as `attr:${K}`]?: IonItemOptionsAttributes[K] } & { [K in keyof IonItemOptions & keyof IonItemOptionsAttributes as `prop:${K}`]?: IonItemOptions[K] }; - "ion-item-sliding": Omit & { [K in keyof IonItemSliding & keyof IonItemSlidingAttributes]?: IonItemSliding[K] } & { [K in keyof IonItemSliding & keyof IonItemSlidingAttributes as `attr:${K}`]?: IonItemSlidingAttributes[K] } & { [K in keyof IonItemSliding & keyof IonItemSlidingAttributes as `prop:${K}`]?: IonItemSliding[K] }; - "ion-label": Omit & { [K in keyof IonLabel & keyof IonLabelAttributes]?: IonLabel[K] } & { [K in keyof IonLabel & keyof IonLabelAttributes as `attr:${K}`]?: IonLabelAttributes[K] } & { [K in keyof IonLabel & keyof IonLabelAttributes as `prop:${K}`]?: IonLabel[K] }; - "ion-list": Omit & { [K in keyof IonList & keyof IonListAttributes]?: IonList[K] } & { [K in keyof IonList & keyof IonListAttributes as `attr:${K}`]?: IonListAttributes[K] } & { [K in keyof IonList & keyof IonListAttributes as `prop:${K}`]?: IonList[K] }; - "ion-list-header": Omit & { [K in keyof IonListHeader & keyof IonListHeaderAttributes]?: IonListHeader[K] } & { [K in keyof IonListHeader & keyof IonListHeaderAttributes as `attr:${K}`]?: IonListHeaderAttributes[K] } & { [K in keyof IonListHeader & keyof IonListHeaderAttributes as `prop:${K}`]?: IonListHeader[K] }; - "ion-loading": Omit & { [K in keyof IonLoading & keyof IonLoadingAttributes]?: IonLoading[K] } & { [K in keyof IonLoading & keyof IonLoadingAttributes as `attr:${K}`]?: IonLoadingAttributes[K] } & { [K in keyof IonLoading & keyof IonLoadingAttributes as `prop:${K}`]?: IonLoading[K] } & OneOf<"overlayIndex", IonLoading["overlayIndex"], IonLoadingAttributes["overlayIndex"]>; - "ion-menu": Omit & { [K in keyof IonMenu & keyof IonMenuAttributes]?: IonMenu[K] } & { [K in keyof IonMenu & keyof IonMenuAttributes as `attr:${K}`]?: IonMenuAttributes[K] } & { [K in keyof IonMenu & keyof IonMenuAttributes as `prop:${K}`]?: IonMenu[K] }; - "ion-menu-button": Omit & { [K in keyof IonMenuButton & keyof IonMenuButtonAttributes]?: IonMenuButton[K] } & { [K in keyof IonMenuButton & keyof IonMenuButtonAttributes as `attr:${K}`]?: IonMenuButtonAttributes[K] } & { [K in keyof IonMenuButton & keyof IonMenuButtonAttributes as `prop:${K}`]?: IonMenuButton[K] }; - "ion-menu-toggle": Omit & { [K in keyof IonMenuToggle & keyof IonMenuToggleAttributes]?: IonMenuToggle[K] } & { [K in keyof IonMenuToggle & keyof IonMenuToggleAttributes as `attr:${K}`]?: IonMenuToggleAttributes[K] } & { [K in keyof IonMenuToggle & keyof IonMenuToggleAttributes as `prop:${K}`]?: IonMenuToggle[K] }; - "ion-modal": Omit & { [K in keyof IonModal & keyof IonModalAttributes]?: IonModal[K] } & { [K in keyof IonModal & keyof IonModalAttributes as `attr:${K}`]?: IonModalAttributes[K] } & { [K in keyof IonModal & keyof IonModalAttributes as `prop:${K}`]?: IonModal[K] } & OneOf<"overlayIndex", IonModal["overlayIndex"], IonModalAttributes["overlayIndex"]>; - "ion-nav": Omit & { [K in keyof IonNav & keyof IonNavAttributes]?: IonNav[K] } & { [K in keyof IonNav & keyof IonNavAttributes as `attr:${K}`]?: IonNavAttributes[K] } & { [K in keyof IonNav & keyof IonNavAttributes as `prop:${K}`]?: IonNav[K] }; - "ion-nav-link": Omit & { [K in keyof IonNavLink & keyof IonNavLinkAttributes]?: IonNavLink[K] } & { [K in keyof IonNavLink & keyof IonNavLinkAttributes as `attr:${K}`]?: IonNavLinkAttributes[K] } & { [K in keyof IonNavLink & keyof IonNavLinkAttributes as `prop:${K}`]?: IonNavLink[K] }; - "ion-note": Omit & { [K in keyof IonNote & keyof IonNoteAttributes]?: IonNote[K] } & { [K in keyof IonNote & keyof IonNoteAttributes as `attr:${K}`]?: IonNoteAttributes[K] } & { [K in keyof IonNote & keyof IonNoteAttributes as `prop:${K}`]?: IonNote[K] }; + "ion-item-option": IonItemOption; + "ion-item-options": IonItemOptions; + "ion-item-sliding": IonItemSliding; + "ion-label": IonLabel; + "ion-list": IonList; + "ion-list-header": IonListHeader; + "ion-loading": IonLoading; + "ion-menu": IonMenu; + "ion-menu-button": IonMenuButton; + "ion-menu-toggle": IonMenuToggle; + "ion-modal": IonModal; + "ion-nav": IonNav; + "ion-nav-link": IonNavLink; + "ion-note": IonNote; "ion-picker": IonPicker; - "ion-picker-column": Omit & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes]?: IonPickerColumn[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `attr:${K}`]?: IonPickerColumnAttributes[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `prop:${K}`]?: IonPickerColumn[K] }; - "ion-picker-column-option": Omit & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes]?: IonPickerColumnOption[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `attr:${K}`]?: IonPickerColumnOptionAttributes[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `prop:${K}`]?: IonPickerColumnOption[K] }; - "ion-picker-legacy": Omit & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes]?: IonPickerLegacy[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `attr:${K}`]?: IonPickerLegacyAttributes[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `prop:${K}`]?: IonPickerLegacy[K] } & OneOf<"overlayIndex", IonPickerLegacy["overlayIndex"], IonPickerLegacyAttributes["overlayIndex"]>; + "ion-picker-column": IonPickerColumn; + "ion-picker-column-option": IonPickerColumnOption; + "ion-picker-legacy": IonPickerLegacy; "ion-picker-legacy-column": IonPickerLegacyColumn; - "ion-popover": Omit & { [K in keyof IonPopover & keyof IonPopoverAttributes]?: IonPopover[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `attr:${K}`]?: IonPopoverAttributes[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `prop:${K}`]?: IonPopover[K] } & OneOf<"overlayIndex", IonPopover["overlayIndex"], IonPopoverAttributes["overlayIndex"]>; - "ion-progress-bar": Omit & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes]?: IonProgressBar[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `attr:${K}`]?: IonProgressBarAttributes[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `prop:${K}`]?: IonProgressBar[K] }; - "ion-radio": Omit & { [K in keyof IonRadio & keyof IonRadioAttributes]?: IonRadio[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `attr:${K}`]?: IonRadioAttributes[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `prop:${K}`]?: IonRadio[K] }; - "ion-radio-group": Omit & { [K in keyof IonRadioGroup & keyof IonRadioGroupAttributes]?: IonRadioGroup[K] } & { [K in keyof IonRadioGroup & keyof IonRadioGroupAttributes as `attr:${K}`]?: IonRadioGroupAttributes[K] } & { [K in keyof IonRadioGroup & keyof IonRadioGroupAttributes as `prop:${K}`]?: IonRadioGroup[K] }; - "ion-range": Omit & { [K in keyof IonRange & keyof IonRangeAttributes]?: IonRange[K] } & { [K in keyof IonRange & keyof IonRangeAttributes as `attr:${K}`]?: IonRangeAttributes[K] } & { [K in keyof IonRange & keyof IonRangeAttributes as `prop:${K}`]?: IonRange[K] }; - "ion-refresher": Omit & { [K in keyof IonRefresher & keyof IonRefresherAttributes]?: IonRefresher[K] } & { [K in keyof IonRefresher & keyof IonRefresherAttributes as `attr:${K}`]?: IonRefresherAttributes[K] } & { [K in keyof IonRefresher & keyof IonRefresherAttributes as `prop:${K}`]?: IonRefresher[K] }; - "ion-refresher-content": Omit & { [K in keyof IonRefresherContent & keyof IonRefresherContentAttributes]?: IonRefresherContent[K] } & { [K in keyof IonRefresherContent & keyof IonRefresherContentAttributes as `attr:${K}`]?: IonRefresherContentAttributes[K] } & { [K in keyof IonRefresherContent & keyof IonRefresherContentAttributes as `prop:${K}`]?: IonRefresherContent[K] }; + "ion-popover": IonPopover; + "ion-progress-bar": IonProgressBar; + "ion-radio": IonRadio; + "ion-radio-group": IonRadioGroup; + "ion-range": IonRange; + "ion-refresher": IonRefresher; + "ion-refresher-content": IonRefresherContent; "ion-reorder": IonReorder; - "ion-reorder-group": Omit & { [K in keyof IonReorderGroup & keyof IonReorderGroupAttributes]?: IonReorderGroup[K] } & { [K in keyof IonReorderGroup & keyof IonReorderGroupAttributes as `attr:${K}`]?: IonReorderGroupAttributes[K] } & { [K in keyof IonReorderGroup & keyof IonReorderGroupAttributes as `prop:${K}`]?: IonReorderGroup[K] }; - "ion-ripple-effect": Omit & { [K in keyof IonRippleEffect & keyof IonRippleEffectAttributes]?: IonRippleEffect[K] } & { [K in keyof IonRippleEffect & keyof IonRippleEffectAttributes as `attr:${K}`]?: IonRippleEffectAttributes[K] } & { [K in keyof IonRippleEffect & keyof IonRippleEffectAttributes as `prop:${K}`]?: IonRippleEffect[K] }; - "ion-route": Omit & { [K in keyof IonRoute & keyof IonRouteAttributes]?: IonRoute[K] } & { [K in keyof IonRoute & keyof IonRouteAttributes as `attr:${K}`]?: IonRouteAttributes[K] } & { [K in keyof IonRoute & keyof IonRouteAttributes as `prop:${K}`]?: IonRoute[K] } & OneOf<"component", IonRoute["component"], IonRouteAttributes["component"]>; - "ion-route-redirect": Omit & { [K in keyof IonRouteRedirect & keyof IonRouteRedirectAttributes]?: IonRouteRedirect[K] } & { [K in keyof IonRouteRedirect & keyof IonRouteRedirectAttributes as `attr:${K}`]?: IonRouteRedirectAttributes[K] } & { [K in keyof IonRouteRedirect & keyof IonRouteRedirectAttributes as `prop:${K}`]?: IonRouteRedirect[K] } & OneOf<"from", IonRouteRedirect["from"], IonRouteRedirectAttributes["from"]> & OneOf<"to", IonRouteRedirect["to"], IonRouteRedirectAttributes["to"]>; - "ion-router": Omit & { [K in keyof IonRouter & keyof IonRouterAttributes]?: IonRouter[K] } & { [K in keyof IonRouter & keyof IonRouterAttributes as `attr:${K}`]?: IonRouterAttributes[K] } & { [K in keyof IonRouter & keyof IonRouterAttributes as `prop:${K}`]?: IonRouter[K] }; - "ion-router-link": Omit & { [K in keyof IonRouterLink & keyof IonRouterLinkAttributes]?: IonRouterLink[K] } & { [K in keyof IonRouterLink & keyof IonRouterLinkAttributes as `attr:${K}`]?: IonRouterLinkAttributes[K] } & { [K in keyof IonRouterLink & keyof IonRouterLinkAttributes as `prop:${K}`]?: IonRouterLink[K] }; - "ion-router-outlet": Omit & { [K in keyof IonRouterOutlet & keyof IonRouterOutletAttributes]?: IonRouterOutlet[K] } & { [K in keyof IonRouterOutlet & keyof IonRouterOutletAttributes as `attr:${K}`]?: IonRouterOutletAttributes[K] } & { [K in keyof IonRouterOutlet & keyof IonRouterOutletAttributes as `prop:${K}`]?: IonRouterOutlet[K] }; + "ion-reorder-group": IonReorderGroup; + "ion-ripple-effect": IonRippleEffect; + "ion-route": IonRoute; + "ion-route-redirect": IonRouteRedirect; + "ion-router": IonRouter; + "ion-router-link": IonRouterLink; + "ion-router-outlet": IonRouterOutlet; "ion-row": IonRow; - "ion-searchbar": Omit & { [K in keyof IonSearchbar & keyof IonSearchbarAttributes]?: IonSearchbar[K] } & { [K in keyof IonSearchbar & keyof IonSearchbarAttributes as `attr:${K}`]?: IonSearchbarAttributes[K] } & { [K in keyof IonSearchbar & keyof IonSearchbarAttributes as `prop:${K}`]?: IonSearchbar[K] }; - "ion-segment": Omit & { [K in keyof IonSegment & keyof IonSegmentAttributes]?: IonSegment[K] } & { [K in keyof IonSegment & keyof IonSegmentAttributes as `attr:${K}`]?: IonSegmentAttributes[K] } & { [K in keyof IonSegment & keyof IonSegmentAttributes as `prop:${K}`]?: IonSegment[K] }; - "ion-segment-button": Omit & { [K in keyof IonSegmentButton & keyof IonSegmentButtonAttributes]?: IonSegmentButton[K] } & { [K in keyof IonSegmentButton & keyof IonSegmentButtonAttributes as `attr:${K}`]?: IonSegmentButtonAttributes[K] } & { [K in keyof IonSegmentButton & keyof IonSegmentButtonAttributes as `prop:${K}`]?: IonSegmentButton[K] }; + "ion-searchbar": IonSearchbar; + "ion-segment": IonSegment; + "ion-segment-button": IonSegmentButton; "ion-segment-content": IonSegmentContent; - "ion-segment-view": Omit & { [K in keyof IonSegmentView & keyof IonSegmentViewAttributes]?: IonSegmentView[K] } & { [K in keyof IonSegmentView & keyof IonSegmentViewAttributes as `attr:${K}`]?: IonSegmentViewAttributes[K] } & { [K in keyof IonSegmentView & keyof IonSegmentViewAttributes as `prop:${K}`]?: IonSegmentView[K] }; - "ion-select": Omit & { [K in keyof IonSelect & keyof IonSelectAttributes]?: IonSelect[K] } & { [K in keyof IonSelect & keyof IonSelectAttributes as `attr:${K}`]?: IonSelectAttributes[K] } & { [K in keyof IonSelect & keyof IonSelectAttributes as `prop:${K}`]?: IonSelect[K] }; - "ion-select-modal": Omit & { [K in keyof IonSelectModal & keyof IonSelectModalAttributes]?: IonSelectModal[K] } & { [K in keyof IonSelectModal & keyof IonSelectModalAttributes as `attr:${K}`]?: IonSelectModalAttributes[K] } & { [K in keyof IonSelectModal & keyof IonSelectModalAttributes as `prop:${K}`]?: IonSelectModal[K] }; - "ion-select-option": Omit & { [K in keyof IonSelectOption & keyof IonSelectOptionAttributes]?: IonSelectOption[K] } & { [K in keyof IonSelectOption & keyof IonSelectOptionAttributes as `attr:${K}`]?: IonSelectOptionAttributes[K] } & { [K in keyof IonSelectOption & keyof IonSelectOptionAttributes as `prop:${K}`]?: IonSelectOption[K] }; - "ion-select-popover": Omit & { [K in keyof IonSelectPopover & keyof IonSelectPopoverAttributes]?: IonSelectPopover[K] } & { [K in keyof IonSelectPopover & keyof IonSelectPopoverAttributes as `attr:${K}`]?: IonSelectPopoverAttributes[K] } & { [K in keyof IonSelectPopover & keyof IonSelectPopoverAttributes as `prop:${K}`]?: IonSelectPopover[K] }; - "ion-skeleton-text": Omit & { [K in keyof IonSkeletonText & keyof IonSkeletonTextAttributes]?: IonSkeletonText[K] } & { [K in keyof IonSkeletonText & keyof IonSkeletonTextAttributes as `attr:${K}`]?: IonSkeletonTextAttributes[K] } & { [K in keyof IonSkeletonText & keyof IonSkeletonTextAttributes as `prop:${K}`]?: IonSkeletonText[K] }; - "ion-spinner": Omit & { [K in keyof IonSpinner & keyof IonSpinnerAttributes]?: IonSpinner[K] } & { [K in keyof IonSpinner & keyof IonSpinnerAttributes as `attr:${K}`]?: IonSpinnerAttributes[K] } & { [K in keyof IonSpinner & keyof IonSpinnerAttributes as `prop:${K}`]?: IonSpinner[K] }; - "ion-split-pane": Omit & { [K in keyof IonSplitPane & keyof IonSplitPaneAttributes]?: IonSplitPane[K] } & { [K in keyof IonSplitPane & keyof IonSplitPaneAttributes as `attr:${K}`]?: IonSplitPaneAttributes[K] } & { [K in keyof IonSplitPane & keyof IonSplitPaneAttributes as `prop:${K}`]?: IonSplitPane[K] }; - "ion-tab": Omit & { [K in keyof IonTab & keyof IonTabAttributes]?: IonTab[K] } & { [K in keyof IonTab & keyof IonTabAttributes as `attr:${K}`]?: IonTabAttributes[K] } & { [K in keyof IonTab & keyof IonTabAttributes as `prop:${K}`]?: IonTab[K] } & OneOf<"tab", IonTab["tab"], IonTabAttributes["tab"]>; - "ion-tab-bar": Omit & { [K in keyof IonTabBar & keyof IonTabBarAttributes]?: IonTabBar[K] } & { [K in keyof IonTabBar & keyof IonTabBarAttributes as `attr:${K}`]?: IonTabBarAttributes[K] } & { [K in keyof IonTabBar & keyof IonTabBarAttributes as `prop:${K}`]?: IonTabBar[K] }; - "ion-tab-button": Omit & { [K in keyof IonTabButton & keyof IonTabButtonAttributes]?: IonTabButton[K] } & { [K in keyof IonTabButton & keyof IonTabButtonAttributes as `attr:${K}`]?: IonTabButtonAttributes[K] } & { [K in keyof IonTabButton & keyof IonTabButtonAttributes as `prop:${K}`]?: IonTabButton[K] }; - "ion-tabs": Omit & { [K in keyof IonTabs & keyof IonTabsAttributes]?: IonTabs[K] } & { [K in keyof IonTabs & keyof IonTabsAttributes as `attr:${K}`]?: IonTabsAttributes[K] } & { [K in keyof IonTabs & keyof IonTabsAttributes as `prop:${K}`]?: IonTabs[K] }; - "ion-text": Omit & { [K in keyof IonText & keyof IonTextAttributes]?: IonText[K] } & { [K in keyof IonText & keyof IonTextAttributes as `attr:${K}`]?: IonTextAttributes[K] } & { [K in keyof IonText & keyof IonTextAttributes as `prop:${K}`]?: IonText[K] }; - "ion-textarea": Omit & { [K in keyof IonTextarea & keyof IonTextareaAttributes]?: IonTextarea[K] } & { [K in keyof IonTextarea & keyof IonTextareaAttributes as `attr:${K}`]?: IonTextareaAttributes[K] } & { [K in keyof IonTextarea & keyof IonTextareaAttributes as `prop:${K}`]?: IonTextarea[K] }; + "ion-segment-view": IonSegmentView; + "ion-select": IonSelect; + "ion-select-modal": IonSelectModal; + "ion-select-option": IonSelectOption; + "ion-select-popover": IonSelectPopover; + "ion-skeleton-text": IonSkeletonText; + "ion-spinner": IonSpinner; + "ion-split-pane": IonSplitPane; + "ion-tab": IonTab; + "ion-tab-bar": IonTabBar; + "ion-tab-button": IonTabButton; + "ion-tabs": IonTabs; + "ion-text": IonText; + "ion-textarea": IonTextarea; "ion-thumbnail": IonThumbnail; - "ion-title": Omit & { [K in keyof IonTitle & keyof IonTitleAttributes]?: IonTitle[K] } & { [K in keyof IonTitle & keyof IonTitleAttributes as `attr:${K}`]?: IonTitleAttributes[K] } & { [K in keyof IonTitle & keyof IonTitleAttributes as `prop:${K}`]?: IonTitle[K] }; - "ion-toast": Omit & { [K in keyof IonToast & keyof IonToastAttributes]?: IonToast[K] } & { [K in keyof IonToast & keyof IonToastAttributes as `attr:${K}`]?: IonToastAttributes[K] } & { [K in keyof IonToast & keyof IonToastAttributes as `prop:${K}`]?: IonToast[K] } & OneOf<"overlayIndex", IonToast["overlayIndex"], IonToastAttributes["overlayIndex"]>; - "ion-toggle": Omit & { [K in keyof IonToggle & keyof IonToggleAttributes]?: IonToggle[K] } & { [K in keyof IonToggle & keyof IonToggleAttributes as `attr:${K}`]?: IonToggleAttributes[K] } & { [K in keyof IonToggle & keyof IonToggleAttributes as `prop:${K}`]?: IonToggle[K] }; - "ion-toolbar": Omit & { [K in keyof IonToolbar & keyof IonToolbarAttributes]?: IonToolbar[K] } & { [K in keyof IonToolbar & keyof IonToolbarAttributes as `attr:${K}`]?: IonToolbarAttributes[K] } & { [K in keyof IonToolbar & keyof IonToolbarAttributes as `prop:${K}`]?: IonToolbar[K] }; + "ion-title": IonTitle; + "ion-toast": IonToast; + "ion-toggle": IonToggle; + "ion-toolbar": IonToolbar; } } export { LocalJSX as JSX }; declare module "@stencil/core" { export namespace JSX { interface IntrinsicElements { - "ion-accordion": LocalJSX.IntrinsicElements["ion-accordion"] & JSXBase.HTMLAttributes; - "ion-accordion-group": LocalJSX.IntrinsicElements["ion-accordion-group"] & JSXBase.HTMLAttributes; - "ion-action-sheet": LocalJSX.IntrinsicElements["ion-action-sheet"] & JSXBase.HTMLAttributes; - "ion-alert": LocalJSX.IntrinsicElements["ion-alert"] & JSXBase.HTMLAttributes; - "ion-app": LocalJSX.IntrinsicElements["ion-app"] & JSXBase.HTMLAttributes; - "ion-avatar": LocalJSX.IntrinsicElements["ion-avatar"] & JSXBase.HTMLAttributes; - "ion-back-button": LocalJSX.IntrinsicElements["ion-back-button"] & JSXBase.HTMLAttributes; - "ion-backdrop": LocalJSX.IntrinsicElements["ion-backdrop"] & JSXBase.HTMLAttributes; - "ion-badge": LocalJSX.IntrinsicElements["ion-badge"] & JSXBase.HTMLAttributes; - "ion-breadcrumb": LocalJSX.IntrinsicElements["ion-breadcrumb"] & JSXBase.HTMLAttributes; - "ion-breadcrumbs": LocalJSX.IntrinsicElements["ion-breadcrumbs"] & JSXBase.HTMLAttributes; - "ion-button": LocalJSX.IntrinsicElements["ion-button"] & JSXBase.HTMLAttributes; - "ion-buttons": LocalJSX.IntrinsicElements["ion-buttons"] & JSXBase.HTMLAttributes; - "ion-card": LocalJSX.IntrinsicElements["ion-card"] & JSXBase.HTMLAttributes; - "ion-card-content": LocalJSX.IntrinsicElements["ion-card-content"] & JSXBase.HTMLAttributes; - "ion-card-header": LocalJSX.IntrinsicElements["ion-card-header"] & JSXBase.HTMLAttributes; - "ion-card-subtitle": LocalJSX.IntrinsicElements["ion-card-subtitle"] & JSXBase.HTMLAttributes; - "ion-card-title": LocalJSX.IntrinsicElements["ion-card-title"] & JSXBase.HTMLAttributes; - "ion-checkbox": LocalJSX.IntrinsicElements["ion-checkbox"] & JSXBase.HTMLAttributes; - "ion-chip": LocalJSX.IntrinsicElements["ion-chip"] & JSXBase.HTMLAttributes; - "ion-col": LocalJSX.IntrinsicElements["ion-col"] & JSXBase.HTMLAttributes; - "ion-content": LocalJSX.IntrinsicElements["ion-content"] & JSXBase.HTMLAttributes; - "ion-datetime": LocalJSX.IntrinsicElements["ion-datetime"] & JSXBase.HTMLAttributes; - "ion-datetime-button": LocalJSX.IntrinsicElements["ion-datetime-button"] & JSXBase.HTMLAttributes; - "ion-divider": LocalJSX.IntrinsicElements["ion-divider"] & JSXBase.HTMLAttributes; - "ion-fab": LocalJSX.IntrinsicElements["ion-fab"] & JSXBase.HTMLAttributes; - "ion-fab-button": LocalJSX.IntrinsicElements["ion-fab-button"] & JSXBase.HTMLAttributes; - "ion-fab-list": LocalJSX.IntrinsicElements["ion-fab-list"] & JSXBase.HTMLAttributes; - "ion-footer": LocalJSX.IntrinsicElements["ion-footer"] & JSXBase.HTMLAttributes; - "ion-grid": LocalJSX.IntrinsicElements["ion-grid"] & JSXBase.HTMLAttributes; - "ion-header": LocalJSX.IntrinsicElements["ion-header"] & JSXBase.HTMLAttributes; - "ion-img": LocalJSX.IntrinsicElements["ion-img"] & JSXBase.HTMLAttributes; - "ion-infinite-scroll": LocalJSX.IntrinsicElements["ion-infinite-scroll"] & JSXBase.HTMLAttributes; - "ion-infinite-scroll-content": LocalJSX.IntrinsicElements["ion-infinite-scroll-content"] & JSXBase.HTMLAttributes; - "ion-input": LocalJSX.IntrinsicElements["ion-input"] & JSXBase.HTMLAttributes; - "ion-input-otp": LocalJSX.IntrinsicElements["ion-input-otp"] & JSXBase.HTMLAttributes; - "ion-input-password-toggle": LocalJSX.IntrinsicElements["ion-input-password-toggle"] & JSXBase.HTMLAttributes; - "ion-item": LocalJSX.IntrinsicElements["ion-item"] & JSXBase.HTMLAttributes; - "ion-item-divider": LocalJSX.IntrinsicElements["ion-item-divider"] & JSXBase.HTMLAttributes; - "ion-item-group": LocalJSX.IntrinsicElements["ion-item-group"] & JSXBase.HTMLAttributes; - "ion-item-option": LocalJSX.IntrinsicElements["ion-item-option"] & JSXBase.HTMLAttributes; - "ion-item-options": LocalJSX.IntrinsicElements["ion-item-options"] & JSXBase.HTMLAttributes; - "ion-item-sliding": LocalJSX.IntrinsicElements["ion-item-sliding"] & JSXBase.HTMLAttributes; - "ion-label": LocalJSX.IntrinsicElements["ion-label"] & JSXBase.HTMLAttributes; - "ion-list": LocalJSX.IntrinsicElements["ion-list"] & JSXBase.HTMLAttributes; - "ion-list-header": LocalJSX.IntrinsicElements["ion-list-header"] & JSXBase.HTMLAttributes; - "ion-loading": LocalJSX.IntrinsicElements["ion-loading"] & JSXBase.HTMLAttributes; - "ion-menu": LocalJSX.IntrinsicElements["ion-menu"] & JSXBase.HTMLAttributes; - "ion-menu-button": LocalJSX.IntrinsicElements["ion-menu-button"] & JSXBase.HTMLAttributes; - "ion-menu-toggle": LocalJSX.IntrinsicElements["ion-menu-toggle"] & JSXBase.HTMLAttributes; - "ion-modal": LocalJSX.IntrinsicElements["ion-modal"] & JSXBase.HTMLAttributes; - "ion-nav": LocalJSX.IntrinsicElements["ion-nav"] & JSXBase.HTMLAttributes; - "ion-nav-link": LocalJSX.IntrinsicElements["ion-nav-link"] & JSXBase.HTMLAttributes; - "ion-note": LocalJSX.IntrinsicElements["ion-note"] & JSXBase.HTMLAttributes; - "ion-picker": LocalJSX.IntrinsicElements["ion-picker"] & JSXBase.HTMLAttributes; - "ion-picker-column": LocalJSX.IntrinsicElements["ion-picker-column"] & JSXBase.HTMLAttributes; - "ion-picker-column-option": LocalJSX.IntrinsicElements["ion-picker-column-option"] & JSXBase.HTMLAttributes; - "ion-picker-legacy": LocalJSX.IntrinsicElements["ion-picker-legacy"] & JSXBase.HTMLAttributes; - "ion-picker-legacy-column": LocalJSX.IntrinsicElements["ion-picker-legacy-column"] & JSXBase.HTMLAttributes; - "ion-popover": LocalJSX.IntrinsicElements["ion-popover"] & JSXBase.HTMLAttributes; - "ion-progress-bar": LocalJSX.IntrinsicElements["ion-progress-bar"] & JSXBase.HTMLAttributes; - "ion-radio": LocalJSX.IntrinsicElements["ion-radio"] & JSXBase.HTMLAttributes; - "ion-radio-group": LocalJSX.IntrinsicElements["ion-radio-group"] & JSXBase.HTMLAttributes; - "ion-range": LocalJSX.IntrinsicElements["ion-range"] & JSXBase.HTMLAttributes; - "ion-refresher": LocalJSX.IntrinsicElements["ion-refresher"] & JSXBase.HTMLAttributes; - "ion-refresher-content": LocalJSX.IntrinsicElements["ion-refresher-content"] & JSXBase.HTMLAttributes; - "ion-reorder": LocalJSX.IntrinsicElements["ion-reorder"] & JSXBase.HTMLAttributes; - "ion-reorder-group": LocalJSX.IntrinsicElements["ion-reorder-group"] & JSXBase.HTMLAttributes; - "ion-ripple-effect": LocalJSX.IntrinsicElements["ion-ripple-effect"] & JSXBase.HTMLAttributes; - "ion-route": LocalJSX.IntrinsicElements["ion-route"] & JSXBase.HTMLAttributes; - "ion-route-redirect": LocalJSX.IntrinsicElements["ion-route-redirect"] & JSXBase.HTMLAttributes; - "ion-router": LocalJSX.IntrinsicElements["ion-router"] & JSXBase.HTMLAttributes; - "ion-router-link": LocalJSX.IntrinsicElements["ion-router-link"] & JSXBase.HTMLAttributes; - "ion-router-outlet": LocalJSX.IntrinsicElements["ion-router-outlet"] & JSXBase.HTMLAttributes; - "ion-row": LocalJSX.IntrinsicElements["ion-row"] & JSXBase.HTMLAttributes; - "ion-searchbar": LocalJSX.IntrinsicElements["ion-searchbar"] & JSXBase.HTMLAttributes; - "ion-segment": LocalJSX.IntrinsicElements["ion-segment"] & JSXBase.HTMLAttributes; - "ion-segment-button": LocalJSX.IntrinsicElements["ion-segment-button"] & JSXBase.HTMLAttributes; - "ion-segment-content": LocalJSX.IntrinsicElements["ion-segment-content"] & JSXBase.HTMLAttributes; - "ion-segment-view": LocalJSX.IntrinsicElements["ion-segment-view"] & JSXBase.HTMLAttributes; - "ion-select": LocalJSX.IntrinsicElements["ion-select"] & JSXBase.HTMLAttributes; - "ion-select-modal": LocalJSX.IntrinsicElements["ion-select-modal"] & JSXBase.HTMLAttributes; - "ion-select-option": LocalJSX.IntrinsicElements["ion-select-option"] & JSXBase.HTMLAttributes; - "ion-select-popover": LocalJSX.IntrinsicElements["ion-select-popover"] & JSXBase.HTMLAttributes; - "ion-skeleton-text": LocalJSX.IntrinsicElements["ion-skeleton-text"] & JSXBase.HTMLAttributes; - "ion-spinner": LocalJSX.IntrinsicElements["ion-spinner"] & JSXBase.HTMLAttributes; - "ion-split-pane": LocalJSX.IntrinsicElements["ion-split-pane"] & JSXBase.HTMLAttributes; - "ion-tab": LocalJSX.IntrinsicElements["ion-tab"] & JSXBase.HTMLAttributes; - "ion-tab-bar": LocalJSX.IntrinsicElements["ion-tab-bar"] & JSXBase.HTMLAttributes; - "ion-tab-button": LocalJSX.IntrinsicElements["ion-tab-button"] & JSXBase.HTMLAttributes; - "ion-tabs": LocalJSX.IntrinsicElements["ion-tabs"] & JSXBase.HTMLAttributes; - "ion-text": LocalJSX.IntrinsicElements["ion-text"] & JSXBase.HTMLAttributes; - "ion-textarea": LocalJSX.IntrinsicElements["ion-textarea"] & JSXBase.HTMLAttributes; - "ion-thumbnail": LocalJSX.IntrinsicElements["ion-thumbnail"] & JSXBase.HTMLAttributes; - "ion-title": LocalJSX.IntrinsicElements["ion-title"] & JSXBase.HTMLAttributes; - "ion-toast": LocalJSX.IntrinsicElements["ion-toast"] & JSXBase.HTMLAttributes; - "ion-toggle": LocalJSX.IntrinsicElements["ion-toggle"] & JSXBase.HTMLAttributes; - "ion-toolbar": LocalJSX.IntrinsicElements["ion-toolbar"] & JSXBase.HTMLAttributes; + "ion-accordion": LocalJSX.IonAccordion & JSXBase.HTMLAttributes; + "ion-accordion-group": LocalJSX.IonAccordionGroup & JSXBase.HTMLAttributes; + "ion-action-sheet": LocalJSX.IonActionSheet & JSXBase.HTMLAttributes; + "ion-alert": LocalJSX.IonAlert & JSXBase.HTMLAttributes; + "ion-app": LocalJSX.IonApp & JSXBase.HTMLAttributes; + "ion-avatar": LocalJSX.IonAvatar & JSXBase.HTMLAttributes; + "ion-back-button": LocalJSX.IonBackButton & JSXBase.HTMLAttributes; + "ion-backdrop": LocalJSX.IonBackdrop & JSXBase.HTMLAttributes; + "ion-badge": LocalJSX.IonBadge & JSXBase.HTMLAttributes; + "ion-breadcrumb": LocalJSX.IonBreadcrumb & JSXBase.HTMLAttributes; + "ion-breadcrumbs": LocalJSX.IonBreadcrumbs & JSXBase.HTMLAttributes; + "ion-button": LocalJSX.IonButton & JSXBase.HTMLAttributes; + "ion-buttons": LocalJSX.IonButtons & JSXBase.HTMLAttributes; + "ion-card": LocalJSX.IonCard & JSXBase.HTMLAttributes; + "ion-card-content": LocalJSX.IonCardContent & JSXBase.HTMLAttributes; + "ion-card-header": LocalJSX.IonCardHeader & JSXBase.HTMLAttributes; + "ion-card-subtitle": LocalJSX.IonCardSubtitle & JSXBase.HTMLAttributes; + "ion-card-title": LocalJSX.IonCardTitle & JSXBase.HTMLAttributes; + "ion-checkbox": LocalJSX.IonCheckbox & JSXBase.HTMLAttributes; + "ion-chip": LocalJSX.IonChip & JSXBase.HTMLAttributes; + "ion-col": LocalJSX.IonCol & JSXBase.HTMLAttributes; + "ion-content": LocalJSX.IonContent & JSXBase.HTMLAttributes; + "ion-datetime": LocalJSX.IonDatetime & JSXBase.HTMLAttributes; + "ion-datetime-button": LocalJSX.IonDatetimeButton & JSXBase.HTMLAttributes; + "ion-divider": LocalJSX.IonDivider & JSXBase.HTMLAttributes; + "ion-fab": LocalJSX.IonFab & JSXBase.HTMLAttributes; + "ion-fab-button": LocalJSX.IonFabButton & JSXBase.HTMLAttributes; + "ion-fab-list": LocalJSX.IonFabList & JSXBase.HTMLAttributes; + "ion-footer": LocalJSX.IonFooter & JSXBase.HTMLAttributes; + "ion-grid": LocalJSX.IonGrid & JSXBase.HTMLAttributes; + "ion-header": LocalJSX.IonHeader & JSXBase.HTMLAttributes; + "ion-img": LocalJSX.IonImg & JSXBase.HTMLAttributes; + "ion-infinite-scroll": LocalJSX.IonInfiniteScroll & JSXBase.HTMLAttributes; + "ion-infinite-scroll-content": LocalJSX.IonInfiniteScrollContent & JSXBase.HTMLAttributes; + "ion-input": LocalJSX.IonInput & JSXBase.HTMLAttributes; + "ion-input-otp": LocalJSX.IonInputOtp & JSXBase.HTMLAttributes; + "ion-input-password-toggle": LocalJSX.IonInputPasswordToggle & JSXBase.HTMLAttributes; + "ion-item": LocalJSX.IonItem & JSXBase.HTMLAttributes; + "ion-item-divider": LocalJSX.IonItemDivider & JSXBase.HTMLAttributes; + "ion-item-group": LocalJSX.IonItemGroup & JSXBase.HTMLAttributes; + "ion-item-option": LocalJSX.IonItemOption & JSXBase.HTMLAttributes; + "ion-item-options": LocalJSX.IonItemOptions & JSXBase.HTMLAttributes; + "ion-item-sliding": LocalJSX.IonItemSliding & JSXBase.HTMLAttributes; + "ion-label": LocalJSX.IonLabel & JSXBase.HTMLAttributes; + "ion-list": LocalJSX.IonList & JSXBase.HTMLAttributes; + "ion-list-header": LocalJSX.IonListHeader & JSXBase.HTMLAttributes; + "ion-loading": LocalJSX.IonLoading & JSXBase.HTMLAttributes; + "ion-menu": LocalJSX.IonMenu & JSXBase.HTMLAttributes; + "ion-menu-button": LocalJSX.IonMenuButton & JSXBase.HTMLAttributes; + "ion-menu-toggle": LocalJSX.IonMenuToggle & JSXBase.HTMLAttributes; + "ion-modal": LocalJSX.IonModal & JSXBase.HTMLAttributes; + "ion-nav": LocalJSX.IonNav & JSXBase.HTMLAttributes; + "ion-nav-link": LocalJSX.IonNavLink & JSXBase.HTMLAttributes; + "ion-note": LocalJSX.IonNote & JSXBase.HTMLAttributes; + "ion-picker": LocalJSX.IonPicker & JSXBase.HTMLAttributes; + "ion-picker-column": LocalJSX.IonPickerColumn & JSXBase.HTMLAttributes; + "ion-picker-column-option": LocalJSX.IonPickerColumnOption & JSXBase.HTMLAttributes; + "ion-picker-legacy": LocalJSX.IonPickerLegacy & JSXBase.HTMLAttributes; + "ion-picker-legacy-column": LocalJSX.IonPickerLegacyColumn & JSXBase.HTMLAttributes; + "ion-popover": LocalJSX.IonPopover & JSXBase.HTMLAttributes; + "ion-progress-bar": LocalJSX.IonProgressBar & JSXBase.HTMLAttributes; + "ion-radio": LocalJSX.IonRadio & JSXBase.HTMLAttributes; + "ion-radio-group": LocalJSX.IonRadioGroup & JSXBase.HTMLAttributes; + "ion-range": LocalJSX.IonRange & JSXBase.HTMLAttributes; + "ion-refresher": LocalJSX.IonRefresher & JSXBase.HTMLAttributes; + "ion-refresher-content": LocalJSX.IonRefresherContent & JSXBase.HTMLAttributes; + "ion-reorder": LocalJSX.IonReorder & JSXBase.HTMLAttributes; + "ion-reorder-group": LocalJSX.IonReorderGroup & JSXBase.HTMLAttributes; + "ion-ripple-effect": LocalJSX.IonRippleEffect & JSXBase.HTMLAttributes; + "ion-route": LocalJSX.IonRoute & JSXBase.HTMLAttributes; + "ion-route-redirect": LocalJSX.IonRouteRedirect & JSXBase.HTMLAttributes; + "ion-router": LocalJSX.IonRouter & JSXBase.HTMLAttributes; + "ion-router-link": LocalJSX.IonRouterLink & JSXBase.HTMLAttributes; + "ion-router-outlet": LocalJSX.IonRouterOutlet & JSXBase.HTMLAttributes; + "ion-row": LocalJSX.IonRow & JSXBase.HTMLAttributes; + "ion-searchbar": LocalJSX.IonSearchbar & JSXBase.HTMLAttributes; + "ion-segment": LocalJSX.IonSegment & JSXBase.HTMLAttributes; + "ion-segment-button": LocalJSX.IonSegmentButton & JSXBase.HTMLAttributes; + "ion-segment-content": LocalJSX.IonSegmentContent & JSXBase.HTMLAttributes; + "ion-segment-view": LocalJSX.IonSegmentView & JSXBase.HTMLAttributes; + "ion-select": LocalJSX.IonSelect & JSXBase.HTMLAttributes; + "ion-select-modal": LocalJSX.IonSelectModal & JSXBase.HTMLAttributes; + "ion-select-option": LocalJSX.IonSelectOption & JSXBase.HTMLAttributes; + "ion-select-popover": LocalJSX.IonSelectPopover & JSXBase.HTMLAttributes; + "ion-skeleton-text": LocalJSX.IonSkeletonText & JSXBase.HTMLAttributes; + "ion-spinner": LocalJSX.IonSpinner & JSXBase.HTMLAttributes; + "ion-split-pane": LocalJSX.IonSplitPane & JSXBase.HTMLAttributes; + "ion-tab": LocalJSX.IonTab & JSXBase.HTMLAttributes; + "ion-tab-bar": LocalJSX.IonTabBar & JSXBase.HTMLAttributes; + "ion-tab-button": LocalJSX.IonTabButton & JSXBase.HTMLAttributes; + "ion-tabs": LocalJSX.IonTabs & JSXBase.HTMLAttributes; + "ion-text": LocalJSX.IonText & JSXBase.HTMLAttributes; + "ion-textarea": LocalJSX.IonTextarea & JSXBase.HTMLAttributes; + "ion-thumbnail": LocalJSX.IonThumbnail & JSXBase.HTMLAttributes; + "ion-title": LocalJSX.IonTitle & JSXBase.HTMLAttributes; + "ion-toast": LocalJSX.IonToast & JSXBase.HTMLAttributes; + "ion-toggle": LocalJSX.IonToggle & JSXBase.HTMLAttributes; + "ion-toolbar": LocalJSX.IonToolbar & JSXBase.HTMLAttributes; } } } diff --git a/core/src/components/action-sheet/action-sheet.tsx b/core/src/components/action-sheet/action-sheet.tsx index 5d79ab90f51..ca0d5e9aa30 100644 --- a/core/src/components/action-sheet/action-sheet.tsx +++ b/core/src/components/action-sheet/action-sheet.tsx @@ -1,5 +1,6 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; import { Watch, Component, Element, Event, Host, Listen, Method, Prop, State, h, readTask } from '@stencil/core'; +import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config'; import type { Gesture } from '@utils/gesture'; import { createButtonActiveGesture } from '@utils/gesture/button-active'; import { raf } from '@utils/helpers'; @@ -16,8 +17,10 @@ import { safeCall, setOverlayId, } from '@utils/overlays'; +import { sanitizeDOMString } from '@utils/sanitization'; import { getClassMap } from '@utils/theme'; +import { config } from '../../global/config'; import { getIonMode, getIonTheme } from '../../global/ionic-global'; import type { AnimationBuilder, CssClassMap, FrameworkDelegate, OverlayInterface } from '../../interface'; import type { OverlayEventDetail } from '../../utils/overlays-interface'; @@ -49,6 +52,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface { private groupEl?: HTMLElement; private gesture?: Gesture; private hasRadioButtons = false; + private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT); presented = false; lastFocus?: HTMLElement; @@ -580,7 +584,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface { > {b.icon && {theme === 'md' && } diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx index e4e98b67a42..628b62555ae 100644 --- a/core/src/components/alert/alert.tsx +++ b/core/src/components/alert/alert.tsx @@ -591,7 +591,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
-
{i.label}
+ {this.renderLabel(i, 'alert-checkbox-label')} {theme === 'md' && } @@ -631,7 +631,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
-
{i.label}
+ {this.renderLabel(i, 'alert-radio-label')} ))} @@ -747,6 +747,14 @@ export class Alert implements ComponentInterface, OverlayInterface { ); } + private renderLabel(formControl: AlertInput, className: string) { + if (this.customHTMLEnabled) { + return
; + } + + return
{formControl.label}
; + } + render() { const { overlayIndex, header, subHeader, message, htmlAttributes } = this; const theme = getIonTheme(this); diff --git a/core/src/components/select-modal/select-modal.tsx b/core/src/components/select-modal/select-modal.tsx index c277c194da8..5a1d22f6d01 100644 --- a/core/src/components/select-modal/select-modal.tsx +++ b/core/src/components/select-modal/select-modal.tsx @@ -1,9 +1,12 @@ import { getIonMode } from '@global/ionic-global'; import type { ComponentInterface } from '@stencil/core'; import { Component, Element, Host, Prop, forceUpdate, h } from '@stencil/core'; +import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config'; import { safeCall } from '@utils/overlays'; +import { sanitizeDOMString } from '@utils/sanitization'; import { getClassMap, hostContext } from '@utils/theme'; +import { config } from '../../global/config'; import type { CheckboxCustomEvent } from '../checkbox/checkbox-interface'; import type { RadioGroupCustomEvent } from '../radio-group/radio-group-interface'; @@ -19,6 +22,8 @@ import type { SelectModalOption } from './select-modal-interface'; scoped: true, }) export class SelectModal implements ComponentInterface { + private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT); + @Element() el!: HTMLIonSelectModalElement; @Prop() header?: string; @@ -118,7 +123,7 @@ export class SelectModal implements ComponentInterface { } }} > - {option.text} + {this.customHTMLEnabled ? : option.text} ))} @@ -148,7 +153,7 @@ export class SelectModal implements ComponentInterface { forceUpdate(this); }} > - {option.text} + {this.customHTMLEnabled ? : option.text} )); diff --git a/core/src/components/select-option/select-option.tsx b/core/src/components/select-option/select-option.tsx index b088f4ea72e..940558d57ee 100644 --- a/core/src/components/select-option/select-option.tsx +++ b/core/src/components/select-option/select-option.tsx @@ -27,8 +27,14 @@ export class SelectOption implements ComponentInterface { */ @Prop() value?: any | null; + /** + * Text that is placed underneath the option text to provide additional details about the option. + */ + @Prop() description?: string; + render() { const theme = getIonTheme(this); + return ( + > + +
+ + {this.description &&
{this.description}
} +
+ + ); } } diff --git a/core/src/components/select-popover/select-popover.tsx b/core/src/components/select-popover/select-popover.tsx index efba1c8d9c1..04e00255710 100644 --- a/core/src/components/select-popover/select-popover.tsx +++ b/core/src/components/select-popover/select-popover.tsx @@ -1,8 +1,11 @@ import type { ComponentInterface } from '@stencil/core'; import { Element, Component, Host, Prop, h, forceUpdate } from '@stencil/core'; +import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config'; import { safeCall } from '@utils/overlays'; +import { sanitizeDOMString } from '@utils/sanitization'; import { getClassMap } from '@utils/theme'; +import { config } from '../../global/config'; import { getIonTheme } from '../../global/ionic-global'; import type { CheckboxCustomEvent } from '../checkbox/checkbox-interface'; import type { RadioGroupCustomEvent } from '../radio-group/radio-group-interface'; @@ -25,6 +28,8 @@ import type { SelectPopoverOption } from './select-popover-interface'; scoped: true, }) export class SelectPopover implements ComponentInterface { + private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT); + @Element() el!: HTMLIonSelectPopoverElement; /** * The header text of the popover @@ -140,7 +145,7 @@ export class SelectPopover implements ComponentInterface { forceUpdate(this); }} > - {option.text} + {this.customHTMLEnabled ? : option.text} )); @@ -174,7 +179,7 @@ export class SelectPopover implements ComponentInterface { } }} > - {option.text} + {this.customHTMLEnabled ? : option.text} ))} diff --git a/core/src/components/select/select.common.scss b/core/src/components/select/select.common.scss index 43f3d13399f..a2b669c9980 100644 --- a/core/src/components/select/select.common.scss +++ b/core/src/components/select/select.common.scss @@ -36,6 +36,8 @@ --highlight-color-focused: #{ion-color(primary, base)}; --highlight-color-valid: #{ion-color(success, base)}; --highlight-color-invalid: #{ion-color(danger, base)}; + --select-text-media-height: 1.5em; + --select-text-media-width: 1.5em; /** * This is a private API that is used to switch @@ -152,6 +154,12 @@ button { overflow: hidden; } +.select-text img, +.select-text ion-img .select-text ion-icon .select-text ion-thumbnail { + width: var(--select-text-media-width); + height: var(--select-text-media-height); +} + // Select Wrapper // -------------------------------------------------- diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx index 8071434ba8c..15e7adaa6f5 100644 --- a/core/src/components/select/select.tsx +++ b/core/src/components/select/select.tsx @@ -1,6 +1,7 @@ import caretDownRegular from '@phosphor-icons/core/assets/regular/caret-down.svg'; import type { ComponentInterface, EventEmitter } from '@stencil/core'; import { Build, Component, Element, Event, Host, Method, Prop, State, Watch, h, forceUpdate } from '@stencil/core'; +import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config'; import type { NotchController } from '@utils/forms'; import { compareOptions, createNotchController, isOptionSelected, checkInvalidState } from '@utils/forms'; import { focusVisibleElement, renderHiddenInput, inheritAttributes } from '@utils/helpers'; @@ -9,6 +10,7 @@ import { printIonWarning } from '@utils/logging'; import { actionSheetController, alertController, popoverController, modalController } from '@utils/overlays'; import type { OverlaySelect } from '@utils/overlays-interface'; import { isRTL } from '@utils/rtl'; +import { sanitizeDOMString } from '@utils/sanitization'; import { createColorClasses, hostContext } from '@utils/theme'; import { watchForOptions } from '@utils/watch-options'; import { caretDownSharp, chevronExpand } from 'ionicons/icons'; @@ -72,8 +74,8 @@ export class Select implements ComponentInterface { private nativeWrapperEl: HTMLElement | undefined; private notchSpacerEl: HTMLElement | undefined; private validationObserver?: MutationObserver; - private notchController?: NotchController; + private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT); @Element() el!: HTMLIonSelectElement; @@ -576,10 +578,11 @@ export class Select implements ComponentInterface { .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; const isSelected = isOptionSelected(selectValue, value, this.compareWith); + const text = this.customHTMLEnabled ? sanitizeDOMString(getOptionHTML(option)) : option.textContent; return { role: isSelected ? 'selected' : '', - text: option.textContent, + text: text || '', cssClass: optClass, handler: () => { this.setValue(value); @@ -616,14 +619,16 @@ export class Select implements ComponentInterface { .filter((cls) => cls !== 'hydrated') .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; + const label = this.customHTMLEnabled ? sanitizeDOMString(getOptionHTML(option)) : option.textContent; return { type: inputType, cssClass: optClass, - label: option.textContent || '', + label: label || '', value, checked: isOptionSelected(selectValue, value, this.compareWith), disabled: option.disabled, + description: option.description, }; }); @@ -639,9 +644,10 @@ export class Select implements ComponentInterface { .filter((cls) => cls !== 'hydrated') .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; + const text = this.customHTMLEnabled ? sanitizeDOMString(getOptionHTML(option)) : option.textContent; return { - text: option.textContent || '', + text: text || '', cssClass: optClass, value, checked: isOptionSelected(selectValue, value, this.compareWith), @@ -879,12 +885,12 @@ export class Select implements ComponentInterface { return; } - private getText(): string { + private getText(useHTML = false): string { const selectedText = this.selectedText; if (selectedText != null && selectedText !== '') { return selectedText; } - return generateText(this.childOpts, this.value, this.compareWith); + return generateText(this.childOpts, this.value, this.compareWith, useHTML); } private setFocus() { @@ -1069,7 +1075,7 @@ export class Select implements ComponentInterface { private renderSelectText() { const { placeholder } = this; - const displayValue = this.getText(); + const displayValue = this.getText(true); let addPlaceholderClass = false; let selectText = displayValue; @@ -1085,6 +1091,10 @@ export class Select implements ComponentInterface { const textPart = addPlaceholderClass ? 'placeholder' : 'text'; + if (this.customHTMLEnabled) { + return ; + } + return ( ); } @@ -609,32 +623,42 @@ export class Alert implements ComponentInterface, OverlayInterface { return (
- {inputs.map((i) => ( -
- - ))} + + ); + })} ); } @@ -747,14 +771,6 @@ export class Alert implements ComponentInterface, OverlayInterface { ); } - private renderLabel(formControl: AlertInput, className: string) { - if (this.customHTMLEnabled) { - return
; - } - - return
{formControl.label}
; - } - render() { const { overlayIndex, header, subHeader, message, htmlAttributes } = this; const theme = getIonTheme(this); diff --git a/core/src/components/select-modal/select-modal-interface.ts b/core/src/components/select-modal/select-modal-interface.ts index 2005400cb82..8ed968c3d12 100644 --- a/core/src/components/select-modal/select-modal-interface.ts +++ b/core/src/components/select-modal/select-modal-interface.ts @@ -1,8 +1,11 @@ export interface SelectModalOption { - text: string; + text: string | HTMLElement; value: string; disabled: boolean; checked: boolean; cssClass?: string | string[]; handler?: (value: any) => boolean | void | { [key: string]: any }; + startContent?: HTMLElement; + endContent?: HTMLElement; + description?: string; } diff --git a/core/src/components/select-modal/select-modal.common.scss b/core/src/components/select-modal/select-modal.common.scss index 683ae23faeb..3bbb48b557d 100644 --- a/core/src/components/select-modal/select-modal.common.scss +++ b/core/src/components/select-modal/select-modal.common.scss @@ -1,3 +1,19 @@ +// Select Modal +// -------------------------------------------------- + :host { height: 100%; } + +// Select Modal: Select Option +// -------------------------------------------------- + +.select-option-label { + display: flex; + + align-items: center; +} + +.select-option-description { + display: block; +} diff --git a/core/src/components/select-modal/select-modal.ionic.scss b/core/src/components/select-modal/select-modal.ionic.scss index 23d7705b660..ca137a075d3 100644 --- a/core/src/components/select-modal/select-modal.ionic.scss +++ b/core/src/components/select-modal/select-modal.ionic.scss @@ -77,3 +77,18 @@ ion-content { --background-focused-opacity: 1; } } + +// Select Modal: Select Option +// -------------------------------------------------- + +.select-option-label { + gap: globals.$ion-space-300; +} + +.select-option-description { + @include globals.typography(globals.$ion-body-md-regular); + + color: globals.$ion-text-subtle; + + font-size: globals.$ion-font-size-350; +} diff --git a/core/src/components/select-modal/select-modal.md.scss b/core/src/components/select-modal/select-modal.md.scss index 505ea2a061c..260f6aba5be 100644 --- a/core/src/components/select-modal/select-modal.md.scss +++ b/core/src/components/select-modal/select-modal.md.scss @@ -1,4 +1,4 @@ -@import "./select-modal.common"; +@import "./select-modal.native"; @import "../../themes/mixins.scss"; @import "../item/item.md.vars"; diff --git a/core/src/components/select-modal/select-modal.native.scss b/core/src/components/select-modal/select-modal.native.scss new file mode 100644 index 00000000000..29b81819fcf --- /dev/null +++ b/core/src/components/select-modal/select-modal.native.scss @@ -0,0 +1,19 @@ +@use "../../themes/native/native.theme.default" as native; +@use "../../themes/mixins" as mixins; +@use "../../themes/functions.font" as font; +@use "./select-modal.common"; + +// Select Modal: Native +// -------------------------------------------------- + +.select-option-label { + gap: 12px; +} + +.select-option-description { + @include mixins.padding(5px, 0, 0, 0); + + color: native.$text-color-step-300; + + font-size: font.dynamic-font(12px); +} diff --git a/core/src/components/select-modal/select-modal.tsx b/core/src/components/select-modal/select-modal.tsx index 5a1d22f6d01..d1ea8723756 100644 --- a/core/src/components/select-modal/select-modal.tsx +++ b/core/src/components/select-modal/select-modal.tsx @@ -1,12 +1,10 @@ import { getIonMode } from '@global/ionic-global'; import type { ComponentInterface } from '@stencil/core'; import { Component, Element, Host, Prop, forceUpdate, h } from '@stencil/core'; -import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config'; import { safeCall } from '@utils/overlays'; -import { sanitizeDOMString } from '@utils/sanitization'; +import { renderOptionLabel } from '@utils/select-option-render'; import { getClassMap, hostContext } from '@utils/theme'; -import { config } from '../../global/config'; import type { CheckboxCustomEvent } from '../checkbox/checkbox-interface'; import type { RadioGroupCustomEvent } from '../radio-group/radio-group-interface'; @@ -22,8 +20,6 @@ import type { SelectModalOption } from './select-modal-interface'; scoped: true, }) export class SelectModal implements ComponentInterface { - private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT); - @Element() el!: HTMLIonSelectModalElement; @Prop() header?: string; @@ -97,66 +93,86 @@ export class SelectModal implements ComponentInterface { return ( this.callOptionHandler(ev)}> - {this.options.map((option) => ( - - this.closeModal()} - onKeyUp={(ev) => { - if (ev.key === ' ') { - /** - * Selecting a radio option with keyboard navigation, - * either through the Enter or Space keys, should - * dismiss the modal. - */ - this.closeModal(); - } + {this.options.map((option) => { + const optionLabelOptions = { + id: option.value, + label: option.text, + startContent: option.startContent, + endContent: option.endContent, + description: option.description, + }; + + return ( + - {this.customHTMLEnabled ? : option.text} - - - ))} + this.closeModal()} + onKeyUp={(ev) => { + if (ev.key === ' ') { + /** + * Selecting a radio option with keyboard navigation, + * either through the Enter or Space keys, should + * dismiss the modal. + */ + this.closeModal(); + } + }} + > + {renderOptionLabel(optionLabelOptions, 'select-option-label')} + + + ); + })} ); } private renderCheckboxOptions() { - return this.options.map((option) => ( - - { - this.setChecked(ev); - this.callOptionHandler(ev); + return this.options.map((option) => { + const optionLabelOptions = { + id: option.value, + label: option.text, + startContent: option.startContent, + endContent: option.endContent, + description: option.description, + }; + + return ( + - {this.customHTMLEnabled ? : option.text} - - - )); + { + this.setChecked(ev); + this.callOptionHandler(ev); + // TODO FW-4784 + forceUpdate(this); + }} + > + {renderOptionLabel(optionLabelOptions, 'select-option-label')} + + + ); + }); } render() { diff --git a/core/src/components/select-option/select-option.tsx b/core/src/components/select-option/select-option.tsx index 940558d57ee..dea73b4fd3c 100644 --- a/core/src/components/select-option/select-option.tsx +++ b/core/src/components/select-option/select-option.tsx @@ -44,10 +44,7 @@ export class SelectOption implements ComponentInterface { id={this.inputId} > -
- - {this.description &&
{this.description}
} -
+ ); diff --git a/core/src/components/select-popover/select-popover-interface.ts b/core/src/components/select-popover/select-popover-interface.ts index 1787234ae75..b0a30bbbf13 100644 --- a/core/src/components/select-popover/select-popover-interface.ts +++ b/core/src/components/select-popover/select-popover-interface.ts @@ -1,8 +1,11 @@ export interface SelectPopoverOption { - text: string; + text: string | HTMLElement; value: string; disabled: boolean; checked: boolean; cssClass?: string | string[]; handler?: (value: any) => boolean | void | { [key: string]: any }; + startContent?: HTMLElement; + endContent?: HTMLElement; + description?: string; } diff --git a/core/src/components/select-popover/select-popover.ionic.scss b/core/src/components/select-popover/select-popover.ionic.scss new file mode 100644 index 00000000000..781b8d3aee6 --- /dev/null +++ b/core/src/components/select-popover/select-popover.ionic.scss @@ -0,0 +1,22 @@ +@use "../../themes/ionic/ionic.globals.scss" as globals; +@use "./select-popover"; +@use "./select-popover.md" as select-popover-md; + +// Ionic Select Popover +// -------------------------------------------------- + +// Select Modal: Select Option +// -------------------------------------------------- + +.select-option-label { + gap: globals.$ion-space-300; +} + +.select-option-description { + @include globals.typography(globals.$ion-body-md-regular); + @include globals.padding(0); + + color: globals.$ion-text-subtle; + + font-size: globals.$ion-font-size-350; +} diff --git a/core/src/components/select-popover/select-popover.ios.scss b/core/src/components/select-popover/select-popover.ios.scss index 3330a261d80..de3cfea6135 100644 --- a/core/src/components/select-popover/select-popover.ios.scss +++ b/core/src/components/select-popover/select-popover.ios.scss @@ -1,2 +1,2 @@ -@import "./select-popover"; +@import "./select-popover.native"; @import "./select-popover.ios.vars"; diff --git a/core/src/components/select-popover/select-popover.md.scss b/core/src/components/select-popover/select-popover.md.scss index 001b0123632..c7728bcaf04 100644 --- a/core/src/components/select-popover/select-popover.md.scss +++ b/core/src/components/select-popover/select-popover.md.scss @@ -1,4 +1,4 @@ -@import "./select-popover"; +@import "./select-popover.native"; @import "./select-popover.md.vars"; ion-list ion-radio::part(container) { diff --git a/core/src/components/select-popover/select-popover.native.scss b/core/src/components/select-popover/select-popover.native.scss new file mode 100644 index 00000000000..8b5e36f701a --- /dev/null +++ b/core/src/components/select-popover/select-popover.native.scss @@ -0,0 +1,19 @@ +@use "../../themes/native/native.theme.default" as native; +@use "../../themes/mixins" as mixins; +@use "../../themes/functions.font" as font; +@use "./select-popover"; + +// Select Popover: Native +// -------------------------------------------------- + +.select-option-label { + gap: 12px; +} + +.select-option-description { + @include mixins.padding(5px, 0, 0, 0); + + color: native.$text-color-step-300; + + font-size: font.dynamic-font(12px); +} diff --git a/core/src/components/select-popover/select-popover.scss b/core/src/components/select-popover/select-popover.scss index de7cb783300..6ac149c96be 100644 --- a/core/src/components/select-popover/select-popover.scss +++ b/core/src/components/select-popover/select-popover.scss @@ -1,5 +1,8 @@ @import "../../themes/native/native.globals"; +// Select Popover +// -------------------------------------------------- + :host ion-list { @include margin(0); } @@ -18,3 +21,39 @@ ion-label { :host { overflow-y: auto; } + +// Select Popover: Select Option +// -------------------------------------------------- + +.select-option-label { + display: flex; + + align-items: center; + gap: 8px; +} + +.select-option-content { + flex: 1; +} + +.select-option-description { + @include padding(5px, 0, 0, 0); + display: block; + + color: $text-color-step-300; + + font-size: dynamic-font(12px); +} + +// Select Popover: Select Option +// -------------------------------------------------- + +.select-option-label { + display: flex; + + align-items: center; +} + +.select-option-description { + display: block; +} diff --git a/core/src/components/select-popover/select-popover.tsx b/core/src/components/select-popover/select-popover.tsx index 04e00255710..fa3c7e34fb5 100644 --- a/core/src/components/select-popover/select-popover.tsx +++ b/core/src/components/select-popover/select-popover.tsx @@ -1,11 +1,9 @@ import type { ComponentInterface } from '@stencil/core'; import { Element, Component, Host, Prop, h, forceUpdate } from '@stencil/core'; -import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config'; import { safeCall } from '@utils/overlays'; -import { sanitizeDOMString } from '@utils/sanitization'; +import { renderOptionLabel } from '@utils/select-option-render'; import { getClassMap } from '@utils/theme'; -import { config } from '../../global/config'; import { getIonTheme } from '../../global/ionic-global'; import type { CheckboxCustomEvent } from '../checkbox/checkbox-interface'; import type { RadioGroupCustomEvent } from '../radio-group/radio-group-interface'; @@ -23,13 +21,11 @@ import type { SelectPopoverOption } from './select-popover-interface'; styleUrls: { ios: 'select-popover.ios.scss', md: 'select-popover.md.scss', - ionic: 'select-popover.md.scss', + ionic: 'select-popover.ionic.scss', }, scoped: true, }) export class SelectPopover implements ComponentInterface { - private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT); - @Element() el!: HTMLIonSelectPopoverElement; /** * The header text of the popover @@ -124,31 +120,41 @@ export class SelectPopover implements ComponentInterface { } renderCheckboxOptions(options: SelectPopoverOption[]) { - return options.map((option) => ( - - { - this.setChecked(ev); - this.callOptionHandler(ev); + return options.map((option) => { + const optionLabelOptions = { + id: option.value, + label: option.text, + startContent: option.startContent, + endContent: option.endContent, + description: option.description, + }; + + return ( + - {this.customHTMLEnabled ? : option.text} - - - )); + { + this.setChecked(ev); + this.callOptionHandler(ev); + // TODO FW-4784 + forceUpdate(this); + }} + > + {renderOptionLabel(optionLabelOptions, 'select-option-label')} + + + ); + }); } renderRadioOptions(options: SelectPopoverOption[]) { @@ -156,33 +162,43 @@ export class SelectPopover implements ComponentInterface { return ( this.callOptionHandler(ev)}> - {options.map((option) => ( - - this.dismissParentPopover()} - onKeyUp={(ev) => { - if (ev.key === ' ') { - /** - * Selecting a radio option with keyboard navigation, - * either through the Enter or Space keys, should - * dismiss the popover. - */ - this.dismissParentPopover(); - } + {options.map((option) => { + const optionLabelOptions = { + id: option.value, + label: option.text, + startContent: option.startContent, + endContent: option.endContent, + description: option.description, + }; + + return ( + - {this.customHTMLEnabled ? : option.text} - - - ))} + this.dismissParentPopover()} + onKeyUp={(ev) => { + if (ev.key === ' ') { + /** + * Selecting a radio option with keyboard navigation, + * either through the Enter or Space keys, should + * dismiss the popover. + */ + this.dismissParentPopover(); + } + }} + > + {renderOptionLabel(optionLabelOptions, 'select-option-label')} + + + ); + })} ); } diff --git a/core/src/components/select/select.common.scss b/core/src/components/select/select.common.scss index a2b669c9980..b3866c6f15b 100644 --- a/core/src/components/select/select.common.scss +++ b/core/src/components/select/select.common.scss @@ -25,6 +25,13 @@ * @prop --border-width: Width of the select border * * @prop --ripple-color: The color of the ripple effect on MD mode. + * + * @prop --select-text-media-width: The width of media (icons/images) in the select text. + * @prop --select-text-media-height: The height of media (icons/images) in the select text. + * @prop --select-text-media-border-width: The border width of media (icons/images) in the select text. + * @prop --select-text-media-border-color: The border color of media (icons/images) in the select text. + * @prop --select-text-media-border-radius: The border radius of media (icons/images) in the select text. + * @prop --select-text-media-border-style: The border style of media (icons/images) in the select text. */ --padding-top: 0px; --padding-end: 0px; @@ -155,9 +162,18 @@ button { } .select-text img, -.select-text ion-img .select-text ion-icon .select-text ion-thumbnail { +.select-text ion-img, +.select-text ion-icon, +.select-text ion-thumbnail, +.select-text ion-avatar { + @include mixins.border-radius(var(--select-text-media-border-radius)); + width: var(--select-text-media-width); height: var(--select-text-media-height); + + border-width: var(--select-text-media-border-width); + border-style: var(--select-text-media-border-style); + border-color: var(--select-text-media-border-color); } // Select Wrapper diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx index 15e7adaa6f5..d13d38f58e3 100644 --- a/core/src/components/select/select.tsx +++ b/core/src/components/select/select.tsx @@ -578,11 +578,11 @@ export class Select implements ComponentInterface { .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; const isSelected = isOptionSelected(selectValue, value, this.compareWith); - const text = this.customHTMLEnabled ? sanitizeDOMString(getOptionHTML(option)) : option.textContent; + const text = this.customHTMLEnabled ? getOptionContentNodes(option) : option.textContent; return { role: isSelected ? 'selected' : '', - text: text || '', + text: text ?? '', cssClass: optClass, handler: () => { this.setValue(value); @@ -591,6 +591,9 @@ export class Select implements ComponentInterface { 'aria-checked': isSelected ? 'true' : 'false', role: 'radio', }, + startContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'start') ?? undefined : undefined, + endContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'end') ?? undefined : undefined, + description: option.description, } as ActionSheetButton; }); @@ -619,15 +622,17 @@ export class Select implements ComponentInterface { .filter((cls) => cls !== 'hydrated') .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; - const label = this.customHTMLEnabled ? sanitizeDOMString(getOptionHTML(option)) : option.textContent; + const label = this.customHTMLEnabled ? getOptionContentNodes(option) : option.textContent; return { type: inputType, cssClass: optClass, - label: label || '', + label: label ?? '', value, checked: isOptionSelected(selectValue, value, this.compareWith), disabled: option.disabled, + startContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'start') ?? undefined : undefined, + endContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'end') ?? undefined : undefined, description: option.description, }; }); @@ -644,10 +649,10 @@ export class Select implements ComponentInterface { .filter((cls) => cls !== 'hydrated') .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; - const text = this.customHTMLEnabled ? sanitizeDOMString(getOptionHTML(option)) : option.textContent; + const text = this.customHTMLEnabled ? getOptionContentNodes(option) : option.textContent; return { - text: text || '', + text: text ?? '', cssClass: optClass, value, checked: isOptionSelected(selectValue, value, this.compareWith), @@ -658,6 +663,9 @@ export class Select implements ComponentInterface { this.close(); } }, + startContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'start') ?? undefined : undefined, + endContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'end') ?? undefined : undefined, + description: option.description, }; }); @@ -1496,29 +1504,36 @@ const getOptionContentHTML = (option: HTMLIonSelectOptionElement, slotName?: str return sanitizeDOMString(temp.innerHTML.trim()) || null; }; -const getOptionHTML = (option: HTMLIonSelectOptionElement): string => { - const startContent = getOptionContentHTML(option, 'start'); - const endContent = getOptionContentHTML(option, 'end'); - const defaultContent = getOptionContentHTML(option) || ''; - const description = option.description; - - let html = ''; +const getOptionContentNodes = (option: HTMLIonSelectOptionElement, slotName?: string): HTMLElement | null => { + let nodes: Node[]; - if (startContent) { - html += `
${startContent}
`; + if (slotName) { + // Named slot: get elements with matching slot attribute + nodes = Array.from(option.children).filter((el) => el.getAttribute('slot') === slotName); + } else { + // Default slot: get nodes without a slot attribute + nodes = Array.from(option.childNodes).filter((node) => { + if (node.nodeType === Node.ELEMENT_NODE) { + return !(node as HTMLElement).hasAttribute('slot'); + } + return node.textContent?.trim().length !== 0; + }); } - html += `
${defaultContent}`; - if (description) { - html += `
${description}
`; - } - html += `
`; + if (nodes.length === 0) return null; - if (endContent) { - html += `
${endContent}
`; - } + const container = document.createElement('div'); + nodes.forEach((n) => { + const clone = n.cloneNode(true); + if (clone.nodeType === Node.TEXT_NODE) { + clone.textContent = clone.textContent?.trim() || ''; + } else { + trimTextNodes(clone); + } + container.appendChild(clone); + }); - return html; + return container; }; let selectIds = 0; diff --git a/core/src/components/select/test/basic/index.html b/core/src/components/select/test/basic/index.html index 944aab9b5b7..dd8d57a8e6c 100644 --- a/core/src/components/select/test/basic/index.html +++ b/core/src/components/select/test/basic/index.html @@ -21,23 +21,16 @@ }; @@ -58,16 +51,17 @@ - - + + + Apples + This is a span element -
test
- Apples
Oranges Pears @@ -76,12 +70,18 @@ - Apples + + + + + Apples + This is a span element + /> + Oranges Pears @@ -89,10 +89,18 @@ - Apples - + + + + + Apples + This is a span element + + Oranges Pears @@ -100,10 +108,18 @@ - Apples - + + + + + Apples + This is a span element + + Oranges Pears @@ -117,12 +133,38 @@ - Apple - + Apple + Apricot + Avocado + Banana + Blackberry + Blueberry + Cantaloupe + Cherry + Coconut + Cranberry + Dragonfruit + Fig + Grape + Grapefruit + Guava + Kiwi + Lemon + Lime + Lychee + Mango + Nectarine + Orange + Papaya + Passion Fruit + Peach + Pear + Pineapple + Plum + Pomegranate + Raspberry + Strawberry + Tangerine Watermelon @@ -254,7 +296,18 @@ - Pepperoni + + + + + Pepperoni + This is a span element + + Bacon Extra Cheese Mushrooms @@ -264,7 +317,18 @@ - Bird + + + + + Bird + This is a span element + + Cat Dog Honey Badger @@ -273,7 +337,18 @@ - Bird + + + + + Bird + This is a span element + + Cat Dog Honey Badger diff --git a/core/src/utils/select-option-render.tsx b/core/src/utils/select-option-render.tsx new file mode 100644 index 00000000000..2f531c98c11 --- /dev/null +++ b/core/src/utils/select-option-render.tsx @@ -0,0 +1,56 @@ +import { h } from '@stencil/core'; + +export interface RichContentOption { + id: string; + label?: string | HTMLElement; + startContent?: HTMLElement; + endContent?: HTMLElement; + description?: string; +} + +const renderClonedContent = (id: string, content: HTMLElement, className: string) => ( + { + if (el && !el.hasChildNodes()) { + Array.from(content.childNodes).forEach((n) => el.appendChild(n.cloneNode(true))); + } + }} + > +); + +export const renderOptionLabel = (option: RichContentOption, className: string) => { + const { id, label, startContent, endContent, description } = option; + const hasRichContent = !!startContent || !!endContent || !!description; + + const labelEl = + typeof label === 'string' || !label ? ( + {label} + ) : ( + renderClonedContent(id, label, `${className}-text`) + ); + + if (!hasRichContent) { + return ( + + {labelEl} + + ); + } + + return ( + + {startContent && renderClonedContent(id, startContent, 'select-option-start')} + + {labelEl} + {description && ( + + {description} + + )} + + {endContent && renderClonedContent(id, endContent, 'select-option-end')} + + ); +}; diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index fecc4aed2a8..77c90635a69 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -2253,14 +2253,14 @@ export declare interface IonSelectModal extends Components.IonSelectModal {} @ProxyCmp({ - inputs: ['disabled', 'mode', 'theme', 'value'] + inputs: ['description', 'disabled', 'mode', 'theme', 'value'] }) @Component({ selector: 'ion-select-option', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['disabled', 'mode', 'theme', 'value'], + inputs: ['description', 'disabled', 'mode', 'theme', 'value'], }) export class IonSelectOption { protected el: HTMLIonSelectOptionElement; diff --git a/packages/angular/standalone/src/directives/proxies.ts b/packages/angular/standalone/src/directives/proxies.ts index 41e27889758..1b0b7a38b2e 100644 --- a/packages/angular/standalone/src/directives/proxies.ts +++ b/packages/angular/standalone/src/directives/proxies.ts @@ -1986,14 +1986,14 @@ export declare interface IonSelectModal extends Components.IonSelectModal {} @ProxyCmp({ defineCustomElementFn: defineIonSelectOption, - inputs: ['disabled', 'mode', 'theme', 'value'] + inputs: ['description', 'disabled', 'mode', 'theme', 'value'] }) @Component({ selector: 'ion-select-option', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['disabled', 'mode', 'theme', 'value'], + inputs: ['description', 'disabled', 'mode', 'theme', 'value'], standalone: true }) export class IonSelectOption { diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index bf7ab19881d..cccb4233b58 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -998,7 +998,8 @@ export const IonSelectModal: StencilVueComponent = /*@__PURE export const IonSelectOption: StencilVueComponent = /*@__PURE__*/ defineContainer('ion-select-option', defineIonSelectOption, [ 'disabled', - 'value' + 'value', + 'description' ]); From d53d62794b499038ffc6eaafcbb686ddfbb7cfb1 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 9 Apr 2026 20:46:30 -0700 Subject: [PATCH 3/9] refactor(many): rename files to common --- .../{action-sheet.scss => action-sheet.common.scss} | 0 core/src/components/action-sheet/action-sheet.ionic.scss | 2 +- core/src/components/action-sheet/action-sheet.native.scss | 2 +- core/src/components/alert/{alert.scss => alert.common.scss} | 0 core/src/components/alert/alert.ionic.scss | 2 +- core/src/components/alert/alert.native.scss | 2 +- .../{select-popover.scss => select-popover.common.scss} | 0 core/src/components/select-popover/select-popover.ionic.scss | 2 +- core/src/components/select-popover/select-popover.native.scss | 2 +- 9 files changed, 6 insertions(+), 6 deletions(-) rename core/src/components/action-sheet/{action-sheet.scss => action-sheet.common.scss} (100%) rename core/src/components/alert/{alert.scss => alert.common.scss} (100%) rename core/src/components/select-popover/{select-popover.scss => select-popover.common.scss} (100%) diff --git a/core/src/components/action-sheet/action-sheet.scss b/core/src/components/action-sheet/action-sheet.common.scss similarity index 100% rename from core/src/components/action-sheet/action-sheet.scss rename to core/src/components/action-sheet/action-sheet.common.scss diff --git a/core/src/components/action-sheet/action-sheet.ionic.scss b/core/src/components/action-sheet/action-sheet.ionic.scss index ba97b5aaba7..b2c749d4e0a 100644 --- a/core/src/components/action-sheet/action-sheet.ionic.scss +++ b/core/src/components/action-sheet/action-sheet.ionic.scss @@ -1,5 +1,5 @@ @use "../../themes/ionic/ionic.globals.scss" as globals; -@use "./action-sheet"; +@use "./action-sheet.common"; @use "./action-sheet.md" as action-sheet-md; // Ionic Action Sheet diff --git a/core/src/components/action-sheet/action-sheet.native.scss b/core/src/components/action-sheet/action-sheet.native.scss index 3d694bdb651..affa6aeb126 100644 --- a/core/src/components/action-sheet/action-sheet.native.scss +++ b/core/src/components/action-sheet/action-sheet.native.scss @@ -1,7 +1,7 @@ @use "../../themes/native/native.theme.default" as native; @use "../../themes/mixins" as mixins; @use "../../themes/functions.font" as font; -@use "./action-sheet"; +@use "./action-sheet.common"; // Action Sheet: Native // -------------------------------------------------- diff --git a/core/src/components/alert/alert.scss b/core/src/components/alert/alert.common.scss similarity index 100% rename from core/src/components/alert/alert.scss rename to core/src/components/alert/alert.common.scss diff --git a/core/src/components/alert/alert.ionic.scss b/core/src/components/alert/alert.ionic.scss index db82f34812d..3c54136b477 100644 --- a/core/src/components/alert/alert.ionic.scss +++ b/core/src/components/alert/alert.ionic.scss @@ -1,5 +1,5 @@ @use "../../themes/ionic/ionic.globals.scss" as globals; -@use "./alert"; +@use "./alert.common"; @use "./alert.md" as alert-md; // Ionic Alert diff --git a/core/src/components/alert/alert.native.scss b/core/src/components/alert/alert.native.scss index a3e89e09af3..e2d5a87b8a5 100644 --- a/core/src/components/alert/alert.native.scss +++ b/core/src/components/alert/alert.native.scss @@ -1,7 +1,7 @@ @use "../../themes/native/native.theme.default" as native; @use "../../themes/mixins" as mixins; @use "../../themes/functions.font" as font; -@use "./alert"; +@use "./alert.common"; // Alert: Native // -------------------------------------------------- diff --git a/core/src/components/select-popover/select-popover.scss b/core/src/components/select-popover/select-popover.common.scss similarity index 100% rename from core/src/components/select-popover/select-popover.scss rename to core/src/components/select-popover/select-popover.common.scss diff --git a/core/src/components/select-popover/select-popover.ionic.scss b/core/src/components/select-popover/select-popover.ionic.scss index 781b8d3aee6..c8321bb30eb 100644 --- a/core/src/components/select-popover/select-popover.ionic.scss +++ b/core/src/components/select-popover/select-popover.ionic.scss @@ -1,5 +1,5 @@ @use "../../themes/ionic/ionic.globals.scss" as globals; -@use "./select-popover"; +@use "./select-popover.common"; @use "./select-popover.md" as select-popover-md; // Ionic Select Popover diff --git a/core/src/components/select-popover/select-popover.native.scss b/core/src/components/select-popover/select-popover.native.scss index 8b5e36f701a..0b52fafe932 100644 --- a/core/src/components/select-popover/select-popover.native.scss +++ b/core/src/components/select-popover/select-popover.native.scss @@ -1,7 +1,7 @@ @use "../../themes/native/native.theme.default" as native; @use "../../themes/mixins" as mixins; @use "../../themes/functions.font" as font; -@use "./select-popover"; +@use "./select-popover.common"; // Select Popover: Native // -------------------------------------------------- From 5415cadb2b4b9d51e3a63372a8848897329ca078 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 9 Apr 2026 20:50:11 -0700 Subject: [PATCH 4/9] chore(select): run build --- core/api.txt | 18 ++++++++++++++++++ .../select-modal/select-modal.ios.scss | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/core/api.txt b/core/api.txt index f2536a2a447..7ee339dacfb 100644 --- a/core/api.txt +++ b/core/api.txt @@ -2326,6 +2326,24 @@ ion-select,css-prop,--placeholder-opacity,md ion-select,css-prop,--ripple-color,ionic ion-select,css-prop,--ripple-color,ios ion-select,css-prop,--ripple-color,md +ion-select,css-prop,--select-text-media-border-color,ionic +ion-select,css-prop,--select-text-media-border-color,ios +ion-select,css-prop,--select-text-media-border-color,md +ion-select,css-prop,--select-text-media-border-radius,ionic +ion-select,css-prop,--select-text-media-border-radius,ios +ion-select,css-prop,--select-text-media-border-radius,md +ion-select,css-prop,--select-text-media-border-style,ionic +ion-select,css-prop,--select-text-media-border-style,ios +ion-select,css-prop,--select-text-media-border-style,md +ion-select,css-prop,--select-text-media-border-width,ionic +ion-select,css-prop,--select-text-media-border-width,ios +ion-select,css-prop,--select-text-media-border-width,md +ion-select,css-prop,--select-text-media-height,ionic +ion-select,css-prop,--select-text-media-height,ios +ion-select,css-prop,--select-text-media-height,md +ion-select,css-prop,--select-text-media-width,ionic +ion-select,css-prop,--select-text-media-width,ios +ion-select,css-prop,--select-text-media-width,md ion-select,part,bottom ion-select,part,container ion-select,part,error-text diff --git a/core/src/components/select-modal/select-modal.ios.scss b/core/src/components/select-modal/select-modal.ios.scss index eea8d57f0ba..abac9c8220b 100644 --- a/core/src/components/select-modal/select-modal.ios.scss +++ b/core/src/components/select-modal/select-modal.ios.scss @@ -1,4 +1,4 @@ -@import "./select-modal.common"; +@import "./select-modal.native"; @import "../item/item.ios.vars"; @import "../radio/radio.ios.vars"; From 8f3e62310a40c99a0ff663449a31c36896e3bec5 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 9 Apr 2026 21:11:43 -0700 Subject: [PATCH 5/9] refactor(select): cleanup --- .../components/select-modal/select-modal.tsx | 8 ++-- .../select-popover/select-popover.common.scss | 23 ---------- .../select-popover/select-popover.tsx | 8 ++-- .../components/select/test/basic/index.html | 42 ++++--------------- core/src/utils/select-option-render.tsx | 9 +++- 5 files changed, 23 insertions(+), 67 deletions(-) diff --git a/core/src/components/select-modal/select-modal.tsx b/core/src/components/select-modal/select-modal.tsx index d1ea8723756..477e42b1c16 100644 --- a/core/src/components/select-modal/select-modal.tsx +++ b/core/src/components/select-modal/select-modal.tsx @@ -93,9 +93,9 @@ export class SelectModal implements ComponentInterface { return ( this.callOptionHandler(ev)}> - {this.options.map((option) => { + {this.options.map((option, index) => { const optionLabelOptions = { - id: option.value, + id: `modal-option-${index}`, label: option.text, startContent: option.startContent, endContent: option.endContent, @@ -138,9 +138,9 @@ export class SelectModal implements ComponentInterface { } private renderCheckboxOptions() { - return this.options.map((option) => { + return this.options.map((option, index) => { const optionLabelOptions = { - id: option.value, + id: `modal-option-${index}`, label: option.text, startContent: option.startContent, endContent: option.endContent, diff --git a/core/src/components/select-popover/select-popover.common.scss b/core/src/components/select-popover/select-popover.common.scss index 6ac149c96be..cedc62bbf3a 100644 --- a/core/src/components/select-popover/select-popover.common.scss +++ b/core/src/components/select-popover/select-popover.common.scss @@ -25,29 +25,6 @@ ion-label { // Select Popover: Select Option // -------------------------------------------------- -.select-option-label { - display: flex; - - align-items: center; - gap: 8px; -} - -.select-option-content { - flex: 1; -} - -.select-option-description { - @include padding(5px, 0, 0, 0); - display: block; - - color: $text-color-step-300; - - font-size: dynamic-font(12px); -} - -// Select Popover: Select Option -// -------------------------------------------------- - .select-option-label { display: flex; diff --git a/core/src/components/select-popover/select-popover.tsx b/core/src/components/select-popover/select-popover.tsx index fa3c7e34fb5..7b5bb28b15c 100644 --- a/core/src/components/select-popover/select-popover.tsx +++ b/core/src/components/select-popover/select-popover.tsx @@ -120,9 +120,9 @@ export class SelectPopover implements ComponentInterface { } renderCheckboxOptions(options: SelectPopoverOption[]) { - return options.map((option) => { + return options.map((option, index) => { const optionLabelOptions = { - id: option.value, + id: `popover-option-${index}`, label: option.text, startContent: option.startContent, endContent: option.endContent, @@ -162,9 +162,9 @@ export class SelectPopover implements ComponentInterface { return ( this.callOptionHandler(ev)}> - {options.map((option) => { + {options.map((option, index) => { const optionLabelOptions = { - id: option.value, + id: `popover-option-${index}`, label: option.text, startContent: option.startContent, endContent: option.endContent, diff --git a/core/src/components/select/test/basic/index.html b/core/src/components/select/test/basic/index.html index dd8d57a8e6c..156f2367ad8 100644 --- a/core/src/components/select/test/basic/index.html +++ b/core/src/components/select/test/basic/index.html @@ -57,11 +57,7 @@
Apples This is a span element - + NEW
Oranges Pears @@ -76,11 +72,7 @@ Apples This is a span element - + NEW Oranges Pears @@ -95,11 +87,7 @@ Apples This is a span element - + NEW Oranges Pears @@ -114,11 +102,7 @@ Apples This is a span element - + NEW Oranges Pears @@ -302,11 +286,7 @@ Pepperoni This is a span element - + NEW Bacon Extra Cheese @@ -323,11 +303,7 @@ Bird This is a span element - + NEW Cat Dog @@ -343,11 +319,7 @@ Bird This is a span element - + NEW Cat Dog diff --git a/core/src/utils/select-option-render.tsx b/core/src/utils/select-option-render.tsx index 2f531c98c11..9100bb9bae1 100644 --- a/core/src/utils/select-option-render.tsx +++ b/core/src/utils/select-option-render.tsx @@ -8,13 +8,20 @@ export interface RichContentOption { description?: string; } +const contentCache = new WeakMap(); + const renderClonedContent = (id: string, content: HTMLElement, className: string) => ( { - if (el && !el.hasChildNodes()) { + if (el) { + const cached = contentCache.get(el); + if (cached === content) return; + + el.innerHTML = ''; Array.from(content.childNodes).forEach((n) => el.appendChild(n.cloneNode(true))); + contentCache.set(el, content); } }} > From a48cf660cd5f5affdeca83b5a867b372bea8a294 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 9 Apr 2026 21:16:59 -0700 Subject: [PATCH 6/9] chore(): run build proper --- core/api.txt | 10 +- core/src/components.d.ts | 1183 ++++++++++++++++++++++++++++++++------ 2 files changed, 1001 insertions(+), 192 deletions(-) diff --git a/core/api.txt b/core/api.txt index 7ee339dacfb..4bf94c415f6 100644 --- a/core/api.txt +++ b/core/api.txt @@ -949,7 +949,7 @@ ion-infinite-scroll-content,prop,theme,"ios" | "md" | "ionic",undefined,false,fa ion-input,scoped ion-input,prop,autocapitalize,string,'off',false,false -ion-input,prop,autocomplete,"name" | "url" | "off" | "on" | "additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday-day" | "bday-month" | "bday-year" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "new-password" | "one-time-code" | "organization" | "postal-code" | "street-address" | "transaction-amount" | "transaction-currency" | "username" | "email" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "nickname" | "organization-title" | "cc-additional-name" | "language" | "bday" | "sex" | "impp" | "photo",'off',false,false +ion-input,prop,autocomplete,"additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday" | "bday-day" | "bday-month" | "bday-year" | "cc-additional-name" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "email" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "impp" | "language" | "name" | "new-password" | "nickname" | "off" | "on" | "one-time-code" | "organization" | "organization-title" | "photo" | "postal-code" | "sex" | "street-address" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "transaction-amount" | "transaction-currency" | "url" | "username",'off',false,false ion-input,prop,autocorrect,"off" | "on",'off',false,false ion-input,prop,autofocus,boolean,false,false,false ion-input,prop,clearInput,boolean,false,false,false @@ -1631,7 +1631,7 @@ ion-nav,prop,animated,boolean,true,false,false ion-nav,prop,animation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-nav,prop,mode,"ios" | "md",undefined,false,false ion-nav,prop,root,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false -ion-nav,prop,rootParams,undefined | { [key: string]: any; },undefined,false,false +ion-nav,prop,rootParams,T | undefined,undefined,false,false ion-nav,prop,swipeGesture,boolean | undefined,undefined,false,false ion-nav,prop,theme,"ios" | "md" | "ionic",undefined,false,false ion-nav,method,canGoBack,canGoBack(view?: ViewController) => Promise @@ -1653,7 +1653,7 @@ ion-nav,event,ionNavWillChange,void,false ion-nav-link,none ion-nav-link,prop,component,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false -ion-nav-link,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false +ion-nav-link,prop,componentProps,T | undefined,undefined,false,false ion-nav-link,prop,mode,"ios" | "md",undefined,false,false ion-nav-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-nav-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false @@ -1758,7 +1758,7 @@ ion-popover,prop,animated,boolean,true,false,false ion-popover,prop,arrow,boolean,true,false,false ion-popover,prop,backdropDismiss,boolean,true,false,false ion-popover,prop,component,Function | HTMLElement | null | string | undefined,undefined,false,false -ion-popover,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false +ion-popover,prop,componentProps,T | undefined,undefined,false,false ion-popover,prop,dismissOnSelect,boolean,false,false,false ion-popover,prop,enterAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-popover,prop,event,any,undefined,false,false @@ -2066,7 +2066,7 @@ ion-row,css-prop,--ion-grid-gap ion-searchbar,scoped ion-searchbar,prop,animated,boolean,false,false,false ion-searchbar,prop,autocapitalize,string,'off',false,false -ion-searchbar,prop,autocomplete,"name" | "url" | "off" | "on" | "additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday-day" | "bday-month" | "bday-year" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "new-password" | "one-time-code" | "organization" | "postal-code" | "street-address" | "transaction-amount" | "transaction-currency" | "username" | "email" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "nickname" | "organization-title" | "cc-additional-name" | "language" | "bday" | "sex" | "impp" | "photo",'off',false,false +ion-searchbar,prop,autocomplete,"additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday" | "bday-day" | "bday-month" | "bday-year" | "cc-additional-name" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "email" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "impp" | "language" | "name" | "new-password" | "nickname" | "off" | "on" | "one-time-code" | "organization" | "organization-title" | "photo" | "postal-code" | "sex" | "street-address" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "transaction-amount" | "transaction-currency" | "url" | "username",'off',false,false ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false ion-searchbar,prop,cancelButtonIcon,string | undefined,undefined,false,false ion-searchbar,prop,cancelButtonText,string,'Cancel',false,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 11810a6766a..86ac882a669 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -6023,6 +6023,8 @@ declare global { } } declare namespace LocalJSX { + type OneOf = { [P in K]: PropT } & { [P in `attr:${K}` | `prop:${K}`]?: never } | { [P in `attr:${K}`]: AttrT } & { [P in K | `prop:${K}`]?: never } | { [P in `prop:${K}`]: PropT } & { [P in K | `attr:${K}`]?: never }; + interface IonAccordion { /** * If `true`, the accordion cannot be interacted with. @@ -7785,6 +7787,10 @@ declare namespace LocalJSX { * @default 'outline' */ "fill"?: 'outline' | 'solid'; + /** + * The `id` of a `` element to associate this element with. + */ + "form"?: string; /** * A hint to the browser for which keyboard to display. Possible values: `"none"`, `"text"`, `"tel"`, `"url"`, `"email"`, `"numeric"`, `"decimal"`, and `"search"`. For numbers (type="number"): "numeric" For text (type="text"): "text" */ @@ -7798,6 +7804,10 @@ declare namespace LocalJSX { * The mode determines the platform behaviors of the component. */ "mode"?: "ios" | "md"; + /** + * The name of the element, used when submitting an HTML form. + */ + "name"?: string; /** * Emitted when the input group loses focus. */ @@ -10230,6 +10240,10 @@ declare namespace LocalJSX { * The fill for the item. If `"solid"` the item will have a background. If `"outline"` the item will be transparent with a border. Only available when the theme is `"md"`. */ "fill"?: 'outline' | 'solid'; + /** + * The `id` of a `` element to associate this element with. + */ + "form"?: string; /** * Text that is placed under the textarea and displayed when no error is detected. */ @@ -10593,209 +10607,1004 @@ declare namespace LocalJSX { */ "titlePlacement"?: 'start' | 'center' | 'end'; } + + interface IonAccordionAttributes { + "value": string; + "disabled": boolean; + "readonly": boolean; + "toggleIcon": string; + "toggleIconSlot": 'start' | 'end'; + } + interface IonAccordionGroupAttributes { + "animated": boolean; + "multiple": boolean; + "value": string | string[] | null; + "disabled": boolean; + "readonly": boolean; + "expand": 'compact' | 'inset'; + "shape": 'soft' | 'round' | 'rectangular'; + } + interface IonActionSheetAttributes { + "overlayIndex": number; + "hasController": boolean; + "keyboardClose": boolean; + "cssClass": string | string[]; + "backdropDismiss": boolean; + "header": string; + "subHeader": string; + "translucent": boolean; + "animated": boolean; + "isOpen": boolean; + "trigger": string | undefined; + } + interface IonAlertAttributes { + "overlayIndex": number; + "hasController": boolean; + "keyboardClose": boolean; + "cssClass": string | string[]; + "header": string; + "subHeader": string; + "message": string | IonicSafeString; + "backdropDismiss": boolean; + "translucent": boolean; + "animated": boolean; + "isOpen": boolean; + "trigger": string | undefined; + } + interface IonAvatarAttributes { + "size": 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'; + "shape": 'soft' | 'round' | 'rectangular'; + "disabled": boolean; + } + interface IonBackButtonAttributes { + "color": Color; + "defaultHref": string; + "disabled": boolean; + "icon": string | null; + "text": string | null; + "type": 'submit' | 'reset' | 'button'; + } + interface IonBackdropAttributes { + "visible": boolean; + "tappable": boolean; + "stopPropagation": boolean; + } + interface IonBadgeAttributes { + "color": Color; + "hue": 'bold' | 'subtle'; + "shape": 'soft' | 'round | rectangular'; + "size": 'small' | 'medium' | 'large'; + "vertical": 'top' | 'bottom'; + } + interface IonBreadcrumbAttributes { + "collapsed": boolean; + "last": boolean; + "showCollapsedIndicator": boolean; + "color": Color; + "active": boolean; + "disabled": boolean; + "download": string | undefined; + "href": string | undefined; + "rel": string | undefined; + "separator": boolean | undefined; + "target": string | undefined; + "routerDirection": RouterDirection; + } + interface IonBreadcrumbsAttributes { + "color": Color; + "maxItems": number; + "itemsBeforeCollapse": number; + "itemsAfterCollapse": number; + } + interface IonButtonAttributes { + "color": Color; + "buttonType": string; + "disabled": boolean; + "expand": 'full' | 'block'; + "fill": 'clear' | 'outline' | 'solid' | 'default'; + "routerDirection": RouterDirection; + "download": string | undefined; + "href": string | undefined; + "rel": string | undefined; + "shape": 'soft' | 'round' | 'rectangular'; + "size": 'small' | 'default' | 'medium' | 'large'; + "strong": boolean; + "target": string | undefined; + "type": 'submit' | 'reset' | 'button'; + "form": string | HTMLFormElement; + } + interface IonButtonsAttributes { + "collapse": boolean; + } + interface IonCardAttributes { + "color": Color; + "button": boolean; + "type": 'submit' | 'reset' | 'button'; + "disabled": boolean; + "download": string | undefined; + "href": string | undefined; + "rel": string | undefined; + "routerDirection": RouterDirection; + "shape": 'soft' | 'round' | 'rectangular'; + "target": string | undefined; + } + interface IonCardHeaderAttributes { + "color": Color; + "translucent": boolean; + } + interface IonCardSubtitleAttributes { + "color": Color; + } + interface IonCardTitleAttributes { + "color": Color; + } + interface IonCheckboxAttributes { + "color": Color; + "name": string; + "checked": boolean; + "indeterminate": boolean; + "disabled": boolean; + "errorText": string; + "helperText": string; + "value": string; + "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; + "justify": 'start' | 'end' | 'space-between'; + "alignment": 'start' | 'center'; + "required": boolean; + "shape": 'soft' | 'rectangular'; + "size": 'small'; + } + interface IonChipAttributes { + "color": Color; + "outline": boolean; + "disabled": boolean; + "hue": 'bold' | 'subtle'; + "shape": 'soft' | 'round' | 'rectangular'; + "size": 'small' | 'large'; + } + interface IonColAttributes { + "offset": string; + "offsetXs": string; + "offsetSm": string; + "offsetMd": string; + "offsetLg": string; + "offsetXl": string; + "order": string; + "orderXs": string; + "orderSm": string; + "orderMd": string; + "orderLg": string; + "orderXl": string; + "pull": string; + "pullXs": string; + "pullSm": string; + "pullMd": string; + "pullLg": string; + "pullXl": string; + "push": string; + "pushXs": string; + "pushSm": string; + "pushMd": string; + "pushLg": string; + "pushXl": string; + "size": string; + "sizeXs": string; + "sizeSm": string; + "sizeMd": string; + "sizeLg": string; + "sizeXl": string; + } + interface IonContentAttributes { + "color": Color; + "fullscreen": boolean; + "fixedSlotPlacement": 'after' | 'before'; + "forceOverscroll": boolean; + "scrollX": boolean; + "scrollY": boolean; + "scrollEvents": boolean; + } + interface IonDatetimeAttributes { + "color": Color; + "name": string; + "disabled": boolean; + "readonly": boolean; + "showAdjacentDays": boolean; + "min": string; + "max": string; + "presentation": DatetimePresentation; + "cancelText": string; + "doneText": string; + "clearText": string; + "yearValues": string; + "monthValues": string; + "dayValues": string; + "hourValues": string; + "minuteValues": string; + "locale": string; + "firstDayOfWeek": number; + "multiple": boolean; + "value": string | string[] | null; + "showDefaultTitle": boolean; + "showDefaultButtons": boolean; + "showClearButton": boolean; + "showDefaultTimeLabel": boolean; + "hourCycle": DatetimeHourCycle; + "size": 'cover' | 'fixed'; + "preferWheel": boolean; + } + interface IonDatetimeButtonAttributes { + "color": Color; + "disabled": boolean; + "datetime": string; + } + interface IonDividerAttributes { + "spacing": 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge'; + "inset": boolean; + } + interface IonFabAttributes { + "horizontal": 'start' | 'end' | 'center'; + "vertical": 'top' | 'bottom' | 'center'; + "edge": boolean; + "activated": boolean; + } + interface IonFabButtonAttributes { + "color": Color; + "activated": boolean; + "disabled": boolean; + "download": string | undefined; + "href": string | undefined; + "rel": string | undefined; + "routerDirection": RouterDirection; + "target": string | undefined; + "show": boolean; + "translucent": boolean; + "type": 'submit' | 'reset' | 'button'; + "size": 'small'; + "closeIcon": string; + } + interface IonFabListAttributes { + "activated": boolean; + "side": 'start' | 'end' | 'top' | 'bottom'; + } + interface IonFooterAttributes { + "collapse": 'fade'; + "translucent": boolean; + } + interface IonGridAttributes { + "fixed": boolean; + } + interface IonHeaderAttributes { + "collapse": 'condense' | 'fade'; + "divider": boolean; + "translucent": boolean; + } + interface IonImgAttributes { + "alt": string; + "src": string; + } + interface IonInfiniteScrollAttributes { + "threshold": string; + "disabled": boolean; + "position": 'top' | 'bottom'; + "preserveRerenderScrollPosition": boolean; + } + interface IonInfiniteScrollContentAttributes { + "loadingSpinner": SpinnerTypes | null; + "loadingText": string | IonicSafeString; + } + interface IonInputAttributes { + "color": Color; + "autocapitalize": string; + "autocomplete": AutocompleteTypes; + "autocorrect": 'on' | 'off'; + "autofocus": boolean; + "clearInput": boolean; + "clearInputIcon": string; + "clearOnEdit": boolean; + "counter": boolean; + "debounce": number; + "disabled": boolean; + "enterkeyhint": 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'; + "errorText": string; + "fill": 'outline' | 'solid'; + "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; + "helperText": string; + "label": string; + "labelPlacement": 'start' | 'end' | 'floating' | 'stacked' | 'fixed'; + "max": string; + "maxlength": number; + "min": string; + "minlength": number; + "multiple": boolean; + "name": string; + "pattern": string; + "placeholder": string; + "readonly": boolean; + "required": boolean; + "shape": 'soft' | 'round' | 'rectangular'; + "spellcheck": boolean; + "step": string; + "size": 'medium' | 'large' | 'xlarge'; + "type": TextFieldTypes; + "value": string; + } + interface IonInputOtpAttributes { + "autocapitalize": string; + "color": Color; + "disabled": boolean; + "fill": 'outline' | 'solid'; + "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; + "length": number; + "pattern": string; + "readonly": boolean; + "separators": 'all' | string | number[]; + "shape": 'round' | 'rectangular' | 'soft'; + "size": 'small' | 'medium' | 'large'; + "type": 'text' | 'number'; + "value": string; + } + interface IonInputPasswordToggleAttributes { + "color": Color; + "showIcon": string; + "hideIcon": string; + "type": TextFieldTypes; + } + interface IonItemAttributes { + "color": Color; + "button": boolean; + "detail": boolean; + "detailIcon": string; + "disabled": boolean; + "download": string | undefined; + "href": string | undefined; + "rel": string | undefined; + "lines": 'full' | 'inset' | 'none'; + "routerDirection": RouterDirection; + "target": string | undefined; + "type": 'submit' | 'reset' | 'button'; + } + interface IonItemDividerAttributes { + "color": Color; + "sticky": boolean; + } + interface IonItemOptionAttributes { + "color": Color; + "disabled": boolean; + "download": string | undefined; + "expandable": boolean; + "href": string | undefined; + "hue": 'bold' | 'subtle'; + "rel": string | undefined; + "target": string | undefined; + "type": 'submit' | 'reset' | 'button'; + "shape": 'soft' | 'round' | 'rectangular'; + } + interface IonItemOptionsAttributes { + "side": Side; + } + interface IonItemSlidingAttributes { + "disabled": boolean; + } + interface IonLabelAttributes { + "color": Color; + "position": 'fixed' | 'stacked' | 'floating'; + } + interface IonListAttributes { + "lines": 'full' | 'inset' | 'none'; + "inset": boolean; + "shape": 'soft' | 'round' | 'rectangular'; + } + interface IonListHeaderAttributes { + "color": Color; + "lines": 'full' | 'inset' | 'none'; + } + interface IonLoadingAttributes { + "overlayIndex": number; + "hasController": boolean; + "keyboardClose": boolean; + "message": string | IonicSafeString; + "cssClass": string | string[]; + "duration": number; + "backdropDismiss": boolean; + "showBackdrop": boolean; + "spinner": SpinnerTypes | null; + "translucent": boolean; + "animated": boolean; + "isOpen": boolean; + "trigger": string | undefined; + } + interface IonMenuAttributes { + "contentId": string; + "menuId": string; + "type": MenuType; + "disabled": boolean; + "side": Side; + "swipeGesture": boolean; + "maxEdgeStart": number; + } + interface IonMenuButtonAttributes { + "color": Color; + "disabled": boolean; + "menu": string; + "autoHide": boolean; + "type": 'submit' | 'reset' | 'button'; + } + interface IonMenuToggleAttributes { + "menu": string; + "autoHide": boolean; + } + interface IonModalAttributes { + "hasController": boolean; + "overlayIndex": number; + "keyboardClose": boolean; + "expandToScroll": boolean; + "initialBreakpoint": number; + "backdropBreakpoint": number; + "handle": boolean; + "handleBehavior": ModalHandleBehavior; + "component": ComponentRef; + "cssClass": string | string[]; + "backdropDismiss": boolean; + "showBackdrop": boolean; + "animated": boolean; + "isOpen": boolean; + "trigger": string | undefined; + "keepContentsMounted": boolean; + "focusTrap": boolean; + "canDismiss": boolean | ((data?: any, role?: string) => Promise); + "shape": 'soft' | 'round' | 'rectangular'; + } + interface IonNavAttributes { + "swipeGesture": boolean; + "animated": boolean; + "root": NavComponent; + } + interface IonNavLinkAttributes { + "component": NavComponent; + "routerDirection": RouterDirection; + } + interface IonNoteAttributes { + "color": Color; + } + interface IonPickerColumnAttributes { + "disabled": boolean; + "value": string; + "color": Color; + "numericInput": boolean; + } + interface IonPickerColumnOptionAttributes { + "disabled": boolean; + "value": string; + "color": Color; + } + interface IonPickerLegacyAttributes { + "overlayIndex": number; + "hasController": boolean; + "keyboardClose": boolean; + "cssClass": string | string[]; + "duration": number; + "showBackdrop": boolean; + "backdropDismiss": boolean; + "animated": boolean; + "isOpen": boolean; + "trigger": string | undefined; + } + interface IonPopoverAttributes { + "hasController": boolean; + "overlayIndex": number; + "component": ComponentRef; + "keyboardClose": boolean; + "cssClass": string | string[]; + "backdropDismiss": boolean; + "event": string; + "showBackdrop": boolean; + "translucent": boolean; + "animated": boolean; + "triggerAction": TriggerAction; + "trigger": string | undefined; + "size": PopoverSize; + "dismissOnSelect": boolean; + "reference": PositionReference; + "side": PositionSide; + "alignment": PositionAlign; + "arrow": boolean; + "isOpen": boolean; + "keyboardEvents": boolean; + "focusTrap": boolean; + "keepContentsMounted": boolean; + } + interface IonProgressBarAttributes { + "type": 'determinate' | 'indeterminate'; + "reversed": boolean; + "value": number; + "buffer": number; + "color": Color; + "shape": 'round' | 'rectangular'; + } + interface IonRadioAttributes { + "color": Color; + "name": string; + "disabled": boolean; + "value": string; + "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; + "justify": 'start' | 'end' | 'space-between'; + "alignment": 'start' | 'center'; + } + interface IonRadioGroupAttributes { + "allowEmptySelection": boolean; + "compareWith": string | RadioGroupCompareFn | null; + "name": string; + "value": string; + "helperText": string; + "errorText": string; + } + interface IonRangeAttributes { + "color": Color; + "debounce": number; + "name": string; + "label": string; + "dualKnobs": boolean; + "min": number; + "max": number; + "pin": boolean; + "snaps": boolean; + "step": number; + "ticks": boolean; + "activeBarStart": number; + "disabled": boolean; + "value": RangeValue; + "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; + } + interface IonRefresherAttributes { + "pullMin": number; + "pullMax": number; + "closeDuration": string; + "snapbackDuration": string; + "pullFactor": number; + "disabled": boolean; + } + interface IonRefresherContentAttributes { + "pullingIcon": SpinnerTypes | string | null; + "pullingText": string | IonicSafeString; + "refreshingSpinner": SpinnerTypes | null; + "refreshingText": string | IonicSafeString; + } + interface IonReorderGroupAttributes { + "disabled": boolean; + } + interface IonRippleEffectAttributes { + "type": 'bounded' | 'unbounded'; + } + interface IonRouteAttributes { + "url": string; + "component": string; + } + interface IonRouteRedirectAttributes { + "from": string; + "to": string | undefined | null; + } + interface IonRouterAttributes { + "root": string; + "useHash": boolean; + } + interface IonRouterLinkAttributes { + "color": Color; + "href": string | undefined; + "rel": string | undefined; + "routerDirection": RouterDirection; + "target": string | undefined; + } + interface IonRouterOutletAttributes { + "mode": "ios" | "md"; + "animated": boolean; + } + interface IonSearchbarAttributes { + "color": Color; + "animated": boolean; + "autocapitalize": string; + "autocomplete": AutocompleteTypes; + "autocorrect": 'on' | 'off'; + "cancelButtonIcon": string; + "cancelButtonText": string; + "clearIcon": string; + "debounce": number; + "disabled": boolean; + "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; + "enterkeyhint": 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'; + "maxlength": number; + "minlength": number; + "name": string; + "placeholder": string; + "searchIcon": string; + "showCancelButton": 'never' | 'focus' | 'always'; + "showClearButton": 'never' | 'focus' | 'always'; + "spellcheck": boolean; + "type": 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url'; + "value": string | null; + "shape": 'soft' | 'round' | 'rectangular'; + "size": 'small' | 'medium' | 'large'; + } + interface IonSegmentAttributes { + "color": Color; + "disabled": boolean; + "scrollable": boolean; + "swipeGesture": boolean; + "value": string; + "selectOnFocus": boolean; + } + interface IonSegmentButtonAttributes { + "contentId": string; + "disabled": boolean; + "layout": SegmentButtonLayout; + "type": 'submit' | 'reset' | 'button'; + "value": string; + } + interface IonSegmentViewAttributes { + "disabled": boolean; + "swipeGesture": boolean; + } + interface IonSelectAttributes { + "cancelText": string; + "color": Color; + "compareWith": string | SelectCompareFn | null; + "disabled": boolean; + "fill": 'outline' | 'solid'; + "errorText": string; + "helperText": string; + "interface": SelectInterface; + "interfaceOptions": string; + "justify": 'start' | 'end' | 'space-between'; + "label": string; + "labelPlacement": 'start' | 'end' | 'floating' | 'stacked' | 'fixed'; + "multiple": boolean; + "name": string; + "okText": string; + "placeholder": string; + "selectedText": string | null; + "toggleIcon": string; + "expandedIcon": string; + "required": boolean; + "shape": 'soft' | 'round' | 'rectangular'; + "size": 'small' | 'medium' | 'large'; + "value": string; + } + interface IonSelectModalAttributes { + "header": string; + "cancelText": string; + "multiple": boolean; + } + interface IonSelectOptionAttributes { + "disabled": boolean; + "value": string; + "description": string; + } + interface IonSelectPopoverAttributes { + "header": string; + "subHeader": string; + "message": string; + "multiple": boolean; + } + interface IonSkeletonTextAttributes { + "animated": boolean; + } + interface IonSpinnerAttributes { + "color": Color; + "duration": number; + "name": SpinnerTypes; + "paused": boolean; + "size": 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'; + } + interface IonSplitPaneAttributes { + "contentId": string; + "disabled": boolean; + "when": string; + } + interface IonTabAttributes { + "active": boolean; + "tab": string; + "component": ComponentRef; + } + interface IonTabBarAttributes { + "color": Color; + "selectedTab": string; + "translucent": boolean; + "expand": 'compact' | 'full'; + "shape": 'soft' | 'round' | 'rectangular'; + } + interface IonTabButtonAttributes { + "disabled": boolean; + "download": string | undefined; + "href": string | undefined; + "rel": string | undefined; + "layout": TabButtonLayout; + "selected": boolean; + "shape": 'soft' | 'round' | 'rectangular'; + "tab": string; + "target": string | undefined; + } + interface IonTabsAttributes { + "useRouter": boolean; + } + interface IonTextAttributes { + "color": Color; + } + interface IonTextareaAttributes { + "color": Color; + "autocapitalize": string; + "autofocus": boolean; + "clearOnEdit": boolean; + "debounce": number; + "disabled": boolean; + "fill": 'outline' | 'solid'; + "inputmode": 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'; + "enterkeyhint": 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'; + "maxlength": number; + "minlength": number; + "name": string; + "placeholder": string; + "readonly": boolean; + "required": boolean; + "spellcheck": boolean; + "cols": number; + "rows": number; + "wrap": 'hard' | 'soft' | 'off'; + "autoGrow": boolean; + "value": string | null; + "counter": boolean; + "errorText": string; + "helperText": string; + "label": string; + "labelPlacement": 'start' | 'end' | 'floating' | 'stacked' | 'fixed'; + "shape": 'soft' | 'round' | 'rectangular'; + "size": 'small' | 'medium' | 'large'; + } + interface IonTitleAttributes { + "color": Color; + "size": 'large' | 'small'; + } + interface IonToastAttributes { + "overlayIndex": number; + "hasController": boolean; + "color": Color; + "cssClass": string | string[]; + "duration": number; + "header": string; + "hue": 'bold' | 'subtle'; + "layout": ToastLayout; + "message": string | IonicSafeString; + "keyboardClose": boolean; + "position": ToastPosition; + "positionAnchor": HTMLElement | string; + "shape": 'soft' | 'round' | 'rectangular'; + "translucent": boolean; + "animated": boolean; + "icon": string; + "swipeGesture": ToastSwipeGestureDirection; + "isOpen": boolean; + "trigger": string | undefined; + } + interface IonToggleAttributes { + "color": Color; + "name": string; + "checked": boolean; + "disabled": boolean; + "errorText": string; + "helperText": string; + "value": string | null; + "enableOnOffLabels": boolean | undefined; + "labelPlacement": 'start' | 'end' | 'fixed' | 'stacked'; + "justify": 'start' | 'end' | 'space-between'; + "alignment": 'start' | 'center'; + "required": boolean; + } + interface IonToolbarAttributes { + "color": Color; + "titlePlacement": 'start' | 'center' | 'end'; + } + interface IntrinsicElements { - "ion-accordion": IonAccordion; - "ion-accordion-group": IonAccordionGroup; - "ion-action-sheet": IonActionSheet; - "ion-alert": IonAlert; + "ion-accordion": Omit & { [K in keyof IonAccordion & keyof IonAccordionAttributes]?: IonAccordion[K] } & { [K in keyof IonAccordion & keyof IonAccordionAttributes as `attr:${K}`]?: IonAccordionAttributes[K] } & { [K in keyof IonAccordion & keyof IonAccordionAttributes as `prop:${K}`]?: IonAccordion[K] }; + "ion-accordion-group": Omit & { [K in keyof IonAccordionGroup & keyof IonAccordionGroupAttributes]?: IonAccordionGroup[K] } & { [K in keyof IonAccordionGroup & keyof IonAccordionGroupAttributes as `attr:${K}`]?: IonAccordionGroupAttributes[K] } & { [K in keyof IonAccordionGroup & keyof IonAccordionGroupAttributes as `prop:${K}`]?: IonAccordionGroup[K] }; + "ion-action-sheet": Omit & { [K in keyof IonActionSheet & keyof IonActionSheetAttributes]?: IonActionSheet[K] } & { [K in keyof IonActionSheet & keyof IonActionSheetAttributes as `attr:${K}`]?: IonActionSheetAttributes[K] } & { [K in keyof IonActionSheet & keyof IonActionSheetAttributes as `prop:${K}`]?: IonActionSheet[K] } & OneOf<"overlayIndex", IonActionSheet["overlayIndex"], IonActionSheetAttributes["overlayIndex"]>; + "ion-alert": Omit & { [K in keyof IonAlert & keyof IonAlertAttributes]?: IonAlert[K] } & { [K in keyof IonAlert & keyof IonAlertAttributes as `attr:${K}`]?: IonAlertAttributes[K] } & { [K in keyof IonAlert & keyof IonAlertAttributes as `prop:${K}`]?: IonAlert[K] } & OneOf<"overlayIndex", IonAlert["overlayIndex"], IonAlertAttributes["overlayIndex"]>; "ion-app": IonApp; - "ion-avatar": IonAvatar; - "ion-back-button": IonBackButton; - "ion-backdrop": IonBackdrop; - "ion-badge": IonBadge; - "ion-breadcrumb": IonBreadcrumb; - "ion-breadcrumbs": IonBreadcrumbs; - "ion-button": IonButton; - "ion-buttons": IonButtons; - "ion-card": IonCard; + "ion-avatar": Omit & { [K in keyof IonAvatar & keyof IonAvatarAttributes]?: IonAvatar[K] } & { [K in keyof IonAvatar & keyof IonAvatarAttributes as `attr:${K}`]?: IonAvatarAttributes[K] } & { [K in keyof IonAvatar & keyof IonAvatarAttributes as `prop:${K}`]?: IonAvatar[K] }; + "ion-back-button": Omit & { [K in keyof IonBackButton & keyof IonBackButtonAttributes]?: IonBackButton[K] } & { [K in keyof IonBackButton & keyof IonBackButtonAttributes as `attr:${K}`]?: IonBackButtonAttributes[K] } & { [K in keyof IonBackButton & keyof IonBackButtonAttributes as `prop:${K}`]?: IonBackButton[K] }; + "ion-backdrop": Omit & { [K in keyof IonBackdrop & keyof IonBackdropAttributes]?: IonBackdrop[K] } & { [K in keyof IonBackdrop & keyof IonBackdropAttributes as `attr:${K}`]?: IonBackdropAttributes[K] } & { [K in keyof IonBackdrop & keyof IonBackdropAttributes as `prop:${K}`]?: IonBackdrop[K] }; + "ion-badge": Omit & { [K in keyof IonBadge & keyof IonBadgeAttributes]?: IonBadge[K] } & { [K in keyof IonBadge & keyof IonBadgeAttributes as `attr:${K}`]?: IonBadgeAttributes[K] } & { [K in keyof IonBadge & keyof IonBadgeAttributes as `prop:${K}`]?: IonBadge[K] }; + "ion-breadcrumb": Omit & { [K in keyof IonBreadcrumb & keyof IonBreadcrumbAttributes]?: IonBreadcrumb[K] } & { [K in keyof IonBreadcrumb & keyof IonBreadcrumbAttributes as `attr:${K}`]?: IonBreadcrumbAttributes[K] } & { [K in keyof IonBreadcrumb & keyof IonBreadcrumbAttributes as `prop:${K}`]?: IonBreadcrumb[K] } & OneOf<"last", IonBreadcrumb["last"], IonBreadcrumbAttributes["last"]> & OneOf<"showCollapsedIndicator", IonBreadcrumb["showCollapsedIndicator"], IonBreadcrumbAttributes["showCollapsedIndicator"]>; + "ion-breadcrumbs": Omit & { [K in keyof IonBreadcrumbs & keyof IonBreadcrumbsAttributes]?: IonBreadcrumbs[K] } & { [K in keyof IonBreadcrumbs & keyof IonBreadcrumbsAttributes as `attr:${K}`]?: IonBreadcrumbsAttributes[K] } & { [K in keyof IonBreadcrumbs & keyof IonBreadcrumbsAttributes as `prop:${K}`]?: IonBreadcrumbs[K] }; + "ion-button": Omit & { [K in keyof IonButton & keyof IonButtonAttributes]?: IonButton[K] } & { [K in keyof IonButton & keyof IonButtonAttributes as `attr:${K}`]?: IonButtonAttributes[K] } & { [K in keyof IonButton & keyof IonButtonAttributes as `prop:${K}`]?: IonButton[K] }; + "ion-buttons": Omit & { [K in keyof IonButtons & keyof IonButtonsAttributes]?: IonButtons[K] } & { [K in keyof IonButtons & keyof IonButtonsAttributes as `attr:${K}`]?: IonButtonsAttributes[K] } & { [K in keyof IonButtons & keyof IonButtonsAttributes as `prop:${K}`]?: IonButtons[K] }; + "ion-card": Omit & { [K in keyof IonCard & keyof IonCardAttributes]?: IonCard[K] } & { [K in keyof IonCard & keyof IonCardAttributes as `attr:${K}`]?: IonCardAttributes[K] } & { [K in keyof IonCard & keyof IonCardAttributes as `prop:${K}`]?: IonCard[K] }; "ion-card-content": IonCardContent; - "ion-card-header": IonCardHeader; - "ion-card-subtitle": IonCardSubtitle; - "ion-card-title": IonCardTitle; - "ion-checkbox": IonCheckbox; - "ion-chip": IonChip; - "ion-col": IonCol; - "ion-content": IonContent; - "ion-datetime": IonDatetime; - "ion-datetime-button": IonDatetimeButton; - "ion-divider": IonDivider; - "ion-fab": IonFab; - "ion-fab-button": IonFabButton; - "ion-fab-list": IonFabList; - "ion-footer": IonFooter; - "ion-grid": IonGrid; - "ion-header": IonHeader; - "ion-img": IonImg; - "ion-infinite-scroll": IonInfiniteScroll; - "ion-infinite-scroll-content": IonInfiniteScrollContent; - "ion-input": IonInput; - "ion-input-otp": IonInputOtp; - "ion-input-password-toggle": IonInputPasswordToggle; - "ion-item": IonItem; - "ion-item-divider": IonItemDivider; + "ion-card-header": Omit & { [K in keyof IonCardHeader & keyof IonCardHeaderAttributes]?: IonCardHeader[K] } & { [K in keyof IonCardHeader & keyof IonCardHeaderAttributes as `attr:${K}`]?: IonCardHeaderAttributes[K] } & { [K in keyof IonCardHeader & keyof IonCardHeaderAttributes as `prop:${K}`]?: IonCardHeader[K] }; + "ion-card-subtitle": Omit & { [K in keyof IonCardSubtitle & keyof IonCardSubtitleAttributes]?: IonCardSubtitle[K] } & { [K in keyof IonCardSubtitle & keyof IonCardSubtitleAttributes as `attr:${K}`]?: IonCardSubtitleAttributes[K] } & { [K in keyof IonCardSubtitle & keyof IonCardSubtitleAttributes as `prop:${K}`]?: IonCardSubtitle[K] }; + "ion-card-title": Omit & { [K in keyof IonCardTitle & keyof IonCardTitleAttributes]?: IonCardTitle[K] } & { [K in keyof IonCardTitle & keyof IonCardTitleAttributes as `attr:${K}`]?: IonCardTitleAttributes[K] } & { [K in keyof IonCardTitle & keyof IonCardTitleAttributes as `prop:${K}`]?: IonCardTitle[K] }; + "ion-checkbox": Omit & { [K in keyof IonCheckbox & keyof IonCheckboxAttributes]?: IonCheckbox[K] } & { [K in keyof IonCheckbox & keyof IonCheckboxAttributes as `attr:${K}`]?: IonCheckboxAttributes[K] } & { [K in keyof IonCheckbox & keyof IonCheckboxAttributes as `prop:${K}`]?: IonCheckbox[K] }; + "ion-chip": Omit & { [K in keyof IonChip & keyof IonChipAttributes]?: IonChip[K] } & { [K in keyof IonChip & keyof IonChipAttributes as `attr:${K}`]?: IonChipAttributes[K] } & { [K in keyof IonChip & keyof IonChipAttributes as `prop:${K}`]?: IonChip[K] }; + "ion-col": Omit & { [K in keyof IonCol & keyof IonColAttributes]?: IonCol[K] } & { [K in keyof IonCol & keyof IonColAttributes as `attr:${K}`]?: IonColAttributes[K] } & { [K in keyof IonCol & keyof IonColAttributes as `prop:${K}`]?: IonCol[K] }; + "ion-content": Omit & { [K in keyof IonContent & keyof IonContentAttributes]?: IonContent[K] } & { [K in keyof IonContent & keyof IonContentAttributes as `attr:${K}`]?: IonContentAttributes[K] } & { [K in keyof IonContent & keyof IonContentAttributes as `prop:${K}`]?: IonContent[K] }; + "ion-datetime": Omit & { [K in keyof IonDatetime & keyof IonDatetimeAttributes]?: IonDatetime[K] } & { [K in keyof IonDatetime & keyof IonDatetimeAttributes as `attr:${K}`]?: IonDatetimeAttributes[K] } & { [K in keyof IonDatetime & keyof IonDatetimeAttributes as `prop:${K}`]?: IonDatetime[K] }; + "ion-datetime-button": Omit & { [K in keyof IonDatetimeButton & keyof IonDatetimeButtonAttributes]?: IonDatetimeButton[K] } & { [K in keyof IonDatetimeButton & keyof IonDatetimeButtonAttributes as `attr:${K}`]?: IonDatetimeButtonAttributes[K] } & { [K in keyof IonDatetimeButton & keyof IonDatetimeButtonAttributes as `prop:${K}`]?: IonDatetimeButton[K] }; + "ion-divider": Omit & { [K in keyof IonDivider & keyof IonDividerAttributes]?: IonDivider[K] } & { [K in keyof IonDivider & keyof IonDividerAttributes as `attr:${K}`]?: IonDividerAttributes[K] } & { [K in keyof IonDivider & keyof IonDividerAttributes as `prop:${K}`]?: IonDivider[K] }; + "ion-fab": Omit & { [K in keyof IonFab & keyof IonFabAttributes]?: IonFab[K] } & { [K in keyof IonFab & keyof IonFabAttributes as `attr:${K}`]?: IonFabAttributes[K] } & { [K in keyof IonFab & keyof IonFabAttributes as `prop:${K}`]?: IonFab[K] }; + "ion-fab-button": Omit & { [K in keyof IonFabButton & keyof IonFabButtonAttributes]?: IonFabButton[K] } & { [K in keyof IonFabButton & keyof IonFabButtonAttributes as `attr:${K}`]?: IonFabButtonAttributes[K] } & { [K in keyof IonFabButton & keyof IonFabButtonAttributes as `prop:${K}`]?: IonFabButton[K] }; + "ion-fab-list": Omit & { [K in keyof IonFabList & keyof IonFabListAttributes]?: IonFabList[K] } & { [K in keyof IonFabList & keyof IonFabListAttributes as `attr:${K}`]?: IonFabListAttributes[K] } & { [K in keyof IonFabList & keyof IonFabListAttributes as `prop:${K}`]?: IonFabList[K] }; + "ion-footer": Omit & { [K in keyof IonFooter & keyof IonFooterAttributes]?: IonFooter[K] } & { [K in keyof IonFooter & keyof IonFooterAttributes as `attr:${K}`]?: IonFooterAttributes[K] } & { [K in keyof IonFooter & keyof IonFooterAttributes as `prop:${K}`]?: IonFooter[K] }; + "ion-grid": Omit & { [K in keyof IonGrid & keyof IonGridAttributes]?: IonGrid[K] } & { [K in keyof IonGrid & keyof IonGridAttributes as `attr:${K}`]?: IonGridAttributes[K] } & { [K in keyof IonGrid & keyof IonGridAttributes as `prop:${K}`]?: IonGrid[K] }; + "ion-header": Omit & { [K in keyof IonHeader & keyof IonHeaderAttributes]?: IonHeader[K] } & { [K in keyof IonHeader & keyof IonHeaderAttributes as `attr:${K}`]?: IonHeaderAttributes[K] } & { [K in keyof IonHeader & keyof IonHeaderAttributes as `prop:${K}`]?: IonHeader[K] }; + "ion-img": Omit & { [K in keyof IonImg & keyof IonImgAttributes]?: IonImg[K] } & { [K in keyof IonImg & keyof IonImgAttributes as `attr:${K}`]?: IonImgAttributes[K] } & { [K in keyof IonImg & keyof IonImgAttributes as `prop:${K}`]?: IonImg[K] }; + "ion-infinite-scroll": Omit & { [K in keyof IonInfiniteScroll & keyof IonInfiniteScrollAttributes]?: IonInfiniteScroll[K] } & { [K in keyof IonInfiniteScroll & keyof IonInfiniteScrollAttributes as `attr:${K}`]?: IonInfiniteScrollAttributes[K] } & { [K in keyof IonInfiniteScroll & keyof IonInfiniteScrollAttributes as `prop:${K}`]?: IonInfiniteScroll[K] }; + "ion-infinite-scroll-content": Omit & { [K in keyof IonInfiniteScrollContent & keyof IonInfiniteScrollContentAttributes]?: IonInfiniteScrollContent[K] } & { [K in keyof IonInfiniteScrollContent & keyof IonInfiniteScrollContentAttributes as `attr:${K}`]?: IonInfiniteScrollContentAttributes[K] } & { [K in keyof IonInfiniteScrollContent & keyof IonInfiniteScrollContentAttributes as `prop:${K}`]?: IonInfiniteScrollContent[K] }; + "ion-input": Omit & { [K in keyof IonInput & keyof IonInputAttributes]?: IonInput[K] } & { [K in keyof IonInput & keyof IonInputAttributes as `attr:${K}`]?: IonInputAttributes[K] } & { [K in keyof IonInput & keyof IonInputAttributes as `prop:${K}`]?: IonInput[K] }; + "ion-input-otp": Omit & { [K in keyof IonInputOtp & keyof IonInputOtpAttributes]?: IonInputOtp[K] } & { [K in keyof IonInputOtp & keyof IonInputOtpAttributes as `attr:${K}`]?: IonInputOtpAttributes[K] } & { [K in keyof IonInputOtp & keyof IonInputOtpAttributes as `prop:${K}`]?: IonInputOtp[K] }; + "ion-input-password-toggle": Omit & { [K in keyof IonInputPasswordToggle & keyof IonInputPasswordToggleAttributes]?: IonInputPasswordToggle[K] } & { [K in keyof IonInputPasswordToggle & keyof IonInputPasswordToggleAttributes as `attr:${K}`]?: IonInputPasswordToggleAttributes[K] } & { [K in keyof IonInputPasswordToggle & keyof IonInputPasswordToggleAttributes as `prop:${K}`]?: IonInputPasswordToggle[K] }; + "ion-item": Omit & { [K in keyof IonItem & keyof IonItemAttributes]?: IonItem[K] } & { [K in keyof IonItem & keyof IonItemAttributes as `attr:${K}`]?: IonItemAttributes[K] } & { [K in keyof IonItem & keyof IonItemAttributes as `prop:${K}`]?: IonItem[K] }; + "ion-item-divider": Omit & { [K in keyof IonItemDivider & keyof IonItemDividerAttributes]?: IonItemDivider[K] } & { [K in keyof IonItemDivider & keyof IonItemDividerAttributes as `attr:${K}`]?: IonItemDividerAttributes[K] } & { [K in keyof IonItemDivider & keyof IonItemDividerAttributes as `prop:${K}`]?: IonItemDivider[K] }; "ion-item-group": IonItemGroup; - "ion-item-option": IonItemOption; - "ion-item-options": IonItemOptions; - "ion-item-sliding": IonItemSliding; - "ion-label": IonLabel; - "ion-list": IonList; - "ion-list-header": IonListHeader; - "ion-loading": IonLoading; - "ion-menu": IonMenu; - "ion-menu-button": IonMenuButton; - "ion-menu-toggle": IonMenuToggle; - "ion-modal": IonModal; - "ion-nav": IonNav; - "ion-nav-link": IonNavLink; - "ion-note": IonNote; + "ion-item-option": Omit & { [K in keyof IonItemOption & keyof IonItemOptionAttributes]?: IonItemOption[K] } & { [K in keyof IonItemOption & keyof IonItemOptionAttributes as `attr:${K}`]?: IonItemOptionAttributes[K] } & { [K in keyof IonItemOption & keyof IonItemOptionAttributes as `prop:${K}`]?: IonItemOption[K] }; + "ion-item-options": Omit & { [K in keyof IonItemOptions & keyof IonItemOptionsAttributes]?: IonItemOptions[K] } & { [K in keyof IonItemOptions & keyof IonItemOptionsAttributes as `attr:${K}`]?: IonItemOptionsAttributes[K] } & { [K in keyof IonItemOptions & keyof IonItemOptionsAttributes as `prop:${K}`]?: IonItemOptions[K] }; + "ion-item-sliding": Omit & { [K in keyof IonItemSliding & keyof IonItemSlidingAttributes]?: IonItemSliding[K] } & { [K in keyof IonItemSliding & keyof IonItemSlidingAttributes as `attr:${K}`]?: IonItemSlidingAttributes[K] } & { [K in keyof IonItemSliding & keyof IonItemSlidingAttributes as `prop:${K}`]?: IonItemSliding[K] }; + "ion-label": Omit & { [K in keyof IonLabel & keyof IonLabelAttributes]?: IonLabel[K] } & { [K in keyof IonLabel & keyof IonLabelAttributes as `attr:${K}`]?: IonLabelAttributes[K] } & { [K in keyof IonLabel & keyof IonLabelAttributes as `prop:${K}`]?: IonLabel[K] }; + "ion-list": Omit & { [K in keyof IonList & keyof IonListAttributes]?: IonList[K] } & { [K in keyof IonList & keyof IonListAttributes as `attr:${K}`]?: IonListAttributes[K] } & { [K in keyof IonList & keyof IonListAttributes as `prop:${K}`]?: IonList[K] }; + "ion-list-header": Omit & { [K in keyof IonListHeader & keyof IonListHeaderAttributes]?: IonListHeader[K] } & { [K in keyof IonListHeader & keyof IonListHeaderAttributes as `attr:${K}`]?: IonListHeaderAttributes[K] } & { [K in keyof IonListHeader & keyof IonListHeaderAttributes as `prop:${K}`]?: IonListHeader[K] }; + "ion-loading": Omit & { [K in keyof IonLoading & keyof IonLoadingAttributes]?: IonLoading[K] } & { [K in keyof IonLoading & keyof IonLoadingAttributes as `attr:${K}`]?: IonLoadingAttributes[K] } & { [K in keyof IonLoading & keyof IonLoadingAttributes as `prop:${K}`]?: IonLoading[K] } & OneOf<"overlayIndex", IonLoading["overlayIndex"], IonLoadingAttributes["overlayIndex"]>; + "ion-menu": Omit & { [K in keyof IonMenu & keyof IonMenuAttributes]?: IonMenu[K] } & { [K in keyof IonMenu & keyof IonMenuAttributes as `attr:${K}`]?: IonMenuAttributes[K] } & { [K in keyof IonMenu & keyof IonMenuAttributes as `prop:${K}`]?: IonMenu[K] }; + "ion-menu-button": Omit & { [K in keyof IonMenuButton & keyof IonMenuButtonAttributes]?: IonMenuButton[K] } & { [K in keyof IonMenuButton & keyof IonMenuButtonAttributes as `attr:${K}`]?: IonMenuButtonAttributes[K] } & { [K in keyof IonMenuButton & keyof IonMenuButtonAttributes as `prop:${K}`]?: IonMenuButton[K] }; + "ion-menu-toggle": Omit & { [K in keyof IonMenuToggle & keyof IonMenuToggleAttributes]?: IonMenuToggle[K] } & { [K in keyof IonMenuToggle & keyof IonMenuToggleAttributes as `attr:${K}`]?: IonMenuToggleAttributes[K] } & { [K in keyof IonMenuToggle & keyof IonMenuToggleAttributes as `prop:${K}`]?: IonMenuToggle[K] }; + "ion-modal": Omit & { [K in keyof IonModal & keyof IonModalAttributes]?: IonModal[K] } & { [K in keyof IonModal & keyof IonModalAttributes as `attr:${K}`]?: IonModalAttributes[K] } & { [K in keyof IonModal & keyof IonModalAttributes as `prop:${K}`]?: IonModal[K] } & OneOf<"overlayIndex", IonModal["overlayIndex"], IonModalAttributes["overlayIndex"]>; + "ion-nav": Omit & { [K in keyof IonNav & keyof IonNavAttributes]?: IonNav[K] } & { [K in keyof IonNav & keyof IonNavAttributes as `attr:${K}`]?: IonNavAttributes[K] } & { [K in keyof IonNav & keyof IonNavAttributes as `prop:${K}`]?: IonNav[K] }; + "ion-nav-link": Omit & { [K in keyof IonNavLink & keyof IonNavLinkAttributes]?: IonNavLink[K] } & { [K in keyof IonNavLink & keyof IonNavLinkAttributes as `attr:${K}`]?: IonNavLinkAttributes[K] } & { [K in keyof IonNavLink & keyof IonNavLinkAttributes as `prop:${K}`]?: IonNavLink[K] }; + "ion-note": Omit & { [K in keyof IonNote & keyof IonNoteAttributes]?: IonNote[K] } & { [K in keyof IonNote & keyof IonNoteAttributes as `attr:${K}`]?: IonNoteAttributes[K] } & { [K in keyof IonNote & keyof IonNoteAttributes as `prop:${K}`]?: IonNote[K] }; "ion-picker": IonPicker; - "ion-picker-column": IonPickerColumn; - "ion-picker-column-option": IonPickerColumnOption; - "ion-picker-legacy": IonPickerLegacy; + "ion-picker-column": Omit & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes]?: IonPickerColumn[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `attr:${K}`]?: IonPickerColumnAttributes[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `prop:${K}`]?: IonPickerColumn[K] }; + "ion-picker-column-option": Omit & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes]?: IonPickerColumnOption[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `attr:${K}`]?: IonPickerColumnOptionAttributes[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `prop:${K}`]?: IonPickerColumnOption[K] }; + "ion-picker-legacy": Omit & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes]?: IonPickerLegacy[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `attr:${K}`]?: IonPickerLegacyAttributes[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `prop:${K}`]?: IonPickerLegacy[K] } & OneOf<"overlayIndex", IonPickerLegacy["overlayIndex"], IonPickerLegacyAttributes["overlayIndex"]>; "ion-picker-legacy-column": IonPickerLegacyColumn; - "ion-popover": IonPopover; - "ion-progress-bar": IonProgressBar; - "ion-radio": IonRadio; - "ion-radio-group": IonRadioGroup; - "ion-range": IonRange; - "ion-refresher": IonRefresher; - "ion-refresher-content": IonRefresherContent; + "ion-popover": Omit & { [K in keyof IonPopover & keyof IonPopoverAttributes]?: IonPopover[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `attr:${K}`]?: IonPopoverAttributes[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `prop:${K}`]?: IonPopover[K] } & OneOf<"overlayIndex", IonPopover["overlayIndex"], IonPopoverAttributes["overlayIndex"]>; + "ion-progress-bar": Omit & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes]?: IonProgressBar[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `attr:${K}`]?: IonProgressBarAttributes[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `prop:${K}`]?: IonProgressBar[K] }; + "ion-radio": Omit & { [K in keyof IonRadio & keyof IonRadioAttributes]?: IonRadio[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `attr:${K}`]?: IonRadioAttributes[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `prop:${K}`]?: IonRadio[K] }; + "ion-radio-group": Omit & { [K in keyof IonRadioGroup & keyof IonRadioGroupAttributes]?: IonRadioGroup[K] } & { [K in keyof IonRadioGroup & keyof IonRadioGroupAttributes as `attr:${K}`]?: IonRadioGroupAttributes[K] } & { [K in keyof IonRadioGroup & keyof IonRadioGroupAttributes as `prop:${K}`]?: IonRadioGroup[K] }; + "ion-range": Omit & { [K in keyof IonRange & keyof IonRangeAttributes]?: IonRange[K] } & { [K in keyof IonRange & keyof IonRangeAttributes as `attr:${K}`]?: IonRangeAttributes[K] } & { [K in keyof IonRange & keyof IonRangeAttributes as `prop:${K}`]?: IonRange[K] }; + "ion-refresher": Omit & { [K in keyof IonRefresher & keyof IonRefresherAttributes]?: IonRefresher[K] } & { [K in keyof IonRefresher & keyof IonRefresherAttributes as `attr:${K}`]?: IonRefresherAttributes[K] } & { [K in keyof IonRefresher & keyof IonRefresherAttributes as `prop:${K}`]?: IonRefresher[K] }; + "ion-refresher-content": Omit & { [K in keyof IonRefresherContent & keyof IonRefresherContentAttributes]?: IonRefresherContent[K] } & { [K in keyof IonRefresherContent & keyof IonRefresherContentAttributes as `attr:${K}`]?: IonRefresherContentAttributes[K] } & { [K in keyof IonRefresherContent & keyof IonRefresherContentAttributes as `prop:${K}`]?: IonRefresherContent[K] }; "ion-reorder": IonReorder; - "ion-reorder-group": IonReorderGroup; - "ion-ripple-effect": IonRippleEffect; - "ion-route": IonRoute; - "ion-route-redirect": IonRouteRedirect; - "ion-router": IonRouter; - "ion-router-link": IonRouterLink; - "ion-router-outlet": IonRouterOutlet; + "ion-reorder-group": Omit & { [K in keyof IonReorderGroup & keyof IonReorderGroupAttributes]?: IonReorderGroup[K] } & { [K in keyof IonReorderGroup & keyof IonReorderGroupAttributes as `attr:${K}`]?: IonReorderGroupAttributes[K] } & { [K in keyof IonReorderGroup & keyof IonReorderGroupAttributes as `prop:${K}`]?: IonReorderGroup[K] }; + "ion-ripple-effect": Omit & { [K in keyof IonRippleEffect & keyof IonRippleEffectAttributes]?: IonRippleEffect[K] } & { [K in keyof IonRippleEffect & keyof IonRippleEffectAttributes as `attr:${K}`]?: IonRippleEffectAttributes[K] } & { [K in keyof IonRippleEffect & keyof IonRippleEffectAttributes as `prop:${K}`]?: IonRippleEffect[K] }; + "ion-route": Omit & { [K in keyof IonRoute & keyof IonRouteAttributes]?: IonRoute[K] } & { [K in keyof IonRoute & keyof IonRouteAttributes as `attr:${K}`]?: IonRouteAttributes[K] } & { [K in keyof IonRoute & keyof IonRouteAttributes as `prop:${K}`]?: IonRoute[K] } & OneOf<"component", IonRoute["component"], IonRouteAttributes["component"]>; + "ion-route-redirect": Omit & { [K in keyof IonRouteRedirect & keyof IonRouteRedirectAttributes]?: IonRouteRedirect[K] } & { [K in keyof IonRouteRedirect & keyof IonRouteRedirectAttributes as `attr:${K}`]?: IonRouteRedirectAttributes[K] } & { [K in keyof IonRouteRedirect & keyof IonRouteRedirectAttributes as `prop:${K}`]?: IonRouteRedirect[K] } & OneOf<"from", IonRouteRedirect["from"], IonRouteRedirectAttributes["from"]> & OneOf<"to", IonRouteRedirect["to"], IonRouteRedirectAttributes["to"]>; + "ion-router": Omit & { [K in keyof IonRouter & keyof IonRouterAttributes]?: IonRouter[K] } & { [K in keyof IonRouter & keyof IonRouterAttributes as `attr:${K}`]?: IonRouterAttributes[K] } & { [K in keyof IonRouter & keyof IonRouterAttributes as `prop:${K}`]?: IonRouter[K] }; + "ion-router-link": Omit & { [K in keyof IonRouterLink & keyof IonRouterLinkAttributes]?: IonRouterLink[K] } & { [K in keyof IonRouterLink & keyof IonRouterLinkAttributes as `attr:${K}`]?: IonRouterLinkAttributes[K] } & { [K in keyof IonRouterLink & keyof IonRouterLinkAttributes as `prop:${K}`]?: IonRouterLink[K] }; + "ion-router-outlet": Omit & { [K in keyof IonRouterOutlet & keyof IonRouterOutletAttributes]?: IonRouterOutlet[K] } & { [K in keyof IonRouterOutlet & keyof IonRouterOutletAttributes as `attr:${K}`]?: IonRouterOutletAttributes[K] } & { [K in keyof IonRouterOutlet & keyof IonRouterOutletAttributes as `prop:${K}`]?: IonRouterOutlet[K] }; "ion-row": IonRow; - "ion-searchbar": IonSearchbar; - "ion-segment": IonSegment; - "ion-segment-button": IonSegmentButton; + "ion-searchbar": Omit & { [K in keyof IonSearchbar & keyof IonSearchbarAttributes]?: IonSearchbar[K] } & { [K in keyof IonSearchbar & keyof IonSearchbarAttributes as `attr:${K}`]?: IonSearchbarAttributes[K] } & { [K in keyof IonSearchbar & keyof IonSearchbarAttributes as `prop:${K}`]?: IonSearchbar[K] }; + "ion-segment": Omit & { [K in keyof IonSegment & keyof IonSegmentAttributes]?: IonSegment[K] } & { [K in keyof IonSegment & keyof IonSegmentAttributes as `attr:${K}`]?: IonSegmentAttributes[K] } & { [K in keyof IonSegment & keyof IonSegmentAttributes as `prop:${K}`]?: IonSegment[K] }; + "ion-segment-button": Omit & { [K in keyof IonSegmentButton & keyof IonSegmentButtonAttributes]?: IonSegmentButton[K] } & { [K in keyof IonSegmentButton & keyof IonSegmentButtonAttributes as `attr:${K}`]?: IonSegmentButtonAttributes[K] } & { [K in keyof IonSegmentButton & keyof IonSegmentButtonAttributes as `prop:${K}`]?: IonSegmentButton[K] }; "ion-segment-content": IonSegmentContent; - "ion-segment-view": IonSegmentView; - "ion-select": IonSelect; - "ion-select-modal": IonSelectModal; - "ion-select-option": IonSelectOption; - "ion-select-popover": IonSelectPopover; - "ion-skeleton-text": IonSkeletonText; - "ion-spinner": IonSpinner; - "ion-split-pane": IonSplitPane; - "ion-tab": IonTab; - "ion-tab-bar": IonTabBar; - "ion-tab-button": IonTabButton; - "ion-tabs": IonTabs; - "ion-text": IonText; - "ion-textarea": IonTextarea; + "ion-segment-view": Omit & { [K in keyof IonSegmentView & keyof IonSegmentViewAttributes]?: IonSegmentView[K] } & { [K in keyof IonSegmentView & keyof IonSegmentViewAttributes as `attr:${K}`]?: IonSegmentViewAttributes[K] } & { [K in keyof IonSegmentView & keyof IonSegmentViewAttributes as `prop:${K}`]?: IonSegmentView[K] }; + "ion-select": Omit & { [K in keyof IonSelect & keyof IonSelectAttributes]?: IonSelect[K] } & { [K in keyof IonSelect & keyof IonSelectAttributes as `attr:${K}`]?: IonSelectAttributes[K] } & { [K in keyof IonSelect & keyof IonSelectAttributes as `prop:${K}`]?: IonSelect[K] }; + "ion-select-modal": Omit & { [K in keyof IonSelectModal & keyof IonSelectModalAttributes]?: IonSelectModal[K] } & { [K in keyof IonSelectModal & keyof IonSelectModalAttributes as `attr:${K}`]?: IonSelectModalAttributes[K] } & { [K in keyof IonSelectModal & keyof IonSelectModalAttributes as `prop:${K}`]?: IonSelectModal[K] }; + "ion-select-option": Omit & { [K in keyof IonSelectOption & keyof IonSelectOptionAttributes]?: IonSelectOption[K] } & { [K in keyof IonSelectOption & keyof IonSelectOptionAttributes as `attr:${K}`]?: IonSelectOptionAttributes[K] } & { [K in keyof IonSelectOption & keyof IonSelectOptionAttributes as `prop:${K}`]?: IonSelectOption[K] }; + "ion-select-popover": Omit & { [K in keyof IonSelectPopover & keyof IonSelectPopoverAttributes]?: IonSelectPopover[K] } & { [K in keyof IonSelectPopover & keyof IonSelectPopoverAttributes as `attr:${K}`]?: IonSelectPopoverAttributes[K] } & { [K in keyof IonSelectPopover & keyof IonSelectPopoverAttributes as `prop:${K}`]?: IonSelectPopover[K] }; + "ion-skeleton-text": Omit & { [K in keyof IonSkeletonText & keyof IonSkeletonTextAttributes]?: IonSkeletonText[K] } & { [K in keyof IonSkeletonText & keyof IonSkeletonTextAttributes as `attr:${K}`]?: IonSkeletonTextAttributes[K] } & { [K in keyof IonSkeletonText & keyof IonSkeletonTextAttributes as `prop:${K}`]?: IonSkeletonText[K] }; + "ion-spinner": Omit & { [K in keyof IonSpinner & keyof IonSpinnerAttributes]?: IonSpinner[K] } & { [K in keyof IonSpinner & keyof IonSpinnerAttributes as `attr:${K}`]?: IonSpinnerAttributes[K] } & { [K in keyof IonSpinner & keyof IonSpinnerAttributes as `prop:${K}`]?: IonSpinner[K] }; + "ion-split-pane": Omit & { [K in keyof IonSplitPane & keyof IonSplitPaneAttributes]?: IonSplitPane[K] } & { [K in keyof IonSplitPane & keyof IonSplitPaneAttributes as `attr:${K}`]?: IonSplitPaneAttributes[K] } & { [K in keyof IonSplitPane & keyof IonSplitPaneAttributes as `prop:${K}`]?: IonSplitPane[K] }; + "ion-tab": Omit & { [K in keyof IonTab & keyof IonTabAttributes]?: IonTab[K] } & { [K in keyof IonTab & keyof IonTabAttributes as `attr:${K}`]?: IonTabAttributes[K] } & { [K in keyof IonTab & keyof IonTabAttributes as `prop:${K}`]?: IonTab[K] } & OneOf<"tab", IonTab["tab"], IonTabAttributes["tab"]>; + "ion-tab-bar": Omit & { [K in keyof IonTabBar & keyof IonTabBarAttributes]?: IonTabBar[K] } & { [K in keyof IonTabBar & keyof IonTabBarAttributes as `attr:${K}`]?: IonTabBarAttributes[K] } & { [K in keyof IonTabBar & keyof IonTabBarAttributes as `prop:${K}`]?: IonTabBar[K] }; + "ion-tab-button": Omit & { [K in keyof IonTabButton & keyof IonTabButtonAttributes]?: IonTabButton[K] } & { [K in keyof IonTabButton & keyof IonTabButtonAttributes as `attr:${K}`]?: IonTabButtonAttributes[K] } & { [K in keyof IonTabButton & keyof IonTabButtonAttributes as `prop:${K}`]?: IonTabButton[K] }; + "ion-tabs": Omit & { [K in keyof IonTabs & keyof IonTabsAttributes]?: IonTabs[K] } & { [K in keyof IonTabs & keyof IonTabsAttributes as `attr:${K}`]?: IonTabsAttributes[K] } & { [K in keyof IonTabs & keyof IonTabsAttributes as `prop:${K}`]?: IonTabs[K] }; + "ion-text": Omit & { [K in keyof IonText & keyof IonTextAttributes]?: IonText[K] } & { [K in keyof IonText & keyof IonTextAttributes as `attr:${K}`]?: IonTextAttributes[K] } & { [K in keyof IonText & keyof IonTextAttributes as `prop:${K}`]?: IonText[K] }; + "ion-textarea": Omit & { [K in keyof IonTextarea & keyof IonTextareaAttributes]?: IonTextarea[K] } & { [K in keyof IonTextarea & keyof IonTextareaAttributes as `attr:${K}`]?: IonTextareaAttributes[K] } & { [K in keyof IonTextarea & keyof IonTextareaAttributes as `prop:${K}`]?: IonTextarea[K] }; "ion-thumbnail": IonThumbnail; - "ion-title": IonTitle; - "ion-toast": IonToast; - "ion-toggle": IonToggle; - "ion-toolbar": IonToolbar; + "ion-title": Omit & { [K in keyof IonTitle & keyof IonTitleAttributes]?: IonTitle[K] } & { [K in keyof IonTitle & keyof IonTitleAttributes as `attr:${K}`]?: IonTitleAttributes[K] } & { [K in keyof IonTitle & keyof IonTitleAttributes as `prop:${K}`]?: IonTitle[K] }; + "ion-toast": Omit & { [K in keyof IonToast & keyof IonToastAttributes]?: IonToast[K] } & { [K in keyof IonToast & keyof IonToastAttributes as `attr:${K}`]?: IonToastAttributes[K] } & { [K in keyof IonToast & keyof IonToastAttributes as `prop:${K}`]?: IonToast[K] } & OneOf<"overlayIndex", IonToast["overlayIndex"], IonToastAttributes["overlayIndex"]>; + "ion-toggle": Omit & { [K in keyof IonToggle & keyof IonToggleAttributes]?: IonToggle[K] } & { [K in keyof IonToggle & keyof IonToggleAttributes as `attr:${K}`]?: IonToggleAttributes[K] } & { [K in keyof IonToggle & keyof IonToggleAttributes as `prop:${K}`]?: IonToggle[K] }; + "ion-toolbar": Omit & { [K in keyof IonToolbar & keyof IonToolbarAttributes]?: IonToolbar[K] } & { [K in keyof IonToolbar & keyof IonToolbarAttributes as `attr:${K}`]?: IonToolbarAttributes[K] } & { [K in keyof IonToolbar & keyof IonToolbarAttributes as `prop:${K}`]?: IonToolbar[K] }; } } export { LocalJSX as JSX }; declare module "@stencil/core" { export namespace JSX { interface IntrinsicElements { - "ion-accordion": LocalJSX.IonAccordion & JSXBase.HTMLAttributes; - "ion-accordion-group": LocalJSX.IonAccordionGroup & JSXBase.HTMLAttributes; - "ion-action-sheet": LocalJSX.IonActionSheet & JSXBase.HTMLAttributes; - "ion-alert": LocalJSX.IonAlert & JSXBase.HTMLAttributes; - "ion-app": LocalJSX.IonApp & JSXBase.HTMLAttributes; - "ion-avatar": LocalJSX.IonAvatar & JSXBase.HTMLAttributes; - "ion-back-button": LocalJSX.IonBackButton & JSXBase.HTMLAttributes; - "ion-backdrop": LocalJSX.IonBackdrop & JSXBase.HTMLAttributes; - "ion-badge": LocalJSX.IonBadge & JSXBase.HTMLAttributes; - "ion-breadcrumb": LocalJSX.IonBreadcrumb & JSXBase.HTMLAttributes; - "ion-breadcrumbs": LocalJSX.IonBreadcrumbs & JSXBase.HTMLAttributes; - "ion-button": LocalJSX.IonButton & JSXBase.HTMLAttributes; - "ion-buttons": LocalJSX.IonButtons & JSXBase.HTMLAttributes; - "ion-card": LocalJSX.IonCard & JSXBase.HTMLAttributes; - "ion-card-content": LocalJSX.IonCardContent & JSXBase.HTMLAttributes; - "ion-card-header": LocalJSX.IonCardHeader & JSXBase.HTMLAttributes; - "ion-card-subtitle": LocalJSX.IonCardSubtitle & JSXBase.HTMLAttributes; - "ion-card-title": LocalJSX.IonCardTitle & JSXBase.HTMLAttributes; - "ion-checkbox": LocalJSX.IonCheckbox & JSXBase.HTMLAttributes; - "ion-chip": LocalJSX.IonChip & JSXBase.HTMLAttributes; - "ion-col": LocalJSX.IonCol & JSXBase.HTMLAttributes; - "ion-content": LocalJSX.IonContent & JSXBase.HTMLAttributes; - "ion-datetime": LocalJSX.IonDatetime & JSXBase.HTMLAttributes; - "ion-datetime-button": LocalJSX.IonDatetimeButton & JSXBase.HTMLAttributes; - "ion-divider": LocalJSX.IonDivider & JSXBase.HTMLAttributes; - "ion-fab": LocalJSX.IonFab & JSXBase.HTMLAttributes; - "ion-fab-button": LocalJSX.IonFabButton & JSXBase.HTMLAttributes; - "ion-fab-list": LocalJSX.IonFabList & JSXBase.HTMLAttributes; - "ion-footer": LocalJSX.IonFooter & JSXBase.HTMLAttributes; - "ion-grid": LocalJSX.IonGrid & JSXBase.HTMLAttributes; - "ion-header": LocalJSX.IonHeader & JSXBase.HTMLAttributes; - "ion-img": LocalJSX.IonImg & JSXBase.HTMLAttributes; - "ion-infinite-scroll": LocalJSX.IonInfiniteScroll & JSXBase.HTMLAttributes; - "ion-infinite-scroll-content": LocalJSX.IonInfiniteScrollContent & JSXBase.HTMLAttributes; - "ion-input": LocalJSX.IonInput & JSXBase.HTMLAttributes; - "ion-input-otp": LocalJSX.IonInputOtp & JSXBase.HTMLAttributes; - "ion-input-password-toggle": LocalJSX.IonInputPasswordToggle & JSXBase.HTMLAttributes; - "ion-item": LocalJSX.IonItem & JSXBase.HTMLAttributes; - "ion-item-divider": LocalJSX.IonItemDivider & JSXBase.HTMLAttributes; - "ion-item-group": LocalJSX.IonItemGroup & JSXBase.HTMLAttributes; - "ion-item-option": LocalJSX.IonItemOption & JSXBase.HTMLAttributes; - "ion-item-options": LocalJSX.IonItemOptions & JSXBase.HTMLAttributes; - "ion-item-sliding": LocalJSX.IonItemSliding & JSXBase.HTMLAttributes; - "ion-label": LocalJSX.IonLabel & JSXBase.HTMLAttributes; - "ion-list": LocalJSX.IonList & JSXBase.HTMLAttributes; - "ion-list-header": LocalJSX.IonListHeader & JSXBase.HTMLAttributes; - "ion-loading": LocalJSX.IonLoading & JSXBase.HTMLAttributes; - "ion-menu": LocalJSX.IonMenu & JSXBase.HTMLAttributes; - "ion-menu-button": LocalJSX.IonMenuButton & JSXBase.HTMLAttributes; - "ion-menu-toggle": LocalJSX.IonMenuToggle & JSXBase.HTMLAttributes; - "ion-modal": LocalJSX.IonModal & JSXBase.HTMLAttributes; - "ion-nav": LocalJSX.IonNav & JSXBase.HTMLAttributes; - "ion-nav-link": LocalJSX.IonNavLink & JSXBase.HTMLAttributes; - "ion-note": LocalJSX.IonNote & JSXBase.HTMLAttributes; - "ion-picker": LocalJSX.IonPicker & JSXBase.HTMLAttributes; - "ion-picker-column": LocalJSX.IonPickerColumn & JSXBase.HTMLAttributes; - "ion-picker-column-option": LocalJSX.IonPickerColumnOption & JSXBase.HTMLAttributes; - "ion-picker-legacy": LocalJSX.IonPickerLegacy & JSXBase.HTMLAttributes; - "ion-picker-legacy-column": LocalJSX.IonPickerLegacyColumn & JSXBase.HTMLAttributes; - "ion-popover": LocalJSX.IonPopover & JSXBase.HTMLAttributes; - "ion-progress-bar": LocalJSX.IonProgressBar & JSXBase.HTMLAttributes; - "ion-radio": LocalJSX.IonRadio & JSXBase.HTMLAttributes; - "ion-radio-group": LocalJSX.IonRadioGroup & JSXBase.HTMLAttributes; - "ion-range": LocalJSX.IonRange & JSXBase.HTMLAttributes; - "ion-refresher": LocalJSX.IonRefresher & JSXBase.HTMLAttributes; - "ion-refresher-content": LocalJSX.IonRefresherContent & JSXBase.HTMLAttributes; - "ion-reorder": LocalJSX.IonReorder & JSXBase.HTMLAttributes; - "ion-reorder-group": LocalJSX.IonReorderGroup & JSXBase.HTMLAttributes; - "ion-ripple-effect": LocalJSX.IonRippleEffect & JSXBase.HTMLAttributes; - "ion-route": LocalJSX.IonRoute & JSXBase.HTMLAttributes; - "ion-route-redirect": LocalJSX.IonRouteRedirect & JSXBase.HTMLAttributes; - "ion-router": LocalJSX.IonRouter & JSXBase.HTMLAttributes; - "ion-router-link": LocalJSX.IonRouterLink & JSXBase.HTMLAttributes; - "ion-router-outlet": LocalJSX.IonRouterOutlet & JSXBase.HTMLAttributes; - "ion-row": LocalJSX.IonRow & JSXBase.HTMLAttributes; - "ion-searchbar": LocalJSX.IonSearchbar & JSXBase.HTMLAttributes; - "ion-segment": LocalJSX.IonSegment & JSXBase.HTMLAttributes; - "ion-segment-button": LocalJSX.IonSegmentButton & JSXBase.HTMLAttributes; - "ion-segment-content": LocalJSX.IonSegmentContent & JSXBase.HTMLAttributes; - "ion-segment-view": LocalJSX.IonSegmentView & JSXBase.HTMLAttributes; - "ion-select": LocalJSX.IonSelect & JSXBase.HTMLAttributes; - "ion-select-modal": LocalJSX.IonSelectModal & JSXBase.HTMLAttributes; - "ion-select-option": LocalJSX.IonSelectOption & JSXBase.HTMLAttributes; - "ion-select-popover": LocalJSX.IonSelectPopover & JSXBase.HTMLAttributes; - "ion-skeleton-text": LocalJSX.IonSkeletonText & JSXBase.HTMLAttributes; - "ion-spinner": LocalJSX.IonSpinner & JSXBase.HTMLAttributes; - "ion-split-pane": LocalJSX.IonSplitPane & JSXBase.HTMLAttributes; - "ion-tab": LocalJSX.IonTab & JSXBase.HTMLAttributes; - "ion-tab-bar": LocalJSX.IonTabBar & JSXBase.HTMLAttributes; - "ion-tab-button": LocalJSX.IonTabButton & JSXBase.HTMLAttributes; - "ion-tabs": LocalJSX.IonTabs & JSXBase.HTMLAttributes; - "ion-text": LocalJSX.IonText & JSXBase.HTMLAttributes; - "ion-textarea": LocalJSX.IonTextarea & JSXBase.HTMLAttributes; - "ion-thumbnail": LocalJSX.IonThumbnail & JSXBase.HTMLAttributes; - "ion-title": LocalJSX.IonTitle & JSXBase.HTMLAttributes; - "ion-toast": LocalJSX.IonToast & JSXBase.HTMLAttributes; - "ion-toggle": LocalJSX.IonToggle & JSXBase.HTMLAttributes; - "ion-toolbar": LocalJSX.IonToolbar & JSXBase.HTMLAttributes; + "ion-accordion": LocalJSX.IntrinsicElements["ion-accordion"] & JSXBase.HTMLAttributes; + "ion-accordion-group": LocalJSX.IntrinsicElements["ion-accordion-group"] & JSXBase.HTMLAttributes; + "ion-action-sheet": LocalJSX.IntrinsicElements["ion-action-sheet"] & JSXBase.HTMLAttributes; + "ion-alert": LocalJSX.IntrinsicElements["ion-alert"] & JSXBase.HTMLAttributes; + "ion-app": LocalJSX.IntrinsicElements["ion-app"] & JSXBase.HTMLAttributes; + "ion-avatar": LocalJSX.IntrinsicElements["ion-avatar"] & JSXBase.HTMLAttributes; + "ion-back-button": LocalJSX.IntrinsicElements["ion-back-button"] & JSXBase.HTMLAttributes; + "ion-backdrop": LocalJSX.IntrinsicElements["ion-backdrop"] & JSXBase.HTMLAttributes; + "ion-badge": LocalJSX.IntrinsicElements["ion-badge"] & JSXBase.HTMLAttributes; + "ion-breadcrumb": LocalJSX.IntrinsicElements["ion-breadcrumb"] & JSXBase.HTMLAttributes; + "ion-breadcrumbs": LocalJSX.IntrinsicElements["ion-breadcrumbs"] & JSXBase.HTMLAttributes; + "ion-button": LocalJSX.IntrinsicElements["ion-button"] & JSXBase.HTMLAttributes; + "ion-buttons": LocalJSX.IntrinsicElements["ion-buttons"] & JSXBase.HTMLAttributes; + "ion-card": LocalJSX.IntrinsicElements["ion-card"] & JSXBase.HTMLAttributes; + "ion-card-content": LocalJSX.IntrinsicElements["ion-card-content"] & JSXBase.HTMLAttributes; + "ion-card-header": LocalJSX.IntrinsicElements["ion-card-header"] & JSXBase.HTMLAttributes; + "ion-card-subtitle": LocalJSX.IntrinsicElements["ion-card-subtitle"] & JSXBase.HTMLAttributes; + "ion-card-title": LocalJSX.IntrinsicElements["ion-card-title"] & JSXBase.HTMLAttributes; + "ion-checkbox": LocalJSX.IntrinsicElements["ion-checkbox"] & JSXBase.HTMLAttributes; + "ion-chip": LocalJSX.IntrinsicElements["ion-chip"] & JSXBase.HTMLAttributes; + "ion-col": LocalJSX.IntrinsicElements["ion-col"] & JSXBase.HTMLAttributes; + "ion-content": LocalJSX.IntrinsicElements["ion-content"] & JSXBase.HTMLAttributes; + "ion-datetime": LocalJSX.IntrinsicElements["ion-datetime"] & JSXBase.HTMLAttributes; + "ion-datetime-button": LocalJSX.IntrinsicElements["ion-datetime-button"] & JSXBase.HTMLAttributes; + "ion-divider": LocalJSX.IntrinsicElements["ion-divider"] & JSXBase.HTMLAttributes; + "ion-fab": LocalJSX.IntrinsicElements["ion-fab"] & JSXBase.HTMLAttributes; + "ion-fab-button": LocalJSX.IntrinsicElements["ion-fab-button"] & JSXBase.HTMLAttributes; + "ion-fab-list": LocalJSX.IntrinsicElements["ion-fab-list"] & JSXBase.HTMLAttributes; + "ion-footer": LocalJSX.IntrinsicElements["ion-footer"] & JSXBase.HTMLAttributes; + "ion-grid": LocalJSX.IntrinsicElements["ion-grid"] & JSXBase.HTMLAttributes; + "ion-header": LocalJSX.IntrinsicElements["ion-header"] & JSXBase.HTMLAttributes; + "ion-img": LocalJSX.IntrinsicElements["ion-img"] & JSXBase.HTMLAttributes; + "ion-infinite-scroll": LocalJSX.IntrinsicElements["ion-infinite-scroll"] & JSXBase.HTMLAttributes; + "ion-infinite-scroll-content": LocalJSX.IntrinsicElements["ion-infinite-scroll-content"] & JSXBase.HTMLAttributes; + "ion-input": LocalJSX.IntrinsicElements["ion-input"] & JSXBase.HTMLAttributes; + "ion-input-otp": LocalJSX.IntrinsicElements["ion-input-otp"] & JSXBase.HTMLAttributes; + "ion-input-password-toggle": LocalJSX.IntrinsicElements["ion-input-password-toggle"] & JSXBase.HTMLAttributes; + "ion-item": LocalJSX.IntrinsicElements["ion-item"] & JSXBase.HTMLAttributes; + "ion-item-divider": LocalJSX.IntrinsicElements["ion-item-divider"] & JSXBase.HTMLAttributes; + "ion-item-group": LocalJSX.IntrinsicElements["ion-item-group"] & JSXBase.HTMLAttributes; + "ion-item-option": LocalJSX.IntrinsicElements["ion-item-option"] & JSXBase.HTMLAttributes; + "ion-item-options": LocalJSX.IntrinsicElements["ion-item-options"] & JSXBase.HTMLAttributes; + "ion-item-sliding": LocalJSX.IntrinsicElements["ion-item-sliding"] & JSXBase.HTMLAttributes; + "ion-label": LocalJSX.IntrinsicElements["ion-label"] & JSXBase.HTMLAttributes; + "ion-list": LocalJSX.IntrinsicElements["ion-list"] & JSXBase.HTMLAttributes; + "ion-list-header": LocalJSX.IntrinsicElements["ion-list-header"] & JSXBase.HTMLAttributes; + "ion-loading": LocalJSX.IntrinsicElements["ion-loading"] & JSXBase.HTMLAttributes; + "ion-menu": LocalJSX.IntrinsicElements["ion-menu"] & JSXBase.HTMLAttributes; + "ion-menu-button": LocalJSX.IntrinsicElements["ion-menu-button"] & JSXBase.HTMLAttributes; + "ion-menu-toggle": LocalJSX.IntrinsicElements["ion-menu-toggle"] & JSXBase.HTMLAttributes; + "ion-modal": LocalJSX.IntrinsicElements["ion-modal"] & JSXBase.HTMLAttributes; + "ion-nav": LocalJSX.IntrinsicElements["ion-nav"] & JSXBase.HTMLAttributes; + "ion-nav-link": LocalJSX.IntrinsicElements["ion-nav-link"] & JSXBase.HTMLAttributes; + "ion-note": LocalJSX.IntrinsicElements["ion-note"] & JSXBase.HTMLAttributes; + "ion-picker": LocalJSX.IntrinsicElements["ion-picker"] & JSXBase.HTMLAttributes; + "ion-picker-column": LocalJSX.IntrinsicElements["ion-picker-column"] & JSXBase.HTMLAttributes; + "ion-picker-column-option": LocalJSX.IntrinsicElements["ion-picker-column-option"] & JSXBase.HTMLAttributes; + "ion-picker-legacy": LocalJSX.IntrinsicElements["ion-picker-legacy"] & JSXBase.HTMLAttributes; + "ion-picker-legacy-column": LocalJSX.IntrinsicElements["ion-picker-legacy-column"] & JSXBase.HTMLAttributes; + "ion-popover": LocalJSX.IntrinsicElements["ion-popover"] & JSXBase.HTMLAttributes; + "ion-progress-bar": LocalJSX.IntrinsicElements["ion-progress-bar"] & JSXBase.HTMLAttributes; + "ion-radio": LocalJSX.IntrinsicElements["ion-radio"] & JSXBase.HTMLAttributes; + "ion-radio-group": LocalJSX.IntrinsicElements["ion-radio-group"] & JSXBase.HTMLAttributes; + "ion-range": LocalJSX.IntrinsicElements["ion-range"] & JSXBase.HTMLAttributes; + "ion-refresher": LocalJSX.IntrinsicElements["ion-refresher"] & JSXBase.HTMLAttributes; + "ion-refresher-content": LocalJSX.IntrinsicElements["ion-refresher-content"] & JSXBase.HTMLAttributes; + "ion-reorder": LocalJSX.IntrinsicElements["ion-reorder"] & JSXBase.HTMLAttributes; + "ion-reorder-group": LocalJSX.IntrinsicElements["ion-reorder-group"] & JSXBase.HTMLAttributes; + "ion-ripple-effect": LocalJSX.IntrinsicElements["ion-ripple-effect"] & JSXBase.HTMLAttributes; + "ion-route": LocalJSX.IntrinsicElements["ion-route"] & JSXBase.HTMLAttributes; + "ion-route-redirect": LocalJSX.IntrinsicElements["ion-route-redirect"] & JSXBase.HTMLAttributes; + "ion-router": LocalJSX.IntrinsicElements["ion-router"] & JSXBase.HTMLAttributes; + "ion-router-link": LocalJSX.IntrinsicElements["ion-router-link"] & JSXBase.HTMLAttributes; + "ion-router-outlet": LocalJSX.IntrinsicElements["ion-router-outlet"] & JSXBase.HTMLAttributes; + "ion-row": LocalJSX.IntrinsicElements["ion-row"] & JSXBase.HTMLAttributes; + "ion-searchbar": LocalJSX.IntrinsicElements["ion-searchbar"] & JSXBase.HTMLAttributes; + "ion-segment": LocalJSX.IntrinsicElements["ion-segment"] & JSXBase.HTMLAttributes; + "ion-segment-button": LocalJSX.IntrinsicElements["ion-segment-button"] & JSXBase.HTMLAttributes; + "ion-segment-content": LocalJSX.IntrinsicElements["ion-segment-content"] & JSXBase.HTMLAttributes; + "ion-segment-view": LocalJSX.IntrinsicElements["ion-segment-view"] & JSXBase.HTMLAttributes; + "ion-select": LocalJSX.IntrinsicElements["ion-select"] & JSXBase.HTMLAttributes; + "ion-select-modal": LocalJSX.IntrinsicElements["ion-select-modal"] & JSXBase.HTMLAttributes; + "ion-select-option": LocalJSX.IntrinsicElements["ion-select-option"] & JSXBase.HTMLAttributes; + "ion-select-popover": LocalJSX.IntrinsicElements["ion-select-popover"] & JSXBase.HTMLAttributes; + "ion-skeleton-text": LocalJSX.IntrinsicElements["ion-skeleton-text"] & JSXBase.HTMLAttributes; + "ion-spinner": LocalJSX.IntrinsicElements["ion-spinner"] & JSXBase.HTMLAttributes; + "ion-split-pane": LocalJSX.IntrinsicElements["ion-split-pane"] & JSXBase.HTMLAttributes; + "ion-tab": LocalJSX.IntrinsicElements["ion-tab"] & JSXBase.HTMLAttributes; + "ion-tab-bar": LocalJSX.IntrinsicElements["ion-tab-bar"] & JSXBase.HTMLAttributes; + "ion-tab-button": LocalJSX.IntrinsicElements["ion-tab-button"] & JSXBase.HTMLAttributes; + "ion-tabs": LocalJSX.IntrinsicElements["ion-tabs"] & JSXBase.HTMLAttributes; + "ion-text": LocalJSX.IntrinsicElements["ion-text"] & JSXBase.HTMLAttributes; + "ion-textarea": LocalJSX.IntrinsicElements["ion-textarea"] & JSXBase.HTMLAttributes; + "ion-thumbnail": LocalJSX.IntrinsicElements["ion-thumbnail"] & JSXBase.HTMLAttributes; + "ion-title": LocalJSX.IntrinsicElements["ion-title"] & JSXBase.HTMLAttributes; + "ion-toast": LocalJSX.IntrinsicElements["ion-toast"] & JSXBase.HTMLAttributes; + "ion-toggle": LocalJSX.IntrinsicElements["ion-toggle"] & JSXBase.HTMLAttributes; + "ion-toolbar": LocalJSX.IntrinsicElements["ion-toolbar"] & JSXBase.HTMLAttributes; } } } From e9eb57546c3fb75e39528a175c7ff4b13be807d5 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Fri, 10 Apr 2026 15:56:46 -0700 Subject: [PATCH 7/9] refactor(select): cleanup and tests --- core/src/components/select/select.common.scss | 2 + core/src/components/select/select.ionic.scss | 2 + core/src/components/select/select.native.scss | 2 + core/src/components/select/select.tsx | 109 +++--- .../components/select/test/basic/index.html | 12 +- .../select/test/basic/select.e2e.ts | 360 ++++++++++++++++++ core/src/utils/select-option-render.tsx | 82 +++- 7 files changed, 500 insertions(+), 69 deletions(-) diff --git a/core/src/components/select/select.common.scss b/core/src/components/select/select.common.scss index b3866c6f15b..d40a75c700c 100644 --- a/core/src/components/select/select.common.scss +++ b/core/src/components/select/select.common.scss @@ -150,6 +150,8 @@ button { // Select Text // -------------------------------------------------- .select-text { + display: flex; + flex: 1; font-size: inherit; diff --git a/core/src/components/select/select.ionic.scss b/core/src/components/select/select.ionic.scss index 2ba5f722406..ba9cf49eea8 100644 --- a/core/src/components/select/select.ionic.scss +++ b/core/src/components/select/select.ionic.scss @@ -44,6 +44,8 @@ min-width: globals.$ion-space-400; color: globals.$ion-text-subtlest; + + gap: globals.$ion-space-300; } :host(.has-value) .select-text { diff --git a/core/src/components/select/select.native.scss b/core/src/components/select/select.native.scss index 876fcb1579f..2b1e6dc891c 100644 --- a/core/src/components/select/select.native.scss +++ b/core/src/components/select/select.native.scss @@ -86,6 +86,8 @@ .select-text { min-width: 16px; + + gap: 12px; } // Select Label diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx index d13d38f58e3..41836a95f96 100644 --- a/core/src/components/select/select.tsx +++ b/core/src/components/select/select.tsx @@ -578,7 +578,11 @@ export class Select implements ComponentInterface { .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; const isSelected = isOptionSelected(selectValue, value, this.compareWith); - const text = this.customHTMLEnabled ? getOptionContentNodes(option) : option.textContent; + const text = this.customHTMLEnabled ? getOptionContent(option) : option.textContent; + const startContent = this.customHTMLEnabled + ? (getOptionContent(option, 'start') as HTMLElement | null) + : undefined; + const endContent = this.customHTMLEnabled ? (getOptionContent(option, 'end') as HTMLElement | null) : undefined; return { role: isSelected ? 'selected' : '', @@ -591,8 +595,8 @@ export class Select implements ComponentInterface { 'aria-checked': isSelected ? 'true' : 'false', role: 'radio', }, - startContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'start') ?? undefined : undefined, - endContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'end') ?? undefined : undefined, + startContent: startContent ?? undefined, + endContent: endContent ?? undefined, description: option.description, } as ActionSheetButton; }); @@ -622,7 +626,11 @@ export class Select implements ComponentInterface { .filter((cls) => cls !== 'hydrated') .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; - const label = this.customHTMLEnabled ? getOptionContentNodes(option) : option.textContent; + const label = this.customHTMLEnabled ? getOptionContent(option) : option.textContent; + const startContent = this.customHTMLEnabled + ? (getOptionContent(option, 'start') as HTMLElement | null) + : undefined; + const endContent = this.customHTMLEnabled ? (getOptionContent(option, 'end') as HTMLElement | null) : undefined; return { type: inputType, @@ -631,8 +639,8 @@ export class Select implements ComponentInterface { value, checked: isOptionSelected(selectValue, value, this.compareWith), disabled: option.disabled, - startContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'start') ?? undefined : undefined, - endContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'end') ?? undefined : undefined, + startContent: startContent ?? undefined, + endContent: endContent ?? undefined, description: option.description, }; }); @@ -649,7 +657,11 @@ export class Select implements ComponentInterface { .filter((cls) => cls !== 'hydrated') .join(' '); const optClass = `${OPTION_CLASS} ${copyClasses}`; - const text = this.customHTMLEnabled ? getOptionContentNodes(option) : option.textContent; + const text = this.customHTMLEnabled ? getOptionContent(option) : option.textContent; + const startContent = this.customHTMLEnabled + ? (getOptionContent(option, 'start') as HTMLElement | null) + : undefined; + const endContent = this.customHTMLEnabled ? (getOptionContent(option, 'end') as HTMLElement | null) : undefined; return { text: text ?? '', @@ -663,8 +675,8 @@ export class Select implements ComponentInterface { this.close(); } }, - startContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'start') ?? undefined : undefined, - endContent: this.customHTMLEnabled ? getOptionContentNodes(option, 'end') ?? undefined : undefined, + startContent: startContent ?? undefined, + endContent: endContent ?? undefined, description: option.description, }; }); @@ -893,6 +905,12 @@ export class Select implements ComponentInterface { return; } + /** + * Returns the text to display in the select based on the selected value. + * + * @param useHTML If `true`, the returned text will include any custom HTML content from the selected option. If `false`, the returned text will be plain text without any HTML. Defaults to `false`. + * @returns The text to display in the select, either with or without HTML based on the `useHTML` parameter. + */ private getText(useHTML = false): string { const selectedText = this.selectedText; if (selectedText != null && selectedText !== '') { @@ -1127,6 +1145,7 @@ export class Select implements ComponentInterface { private get ariaLabel() { const { placeholder, inheritedAttributes } = this; + // Get the plain text from the selected text const displayValue = this.getText(); // The aria label should be preferred over visible text if both are specified @@ -1458,10 +1477,20 @@ const textForValue = ( if (!selectOpt) return null; - // Use the HTML filter for the UI, but textContent for a11y/strings - return customHTMLEnabled && useHTML ? getOptionContentHTML(selectOpt) : selectOpt.textContent; + return customHTMLEnabled && useHTML + ? (getOptionContent(selectOpt, undefined, true) as string | null) + : selectOpt.textContent; }; +/** + * Trims whitespace from all text nodes within a DOM tree. + * This prevents invisible layout shifts and unwanted gaps between + * elements when HTML content is injected via innerHTML or cloneNode, + * as browsers preserve whitespace (tabs, newlines, spaces) from + * the original source markup. + * + * @param node The root node to start trimming text nodes from. + */ const trimTextNodes = (node: Node): void => { node.childNodes.forEach((child) => { if (child.nodeType === Node.TEXT_NODE) { @@ -1472,7 +1501,22 @@ const trimTextNodes = (node: Node): void => { }); }; -const getOptionContentHTML = (option: HTMLIonSelectOptionElement, slotName?: string): string | null => { +/** + * Extracts and clones content from an `ion-select-option` element + * for rendering within overlay interfaces or the select text when `customHTMLEnabled` is `true`. + * + * @param option - The `ion-select-option` element to extract content from. + * @param slotName - Optional slot name to extract. If omitted, extracts the default slot content. + * @param useHTML - If `true`, the returned string will include any custom HTML content. If `false`, the returned string will be plain text without any HTML. + * @returns When `useHTML` is `true`, a sanitized HTML string. When `false`, a + * div element containing cloned child nodes. Returns `null` if no matching + * content is found. + */ +const getOptionContent = ( + option: HTMLIonSelectOptionElement, + slotName?: string, + useHTML: boolean = false +): HTMLElement | string | null => { let nodes: Node[]; if (slotName) { @@ -1484,44 +1528,17 @@ const getOptionContentHTML = (option: HTMLIonSelectOptionElement, slotName?: str if (node.nodeType === Node.ELEMENT_NODE) { return !(node as HTMLElement).hasAttribute('slot'); } - return node.textContent?.trim().length !== 0; - }); - } - - if (nodes.length === 0) return null; - - const temp = document.createElement('div'); - nodes.forEach((n) => { - const clone = n.cloneNode(true); - if (clone.nodeType === Node.TEXT_NODE) { - clone.textContent = clone.textContent?.trim() || ''; - } else { - trimTextNodes(clone); - } - temp.appendChild(clone); - }); - - return sanitizeDOMString(temp.innerHTML.trim()) || null; -}; -const getOptionContentNodes = (option: HTMLIonSelectOptionElement, slotName?: string): HTMLElement | null => { - let nodes: Node[]; - - if (slotName) { - // Named slot: get elements with matching slot attribute - nodes = Array.from(option.children).filter((el) => el.getAttribute('slot') === slotName); - } else { - // Default slot: get nodes without a slot attribute - nodes = Array.from(option.childNodes).filter((node) => { - if (node.nodeType === Node.ELEMENT_NODE) { - return !(node as HTMLElement).hasAttribute('slot'); - } + // Exclude whitespace-only text nodes to prevent empty container returns return node.textContent?.trim().length !== 0; }); } - if (nodes.length === 0) return null; + if (nodes.length === 0) { + return null; + } + // Clone each node into a temporary container const container = document.createElement('div'); nodes.forEach((n) => { const clone = n.cloneNode(true); @@ -1533,6 +1550,10 @@ const getOptionContentNodes = (option: HTMLIonSelectOptionElement, slotName?: st container.appendChild(clone); }); + if (useHTML) { + return sanitizeDOMString(container.innerHTML.trim()) || null; + } + return container; }; diff --git a/core/src/components/select/test/basic/index.html b/core/src/components/select/test/basic/index.html index 156f2367ad8..631fca2e918 100644 --- a/core/src/components/select/test/basic/index.html +++ b/core/src/components/select/test/basic/index.html @@ -65,7 +65,7 @@
- + @@ -80,7 +80,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -279,7 +279,7 @@ - + @@ -296,7 +296,7 @@ - + @@ -312,7 +312,7 @@ - + diff --git a/core/src/components/select/test/basic/select.e2e.ts b/core/src/components/select/test/basic/select.e2e.ts index bf23678e657..881e1f35eb3 100644 --- a/core/src/components/select/test/basic/select.e2e.ts +++ b/core/src/components/select/test/basic/select.e2e.ts @@ -605,3 +605,363 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => { }); }); }); + +/** + * This behavior does not vary across modes/directions + */ +configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => { + test.describe(title('select: rich content options'), () => { + test.beforeEach(async ({ page }) => { + await page.goto('/src/components/select/test/basic', config); + }); + + test('it should render for alert interface and single selection', async ({ page }) => { + const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent'); + const ionAlertDidDismiss = await page.spyOnEvent('ionAlertDidDismiss'); + + const select = page.locator('#alert-select'); + + await select.click(); + + await ionAlertDidPresent.next(); + + const alert = page.locator('ion-alert'); + const firstOption = alert.locator('.alert-radio-label').first(); + const avatar = firstOption.locator('ion-avatar'); + const spanText = await firstOption.locator('.span-style').textContent(); + const firstOptionText = 'Apples'; + + await expect(firstOption).toContainText(firstOptionText); + await expect(avatar).toBeVisible(); + + // Click on the first option + await firstOption.click(); + + // Confirm the selection + const confirmButton = alert.locator('.alert-button:not(.alert-button-role-cancel)'); + await confirmButton.click(); + + await ionAlertDidDismiss.next(); + + // Verify that the select text includes the option text + const selectText = await select.locator('.select-text').textContent(); + + expect(selectText).toContain(firstOptionText); + expect(selectText).toContain(spanText); + + // Verify that the select text does not include the avatar and badge + const selectTextAvatar = select.locator('.select-text ion-avatar'); + const selectTextBadge = select.locator('.select-text ion-badge'); + + await expect(selectTextAvatar).toHaveCount(0); + await expect(selectTextBadge).toHaveCount(0); + }); + + test('it should render for alert interface and multiple selection', async ({ page }) => { + const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent'); + const ionAlertDidDismiss = await page.spyOnEvent('ionAlertDidDismiss'); + + const select = page.locator('#alert-select-multiple'); + + await select.click(); + + await ionAlertDidPresent.next(); + + const alert = page.locator('ion-alert'); + const firstOption = alert.locator('.alert-checkbox-label').first(); + const avatar = firstOption.locator('ion-avatar'); + const spanText = await firstOption.locator('.span-style').textContent(); + const firstOptionText = 'Pepperoni'; + + await expect(firstOption).toContainText(firstOptionText); + await expect(avatar).toBeVisible(); + + // Click on the first option + await firstOption.click(); + + // Confirm the selection + const confirmButton = alert.locator('.alert-button:not(.alert-button-role-cancel)'); + await confirmButton.click(); + + await ionAlertDidDismiss.next(); + + // Verify that the select text includes the option text + const selectText = await select.locator('.select-text').textContent(); + + expect(selectText).toContain(firstOptionText); + expect(selectText).toContain(spanText); + + // Verify that the select text does not include the avatar and badge + const selectTextAvatar = select.locator('.select-text ion-avatar'); + const selectTextBadge = select.locator('.select-text ion-badge'); + + await expect(selectTextAvatar).toHaveCount(0); + await expect(selectTextBadge).toHaveCount(0); + }); + + test('it should render for action sheet interface', async ({ page }) => { + const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent'); + const ionActionSheetDidDismiss = await page.spyOnEvent('ionActionSheetDidDismiss'); + + const select = page.locator('#action-sheet-select'); + + await select.click(); + + await ionActionSheetDidPresent.next(); + + const actionSheet = page.locator('ion-action-sheet'); + const firstOption = actionSheet.locator('.action-sheet-button-label').first(); + const avatar = firstOption.locator('ion-avatar'); + const spanText = await firstOption.locator('.span-style').textContent(); + const firstOptionText = 'Apples'; + + await expect(firstOption).toContainText(firstOptionText); + await expect(avatar).toBeVisible(); + + // Click on the first option + await firstOption.click(); + + await ionActionSheetDidDismiss.next(); + + // Verify that the select text includes the option text + const selectText = await select.locator('.select-text').textContent(); + + expect(selectText).toContain(firstOptionText); + expect(selectText).toContain(spanText); + + // Verify that the select text does not include the avatar and badge + const selectTextAvatar = select.locator('.select-text ion-avatar'); + const selectTextBadge = select.locator('.select-text ion-badge'); + + await expect(selectTextAvatar).toHaveCount(0); + await expect(selectTextBadge).toHaveCount(0); + }); + + test('it should render for popover interface and single selection', async ({ page }) => { + const ionPopoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent'); + const ionPopoverDidDismiss = await page.spyOnEvent('ionPopoverDidDismiss'); + + const select = page.locator('#popover-select'); + + await select.click(); + + await ionPopoverDidPresent.next(); + + const popover = page.locator('ion-popover'); + const firstOption = popover.locator('.select-option-label').first(); + const avatar = firstOption.locator('ion-avatar'); + const spanText = await firstOption.locator('.span-style').textContent(); + const firstOptionText = 'Apples'; + + await expect(firstOption).toContainText(firstOptionText); + await expect(avatar).toBeVisible(); + + // Click on the first option + await firstOption.click(); + + await ionPopoverDidDismiss.next(); + + // Verify that the select text includes the option text + const selectText = await select.locator('.select-text').textContent(); + + expect(selectText).toContain(firstOptionText); + expect(selectText).toContain(spanText); + + // Verify that the select text does not include the avatar and badge + const selectTextAvatar = select.locator('.select-text ion-avatar'); + const selectTextBadge = select.locator('.select-text ion-badge'); + + await expect(selectTextAvatar).toHaveCount(0); + await expect(selectTextBadge).toHaveCount(0); + }); + + test('it should render for popover interface and multiple selection', async ({ page }) => { + const ionPopoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent'); + const ionPopoverDidDismiss = await page.spyOnEvent('ionPopoverDidDismiss'); + + const select = page.locator('#popover-select-multiple'); + + await select.click(); + + await ionPopoverDidPresent.next(); + + const popover = page.locator('ion-popover'); + const firstOption = popover.locator('.select-option-label').first(); + const avatar = firstOption.locator('ion-avatar'); + const spanText = await firstOption.locator('.span-style').textContent(); + const firstOptionText = 'Bird'; + + await expect(firstOption).toContainText(firstOptionText); + await expect(avatar).toBeVisible(); + + // Click on the first option + await firstOption.click(); + + // Confirm the selection + const backdrop = page.locator('ion-backdrop'); + await backdrop.click({ position: { x: 10, y: 10 } }); + + await ionPopoverDidDismiss.next(); + + // Verify that the select text includes the option text + const selectText = await select.locator('.select-text').textContent(); + + expect(selectText).toContain(firstOptionText); + expect(selectText).toContain(spanText); + + // Verify that the select text does not include the avatar and badge + const selectTextAvatar = select.locator('.select-text ion-avatar'); + const selectTextBadge = select.locator('.select-text ion-badge'); + + await expect(selectTextAvatar).toHaveCount(0); + await expect(selectTextBadge).toHaveCount(0); + }); + + test('it should render for modal interface and single selection', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss'); + + const select = page.locator('#modal-select'); + + await select.click(); + + await ionModalDidPresent.next(); + + const modal = page.locator('ion-modal'); + const firstOption = modal.locator('.select-option-label').first(); + const avatar = firstOption.locator('ion-avatar'); + const spanText = await firstOption.locator('.span-style').textContent(); + const firstOptionText = 'Apples'; + + await expect(firstOption).toContainText(firstOptionText); + await expect(avatar).toBeVisible(); + + // Click on the first option + await firstOption.click(); + + await ionModalDidDismiss.next(); + + // Verify that the select text includes the option text + const selectText = await select.locator('.select-text').textContent(); + + expect(selectText).toContain(firstOptionText); + expect(selectText).toContain(spanText); + + // Verify that the select text does not include the avatar and badge + const selectTextAvatar = select.locator('.select-text ion-avatar'); + const selectTextBadge = select.locator('.select-text ion-badge'); + + await expect(selectTextAvatar).toHaveCount(0); + await expect(selectTextBadge).toHaveCount(0); + }); + + test('it should render for modal interface and multiple selection', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const ionModalDidDismiss = await page.spyOnEvent('ionModalDidDismiss'); + + const select = page.locator('#modal-select-multiple'); + + await select.click(); + + await ionModalDidPresent.next(); + + const modal = page.locator('ion-modal'); + const firstOption = modal.locator('.select-option-label').first(); + const avatar = firstOption.locator('ion-avatar'); + const spanText = await firstOption.locator('.span-style').textContent(); + const firstOptionText = 'Bird'; + + await expect(firstOption).toContainText(firstOptionText); + await expect(avatar).toBeVisible(); + + // Click on the first option + await firstOption.click(); + + // Confirm the selection + const cancelButton = modal.getByRole('button', { name: 'Cancel' }); + + await cancelButton.click(); + await ionModalDidDismiss.next(); + + // Verify that the select text includes the option text + const selectText = await select.locator('.select-text').textContent(); + + expect(selectText).toContain(firstOptionText); + expect(selectText).toContain(spanText); + + // Verify that the select text does not include the avatar and badge + const selectTextAvatar = select.locator('.select-text ion-avatar'); + const selectTextBadge = select.locator('.select-text ion-badge'); + + await expect(selectTextAvatar).toHaveCount(0); + await expect(selectTextBadge).toHaveCount(0); + }); + }); +}); + +/** + * This behavior does not vary across modes + */ +configs({ modes: ['md'] }).forEach(({ title, config }) => { + test.describe(title('select: rich content options'), () => { + test('it should render slots in the correct places', async ({ page }) => { + await page.setContent( + ` + + + NEW + + + + Apples + + + + + `, + config + ); + + const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent'); + + await page.locator('ion-select').click(); + + await ionAlertDidPresent.next(); + + const alert = page.locator('ion-alert'); + const firstOption = alert.locator('.alert-radio-label').first(); + const startContainer = firstOption.locator('.select-option-start'); + const endContainer = firstOption.locator('.select-option-end'); + + const avatar = startContainer.locator('ion-avatar'); + const badge = endContainer.locator('ion-badge'); + + await expect(avatar).toBeVisible(); + await expect(badge).toBeVisible(); + + const isRTL = await page.evaluate(() => document.dir === 'rtl'); + const optionBox = await firstOption.boundingBox(); + const startBox = await startContainer.boundingBox(); + const endBox = await endContainer.boundingBox(); + const optionMidpointX = optionBox!.x + optionBox!.width / 2; + + if (isRTL) { + // Verify the start container is rendered on the right, + // and the end container is rendered on the left + expect(startBox!.x).toBeGreaterThan(optionMidpointX); + expect(endBox!.x).toBeLessThan(optionMidpointX); + } else { + // Verify the start container is rendered on the left, + // and the end container is rendered on the right + expect(startBox!.x).toBeLessThan(optionMidpointX); + expect(endBox!.x).toBeGreaterThan(optionMidpointX); + } + }); + }); +}); diff --git a/core/src/utils/select-option-render.tsx b/core/src/utils/select-option-render.tsx index 9100bb9bae1..621229f53b3 100644 --- a/core/src/utils/select-option-render.tsx +++ b/core/src/utils/select-option-render.tsx @@ -1,36 +1,80 @@ import { h } from '@stencil/core'; -export interface RichContentOption { +interface RichContentOption { + /** Unique identifier for stable virtual DOM keys across re-renders. */ id: string; + /** The main label for the option as a string or an HTMLElement. */ label?: string | HTMLElement; + /** Content to display at the start of the option. */ startContent?: HTMLElement; + /** Content to display at the end of the option. */ endContent?: HTMLElement; + /** A description for the option. */ description?: string; } +/** + * Cache that maps rendered span elements to the source HTMLElement + * they were cloned from. This prevents flickering when a user + * selects an option that has rich content, as the content will only be + * re-rendered if the source HTMLElement changes. + */ const contentCache = new WeakMap(); -const renderClonedContent = (id: string, content: HTMLElement, className: string) => ( - { - if (el) { - const cached = contentCache.get(el); - if (cached === content) return; - - el.innerHTML = ''; - Array.from(content.childNodes).forEach((n) => el.appendChild(n.cloneNode(true))); - contentCache.set(el, content); - } - }} - > -); - -export const renderOptionLabel = (option: RichContentOption, className: string) => { +/** + * Renders cloned DOM content into a span element via a ref callback. + * The content is only cloned when the source element changes, + * preventing flicker caused by destroying and recreating web + * components (e.g., ion-avatar) on every re-render cycle. + * + * Uses span elements because this content may render within buttons, + * depending on the select interface. Buttons can only have phrasing + * content to prevent accessibility issues. + * + * @param id - Unique identifier for generating stable virtual DOM keys. + * @param content - The HTMLElement container whose child nodes will be cloned. + * @param className - CSS class applied to the wrapper span. + */ +const renderClonedContent = (id: string, content: HTMLElement, className: string) => { + return ( + { + if (el) { + const cached = contentCache.get(el); + // Skip if this element already has clones from the same source + if (cached === content) { + return; + } + + // Clear previous content and clone new nodes + el.innerHTML = ''; + Array.from(content.childNodes).forEach((n) => el.appendChild(n.cloneNode(true))); + contentCache.set(el, content); + } + }} + > + ); +}; + +/** + * Renders the label content for a select option within an overlay + * interface based on the presence of rich content. + * + * Uses span elements because this content may render within buttons, + * depending on the select interface. Buttons can only have phrasing + * content to prevent accessibility issues. + * + * @param option - The content option data containing label, slots, + * and description. + * @param className - The base CSS class for the label element. + */ +export const renderOptionLabel = (option: RichContentOption, className: string): HTMLElement => { const { id, label, startContent, endContent, description } = option; const hasRichContent = !!startContent || !!endContent || !!description; + // Render the main label const labelEl = typeof label === 'string' || !label ? ( {label} From e4bce6b10d8b607bf66884985dc96342d7819d50 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Fri, 10 Apr 2026 16:33:08 -0700 Subject: [PATCH 8/9] refactor(select): select text spacing --- core/src/components/select/select.common.scss | 2 -- core/src/components/select/select.ionic.scss | 11 +++++++---- core/src/components/select/select.native.scss | 9 ++++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/core/src/components/select/select.common.scss b/core/src/components/select/select.common.scss index d40a75c700c..b3866c6f15b 100644 --- a/core/src/components/select/select.common.scss +++ b/core/src/components/select/select.common.scss @@ -150,8 +150,6 @@ button { // Select Text // -------------------------------------------------- .select-text { - display: flex; - flex: 1; font-size: inherit; diff --git a/core/src/components/select/select.ionic.scss b/core/src/components/select/select.ionic.scss index ba9cf49eea8..55a4b88fe74 100644 --- a/core/src/components/select/select.ionic.scss +++ b/core/src/components/select/select.ionic.scss @@ -44,12 +44,15 @@ min-width: globals.$ion-space-400; color: globals.$ion-text-subtlest; - - gap: globals.$ion-space-300; } -:host(.has-value) .select-text { - color: globals.$ion-text-default; +/** + * If the select text contains rich content, we want to add some + * spacing between the items without changing the display to prevent + * losing the ellipsis behavior. + */ +.select-text > * { + margin-inline-start: globals.$ion-space-200; } // Select Label diff --git a/core/src/components/select/select.native.scss b/core/src/components/select/select.native.scss index 2b1e6dc891c..262b6efdbee 100644 --- a/core/src/components/select/select.native.scss +++ b/core/src/components/select/select.native.scss @@ -86,8 +86,15 @@ .select-text { min-width: 16px; +} - gap: 12px; +/** + * If the select text contains rich content, we want to add some + * spacing between the items without changing the display to prevent + * losing the ellipsis behavior. + */ +.select-text > * { + margin-inline-start: 8px; } // Select Label From 03b8351b772d52cf62356ffe5a5b545c7735e99d Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Fri, 10 Apr 2026 17:56:40 -0700 Subject: [PATCH 9/9] fix(select): revert deletion --- core/src/components/select/select.ionic.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/components/select/select.ionic.scss b/core/src/components/select/select.ionic.scss index 55a4b88fe74..5f0bf27977f 100644 --- a/core/src/components/select/select.ionic.scss +++ b/core/src/components/select/select.ionic.scss @@ -46,6 +46,10 @@ color: globals.$ion-text-subtlest; } +:host(.has-value) .select-text { + color: globals.$ion-text-default; +} + /** * If the select text contains rich content, we want to add some * spacing between the items without changing the display to prevent