Compare commits

...

10 Commits

Author SHA1 Message Date
Sean Perkins
4d7140694a feat: add a new stylesheet for the ionic theme 2024-03-25 19:12:41 -04:00
Sean Perkins
f664329f71 chore: sync with feature-8.0 (#29202)
Issue number: N/A

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Syncs the `next` branch with `feature-8.0`

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2024-03-21 16:45:15 -04:00
Sean Perkins
d73de9194d Merge remote-tracking branch 'origin/feature-8.0' into sp/sync-next-03-21 2024-03-21 16:28:35 -04:00
Sean Perkins
e8169bfddb chore: sync next with feature-8.0 (#29194)
Issue number: Internal

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

N/A

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Syncs `next` with the latest changes from `feature-8.0`

## Does this introduce a breaking change?

- [ ] Yes
- [ ] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
2024-03-21 12:13:34 -04:00
ionitron
e375508647 chore(): add updated snapshots 2024-03-21 04:45:01 +00:00
Sean Perkins
6965205824 chore: use theme for rendering datetime 2024-03-20 21:11:01 -04:00
Sean Perkins
245a5c6f23 Merge remote-tracking branch 'origin/feature-8.0' into sp/sync-next-with-v8 2024-03-20 21:05:35 -04:00
Sean Perkins
284eb8ecaf feat: add ionic theme architecture (#29132)
Issue number: Internal

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

Adds the base architecture to add a new theme configuration to Ionic
Framework components.
- Components can now specify an additional stylesheet for the `ionic`
theme.
- Developers can specify the `theme` and `mode` independently to control
look and feel of a component.

Test infrastructure has been updated to add support for testing the
theme configuration with Playwright.
- Existing `themes` test configuration has been renamed to `palettes`

This PR is just the initial effort to decouple Ionic's architecture to
separate look and feel and allow our dev team to start introducing the
new component appearance to the UI. There will be additional changes
required to completely add support for the Ionic theme. These changes
are targeted against the `next` branch and are not expected to be used
in a production environment at this time.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

---------

Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
2024-03-18 15:45:01 -04:00
Sean Perkins
76b48a6c77 Merge remote-tracking branch 'origin/feature-8.0' into next 2024-03-14 10:34:28 -04:00
Sean Perkins
668ab98f0e Merge remote-tracking branch 'origin/feature-8.0' into next 2024-03-09 15:48:50 -05:00
121 changed files with 2978 additions and 1072 deletions

View File

@@ -18,6 +18,7 @@
* [Component Structure](#component-structure-1)
- [Converting Scoped to Shadow](#converting-scoped-to-shadow)
- [RTL](#rtl)
- [Themes vs. Modes](#themes-vs-modes)
## Button States
@@ -349,7 +350,7 @@ The ripple effect should be added to elements for Material Design. It *requires*
```jsx
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
@@ -359,7 +360,7 @@ return (
>
<button>
<slot></slot>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
</Host>
);
@@ -743,3 +744,37 @@ class={{
transform-origin: right center;
}
```
## Themes vs. Modes
Themes and modes are two different concepts in Ionic. Themes refer to the "look" of the component, such as the stylesheet that is used. Modes refer to the "behavior" of the component, such as the platform specific behaviors on iOS and Android.
To detect the theme, you can use the `getIonTheme` function:
```tsx
const theme = getIonTheme(this);
return (
<Host class={theme}>
{theme === "md" && <ion-ripple-effect></ion-ripple-effect>}
</Host>
);
```
Theme can be both used for styling decisions and conditional rendering of elements. For example, the ripple effect is only used in the Material Design theme.
To detect the mode, you can use the `getIonMode` function:
```tsx
const mode = getIonMode(this);
if (mode === "ios") {
enableRubberBandScrolling();
}
```
Mode can be used for behavior tied to the platform the app is running on. For example, iOS has rubber band scrolling, while Android does not.
Use mode for functionality that remains consistent across all themes but is intended specifically for a certain platform.
Functionality that is applied only to a specific theme should use theme.

View File

@@ -3,6 +3,7 @@ ion-accordion,shadow
ion-accordion,prop,disabled,boolean,false,false,false
ion-accordion,prop,mode,"ios" | "md",undefined,false,false
ion-accordion,prop,readonly,boolean,false,false,false
ion-accordion,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-accordion,prop,toggleIcon,string,chevronDown,false,false
ion-accordion,prop,toggleIconSlot,"end" | "start",'end',false,false
ion-accordion,prop,value,string,`ion-accordion-${accordionIds++}`,false,false
@@ -17,6 +18,7 @@ ion-accordion-group,prop,expand,"compact" | "inset",'compact',false,false
ion-accordion-group,prop,mode,"ios" | "md",undefined,false,false
ion-accordion-group,prop,multiple,boolean | undefined,undefined,false,false
ion-accordion-group,prop,readonly,boolean,false,false,false
ion-accordion-group,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-accordion-group,prop,value,null | string | string[] | undefined,undefined,false,false
ion-accordion-group,event,ionChange,AccordionGroupChangeEventDetail<any>,true
@@ -33,6 +35,7 @@ ion-action-sheet,prop,keyboardClose,boolean,true,false,false
ion-action-sheet,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-action-sheet,prop,mode,"ios" | "md",undefined,false,false
ion-action-sheet,prop,subHeader,string | undefined,undefined,false,false
ion-action-sheet,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-action-sheet,prop,translucent,boolean,false,false,false
ion-action-sheet,prop,trigger,string | undefined,undefined,false,false
ion-action-sheet,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
@@ -87,6 +90,7 @@ ion-alert,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefin
ion-alert,prop,message,IonicSafeString | string | undefined,undefined,false,false
ion-alert,prop,mode,"ios" | "md",undefined,false,false
ion-alert,prop,subHeader,string | undefined,undefined,false,false
ion-alert,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-alert,prop,translucent,boolean,false,false,false
ion-alert,prop,trigger,string | undefined,undefined,false,false
ion-alert,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
@@ -111,8 +115,12 @@ ion-alert,css-prop,--min-width
ion-alert,css-prop,--width
ion-app,none
ion-app,prop,mode,"ios" | "md",undefined,false,false
ion-app,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-avatar,shadow
ion-avatar,prop,mode,"ios" | "md",undefined,false,false
ion-avatar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-avatar,css-prop,--border-radius
ion-back-button,shadow
@@ -123,6 +131,7 @@ ion-back-button,prop,icon,null | string | undefined,undefined,false,false
ion-back-button,prop,mode,"ios" | "md",undefined,false,false
ion-back-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-back-button,prop,text,null | string | undefined,undefined,false,false
ion-back-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-back-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-back-button,css-prop,--background
ion-back-button,css-prop,--background-focused
@@ -161,14 +170,17 @@ ion-back-button,part,native
ion-back-button,part,text
ion-backdrop,shadow
ion-backdrop,prop,mode,"ios" | "md",undefined,false,false
ion-backdrop,prop,stopPropagation,boolean,true,false,false
ion-backdrop,prop,tappable,boolean,true,false,false
ion-backdrop,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-backdrop,prop,visible,boolean,true,false,false
ion-backdrop,event,ionBackdropTap,void,true
ion-badge,shadow
ion-badge,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-badge,prop,mode,"ios" | "md",undefined,false,false
ion-badge,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-badge,css-prop,--background
ion-badge,css-prop,--color
ion-badge,css-prop,--padding-bottom
@@ -188,6 +200,7 @@ ion-breadcrumb,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | u
ion-breadcrumb,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-breadcrumb,prop,separator,boolean | undefined,undefined,false,false
ion-breadcrumb,prop,target,string | undefined,undefined,false,false
ion-breadcrumb,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-breadcrumb,event,ionBlur,void,true
ion-breadcrumb,event,ionFocus,void,true
ion-breadcrumb,css-prop,--background-focused
@@ -205,6 +218,7 @@ ion-breadcrumbs,prop,itemsAfterCollapse,number,1,false,false
ion-breadcrumbs,prop,itemsBeforeCollapse,number,1,false,false
ion-breadcrumbs,prop,maxItems,number | undefined,undefined,false,false
ion-breadcrumbs,prop,mode,"ios" | "md",undefined,false,false
ion-breadcrumbs,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-breadcrumbs,event,ionCollapsedClick,BreadcrumbCollapsedClickEventDetail,true
ion-button,shadow
@@ -224,6 +238,7 @@ ion-button,prop,shape,"round" | undefined,undefined,false,true
ion-button,prop,size,"default" | "large" | "small" | undefined,undefined,false,true
ion-button,prop,strong,boolean,false,false,false
ion-button,prop,target,string | undefined,undefined,false,false
ion-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-button,event,ionBlur,void,true
ion-button,event,ionFocus,void,true
@@ -254,6 +269,8 @@ ion-button,part,native
ion-buttons,scoped
ion-buttons,prop,collapse,boolean,false,false,false
ion-buttons,prop,mode,"ios" | "md",undefined,false,false
ion-buttons,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-card,shadow
ion-card,prop,button,boolean,false,false,false
@@ -266,6 +283,7 @@ ion-card,prop,rel,string | undefined,undefined,false,false
ion-card,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-card,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-card,prop,target,string | undefined,undefined,false,false
ion-card,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-card,prop,type,"button" | "reset" | "submit",'button',false,false
ion-card,css-prop,--background
ion-card,css-prop,--color
@@ -273,20 +291,24 @@ ion-card,part,native
ion-card-content,none
ion-card-content,prop,mode,"ios" | "md",undefined,false,false
ion-card-content,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-card-header,shadow
ion-card-header,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-card-header,prop,mode,"ios" | "md",undefined,false,false
ion-card-header,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-card-header,prop,translucent,boolean,false,false,false
ion-card-subtitle,shadow
ion-card-subtitle,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-card-subtitle,prop,mode,"ios" | "md",undefined,false,false
ion-card-subtitle,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-card-subtitle,css-prop,--color
ion-card-title,shadow
ion-card-title,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-card-title,prop,mode,"ios" | "md",undefined,false,false
ion-card-title,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-card-title,css-prop,--color
ion-checkbox,shadow
@@ -299,6 +321,7 @@ ion-checkbox,prop,justify,"end" | "space-between" | "start",'space-between',fals
ion-checkbox,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',false,false
ion-checkbox,prop,mode,"ios" | "md",undefined,false,false
ion-checkbox,prop,name,string,this.inputId,false,false
ion-checkbox,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-checkbox,prop,value,any,'on',false,false
ion-checkbox,event,ionBlur,void,true
ion-checkbox,event,ionChange,CheckboxChangeEventDetail<any>,true
@@ -323,10 +346,12 @@ ion-chip,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "second
ion-chip,prop,disabled,boolean,false,false,false
ion-chip,prop,mode,"ios" | "md",undefined,false,false
ion-chip,prop,outline,boolean,false,false,false
ion-chip,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-chip,css-prop,--background
ion-chip,css-prop,--color
ion-col,shadow
ion-col,prop,mode,"ios" | "md",undefined,false,false
ion-col,prop,offset,string | undefined,undefined,false,false
ion-col,prop,offsetLg,string | undefined,undefined,false,false
ion-col,prop,offsetMd,string | undefined,undefined,false,false
@@ -351,6 +376,7 @@ ion-col,prop,sizeMd,string | undefined,undefined,false,false
ion-col,prop,sizeSm,string | undefined,undefined,false,false
ion-col,prop,sizeXl,string | undefined,undefined,false,false
ion-col,prop,sizeXs,string | undefined,undefined,false,false
ion-col,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-col,css-prop,--ion-grid-column-padding
ion-col,css-prop,--ion-grid-column-padding-lg
ion-col,css-prop,--ion-grid-column-padding-md
@@ -363,9 +389,11 @@ ion-content,shadow
ion-content,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-content,prop,forceOverscroll,boolean | undefined,undefined,false,false
ion-content,prop,fullscreen,boolean,false,false,false
ion-content,prop,mode,"ios" | "md",undefined,false,false
ion-content,prop,scrollEvents,boolean,false,false,false
ion-content,prop,scrollX,boolean,false,false,false
ion-content,prop,scrollY,boolean,true,false,false
ion-content,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-content,method,getScrollElement,getScrollElement() => Promise<HTMLElement>
ion-content,method,scrollByPoint,scrollByPoint(x: number, y: number, duration: number) => Promise<void>
ion-content,method,scrollToBottom,scrollToBottom(duration?: number) => Promise<void>
@@ -415,6 +443,7 @@ ion-datetime,prop,showDefaultButtons,boolean,false,false,false
ion-datetime,prop,showDefaultTimeLabel,boolean,true,false,false
ion-datetime,prop,showDefaultTitle,boolean,false,false,false
ion-datetime,prop,size,"cover" | "fixed",'fixed',false,false
ion-datetime,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-datetime,prop,titleSelectedDatesFormatter,((selectedDates: string[]) => string) | undefined,undefined,false,false
ion-datetime,prop,value,null | string | string[] | undefined,undefined,false,false
ion-datetime,prop,yearValues,number | number[] | string | undefined,undefined,false,false
@@ -446,12 +475,15 @@ ion-datetime-button,prop,color,"danger" | "dark" | "light" | "medium" | "primary
ion-datetime-button,prop,datetime,string | undefined,undefined,false,false
ion-datetime-button,prop,disabled,boolean,false,false,true
ion-datetime-button,prop,mode,"ios" | "md",undefined,false,false
ion-datetime-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-datetime-button,part,native
ion-fab,shadow
ion-fab,prop,activated,boolean,false,false,false
ion-fab,prop,edge,boolean,false,false,false
ion-fab,prop,horizontal,"center" | "end" | "start" | undefined,undefined,false,false
ion-fab,prop,mode,"ios" | "md",undefined,false,false
ion-fab,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-fab,prop,vertical,"bottom" | "center" | "top" | undefined,undefined,false,false
ion-fab,method,close,close() => Promise<void>
@@ -469,6 +501,7 @@ ion-fab-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,
ion-fab-button,prop,show,boolean,false,false,false
ion-fab-button,prop,size,"small" | undefined,undefined,false,false
ion-fab-button,prop,target,string | undefined,undefined,false,false
ion-fab-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-fab-button,prop,translucent,boolean,false,false,false
ion-fab-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-fab-button,event,ionBlur,void,true
@@ -501,15 +534,20 @@ ion-fab-button,part,native
ion-fab-list,shadow
ion-fab-list,prop,activated,boolean,false,false,false
ion-fab-list,prop,mode,"ios" | "md",undefined,false,false
ion-fab-list,prop,side,"bottom" | "end" | "start" | "top",'bottom',false,false
ion-fab-list,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-footer,none
ion-footer,prop,collapse,"fade" | undefined,undefined,false,false
ion-footer,prop,mode,"ios" | "md",undefined,false,false
ion-footer,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-footer,prop,translucent,boolean,false,false,false
ion-grid,shadow
ion-grid,prop,fixed,boolean,false,false,false
ion-grid,prop,mode,"ios" | "md",undefined,false,false
ion-grid,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-grid,css-prop,--ion-grid-padding
ion-grid,css-prop,--ion-grid-padding-lg
ion-grid,css-prop,--ion-grid-padding-md
@@ -526,11 +564,14 @@ ion-grid,css-prop,--ion-grid-width-xs
ion-header,none
ion-header,prop,collapse,"condense" | "fade" | undefined,undefined,false,false
ion-header,prop,mode,"ios" | "md",undefined,false,false
ion-header,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-header,prop,translucent,boolean,false,false,false
ion-img,shadow
ion-img,prop,alt,string | undefined,undefined,false,false
ion-img,prop,mode,"ios" | "md",undefined,false,false
ion-img,prop,src,string | undefined,undefined,false,false
ion-img,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-img,event,ionError,void,true
ion-img,event,ionImgDidLoad,void,true
ion-img,event,ionImgWillLoad,void,true
@@ -538,7 +579,9 @@ ion-img,part,image
ion-infinite-scroll,none
ion-infinite-scroll,prop,disabled,boolean,false,false,false
ion-infinite-scroll,prop,mode,"ios" | "md",undefined,false,false
ion-infinite-scroll,prop,position,"bottom" | "top",'bottom',false,false
ion-infinite-scroll,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-infinite-scroll,prop,threshold,string,'15%',false,false
ion-infinite-scroll,method,complete,complete() => Promise<void>
ion-infinite-scroll,event,ionInfinite,void,true
@@ -546,6 +589,8 @@ ion-infinite-scroll,event,ionInfinite,void,true
ion-infinite-scroll-content,none
ion-infinite-scroll-content,prop,loadingSpinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-sharp" | "lines-sharp-small" | "lines-small" | null | undefined,undefined,false,false
ion-infinite-scroll-content,prop,loadingText,IonicSafeString | string | undefined,undefined,false,false
ion-infinite-scroll-content,prop,mode,"ios" | "md",undefined,false,false
ion-infinite-scroll-content,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-input,scoped
ion-input,prop,autocapitalize,string,'off',false,false
@@ -580,6 +625,7 @@ ion-input,prop,required,boolean,false,false,false
ion-input,prop,shape,"round" | undefined,undefined,false,false
ion-input,prop,spellcheck,boolean,false,false,false
ion-input,prop,step,string | undefined,undefined,false,false
ion-input,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-input,prop,type,"date" | "datetime-local" | "email" | "month" | "number" | "password" | "search" | "tel" | "text" | "time" | "url" | "week",'text',false,false
ion-input,prop,value,null | number | string | undefined,'',false,false
ion-input,method,getInputElement,getInputElement() => Promise<HTMLInputElement>
@@ -621,6 +667,7 @@ ion-item,prop,rel,string | undefined,undefined,false,false
ion-item,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-item,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-item,prop,target,string | undefined,undefined,false,false
ion-item,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-item,prop,type,"button" | "reset" | "submit",'button',false,false
ion-item,css-prop,--background
ion-item,css-prop,--background-activated
@@ -660,6 +707,7 @@ ion-item-divider,shadow
ion-item-divider,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-item-divider,prop,mode,"ios" | "md",undefined,false,false
ion-item-divider,prop,sticky,boolean,false,false,false
ion-item-divider,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-item-divider,css-prop,--background
ion-item-divider,css-prop,--color
ion-item-divider,css-prop,--inner-padding-bottom
@@ -672,6 +720,8 @@ ion-item-divider,css-prop,--padding-start
ion-item-divider,css-prop,--padding-top
ion-item-group,none
ion-item-group,prop,mode,"ios" | "md",undefined,false,false
ion-item-group,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-item-option,shadow
ion-item-option,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
@@ -682,17 +732,22 @@ ion-item-option,prop,href,string | undefined,undefined,false,false
ion-item-option,prop,mode,"ios" | "md",undefined,false,false
ion-item-option,prop,rel,string | undefined,undefined,false,false
ion-item-option,prop,target,string | undefined,undefined,false,false
ion-item-option,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-item-option,prop,type,"button" | "reset" | "submit",'button',false,false
ion-item-option,css-prop,--background
ion-item-option,css-prop,--color
ion-item-option,part,native
ion-item-options,none
ion-item-options,prop,mode,"ios" | "md",undefined,false,false
ion-item-options,prop,side,"end" | "start",'end',false,false
ion-item-options,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-item-options,event,ionSwipe,any,true
ion-item-sliding,none
ion-item-sliding,prop,disabled,boolean,false,false,false
ion-item-sliding,prop,mode,"ios" | "md",undefined,false,false
ion-item-sliding,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-item-sliding,method,close,close() => Promise<void>
ion-item-sliding,method,closeOpened,closeOpened() => Promise<boolean>
ion-item-sliding,method,getOpenAmount,getOpenAmount() => Promise<number>
@@ -704,18 +759,21 @@ ion-label,scoped
ion-label,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-label,prop,mode,"ios" | "md",undefined,false,false
ion-label,prop,position,"fixed" | "floating" | "stacked" | undefined,undefined,false,false
ion-label,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-label,css-prop,--color
ion-list,none
ion-list,prop,inset,boolean,false,false,false
ion-list,prop,lines,"full" | "inset" | "none" | undefined,undefined,false,false
ion-list,prop,mode,"ios" | "md",undefined,false,false
ion-list,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-list,method,closeSlidingItems,closeSlidingItems() => Promise<boolean>
ion-list-header,shadow
ion-list-header,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-list-header,prop,lines,"full" | "inset" | "none" | undefined,undefined,false,false
ion-list-header,prop,mode,"ios" | "md",undefined,false,false
ion-list-header,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-list-header,css-prop,--background
ion-list-header,css-prop,--border-color
ion-list-header,css-prop,--border-style
@@ -737,6 +795,7 @@ ion-loading,prop,message,IonicSafeString | string | undefined,undefined,false,fa
ion-loading,prop,mode,"ios" | "md",undefined,false,false
ion-loading,prop,showBackdrop,boolean,true,false,false
ion-loading,prop,spinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-sharp" | "lines-sharp-small" | "lines-small" | null | undefined,undefined,false,false
ion-loading,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-loading,prop,translucent,boolean,false,false,false
ion-loading,prop,trigger,string | undefined,undefined,false,false
ion-loading,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
@@ -766,8 +825,10 @@ ion-menu,prop,contentId,string | undefined,undefined,false,true
ion-menu,prop,disabled,boolean,false,false,false
ion-menu,prop,maxEdgeStart,number,50,false,false
ion-menu,prop,menuId,string | undefined,undefined,false,true
ion-menu,prop,mode,"ios" | "md",undefined,false,false
ion-menu,prop,side,"end" | "start",'start',false,true
ion-menu,prop,swipeGesture,boolean,true,false,false
ion-menu,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-menu,prop,type,"overlay" | "push" | "reveal" | undefined,undefined,false,false
ion-menu,method,close,close(animated?: boolean) => Promise<boolean>
ion-menu,method,isActive,isActive() => Promise<boolean>
@@ -795,6 +856,7 @@ ion-menu-button,prop,color,"danger" | "dark" | "light" | "medium" | "primary" |
ion-menu-button,prop,disabled,boolean,false,false,false
ion-menu-button,prop,menu,string | undefined,undefined,false,false
ion-menu-button,prop,mode,"ios" | "md",undefined,false,false
ion-menu-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-menu-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-menu-button,css-prop,--background
ion-menu-button,css-prop,--background-focused
@@ -815,6 +877,8 @@ ion-menu-button,part,native
ion-menu-toggle,shadow
ion-menu-toggle,prop,autoHide,boolean,true,false,false
ion-menu-toggle,prop,menu,string | undefined,undefined,false,false
ion-menu-toggle,prop,mode,"ios" | "md",undefined,false,false
ion-menu-toggle,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-modal,shadow
ion-modal,prop,animated,boolean,true,false,false
@@ -834,6 +898,7 @@ ion-modal,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefin
ion-modal,prop,mode,"ios" | "md",undefined,false,false
ion-modal,prop,presentingElement,HTMLElement | undefined,undefined,false,false
ion-modal,prop,showBackdrop,boolean,true,false,false
ion-modal,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-modal,prop,trigger,string | undefined,undefined,false,false
ion-modal,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
ion-modal,method,getCurrentBreakpoint,getCurrentBreakpoint() => Promise<number | undefined>
@@ -869,9 +934,11 @@ ion-modal,part,handle
ion-nav,shadow
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,swipeGesture,boolean | undefined,undefined,false,false
ion-nav,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-nav,method,canGoBack,canGoBack(view?: ViewController) => Promise<boolean>
ion-nav,method,getActive,getActive() => Promise<ViewController | undefined>
ion-nav,method,getByIndex,getByIndex(index: number) => Promise<ViewController | undefined>
@@ -892,16 +959,20 @@ 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,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
ion-nav-link,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-note,shadow
ion-note,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-note,prop,mode,"ios" | "md",undefined,false,false
ion-note,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-note,css-prop,--color
ion-picker,shadow
ion-picker,prop,mode,"ios" | "md",undefined,false,false
ion-picker,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-picker,css-prop,--fade-background-rgb
ion-picker,css-prop,--highlight-background
ion-picker,css-prop,--highlight-border-radius
@@ -910,6 +981,7 @@ ion-picker-column,shadow
ion-picker-column,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,'primary',false,true
ion-picker-column,prop,disabled,boolean,false,false,false
ion-picker-column,prop,mode,"ios" | "md",undefined,false,false
ion-picker-column,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-picker-column,prop,value,number | string | undefined,undefined,false,false
ion-picker-column,method,setFocus,setFocus() => Promise<void>
ion-picker-column,event,ionChange,PickerColumnChangeEventDetail,true
@@ -917,6 +989,8 @@ ion-picker-column,event,ionChange,PickerColumnChangeEventDetail,true
ion-picker-column-option,shadow
ion-picker-column-option,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,'primary',false,true
ion-picker-column-option,prop,disabled,boolean,false,false,false
ion-picker-column-option,prop,mode,"ios" | "md",undefined,false,false
ion-picker-column-option,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-picker-column-option,prop,value,any,undefined,false,false
ion-picker-legacy,scoped
@@ -933,6 +1007,7 @@ ion-picker-legacy,prop,keyboardClose,boolean,true,false,false
ion-picker-legacy,prop,leaveAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-picker-legacy,prop,mode,"ios" | "md",undefined,false,false
ion-picker-legacy,prop,showBackdrop,boolean,true,false,false
ion-picker-legacy,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-picker-legacy,prop,trigger,string | undefined,undefined,false,false
ion-picker-legacy,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
ion-picker-legacy,method,getColumn,getColumn(name: string) => Promise<PickerColumn | undefined>
@@ -981,6 +1056,7 @@ ion-popover,prop,reference,"event" | "trigger",'trigger',false,false
ion-popover,prop,showBackdrop,boolean,true,false,false
ion-popover,prop,side,"bottom" | "end" | "left" | "right" | "start" | "top",'bottom',false,false
ion-popover,prop,size,"auto" | "cover",'auto',false,false
ion-popover,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-popover,prop,translucent,boolean,false,false,false
ion-popover,prop,trigger,string | undefined,undefined,false,false
ion-popover,prop,triggerAction,"click" | "context-menu" | "hover",'click',false,false
@@ -1016,6 +1092,7 @@ ion-progress-bar,prop,buffer,number,1,false,false
ion-progress-bar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-progress-bar,prop,mode,"ios" | "md",undefined,false,false
ion-progress-bar,prop,reversed,boolean,false,false,false
ion-progress-bar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-progress-bar,prop,type,"determinate" | "indeterminate",'determinate',false,false
ion-progress-bar,prop,value,number,0,false,false
ion-progress-bar,css-prop,--background
@@ -1032,6 +1109,7 @@ ion-radio,prop,justify,"end" | "space-between" | "start",'space-between',false,f
ion-radio,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',false,false
ion-radio,prop,mode,"ios" | "md",undefined,false,false
ion-radio,prop,name,string,this.inputId,false,false
ion-radio,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-radio,prop,value,any,undefined,false,false
ion-radio,event,ionBlur,void,true
ion-radio,event,ionFocus,void,true
@@ -1046,7 +1124,9 @@ ion-radio,part,mark
ion-radio-group,none
ion-radio-group,prop,allowEmptySelection,boolean,false,false,false
ion-radio-group,prop,compareWith,((currentValue: any, compareValue: any) => boolean) | null | string | undefined,undefined,false,false
ion-radio-group,prop,mode,"ios" | "md",undefined,false,false
ion-radio-group,prop,name,string,this.inputId,false,false
ion-radio-group,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-radio-group,prop,value,any,undefined,false,false
ion-radio-group,event,ionChange,RadioGroupChangeEventDetail<any>,true
@@ -1066,6 +1146,7 @@ ion-range,prop,pin,boolean,false,false,false
ion-range,prop,pinFormatter,(value: number) => string | number,(value: number): number => Math.round(value),false,false
ion-range,prop,snaps,boolean,false,false,false
ion-range,prop,step,number,1,false,false
ion-range,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-range,prop,ticks,boolean,true,false,false
ion-range,prop,value,number | { lower: number; upper: number; },0,false,false
ion-range,event,ionBlur,void,true
@@ -1101,6 +1182,7 @@ ion-refresher,prop,pullFactor,number,1,false,false
ion-refresher,prop,pullMax,number,this.pullMin + 60,false,false
ion-refresher,prop,pullMin,number,60,false,false
ion-refresher,prop,snapbackDuration,string,'280ms',false,false
ion-refresher,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-refresher,method,cancel,cancel() => Promise<void>
ion-refresher,method,complete,complete() => Promise<void>
ion-refresher,method,getProgress,getProgress() => Promise<number>
@@ -1109,20 +1191,28 @@ ion-refresher,event,ionRefresh,RefresherEventDetail,true
ion-refresher,event,ionStart,void,true
ion-refresher-content,none
ion-refresher-content,prop,mode,"ios" | "md",undefined,false,false
ion-refresher-content,prop,pullingIcon,null | string | undefined,undefined,false,false
ion-refresher-content,prop,pullingText,IonicSafeString | string | undefined,undefined,false,false
ion-refresher-content,prop,refreshingSpinner,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-sharp" | "lines-sharp-small" | "lines-small" | null | undefined,undefined,false,false
ion-refresher-content,prop,refreshingText,IonicSafeString | string | undefined,undefined,false,false
ion-refresher-content,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-reorder,shadow
ion-reorder,prop,mode,"ios" | "md",undefined,false,false
ion-reorder,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-reorder,part,icon
ion-reorder-group,none
ion-reorder-group,prop,disabled,boolean,true,false,false
ion-reorder-group,prop,mode,"ios" | "md",undefined,false,false
ion-reorder-group,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-reorder-group,method,complete,complete(listOrReorder?: boolean | any[]) => Promise<any>
ion-reorder-group,event,ionItemReorder,ItemReorderEventDetail,true
ion-ripple-effect,shadow
ion-ripple-effect,prop,mode,"ios" | "md",undefined,false,false
ion-ripple-effect,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-ripple-effect,prop,type,"bounded" | "unbounded",'bounded',false,false
ion-ripple-effect,method,addRipple,addRipple(x: number, y: number) => Promise<() => void>
@@ -1131,6 +1221,8 @@ ion-route,prop,beforeEnter,(() => NavigationHookResult | Promise<NavigationHookR
ion-route,prop,beforeLeave,(() => NavigationHookResult | Promise<NavigationHookResult>) | undefined,undefined,false,false
ion-route,prop,component,string,undefined,true,false
ion-route,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false
ion-route,prop,mode,"ios" | "md",undefined,false,false
ion-route,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-route,prop,url,string,'',false,false
ion-route,event,ionRouteDataChanged,any,true
@@ -1140,7 +1232,9 @@ ion-route-redirect,prop,to,null | string | undefined,undefined,true,false
ion-route-redirect,event,ionRouteRedirectChanged,any,true
ion-router,none
ion-router,prop,mode,"ios" | "md",undefined,false,false
ion-router,prop,root,string,'/',false,false
ion-router,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-router,prop,useHash,boolean,true,false,false
ion-router,method,back,back() => Promise<void>
ion-router,method,push,push(path: string, direction?: RouterDirection, animation?: AnimationBuilder) => Promise<boolean>
@@ -1150,10 +1244,12 @@ ion-router,event,ionRouteWillChange,RouterEventDetail,true
ion-router-link,shadow
ion-router-link,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-router-link,prop,href,string | undefined,undefined,false,false
ion-router-link,prop,mode,"ios" | "md",undefined,false,false
ion-router-link,prop,rel,string | undefined,undefined,false,false
ion-router-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-router-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-router-link,prop,target,string | undefined,undefined,false,false
ion-router-link,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-router-link,css-prop,--background
ion-router-link,css-prop,--color
@@ -1161,8 +1257,11 @@ ion-router-outlet,shadow
ion-router-outlet,prop,animated,boolean,true,false,false
ion-router-outlet,prop,animation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-router-outlet,prop,mode,"ios" | "md",getIonMode(this),false,false
ion-router-outlet,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-row,shadow
ion-row,prop,mode,"ios" | "md",undefined,false,false
ion-row,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-searchbar,scoped
ion-searchbar,prop,animated,boolean,false,false,false
@@ -1186,6 +1285,7 @@ ion-searchbar,prop,searchIcon,string | undefined,undefined,false,false
ion-searchbar,prop,showCancelButton,"always" | "focus" | "never",'never',false,false
ion-searchbar,prop,showClearButton,"always" | "focus" | "never",'always',false,false
ion-searchbar,prop,spellcheck,boolean,false,false,false
ion-searchbar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-searchbar,prop,type,"email" | "number" | "password" | "search" | "tel" | "text" | "url",'search',false,false
ion-searchbar,prop,value,null | string | undefined,'',false,false
ion-searchbar,method,getInputElement,getInputElement() => Promise<HTMLInputElement>
@@ -1215,6 +1315,7 @@ ion-segment,prop,mode,"ios" | "md",undefined,false,false
ion-segment,prop,scrollable,boolean,false,false,false
ion-segment,prop,selectOnFocus,boolean,false,false,false
ion-segment,prop,swipeGesture,boolean,true,false,false
ion-segment,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-segment,prop,value,number | string | undefined,undefined,false,false
ion-segment,event,ionChange,SegmentChangeEventDetail,true
ion-segment,css-prop,--background
@@ -1223,6 +1324,7 @@ ion-segment-button,shadow
ion-segment-button,prop,disabled,boolean,false,false,false
ion-segment-button,prop,layout,"icon-bottom" | "icon-end" | "icon-hide" | "icon-start" | "icon-top" | "label-hide" | undefined,'icon-top',false,false
ion-segment-button,prop,mode,"ios" | "md",undefined,false,false
ion-segment-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-segment-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-segment-button,prop,value,number | string,'ion-sb-' + ids++,false,false
ion-segment-button,css-prop,--background
@@ -1276,6 +1378,7 @@ ion-select,prop,okText,string,'OK',false,false
ion-select,prop,placeholder,string | undefined,undefined,false,false
ion-select,prop,selectedText,null | string | undefined,undefined,false,false
ion-select,prop,shape,"round" | undefined,undefined,false,false
ion-select,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-select,prop,toggleIcon,string | undefined,undefined,false,false
ion-select,prop,value,any,undefined,false,false
ion-select,method,open,open(event?: UIEvent) => Promise<any>
@@ -1308,10 +1411,14 @@ ion-select,part,text
ion-select-option,shadow
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
ion-select-option,prop,value,any,undefined,false,false
ion-skeleton-text,shadow
ion-skeleton-text,prop,animated,boolean,false,false,false
ion-skeleton-text,prop,mode,"ios" | "md",undefined,false,false
ion-skeleton-text,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-skeleton-text,css-prop,--background
ion-skeleton-text,css-prop,--background-rgb
ion-skeleton-text,css-prop,--border-radius
@@ -1319,13 +1426,17 @@ ion-skeleton-text,css-prop,--border-radius
ion-spinner,shadow
ion-spinner,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-spinner,prop,duration,number | undefined,undefined,false,false
ion-spinner,prop,mode,"ios" | "md",undefined,false,false
ion-spinner,prop,name,"bubbles" | "circles" | "circular" | "crescent" | "dots" | "lines" | "lines-sharp" | "lines-sharp-small" | "lines-small" | undefined,undefined,false,false
ion-spinner,prop,paused,boolean,false,false,false
ion-spinner,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-spinner,css-prop,--color
ion-split-pane,shadow
ion-split-pane,prop,contentId,string | undefined,undefined,false,true
ion-split-pane,prop,disabled,boolean,false,false,false
ion-split-pane,prop,mode,"ios" | "md",undefined,false,false
ion-split-pane,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-split-pane,prop,when,boolean | string,QUERY['lg'],false,false
ion-split-pane,event,ionSplitPaneVisible,{ visible: boolean; },true
ion-split-pane,css-prop,--border
@@ -1335,13 +1446,16 @@ ion-split-pane,css-prop,--side-width
ion-tab,shadow
ion-tab,prop,component,Function | HTMLElement | null | string | undefined,undefined,false,false
ion-tab,prop,mode,"ios" | "md",undefined,false,false
ion-tab,prop,tab,string,undefined,true,false
ion-tab,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-tab,method,setActive,setActive() => Promise<void>
ion-tab-bar,shadow
ion-tab-bar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-tab-bar,prop,mode,"ios" | "md",undefined,false,false
ion-tab-bar,prop,selectedTab,string | undefined,undefined,false,false
ion-tab-bar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-tab-bar,prop,translucent,boolean,false,false,false
ion-tab-bar,css-prop,--background
ion-tab-bar,css-prop,--border
@@ -1357,6 +1471,7 @@ ion-tab-button,prop,rel,string | undefined,undefined,false,false
ion-tab-button,prop,selected,boolean,false,false,false
ion-tab-button,prop,tab,string | undefined,undefined,false,false
ion-tab-button,prop,target,string | undefined,undefined,false,false
ion-tab-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-tab-button,css-prop,--background
ion-tab-button,css-prop,--background-focused
ion-tab-button,css-prop,--background-focused-opacity
@@ -1371,6 +1486,8 @@ ion-tab-button,css-prop,--ripple-color
ion-tab-button,part,native
ion-tabs,shadow
ion-tabs,prop,mode,"ios" | "md",undefined,false,false
ion-tabs,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-tabs,method,getSelected,getSelected() => Promise<string | undefined>
ion-tabs,method,getTab,getTab(tab: string | HTMLIonTabElement) => Promise<HTMLIonTabElement | undefined>
ion-tabs,method,select,select(tab: string | HTMLIonTabElement) => Promise<boolean>
@@ -1380,6 +1497,7 @@ ion-tabs,event,ionTabsWillChange,{ tab: string; },false
ion-text,shadow
ion-text,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-text,prop,mode,"ios" | "md",undefined,false,false
ion-text,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-textarea,scoped
ion-textarea,prop,autoGrow,boolean,false,false,true
@@ -1409,6 +1527,7 @@ ion-textarea,prop,required,boolean,false,false,false
ion-textarea,prop,rows,number | undefined,undefined,false,false
ion-textarea,prop,shape,"round" | undefined,undefined,false,false
ion-textarea,prop,spellcheck,boolean,false,false,false
ion-textarea,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-textarea,prop,value,null | string | undefined,'',false,false
ion-textarea,prop,wrap,"hard" | "off" | "soft" | undefined,undefined,false,false
ion-textarea,method,getInputElement,getInputElement() => Promise<HTMLTextAreaElement>
@@ -1437,12 +1556,16 @@ ion-textarea,css-prop,--placeholder-font-weight
ion-textarea,css-prop,--placeholder-opacity
ion-thumbnail,shadow
ion-thumbnail,prop,mode,"ios" | "md",undefined,false,false
ion-thumbnail,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-thumbnail,css-prop,--border-radius
ion-thumbnail,css-prop,--size
ion-title,shadow
ion-title,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-title,prop,mode,"ios" | "md",undefined,false,false
ion-title,prop,size,"large" | "small" | undefined,undefined,false,false
ion-title,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-title,css-prop,--color
ion-toast,shadow
@@ -1464,6 +1587,7 @@ ion-toast,prop,mode,"ios" | "md",undefined,false,false
ion-toast,prop,position,"bottom" | "middle" | "top",'bottom',false,false
ion-toast,prop,positionAnchor,HTMLElement | string | undefined,undefined,false,false
ion-toast,prop,swipeGesture,"vertical" | undefined,undefined,false,false
ion-toast,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-toast,prop,translucent,boolean,false,false,false
ion-toast,prop,trigger,string | undefined,undefined,false,false
ion-toast,method,dismiss,dismiss(data?: any, role?: string) => Promise<boolean>
@@ -1512,6 +1636,7 @@ ion-toggle,prop,justify,"end" | "space-between" | "start",'space-between',false,
ion-toggle,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',false,false
ion-toggle,prop,mode,"ios" | "md",undefined,false,false
ion-toggle,prop,name,string,this.inputId,false,false
ion-toggle,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-toggle,prop,value,null | string | undefined,'on',false,false
ion-toggle,event,ionBlur,void,true
ion-toggle,event,ionChange,ToggleChangeEventDetail<any>,true
@@ -1535,6 +1660,7 @@ ion-toggle,part,track
ion-toolbar,shadow
ion-toolbar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-toolbar,prop,mode,"ios" | "md",undefined,false,false
ion-toolbar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-toolbar,css-prop,--background
ion-toolbar,css-prop,--border-color
ion-toolbar,css-prop,--border-style

1392
core/src/components.d.ts vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -2,18 +2,20 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Listen, Method, Prop, Watch, h } from '@stencil/core';
import { printIonWarning } from '@utils/logging';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AccordionGroupChangeEventDetail } from './accordion-group-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-accordion-group',
styleUrls: {
ios: 'accordion-group.ios.scss',
md: 'accordion-group.md.scss',
ionic: 'accordion-group.md.scss',
},
shadow: true,
})
@@ -279,12 +281,12 @@ export class AccordionGroup implements ComponentInterface {
render() {
const { disabled, readonly, expand } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'accordion-group-disabled': disabled,
'accordion-group-readonly': readonly,
[`accordion-group-expand-${expand}`]: true,

View File

@@ -4,7 +4,7 @@ import { addEventListener, getElementRoot, raf, removeEventListener, transitionE
import { chevronDown } from 'ionicons/icons';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
const enum AccordionState {
Collapsed = 1 << 0,
@@ -14,7 +14,8 @@ const enum AccordionState {
}
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot header - Content is placed at the top and is used to
* expand or collapse the accordion item.
@@ -31,6 +32,7 @@ const enum AccordionState {
styleUrls: {
ios: 'accordion.ios.scss',
md: 'accordion.md.scss',
ionic: 'accordion.md.scss',
},
shadow: {
delegatesFocus: true,
@@ -402,7 +404,7 @@ export class Accordion implements ComponentInterface {
render() {
const { disabled, readonly } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const expanded = this.state === AccordionState.Expanded || this.state === AccordionState.Expanding;
const headerPart = expanded ? 'header expanded' : 'header';
const contentPart = expanded ? 'content expanded' : 'content';
@@ -412,7 +414,7 @@ export class Accordion implements ComponentInterface {
return (
<Host
class={{
[mode]: true,
[theme]: true,
'accordion-expanding': this.state === AccordionState.Expanding,
'accordion-expanded': this.state === AccordionState.Expanded,
'accordion-collapsing': this.state === AccordionState.Collapsing,

View File

@@ -1,20 +1,16 @@
import type { AnimationBuilder, LiteralUnion, Mode } from '../../interface';
import type { OverlayOptions } from '@utils/overlays-interface';
export interface ActionSheetOptions {
import type { LiteralUnion } from '../../interface';
export interface ActionSheetOptions extends OverlayOptions {
header?: string;
subHeader?: string;
cssClass?: string | string[];
buttons: (ActionSheetButton | string)[];
backdropDismiss?: boolean;
translucent?: boolean;
animated?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: { [key: string]: any };
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
export interface ActionSheetButton<T = any> {

View File

@@ -18,7 +18,7 @@ import {
} from '@utils/overlays';
import { getClassMap } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, CssClassMap, FrameworkDelegate, OverlayInterface } from '../../interface';
import type { OverlayEventDetail } from '../../utils/overlays-interface';
@@ -29,13 +29,15 @@ import { mdEnterAnimation } from './animations/md.enter';
import { mdLeaveAnimation } from './animations/md.leave';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-action-sheet',
styleUrls: {
ios: 'action-sheet.ios.scss',
md: 'action-sheet.md.scss',
ionic: 'action-sheet.md.scss',
},
scoped: true,
})
@@ -105,7 +107,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
/**
* If `true`, the action sheet will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
@Prop() translucent = false;
@@ -314,6 +316,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
}
componentDidLoad() {
const mode = getIonMode(this);
/**
* Only create gesture if:
* 1. A gesture does not already exist
@@ -322,7 +325,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
* 4. A group ref exists
*/
const { groupEl, wrapperEl } = this;
if (!this.gesture && getIonMode(this) === 'ios' && wrapperEl && groupEl) {
if (!this.gesture && mode === 'ios' && wrapperEl && groupEl) {
readTask(() => {
const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
if (!isScrollable) {
@@ -356,7 +359,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
render() {
const { header, htmlAttributes, overlayIndex } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const allButtons = this.getButtons();
const cancelButton = allButtons.find((b) => b.role === 'cancel');
const buttons = allButtons.filter((b) => b.role !== 'cancel');
@@ -373,7 +376,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
zIndex: `${20000 + this.overlayIndex}`,
}}
class={{
[mode]: true,
[theme]: true,
...getClassMap(this.cssClass),
'overlay-hidden': true,
'action-sheet-translucent': this.translucent,
@@ -413,7 +416,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
{b.icon && <ion-icon icon={b.icon} aria-hidden="true" lazy={false} class="action-sheet-icon" />}
{b.text}
</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
))}
</div>
@@ -437,7 +440,7 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
)}
{cancelButton.text}
</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
</div>
)}

View File

@@ -1,7 +1,9 @@
import type { AnimationBuilder, LiteralUnion, Mode, TextFieldTypes } from '../../interface';
import type { OverlayOptions } from '@utils/overlays-interface';
import type { LiteralUnion, TextFieldTypes } from '../../interface';
import type { IonicSafeString } from '../../utils/sanitization';
export interface AlertOptions {
export interface AlertOptions extends OverlayOptions {
header?: string;
subHeader?: string;
message?: string | IonicSafeString;
@@ -10,15 +12,9 @@ export interface AlertOptions {
buttons?: (AlertButton | string)[];
backdropDismiss?: boolean;
translucent?: boolean;
animated?: boolean;
htmlAttributes?: { [key: string]: any };
mode?: Mode;
keyboardClose?: boolean;
id?: string;
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}
export interface AlertInput {

View File

@@ -21,7 +21,7 @@ import { sanitizeDOMString } from '@utils/sanitization';
import { getClassMap } from '@utils/theme';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, CssClassMap, OverlayInterface, FrameworkDelegate } from '../../interface';
import type { OverlayEventDetail } from '../../utils/overlays-interface';
import type { IonicSafeString } from '../../utils/sanitization';
@@ -35,13 +35,15 @@ import { mdLeaveAnimation } from './animations/md.leave';
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-alert',
styleUrls: {
ios: 'alert.ios.scss',
md: 'alert.md.scss',
ionic: 'alert.md.scss',
},
scoped: true,
})
@@ -135,7 +137,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
/**
* If `true`, the alert will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
@Prop() translucent = false;
@@ -533,7 +535,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
private renderCheckbox() {
const inputs = this.processedInputs;
const mode = getIonMode(this);
const theme = getIonTheme(this);
if (inputs.length === 0) {
return null;
@@ -565,7 +567,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
</div>
<div class="alert-checkbox-label">{i.label}</div>
</div>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
))}
</div>
@@ -682,7 +684,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
private renderAlertButtons() {
const buttons = this.processedButtons;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const alertButtonGroupClass = {
'alert-button-group': true,
'alert-button-group-vertical': buttons.length > 2,
@@ -699,7 +701,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
onClick={() => this.buttonClick(button)}
>
<span class="alert-button-inner">{button.text}</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
))}
</div>
@@ -721,7 +723,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
render() {
const { overlayIndex, header, subHeader, message, htmlAttributes } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const hdrId = `alert-${overlayIndex}-hdr`;
const subHdrId = `alert-${overlayIndex}-sub-hdr`;
const msgId = `alert-${overlayIndex}-msg`;
@@ -746,7 +748,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
}}
class={{
...getClassMap(this.cssClass),
[mode]: true,
[theme]: true,
'overlay-hidden': true,
'alert-translucent': this.translucent,
}}

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -6,8 +6,12 @@ import { printIonWarning } from '@utils/logging';
import { isPlatform } from '@utils/platform';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-app',
styleUrl: 'app.scss',
@@ -78,11 +82,11 @@ export class App implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'ion-page': true,
'force-statusbar-padding': config.getBoolean('_forceStatusbarPadding'),
}}

View File

@@ -1,20 +1,30 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-avatar',
styleUrls: {
ios: 'avatar.ios.scss',
md: 'avatar.md.scss',
ionic: 'avatar.md.scss',
},
shadow: true,
})
export class Avatar implements ComponentInterface {
render() {
const theme = getIonTheme(this);
return (
<Host class={getIonMode(this)}>
<Host
class={{
[theme]: true,
}}
>
<slot></slot>
</Host>
);

View File

@@ -7,11 +7,12 @@ import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { arrowBackSharp, chevronBack } from 'ionicons/icons';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part native - The native HTML button element that wraps all child elements.
* @part icon - The back button icon (uses ion-icon).
@@ -22,6 +23,7 @@ import type { AnimationBuilder, Color } from '../../interface';
styleUrls: {
ios: 'back-button.ios.scss',
md: 'back-button.md.scss',
ionic: 'back-button.md.scss',
},
shadow: true,
})
@@ -84,7 +86,7 @@ export class BackButton implements ComponentInterface, ButtonInterface {
return icon;
}
if (getIonMode(this) === 'ios') {
if (getIonTheme(this) === 'ios') {
// default ios back button icon
return config.get('backButtonIcon', chevronBack);
}
@@ -94,7 +96,7 @@ export class BackButton implements ComponentInterface, ButtonInterface {
}
get backButtonText() {
const defaultBackButtonText = getIonMode(this) === 'ios' ? 'Back' : null;
const defaultBackButtonText = getIonTheme(this) === 'ios' ? 'Back' : null;
return this.text != null ? this.text : config.get('backButtonText', defaultBackButtonText);
}
@@ -135,14 +137,14 @@ export class BackButton implements ComponentInterface, ButtonInterface {
inheritedAttributes,
} = this;
const showBackButton = defaultHref !== undefined;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const ariaLabel = inheritedAttributes['aria-label'] || backButtonText || 'back';
return (
<Host
onClick={this.onClick}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
button: true, // ion-buttons target .button
'back-button-disabled': disabled,
'back-button-has-icon-only': hasIconOnly,
@@ -170,7 +172,7 @@ export class BackButton implements ComponentInterface, ButtonInterface {
</span>
)}
</span>
{mode === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
</button>
</Host>
);

View File

@@ -1,13 +1,18 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Event, Host, Listen, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-backdrop',
styleUrls: {
ios: 'backdrop.ios.scss',
md: 'backdrop.md.scss',
ionic: 'backdrop.md.scss',
},
shadow: true,
})
@@ -48,13 +53,13 @@ export class Backdrop implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
tabindex="-1"
aria-hidden="true"
class={{
[mode]: true,
[theme]: true,
'backdrop-hide': !this.visible,
'backdrop-no-tappable': !this.tappable,
}}

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-badge',
styleUrls: {
ios: 'badge.ios.scss',
md: 'badge.md.scss',
ionic: 'badge.md.scss',
},
shadow: true,
})
@@ -25,11 +27,11 @@ export class Badge implements ComponentInterface {
@Prop({ reflect: true }) color?: Color;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
})}
>
<slot></slot>

View File

@@ -5,14 +5,15 @@ import { inheritAriaAttributes } from '@utils/helpers';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { chevronForwardOutline, ellipsisHorizontal } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
import type { RouterDirection } from '../router/utils/interface';
import type { BreadcrumbCollapsedClickEventDetail } from './breadcrumb-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part native - The native HTML anchor or div element that wraps all child elements.
* @part separator - The separator element between each breadcrumb.
@@ -23,6 +24,7 @@ import type { BreadcrumbCollapsedClickEventDetail } from './breadcrumb-interface
styleUrls: {
ios: 'breadcrumb.ios.scss',
md: 'breadcrumb.md.scss',
ionic: 'breadcrumb.md.scss',
},
shadow: true,
})
@@ -168,7 +170,7 @@ export class Breadcrumb implements ComponentInterface {
// Links can still be tabbed to when set to disabled if they have an href
// in order to truly disable them we can keep it as an anchor but remove the href
const href = disabled ? undefined : this.href;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const attrs =
TagType === 'span'
? {}
@@ -188,7 +190,7 @@ export class Breadcrumb implements ComponentInterface {
onClick={(ev: Event) => openURL(href, ev, routerDirection, routerAnimation)}
aria-disabled={disabled ? 'true' : null}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
'breadcrumb-active': active,
'breadcrumb-collapsed': collapsed,
'breadcrumb-disabled': disabled,
@@ -233,7 +235,7 @@ export class Breadcrumb implements ComponentInterface {
*/
<span class="breadcrumb-separator" part="separator" aria-hidden="true">
<slot name="separator">
{mode === 'ios' ? (
{theme === 'ios' ? (
<ion-icon icon={chevronForwardOutline} lazy={false} flip-rtl></ion-icon>
) : (
<span>/</span>

View File

@@ -2,19 +2,20 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Listen, Prop, State, Watch, h } from '@stencil/core';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
import type { BreadcrumbCollapsedClickEventDetail } from '../breadcrumb/breadcrumb-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-breadcrumbs',
styleUrls: {
ios: 'breadcrumbs.ios.scss',
md: 'breadcrumbs.md.scss',
ionic: 'breadcrumbs.md.scss',
},
shadow: true,
})
@@ -170,12 +171,12 @@ export class Breadcrumbs implements ComponentInterface {
render() {
const { color, collapsed } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'breadcrumbs-collapsed': collapsed,

View File

@@ -6,12 +6,13 @@ import { inheritAriaAttributes, hasShadowDom } from '@utils/helpers';
import { printIonWarning } from '@utils/logging';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
import type { RouterDirection } from '../router/utils/interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot icon-only - Should be used on an icon in a button that has no text.
@@ -25,6 +26,7 @@ import type { RouterDirection } from '../router/utils/interface';
styleUrls: {
ios: 'button.ios.scss',
md: 'button.md.scss',
ionic: 'button.md.scss',
},
shadow: true,
})
@@ -313,7 +315,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
};
render() {
const mode = getIonMode(this);
const {
buttonType,
type,
@@ -329,6 +330,8 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
strong,
inheritedAttributes,
} = this;
const theme = getIonTheme(this);
const finalSize = size === undefined && this.inItem ? 'small' : size;
const TagType = href === undefined ? 'button' : ('a' as any);
const attrs =
@@ -365,7 +368,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
onClick={this.handleClick}
aria-disabled={disabled ? 'true' : null}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
[buttonType]: true,
[`${buttonType}-${expand}`]: expand !== undefined,
[`${buttonType}-${finalSize}`]: finalSize !== undefined,
@@ -396,7 +399,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
<slot></slot>
<slot name="end"></slot>
</span>
{mode === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect type={this.rippleType}></ion-ripple-effect>}
</TagType>
</Host>
);

View File

@@ -1,13 +1,18 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-buttons',
styleUrls: {
ios: 'buttons.ios.scss',
md: 'buttons.md.scss',
ionic: 'buttons.md.scss',
},
scoped: true,
})
@@ -19,7 +24,7 @@ export class Buttons implements ComponentInterface {
* first toolbar, the buttons will be hidden and will
* only be shown once all toolbars have fully collapsed.
*
* Only applies in `ios` mode with `collapse` set to
* Only applies in the `ios` theme with `collapse` set to
* `true` on `ion-header`.
*
* Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
@@ -27,11 +32,11 @@ export class Buttons implements ComponentInterface {
@Prop() collapse = false;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
['buttons-collapse']: this.collapse,
}}
>

View File

@@ -1,28 +1,30 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-card-content',
styleUrls: {
ios: 'card-content.ios.scss',
md: 'card-content.md.scss',
ionic: 'card-content.md.scss',
},
})
export class CardContent implements ComponentInterface {
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`card-content-${mode}`]: true,
[`card-content-${theme}`]: true,
}}
></Host>
);

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-card-header',
styleUrls: {
ios: 'card-header.ios.scss',
md: 'card-header.md.scss',
ionic: 'card-header.md.scss',
},
shadow: true,
})
@@ -26,19 +28,19 @@ export class CardHeader implements ComponentInterface {
/**
* If `true`, the card header will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
@Prop() translucent = false;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
'card-header-translucent': this.translucent,
'ion-inherit-color': true,
[mode]: true,
[theme]: true,
})}
>
<slot></slot>

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-card-subtitle',
styleUrls: {
ios: 'card-subtitle.ios.scss',
md: 'card-subtitle.md.scss',
ionic: 'card-subtitle.md.scss',
},
shadow: true,
})
@@ -25,14 +27,14 @@ export class CardSubtitle implements ComponentInterface {
@Prop({ reflect: true }) color?: Color;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
role="heading"
aria-level="3"
class={createColorClasses(this.color, {
'ion-inherit-color': true,
[mode]: true,
[theme]: true,
})}
>
<slot></slot>

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-card-title',
styleUrls: {
ios: 'card-title.ios.scss',
md: 'card-title.md.scss',
ionic: 'card-title.md.scss',
},
shadow: true,
})
@@ -25,14 +27,14 @@ export class CardTitle implements ComponentInterface {
@Prop({ reflect: true }) color?: Color;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
role="heading"
aria-level="2"
class={createColorClasses(this.color, {
'ion-inherit-color': true,
[mode]: true,
[theme]: true,
})}
>
<slot></slot>

View File

@@ -5,12 +5,13 @@ import type { Attributes } from '@utils/helpers';
import { inheritAttributes } from '@utils/helpers';
import { createColorClasses, openURL } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import type { AnimationBuilder, Color, Mode } from '../../interface';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color, Theme } from '../../interface';
import type { RouterDirection } from '../router/utils/interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part native - The native HTML button, anchor, or div element that wraps all child elements.
*/
@@ -19,6 +20,7 @@ import type { RouterDirection } from '../router/utils/interface';
styleUrls: {
ios: 'card.ios.scss',
md: 'card.md.scss',
ionic: 'card.md.scss',
},
shadow: true,
})
@@ -95,7 +97,7 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
return this.href !== undefined || this.button;
}
private renderCard(mode: Mode) {
private renderCard(theme: Theme) {
const clickable = this.isClickable();
if (!clickable) {
@@ -123,22 +125,23 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
onClick={(ev: Event) => openURL(href, ev, routerDirection, routerAnimation)}
>
<slot></slot>
{clickable && mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{clickable && theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</TagType>
);
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'card-disabled': this.disabled,
'ion-activatable': this.isClickable(),
})}
>
{this.renderCard(mode)}
{this.renderCard(theme)}
</Host>
);
}

View File

@@ -4,13 +4,14 @@ import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes, renderHiddenInput } from '@utils/helpers';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import type { Color, Mode } from '../../interface';
import { getIonTheme } from '../../global/ionic-global';
import type { Color, Theme } from '../../interface';
import type { CheckboxChangeEventDetail } from './checkbox-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - The label text to associate with the checkbox. Use the "labelPlacement" property to control where the label is placed relative to the checkbox.
*
@@ -23,6 +24,7 @@ import type { CheckboxChangeEventDetail } from './checkbox-interface';
styleUrls: {
ios: 'checkbox.ios.scss',
md: 'checkbox.md.scss',
ionic: 'checkbox.md.scss',
},
shadow: true,
})
@@ -180,8 +182,9 @@ export class Checkbox implements ComponentInterface {
value,
alignment,
} = this;
const mode = getIonMode(this);
const path = getSVGPath(mode, indeterminate);
const theme = getIonTheme(this);
const path = getSVGPath(theme, indeterminate);
renderHiddenInput(true, el, name, checked ? value : '', disabled);
@@ -189,7 +192,7 @@ export class Checkbox implements ComponentInterface {
<Host
aria-checked={indeterminate ? 'mixed' : `${checked}`}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
'in-item': hostContext('ion-item', el),
'checkbox-checked': checked,
'checkbox-disabled': disabled,
@@ -236,14 +239,14 @@ export class Checkbox implements ComponentInterface {
);
}
private getSVGPath(mode: Mode, indeterminate: boolean): HTMLElement {
private getSVGPath(theme: Theme, indeterminate: boolean): HTMLElement {
let path = indeterminate ? (
<path d="M6 12L18 12" part="mark" />
) : (
<path d="M5.9,12.5l3.8,3.8l8.8-8.8" part="mark" />
);
if (mode === 'md') {
if (theme === 'md') {
path = indeterminate ? (
<path d="M2 12H22" part="mark" />
) : (

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-chip',
styleUrls: {
ios: 'chip.ios.scss',
md: 'chip.md.scss',
ionic: 'chip.md.scss',
},
shadow: true,
})
@@ -35,20 +37,20 @@ export class Chip implements ComponentInterface {
@Prop() disabled = false;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
aria-disabled={this.disabled ? 'true' : null}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'chip-outline': this.outline,
'chip-disabled': this.disabled,
'ion-activatable': true,
})}
>
<slot></slot>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</Host>
);
}

View File

@@ -2,13 +2,17 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Listen, Prop, forceUpdate, h } from '@stencil/core';
import { matchBreakpoint } from '@utils/media';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
const win = typeof (window as any) !== 'undefined' ? (window as any) : undefined;
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const SUPPORTS_VARS = win && !!(win.CSS && win.CSS.supports && win.CSS.supports('--a: 0'));
const BREAKPOINTS = ['', 'xs', 'sm', 'md', 'lg', 'xl'];
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-col',
styleUrl: 'col.scss',
@@ -249,11 +253,11 @@ export class Col implements ComponentInterface {
render() {
const isRTL = document.dir === 'rtl';
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
}}
style={{
...this.calculateOffset(isRTL),

View File

@@ -5,12 +5,15 @@ import { isPlatform } from '@utils/platform';
import { isRTL } from '@utils/rtl';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import type { Color } from '../../interface';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { Color, Mode } from '../../interface';
import type { ScrollBaseDetail, ScrollDetail } from './content-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed in the scrollable area if provided without a slot.
* @slot fixed - Should be used for fixed content that should not scroll.
*
@@ -214,9 +217,8 @@ export class Content implements ComponentInterface {
}, 100);
}
private shouldForceOverscroll() {
private shouldForceOverscroll(mode: Mode) {
const { forceOverscroll } = this;
const mode = getIonMode(this);
return forceOverscroll === undefined ? mode === 'ios' && isPlatform('ios') : forceOverscroll;
}
@@ -425,9 +427,10 @@ export class Content implements ComponentInterface {
render() {
const { isMainContent, scrollX, scrollY, el } = this;
const rtl = isRTL(el) ? 'rtl' : 'ltr';
const mode = getIonMode(this);
const forceOverscroll = this.shouldForceOverscroll();
const transitionShadow = mode === 'ios';
const theme = getIonTheme(this);
const mode = getIonMode(this, theme);
const forceOverscroll = this.shouldForceOverscroll(mode);
const transitionShadow = theme === 'ios';
this.resize();
@@ -435,7 +438,7 @@ export class Content implements ComponentInterface {
<Host
role={isMainContent ? 'main' : undefined}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'content-sizing': hostContext('ion-popover', this.el),
overscroll: forceOverscroll,
[`content-${rtl}`]: true,

View File

@@ -4,7 +4,7 @@ import { componentOnReady, addEventListener } from '@utils/helpers';
import { printIonError } from '@utils/logging';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
import type { DatetimePresentation } from '../datetime/datetime-interface';
import { getToday } from '../datetime/utils/data';
@@ -12,7 +12,8 @@ import { getLocalizedDateTime, getLocalizedTime } from '../datetime/utils/format
import { getHourCycle } from '../datetime/utils/helpers';
import { parseDate } from '../datetime/utils/parse';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot date-target - Content displayed inside of the date button.
* @slot time-target - Content displayed inside of the time button.
@@ -24,6 +25,7 @@ import { parseDate } from '../datetime/utils/parse';
styleUrls: {
ios: 'datetime-button.ios.scss',
md: 'datetime-button.md.scss',
ionic: 'datetime-button.md.scss',
},
shadow: true,
})
@@ -425,12 +427,12 @@ export class DatetimeButton implements ComponentInterface {
render() {
const { color, dateText, timeText, selectedButton, datetimeActive, disabled } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
[`${selectedButton}-active`]: datetimeActive,
['datetime-button-disabled']: disabled,
})}
@@ -446,7 +448,7 @@ export class DatetimeButton implements ComponentInterface {
ref={(el) => (this.dateTargetEl = el)}
>
<slot name="date-target">{dateText}</slot>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
)}
@@ -461,7 +463,7 @@ export class DatetimeButton implements ComponentInterface {
ref={(el) => (this.timeTargetEl = el)}
>
<slot name="time-target">{timeText}</slot>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
)}
</Host>

View File

@@ -7,8 +7,8 @@ import { isRTL } from '@utils/rtl';
import { createColorClasses } from '@utils/theme';
import { caretDownSharp, caretUpSharp, chevronBack, chevronDown, chevronForward } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import type { Color, Mode, StyleEventDetail } from '../../interface';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { Color, StyleEventDetail, Theme } from '../../interface';
import type {
DatetimePresentation,
@@ -72,7 +72,8 @@ import {
import { checkForPresentationFormatMismatch, warnIfTimeZoneProvided } from './utils/validate';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot title - The title of the datetime.
* @slot buttons - The buttons in the datetime.
@@ -100,6 +101,7 @@ import { checkForPresentationFormatMismatch, warnIfTimeZoneProvided } from './ut
styleUrls: {
ios: 'datetime.ios.scss',
md: 'datetime.md.scss',
ionic: 'datetime.md.scss',
},
shadow: true,
})
@@ -2102,10 +2104,10 @@ export class Datetime implements ComponentInterface {
* Grid Render Methods
*/
private renderCalendarHeader(mode: Mode) {
private renderCalendarHeader(theme: Theme) {
const { disabled } = this;
const expandedIcon = mode === 'ios' ? chevronDown : caretUpSharp;
const collapsedIcon = mode === 'ios' ? chevronForward : caretDownSharp;
const expandedIcon = theme === 'ios' ? chevronDown : caretUpSharp;
const collapsedIcon = theme === 'ios' ? chevronForward : caretDownSharp;
const prevMonthDisabled = disabled || isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
const nextMonthDisabled = disabled || isNextMonthDisabled(this.workingParts, this.maxParts);
@@ -2137,7 +2139,7 @@ export class Datetime implements ComponentInterface {
flipRtl={true}
></ion-icon>
</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
</div>
@@ -2167,7 +2169,7 @@ export class Datetime implements ComponentInterface {
</div>
</div>
<div class="calendar-days-of-week" aria-hidden="true">
{getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map((d) => {
{getDaysOfWeek(this.locale, theme, this.firstDayOfWeek % 7).map((d) => {
return <div class="day-of-week">{d}</div>;
})}
</div>
@@ -2374,10 +2376,10 @@ export class Datetime implements ComponentInterface {
</div>
);
}
private renderCalendar(mode: Mode) {
private renderCalendar(theme: Theme) {
return (
<div class="datetime-calendar" key="datetime-calendar">
{this.renderCalendarHeader(mode)}
{this.renderCalendarHeader(theme)}
{this.renderCalendarBody()}
</div>
);
@@ -2536,7 +2538,7 @@ export class Datetime implements ComponentInterface {
* All presentation types are rendered from here.
*/
private renderDatetime(mode: Mode) {
private renderDatetime(theme: Theme) {
const { presentation, preferWheel } = this;
/**
@@ -2552,7 +2554,7 @@ export class Datetime implements ComponentInterface {
case 'date-time':
return [
this.renderHeader(),
this.renderCalendar(mode),
this.renderCalendar(theme),
this.renderCalendarViewMonthYearPicker(),
this.renderTime(),
this.renderFooter(),
@@ -2561,7 +2563,7 @@ export class Datetime implements ComponentInterface {
return [
this.renderHeader(),
this.renderTime(),
this.renderCalendar(mode),
this.renderCalendar(theme),
this.renderCalendarViewMonthYearPicker(),
this.renderFooter(),
];
@@ -2574,7 +2576,7 @@ export class Datetime implements ComponentInterface {
default:
return [
this.renderHeader(),
this.renderCalendar(mode),
this.renderCalendar(theme),
this.renderCalendarViewMonthYearPicker(),
this.renderFooter(),
];
@@ -2595,7 +2597,7 @@ export class Datetime implements ComponentInterface {
size,
isGridStyle,
} = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const isMonthAndYearPresentation =
presentation === 'year' || presentation === 'month' || presentation === 'month-year';
const shouldShowMonthAndYear = showMonthAndYear || isMonthAndYearPresentation;
@@ -2612,7 +2614,7 @@ export class Datetime implements ComponentInterface {
onBlur={this.onBlur}
class={{
...createColorClasses(color, {
[mode]: true,
[theme]: true,
['datetime-readonly']: readonly,
['datetime-disabled']: disabled,
'show-month-and-year': shouldShowMonthAndYear,
@@ -2638,7 +2640,7 @@ export class Datetime implements ComponentInterface {
otherwise the IO callback may fire at unexpected times.
*/}
<div class="intersection-tracker" ref={(el) => (this.intersectionTrackerRef = el)}></div>
{this.renderDatetime(mode)}
{this.renderDatetime(theme)}
</Host>
);
}

View File

@@ -1,4 +1,4 @@
import type { Mode } from '../../../interface';
import type { Theme } from '../../../interface';
import type { DatetimeParts, DatetimeHourCycle } from '../datetime-interface';
import { isAfter, isBefore, isSameDay } from './comparison';
@@ -63,20 +63,20 @@ const hour23 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
const hour24 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0];
/**
* Given a locale and a mode,
* Given a locale and a theme,
* return an array with formatted days
* of the week. iOS should display days
* such as "Mon" or "Tue".
* MD should display days such as "M"
* or "T".
*/
export const getDaysOfWeek = (locale: string, mode: Mode, firstDayOfWeek = 0) => {
export const getDaysOfWeek = (locale: string, theme: Theme, firstDayOfWeek = 0) => {
/**
* Nov 1st, 2020 starts on a Sunday.
* ion-datetime assumes weeks start on Sunday,
* but is configurable via `firstDayOfWeek`.
*/
const weekdayFormat = mode === 'ios' ? 'short' : 'narrow';
const weekdayFormat = theme === 'ios' ? 'short' : 'narrow';
const intl = new Intl.DateTimeFormat(locale, { weekday: weekdayFormat });
const startDate = new Date('11/01/2020');
const daysOfWeek = [];

View File

@@ -6,12 +6,13 @@ import type { Attributes } from '@utils/helpers';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { close } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
import type { RouterDirection } from '../router/utils/interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part native - The native HTML button or anchor element that wraps all child elements.
* @part close-icon - The close icon that is displayed when a fab list opens (uses ion-icon).
@@ -21,6 +22,7 @@ import type { RouterDirection } from '../router/utils/interface';
styleUrls: {
ios: 'fab-button.ios.scss',
md: 'fab-button.md.scss',
ionic: 'fab-button.md.scss',
},
shadow: true,
})
@@ -93,7 +95,7 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt
/**
* If `true`, the fab button will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
@Prop() translucent = false;
@@ -153,7 +155,7 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt
render() {
const { el, disabled, color, href, activated, show, translucent, size, inheritedAttributes } = this;
const inList = hostContext('ion-fab-list', el);
const mode = getIonMode(this);
const theme = getIonTheme(this);
const TagType = href === undefined ? 'button' : ('a' as any);
const attrs =
TagType === 'button'
@@ -170,7 +172,7 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt
onClick={this.onClick}
aria-disabled={disabled ? 'true' : null}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
'fab-button-in-list': inList,
'fab-button-translucent-in-list': inList && translucent,
'fab-button-close-active': activated,
@@ -202,7 +204,7 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt
<span class="button-inner">
<slot></slot>
</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</TagType>
</Host>
);

View File

@@ -1,8 +1,12 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, Watch, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-fab-list',
styleUrl: 'fab-list.scss',
@@ -33,11 +37,11 @@ export class FabList implements ComponentInterface {
@Prop() side: 'start' | 'end' | 'top' | 'bottom' = 'bottom';
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'fab-list-active': this.activated,
[`fab-list-side-${this.side}`]: true,
}}

View File

@@ -1,8 +1,12 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Method, Prop, Watch, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-fab',
styleUrl: 'fab.scss',
@@ -76,11 +80,11 @@ export class Fab implements ComponentInterface {
render() {
const { horizontal, vertical, edge } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
[`fab-horizontal-${horizontal}`]: horizontal !== undefined,
[`fab-vertical-${vertical}`]: vertical !== undefined,
'fab-edge': edge,

View File

@@ -4,18 +4,20 @@ import { findIonContent, getScrollElement, printIonContentErrorMsg } from '@util
import type { KeyboardController } from '@utils/keyboard/keyboard-controller';
import { createKeyboardController } from '@utils/keyboard/keyboard-controller';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import { handleFooterFade } from './footer.utils';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-footer',
styleUrls: {
ios: 'footer.ios.scss',
md: 'footer.md.scss',
ionic: 'footer.md.scss',
},
})
export class Footer implements ComponentInterface {
@@ -29,13 +31,13 @@ export class Footer implements ComponentInterface {
/**
* Describes the scroll effect that will be applied to the footer.
* Only applies in iOS mode.
* Only applies when the theme is `"ios"`.
*/
@Prop() collapse?: 'fade';
/**
* If `true`, the footer will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*
* Note: In order to scroll content behind the footer, the `fullscreen`
@@ -73,8 +75,8 @@ export class Footer implements ComponentInterface {
}
private checkCollapsibleFooter = () => {
const mode = getIonMode(this);
if (mode !== 'ios') {
const theme = getIonTheme(this);
if (theme !== 'ios') {
return;
}
@@ -119,7 +121,7 @@ export class Footer implements ComponentInterface {
render() {
const { translucent, collapse } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const tabs = this.el.closest('ion-tabs');
const tabBar = tabs?.querySelector(':scope > ion-tab-bar');
@@ -127,19 +129,19 @@ export class Footer implements ComponentInterface {
<Host
role="contentinfo"
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`footer-${mode}`]: true,
[`footer-${theme}`]: true,
[`footer-translucent`]: translucent,
[`footer-translucent-${mode}`]: translucent,
[`footer-translucent-${theme}`]: translucent,
['footer-toolbar-padding']: !this.keyboardVisible && (!tabBar || tabBar.slot !== 'bottom'),
[`footer-collapse-${collapse}`]: collapse !== undefined,
}}
>
{mode === 'ios' && translucent && <div class="footer-background"></div>}
{theme === 'ios' && translucent && <div class="footer-background"></div>}
<slot></slot>
</Host>
);

View File

@@ -1,8 +1,12 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-grid',
styleUrl: 'grid.scss',
@@ -15,11 +19,11 @@ export class Grid implements ComponentInterface {
@Prop() fixed = false;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'grid-fixed': this.fixed,
}}
>

View File

@@ -5,7 +5,7 @@ import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes } from '@utils/helpers';
import { hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import {
cloneElement,
@@ -18,13 +18,15 @@ import {
} from './header.utils';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-header',
styleUrls: {
ios: 'header.ios.scss',
md: 'header.md.scss',
ionic: 'header.md.scss',
},
})
export class Header implements ComponentInterface {
@@ -38,7 +40,7 @@ export class Header implements ComponentInterface {
/**
* Describes the scroll effect that will be applied to the header.
* Only applies in iOS mode.
* Only applies when the theme is `"ios"`.
*
* Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
*/
@@ -46,7 +48,7 @@ export class Header implements ComponentInterface {
/**
* If `true`, the header will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*
* Note: In order to scroll content behind the header, the `fullscreen`
@@ -71,9 +73,9 @@ export class Header implements ComponentInterface {
}
private async checkCollapsibleHeader() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
if (mode !== 'ios') {
if (theme !== 'ios') {
return;
}
@@ -206,7 +208,7 @@ export class Header implements ComponentInterface {
render() {
const { translucent, inheritedAttributes } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const collapse = this.collapse || 'none';
// banner role must be at top level, so remove role if inside a menu
@@ -216,18 +218,18 @@ export class Header implements ComponentInterface {
<Host
role={roleType}
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`header-${mode}`]: true,
[`header-${theme}`]: true,
[`header-translucent`]: this.translucent,
[`header-collapse-${collapse}`]: true,
[`header-translucent-${mode}`]: this.translucent,
[`header-translucent-${theme}`]: this.translucent,
}}
{...inheritedAttributes}
>
{mode === 'ios' && translucent && <div class="header-background"></div>}
{theme === 'ios' && translucent && <div class="header-background"></div>}
<slot></slot>
</Host>
);

View File

@@ -3,9 +3,12 @@ import { Component, Element, Event, Host, Prop, State, Watch, h } from '@stencil
import type { Attributes } from '@utils/helpers';
import { inheritAttributes } from '@utils/helpers';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part image - The inner `img` element.
*/
@Component({
@@ -110,8 +113,13 @@ export class Img implements ComponentInterface {
render() {
const { loadSrc, alt, onLoad, loadError, inheritedAttributes } = this;
const { draggable } = inheritedAttributes;
const theme = getIonTheme(this);
return (
<Host class={getIonMode(this)}>
<Host
class={{
[theme]: true,
}}
>
<img
decoding="async"
src={loadSrc}

View File

@@ -4,15 +4,20 @@ import { ENABLE_HTML_CONTENT_DEFAULT } from '@utils/config';
import { sanitizeDOMString } from '@utils/sanitization';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { IonicSafeString } from '../../utils/sanitization';
import type { SpinnerTypes } from '../spinner/spinner-configs';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-infinite-scroll-content',
styleUrls: {
ios: 'infinite-scroll-content.ios.scss',
md: 'infinite-scroll-content.md.scss',
ionic: 'infinite-scroll-content.md.scss',
},
})
export class InfiniteScrollContent implements ComponentInterface {
@@ -41,10 +46,10 @@ export class InfiniteScrollContent implements ComponentInterface {
componentDidLoad() {
if (this.loadingSpinner === undefined) {
const mode = getIonMode(this);
const theme = getIonTheme(this);
this.loadingSpinner = config.get(
'infiniteLoadingSpinner',
config.get('spinner', mode === 'ios' ? 'lines' : 'crescent')
config.get('spinner', theme === 'ios' ? 'lines' : 'crescent')
);
}
}
@@ -59,14 +64,14 @@ export class InfiniteScrollContent implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`infinite-scroll-content-${mode}`]: true,
[`infinite-scroll-content-${theme}`]: true,
}}
>
<div class="infinite-loading">

View File

@@ -2,8 +2,12 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Method, Prop, State, Watch, h, readTask, writeTask } from '@stencil/core';
import { findClosestIonContent, getScrollElement, printIonContentErrorMsg } from '@utils/content';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-infinite-scroll',
styleUrl: 'infinite-scroll.scss',
@@ -221,12 +225,12 @@ export class InfiniteScroll implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const disabled = this.disabled;
return (
<Host
class={{
[mode]: true,
[theme]: true,
'infinite-scroll-loading': this.isLoading,
'infinite-scroll-enabled': !disabled,
}}

View File

@@ -9,14 +9,15 @@ import type { SlotMutationController } from '@utils/slot-mutation-controller';
import { createColorClasses, hostContext } from '@utils/theme';
import { closeCircle, closeSharp } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AutocompleteTypes, Color, TextFieldTypes } from '../../interface';
import type { InputChangeEventDetail, InputInputEventDetail } from './input-interface';
import { getCounterText } from './input.utils';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot label - The label text to associate with the input. Use the `labelPlacement` property to control where the label is placed relative to the input. Use this if you need to render a label with custom HTML. (EXPERIMENTAL)
* @slot start - Content to display at the leading edge of the input. (EXPERIMENTAL)
@@ -27,6 +28,7 @@ import { getCounterText } from './input.utils';
styleUrls: {
ios: 'input.ios.scss',
md: 'input.md.scss',
ionic: 'input.md.scss',
},
scoped: true,
})
@@ -146,7 +148,7 @@ export class Input implements ComponentInterface {
/**
* 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 in `md` mode.
* `"outline"` the item will be transparent with a border. Only available when the theme is `"md"`.
*/
@Prop() fill?: 'outline' | 'solid';
@@ -621,8 +623,8 @@ export class Input implements ComponentInterface {
* when fill="outline".
*/
private renderLabelContainer() {
const mode = getIonMode(this);
const hasOutlineFill = mode === 'md' && this.fill === 'outline';
const theme = getIonTheme(this);
const hasOutlineFill = theme === 'md' && this.fill === 'outline';
if (hasOutlineFill) {
/**
@@ -660,10 +662,10 @@ export class Input implements ComponentInterface {
render() {
const { disabled, fill, readonly, shape, inputId, labelPlacement, el, hasFocus } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const value = this.getValue();
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
const shouldRenderHighlight = theme === 'md' && fill !== 'outline' && !inItem;
const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
@@ -691,7 +693,7 @@ export class Input implements ComponentInterface {
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'has-value': hasValue,
'has-focus': hasFocus,
'label-floating': labelShouldFloat,
@@ -762,7 +764,7 @@ export class Input implements ComponentInterface {
}}
onClick={this.clearTextInput}
>
<ion-icon aria-hidden="true" icon={mode === 'ios' ? closeCircle : closeSharp}></ion-icon>
<ion-icon aria-hidden="true" icon={theme === 'ios' ? closeCircle : closeSharp}></ion-icon>
</button>
)}
<slot name="end"></slot>

View File

@@ -2,11 +2,12 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the divider text in LTR, and to the right in RTL.
@@ -17,6 +18,7 @@ import type { Color } from '../../interface';
styleUrls: {
ios: 'item-divider.ios.scss',
md: 'item-divider.md.scss',
ionic: 'item-divider.md.scss',
},
shadow: true,
})
@@ -40,11 +42,11 @@ export class ItemDivider implements ComponentInterface {
@Prop() sticky = false;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'item-divider-sticky': this.sticky,
item: true,
})}

View File

@@ -1,26 +1,31 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-item-group',
styleUrls: {
ios: 'item-group.ios.scss',
md: 'item-group.md.scss',
ionic: 'item-group.md.scss',
},
})
export class ItemGroup implements ComponentInterface {
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
role="group"
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`item-group-${mode}`]: true,
[`item-group-${theme}`]: true,
item: true,
}}

View File

@@ -3,11 +3,12 @@ import { Component, Element, Host, Prop, h } from '@stencil/core';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the option text in LTR, and to the right in RTL.
@@ -23,6 +24,7 @@ import type { Color } from '../../interface';
styleUrls: {
ios: 'item-option.ios.scss',
md: 'item-option.md.scss',
ionic: 'item-option.md.scss',
},
shadow: true,
})
@@ -88,7 +90,7 @@ export class ItemOption implements ComponentInterface, AnchorInterface, ButtonIn
render() {
const { disabled, expandable, href } = this;
const TagType = href === undefined ? 'button' : ('a' as any);
const mode = getIonMode(this);
const theme = getIonTheme(this);
const attrs =
TagType === 'button'
? { type: this.type }
@@ -102,7 +104,7 @@ export class ItemOption implements ComponentInterface, AnchorInterface, ButtonIn
<Host
onClick={this.onClick}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'item-option-disabled': disabled,
'item-option-expandable': expandable,
'ion-activatable': true,
@@ -119,7 +121,7 @@ export class ItemOption implements ComponentInterface, AnchorInterface, ButtonIn
</div>
<slot name="bottom"></slot>
</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</TagType>
</Host>
);

View File

@@ -2,14 +2,19 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Method, Prop, h } from '@stencil/core';
import { isEndSide } from '@utils/helpers';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Side } from '../menu/menu-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-item-options',
styleUrls: {
ios: 'item-options.ios.scss',
md: 'item-options.md.scss',
ionic: 'item-options.md.scss',
},
})
export class ItemOptions implements ComponentInterface {
@@ -35,15 +40,15 @@ export class ItemOptions implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const isEnd = isEndSide(this.side);
return (
<Host
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`item-options-${mode}`]: true,
[`item-options-${theme}`]: true,
/**
* Note: The "start" and "end" terms refer to the

View File

@@ -4,7 +4,7 @@ import { findClosestIonContent, disableContentScrollY, resetContentScrollY } fro
import { isEndSide } from '@utils/helpers';
import { watchForOptions } from '@utils/watch-options';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Gesture, GestureDetail } from '../../interface';
import type { Side } from '../menu/menu-interface';
@@ -30,6 +30,10 @@ const enum SlidingState {
let openSlidingItem: HTMLIonItemSlidingElement | undefined;
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-item-sliding',
styleUrl: 'item-sliding.scss',
@@ -482,11 +486,11 @@ export class ItemSliding implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'item-sliding-active-slide': this.state !== SlidingState.Disabled,
'item-sliding-active-options-end': (this.state & SlidingState.End) !== 0,
'item-sliding-active-options-start': (this.state & SlidingState.Start) !== 0,

View File

@@ -6,12 +6,13 @@ import { inheritAttributes, raf } from '@utils/helpers';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { chevronForward } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color, CssClassMap, StyleEventDetail } from '../../interface';
import type { RouterDirection } from '../router/utils/interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the item text in LTR, and to the right in RTL.
@@ -25,6 +26,7 @@ import type { RouterDirection } from '../router/utils/interface';
styleUrls: {
ios: 'item.ios.scss',
md: 'item.md.scss',
ionic: 'item.md.scss',
},
shadow: true,
})
@@ -51,8 +53,8 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
@Prop() button = false;
/**
* If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `mode`
* is `ios` and an `href` or `button` property is present.
* If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `theme`
* is `"ios"` and an `href` or `button` property is present.
*/
@Prop() detail?: boolean;
@@ -256,7 +258,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
multipleInputs,
} = this;
const childStyles = {} as StyleEventDetail;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const clickable = this.isClickable();
const canActivate = this.canActivate();
const TagType = clickable ? (href === undefined ? 'button' : 'a') : ('div' as any);
@@ -314,7 +316,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
};
}
const showDetail = detail !== undefined ? detail : mode === 'ios' && clickable;
const showDetail = detail !== undefined ? detail : theme === 'ios' && clickable;
this.itemStyles.forEach((value) => {
Object.assign(childStyles, value);
});
@@ -336,7 +338,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
...labelColorStyles,
...createColorClasses(this.color, {
item: true,
[mode]: true,
[theme]: true,
'item-lines-default': lines === undefined,
[`item-lines-${lines}`]: lines !== undefined,
'item-control-needs-pointer-cursor': firstInteractiveNeedsPointerCursor,
@@ -375,7 +377,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
></ion-icon>
)}
</div>
{canActivate && mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{canActivate && theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</TagType>
</Host>
);

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, State, Watch, h } from '@stencil/core';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color, StyleEventDetail } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-label',
styleUrls: {
ios: 'label.ios.scss',
md: 'label.md.scss',
ionic: 'label.md.scss',
},
scoped: true,
})
@@ -97,11 +99,11 @@ export class Label implements ComponentInterface {
render() {
const position = this.position;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'in-item-color': hostContext('ion-item.ion-color', this.el),
[`label-${position}`]: position !== undefined,
[`label-no-animate`]: this.noAnimate,

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-list-header',
styleUrls: {
ios: 'list-header.ios.scss',
md: 'list-header.md.scss',
ionic: 'list-header.md.scss',
},
shadow: true,
})
@@ -31,12 +33,12 @@ export class ListHeader implements ComponentInterface {
render() {
const { lines } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
[`list-header-lines-${lines}`]: lines !== undefined,
})}
>

View File

@@ -1,16 +1,18 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Method, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-list',
styleUrls: {
ios: 'list.ios.scss',
md: 'list.md.scss',
ionic: 'list.md.scss',
},
})
export class List implements ComponentInterface {
@@ -42,20 +44,20 @@ export class List implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const { lines, inset } = this;
return (
<Host
role="list"
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`list-${mode}`]: true,
[`list-${theme}`]: true,
'list-inset': inset,
[`list-lines-${lines}`]: lines !== undefined,
[`list-${mode}-lines-${lines}`]: lines !== undefined,
[`list-${theme}-lines-${lines}`]: lines !== undefined,
}}
></Host>
);

View File

@@ -1,21 +1,16 @@
import type { AnimationBuilder, Mode } from '../../interface';
import type { OverlayOptions } from '@utils/overlays-interface';
import type { IonicSafeString } from '../../utils/sanitization';
import type { SpinnerTypes } from '../spinner/spinner-configs';
export interface LoadingOptions {
export interface LoadingOptions extends OverlayOptions {
spinner?: SpinnerTypes | null;
message?: string | IonicSafeString;
cssClass?: string | string[];
showBackdrop?: boolean;
duration?: number;
translucent?: boolean;
animated?: boolean;
backdropDismiss?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: { [key: string]: any };
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
}

View File

@@ -17,7 +17,7 @@ import { sanitizeDOMString } from '@utils/sanitization';
import { getClassMap } from '@utils/theme';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, FrameworkDelegate, OverlayInterface } from '../../interface';
import type { OverlayEventDetail } from '../../utils/overlays-interface';
import type { IonicSafeString } from '../../utils/sanitization';
@@ -31,13 +31,15 @@ import { mdLeaveAnimation } from './animations/md.leave';
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-loading',
styleUrls: {
ios: 'loading.ios.scss',
md: 'loading.md.scss',
ionic: 'loading.md.scss',
},
scoped: true,
})
@@ -115,7 +117,7 @@ export class Loading implements ComponentInterface, OverlayInterface {
/**
* If `true`, the loading indicator will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
@Prop() translucent = false;
@@ -211,8 +213,8 @@ export class Loading implements ComponentInterface, OverlayInterface {
componentWillLoad() {
if (this.spinner === undefined) {
const mode = getIonMode(this);
this.spinner = config.get('loadingSpinner', config.get('spinner', mode === 'ios' ? 'lines' : 'crescent'));
const theme = getIonTheme(this);
this.spinner = config.get('loadingSpinner', config.get('spinner', theme === 'ios' ? 'lines' : 'crescent'));
}
setOverlayId(this.el);
}
@@ -326,7 +328,7 @@ export class Loading implements ComponentInterface, OverlayInterface {
render() {
const { message, spinner, htmlAttributes, overlayIndex } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const msgId = `loading-${overlayIndex}-msg`;
/**
* If the message is defined, use that as the label.
@@ -347,7 +349,7 @@ export class Loading implements ComponentInterface, OverlayInterface {
onIonBackdropTap={this.onBackdropTap}
class={{
...getClassMap(this.cssClass),
[mode]: true,
[theme]: true,
'overlay-hidden': true,
'loading-translucent': this.translucent,
}}

View File

@@ -8,12 +8,13 @@ import { createColorClasses, hostContext } from '@utils/theme';
import { menuOutline, menuSharp } from 'ionicons/icons';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
import { updateVisibility } from '../menu-toggle/menu-toggle-util';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part native - The native HTML button element that wraps all child elements.
* @part icon - The menu button icon (uses ion-icon).
@@ -23,6 +24,7 @@ import { updateVisibility } from '../menu-toggle/menu-toggle-util';
styleUrls: {
ios: 'menu-button.ios.scss',
md: 'menu-button.md.scss',
ionic: 'menu-button.md.scss',
},
shadow: true,
})
@@ -80,8 +82,8 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
render() {
const { color, disabled, inheritedAttributes } = this;
const mode = getIonMode(this);
const menuIcon = config.get('menuIcon', mode === 'ios' ? menuOutline : menuSharp);
const theme = getIonTheme(this);
const menuIcon = config.get('menuIcon', theme === 'ios' ? menuOutline : menuSharp);
const hidden = this.autoHide && !this.visible;
const attrs = {
@@ -96,7 +98,7 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
aria-disabled={disabled ? 'true' : null}
aria-hidden={hidden ? 'true' : null}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
button: true, // ion-buttons target .button
'menu-button-hidden': hidden,
'menu-button-disabled': disabled,
@@ -109,10 +111,10 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
<button {...attrs} disabled={disabled} class="button-native" part="native" aria-label={ariaLabel}>
<span class="button-inner">
<slot>
<ion-icon part="icon" icon={menuIcon} mode={mode} lazy={false} aria-hidden="true"></ion-icon>
<ion-icon part="icon" icon={menuIcon} lazy={false} aria-hidden="true"></ion-icon>
</slot>
</span>
{mode === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
</button>
</Host>
);

View File

@@ -2,11 +2,14 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Listen, Prop, State, h } from '@stencil/core';
import { menuController } from '@utils/menu-controller';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import { updateVisibility } from './menu-toggle-util';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed inside the toggle to act as the click target.
*/
@Component({
@@ -50,7 +53,7 @@ export class MenuToggle implements ComponentInterface {
};
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const hidden = this.autoHide && !this.visible;
return (
@@ -58,7 +61,7 @@ export class MenuToggle implements ComponentInterface {
onClick={this.onClick}
aria-hidden={hidden ? 'true' : null}
class={{
[mode]: true,
[theme]: true,
'menu-toggle-hidden': hidden,
}}
>

View File

@@ -11,7 +11,7 @@ import { getPresentedOverlay } from '@utils/overlays';
import { hostContext } from '@utils/theme';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { Animation, Gesture, GestureDetail } from '../../interface';
import type { MenuChangeEventDetail, MenuI, MenuType, Side } from './menu-interface';
@@ -22,6 +22,9 @@ const iosEasingReverse = 'cubic-bezier(1, 0, 0.68, 0.28)';
const mdEasingReverse = 'cubic-bezier(0.4, 0, 0.6, 1)';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part container - The container for the menu content.
* @part backdrop - The backdrop that appears over the main content when the menu is open.
*/
@@ -30,6 +33,7 @@ const mdEasingReverse = 'cubic-bezier(0.4, 0, 0.6, 1)';
styleUrls: {
ios: 'menu.ios.scss',
md: 'menu.md.scss',
ionic: 'menu.md.scss',
},
shadow: true,
})
@@ -773,7 +777,7 @@ export class Menu implements ComponentInterface, MenuI {
render() {
const { type, disabled, el, isPaneVisible, inheritedAttributes, side } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
/**
* If the Close Watcher is enabled then
@@ -786,7 +790,7 @@ export class Menu implements ComponentInterface, MenuI {
role="navigation"
aria-label={inheritedAttributes['aria-label'] || 'menu'}
class={{
[mode]: true,
[theme]: true,
[`menu-type-${type}`]: true,
'menu-enabled': !disabled,
[`menu-side-${side}`]: true,

View File

@@ -1,6 +1,8 @@
import type { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode } from '../../interface';
import type { OverlayOptions } from '@utils/overlays-interface';
export interface ModalOptions<T extends ComponentRef = ComponentRef> {
import type { ComponentProps, ComponentRef, FrameworkDelegate } from '../../interface';
export interface ModalOptions<T extends ComponentRef = ComponentRef> extends OverlayOptions {
component: T;
componentProps?: ComponentProps<T>;
presentingElement?: HTMLElement;
@@ -8,17 +10,10 @@ export interface ModalOptions<T extends ComponentRef = ComponentRef> {
backdropDismiss?: boolean;
cssClass?: string | string[];
delegate?: FrameworkDelegate;
animated?: boolean;
canDismiss?: boolean | ((data?: any, role?: string) => Promise<boolean>);
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: { [key: string]: any };
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
breakpoints?: number[];
initialBreakpoint?: number;
backdropBreakpoint?: number;

View File

@@ -21,7 +21,7 @@ import { getClassMap } from '@utils/theme';
import { deepReady, waitForMount } from '@utils/transition';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type {
Animation,
AnimationBuilder,
@@ -47,7 +47,8 @@ import { setCardStatusBarDark, setCardStatusBarDefault } from './utils';
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed inside of the `.modal-content` element.
*
@@ -60,6 +61,7 @@ import { setCardStatusBarDark, setCardStatusBarDefault } from './utils';
styleUrls: {
ios: 'modal.ios.scss',
md: 'modal.md.scss',
ionic: 'modal.md.scss',
},
shadow: true,
})
@@ -908,8 +910,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes } = this;
const showHandle = handle !== false && isSheetModal;
const mode = getIonMode(this);
const isCardModal = presentingElement !== undefined && mode === 'ios';
const theme = getIonTheme(this);
const isCardModal = presentingElement !== undefined && theme === 'ios';
const isHandleCycle = handleBehavior === 'cycle';
return (
@@ -921,7 +923,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
zIndex: `${20000 + this.overlayIndex}`,
}}
class={{
[mode]: true,
[theme]: true,
['modal-default']: !isCardModal && !isSheetModal,
[`modal-card`]: isCardModal,
[`modal-sheet`]: isSheetModal,
@@ -941,7 +943,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
part="backdrop"
/>
{mode === 'ios' && <div class="modal-shadow"></div>}
{theme === 'ios' && <div class="modal-shadow"></div>}
<div
/*

View File

@@ -7,6 +7,10 @@ import type { RouterDirection } from '../router/utils/interface';
import { navLink } from './nav-link-utils';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-nav-link',
})

View File

@@ -1,4 +1,4 @@
import type { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode } from '../../interface';
import type { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate, Mode, Theme } from '../../interface';
import type { ViewController } from './view-controller';
@@ -34,7 +34,15 @@ export interface RouterOutletOptions {
showGoBack?: boolean;
direction?: NavDirection;
deepWait?: boolean;
/**
* To change the default appearance of the component, use the `theme` option.
* Mode is used to change the platform behavior of the component.
*/
mode?: Mode;
/**
* The theme determines the visual appearance of the component.
*/
theme?: Theme;
keyboardClose?: boolean;
skipIfBusy?: boolean;
progressAnimation?: boolean;

View File

@@ -7,7 +7,7 @@ import type { TransitionOptions } from '@utils/transition';
import { lifecycle, setPageHidden, transition } from '@utils/transition';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { Animation, AnimationBuilder, ComponentProps, FrameworkDelegate, Gesture } from '../../interface';
import type { NavOutlet, RouteID, RouteWrite, RouterDirection } from '../router/utils/interface';
@@ -23,6 +23,10 @@ import type {
import type { ViewController } from './view-controller';
import { VIEW_STATE_ATTACHED, VIEW_STATE_DESTROYED, VIEW_STATE_NEW, convertToViews, matches } from './view-controller';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-nav',
styleUrl: 'nav.scss',
@@ -61,7 +65,7 @@ export class Nav implements NavOutlet {
@Prop() animated = true;
/**
* By default `ion-nav` animates transition between pages based in the mode (ios or material design).
* By default `ion-nav` animates transition between pages based on the mode ("ios" or "md").
* However, this property allows to create custom transition using `AnimationBuilder` functions.
*/
@Prop() animation?: AnimationBuilder;
@@ -903,12 +907,14 @@ export class Nav implements NavOutlet {
}
}
: undefined;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const mode = getIonMode(this, theme);
const enteringEl = enteringView.element!;
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const leavingEl = leavingView && leavingView.element!;
const animationOpts: TransitionOptions = {
mode,
theme,
showGoBack: this.canGoBackSync(enteringView),
baseEl: this.el,
progressCallback,

View File

@@ -2,17 +2,19 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-note',
styleUrls: {
ios: 'note.ios.scss',
md: 'note.md.scss',
ionic: 'note.md.scss',
},
shadow: true,
})
@@ -25,11 +27,11 @@ export class Note implements ComponentInterface {
@Prop({ reflect: true }) color?: Color;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
})}
>
<slot></slot>

View File

@@ -3,14 +3,19 @@ import { Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';
import { inheritAttributes } from '@utils/helpers';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-picker-column-option',
styleUrls: {
ios: 'picker-column-option.ios.scss',
md: 'picker-column-option.md.scss',
ionic: 'picker-column-option.md.scss',
},
shadow: true,
})
@@ -115,12 +120,12 @@ export class PickerColumnOption implements ComponentInterface {
render() {
const { color, disabled, ariaLabel } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
['option-disabled']: disabled,
})}
>

View File

@@ -5,15 +5,16 @@ import { getElementRoot, raf } from '@utils/helpers';
import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from '@utils/native/haptic';
import { isPlatform } from '@utils/platform';
import { createColorClasses } from '@utils/theme';
import { getIonTheme } from 'src/global/ionic-global';
import { getIonMode } from '../../global/ionic-global';
import type { Color } from '../../interface';
import type { PickerCustomEvent } from '../picker/picker-interfaces';
import type { PickerColumnChangeEventDetail, PickerColumnValue } from './picker-column-interfaces';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot prefix - Content to show on the left side of the picker options.
* @slot suffix - Content to show on the right side of the picker options.
@@ -483,12 +484,12 @@ export class PickerColumn implements ComponentInterface {
render() {
const { color, disabled, isActive, numericInput } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
['picker-column-active']: isActive,
['picker-column-numeric-input']: numericInput,
['picker-column-disabled']: disabled,

View File

@@ -4,7 +4,7 @@ import { clamp } from '@utils/helpers';
import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from '@utils/native/haptic';
import { getClassMap } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { Gesture, GestureDetail } from '../../interface';
import type { PickerColumn } from '../picker-legacy/picker-interface';
@@ -394,11 +394,11 @@ export class PickerColumnCmp implements ComponentInterface {
render() {
const col = this.col;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'picker-col': true,
'picker-opts-left': this.col.align === 'left',
'picker-opts-right': this.col.align === 'right',

View File

@@ -17,7 +17,7 @@ import {
} from '@utils/overlays';
import { getClassMap } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, CssClassMap, OverlayInterface, FrameworkDelegate } from '../../interface';
import type { OverlayEventDetail } from '../../utils/overlays-interface';
@@ -28,7 +28,8 @@ import type { PickerButton, PickerColumn } from './picker-interface';
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-picker-legacy',
@@ -351,7 +352,7 @@ export class Picker implements ComponentInterface, OverlayInterface {
render() {
const { htmlAttributes } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
aria-modal="true"
@@ -361,10 +362,10 @@ export class Picker implements ComponentInterface, OverlayInterface {
zIndex: `${20000 + this.overlayIndex}`,
}}
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`picker-${mode}`]: true,
[`picker-${theme}`]: true,
'overlay-hidden': true,
...getClassMap(this.cssClass),
}}

View File

@@ -5,13 +5,15 @@ import { getElementRoot } from '@utils/helpers';
import type { PickerChangeEventDetail } from './picker-interfaces';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-picker',
styleUrls: {
ios: 'picker.ios.scss',
md: 'picker.md.scss',
ionic: 'picker.md.scss',
},
shadow: true,
})

View File

@@ -1,17 +1,12 @@
import type {
AnimationBuilder,
ComponentProps,
ComponentRef,
FrameworkDelegate,
Mode,
OverlayInterface,
} from '../../interface';
import type { OverlayOptions } from '@utils/overlays-interface';
import type { ComponentProps, ComponentRef, FrameworkDelegate, OverlayInterface } from '../../interface';
export interface PopoverInterface extends OverlayInterface {
present: (event?: MouseEvent | TouchEvent | PointerEvent) => Promise<void>;
}
export interface PopoverOptions<T extends ComponentRef = ComponentRef> {
export interface PopoverOptions<T extends ComponentRef = ComponentRef> extends OverlayOptions {
component: T;
componentProps?: ComponentProps<T>;
showBackdrop?: boolean;
@@ -20,16 +15,9 @@ export interface PopoverOptions<T extends ComponentRef = ComponentRef> {
cssClass?: string | string[];
event?: Event;
delegate?: FrameworkDelegate;
animated?: boolean;
mode?: Mode;
keyboardClose?: boolean;
id?: string;
htmlAttributes?: { [key: string]: any };
enterAnimation?: AnimationBuilder;
leaveAnimation?: AnimationBuilder;
size?: PopoverSize;
dismissOnSelect?: boolean;
reference?: PositionReference;

View File

@@ -10,7 +10,7 @@ import { isPlatform } from '@utils/platform';
import { getClassMap } from '@utils/theme';
import { deepReady, waitForMount } from '@utils/transition';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, ComponentProps, ComponentRef, FrameworkDelegate } from '../../interface';
import type { OverlayEventDetail } from '../../utils/overlays-interface';
@@ -31,12 +31,13 @@ import { configureDismissInteraction, configureKeyboardInteraction, configureTri
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed inside of the `.popover-content` element.
*
* @part backdrop - The `ion-backdrop` element.
* @part arrow - The arrow that points to the reference element. Only applies on `ios` mode.
* @part arrow - The arrow that points to the reference element. Only applies on `"ios"` theme.
* @part content - The wrapper element for the default slot.
*/
@Component({
@@ -44,6 +45,7 @@ import { configureDismissInteraction, configureKeyboardInteraction, configureTri
styleUrls: {
ios: 'popover.ios.scss',
md: 'popover.md.scss',
ionic: 'popover.md.scss',
},
shadow: true,
})
@@ -136,7 +138,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
/**
* If `true`, the popover will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
@Prop() translucent = false;
@@ -204,13 +206,13 @@ export class Popover implements ComponentInterface, PopoverInterface {
/**
* Describes how to align the popover content with the `reference` point.
* Defaults to `"center"` for `ios` mode, and `"start"` for `md` mode.
* Defaults to `"center"` for `"ios"` theme, and `"start"` for `"md"` theme.
*/
@Prop({ mutable: true }) alignment?: PositionAlign;
/**
* If `true`, the popover will display an arrow that points at the
* `reference` when running in `ios` mode. Does not apply in `md` mode.
* `reference` on `"ios"` theme.
*/
@Prop() arrow = true;
@@ -343,7 +345,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
this.parentPopover = el.closest(`ion-popover:not(#${popoverId})`) as HTMLIonPopoverElement | null;
if (this.alignment === undefined) {
this.alignment = getIonMode(this) === 'ios' ? 'center' : 'start';
this.alignment = getIonTheme(this) === 'ios' ? 'center' : 'start';
}
}
@@ -655,7 +657,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
};
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const { onLifecycle, parentPopover, dismissOnSelect, side, arrow, htmlAttributes } = this;
const desktop = isPlatform('desktop');
const enableArrow = arrow && !parentPopover;
@@ -671,7 +673,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
}}
class={{
...getClassMap(this.cssClass),
[mode]: true,
[theme]: true,
'popover-translucent': this.translucent,
'overlay-hidden': true,
'popover-desktop': desktop,

View File

@@ -4,11 +4,12 @@ import { clamp } from '@utils/helpers';
import { createColorClasses } from '@utils/theme';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part progress - The progress bar that shows the current value when `type` is `"determinate"` and slides back and forth when `type` is `"indeterminate"`.
* @part stream - The animated circles that appear while buffering. This only shows when `buffer` is set and `type` is `"determinate"`.
@@ -20,6 +21,7 @@ import type { Color } from '../../interface';
styleUrls: {
ios: 'progress-bar.ios.scss',
md: 'progress-bar.md.scss',
ionic: 'progress-bar.md.scss',
},
shadow: true,
})
@@ -58,7 +60,7 @@ export class ProgressBar implements ComponentInterface {
render() {
const { color, type, reversed, value, buffer } = this;
const paused = config.getBoolean('_testing');
const mode = getIonMode(this);
const theme = getIonTheme(this);
// If the progress is displayed as a solid bar.
const progressSolid = buffer === 1;
return (
@@ -68,7 +70,7 @@ export class ProgressBar implements ComponentInterface {
aria-valuemin="0"
aria-valuemax="1"
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
[`progress-bar-${type}`]: true,
'progress-paused': paused,
'progress-bar-reversed': document.dir === 'rtl' ? !reversed : reversed,

View File

@@ -2,10 +2,14 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Listen, Prop, Watch, h } from '@stencil/core';
import { renderHiddenInput } from '@utils/helpers';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { RadioGroupChangeEventDetail, RadioGroupCompareFn } from './radio-group-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-radio-group',
})
@@ -215,11 +219,20 @@ export class RadioGroup implements ComponentInterface {
render() {
const { label, labelId, el, name, value } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
renderHiddenInput(true, el, name, value, false);
return <Host role="radiogroup" aria-labelledby={label ? labelId : null} onClick={this.onClick} class={mode}></Host>;
return (
<Host
class={{
[theme]: true,
}}
role="radiogroup"
aria-labelledby={label ? labelId : null}
onClick={this.onClick}
></Host>
);
}
}

View File

@@ -4,11 +4,12 @@ import { isOptionSelected } from '@utils/forms';
import { addEventListener, removeEventListener } from '@utils/helpers';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - The label text to associate with the radio. Use the "labelPlacement" property to control where the label is placed relative to the radio.
*
@@ -21,6 +22,7 @@ import type { Color } from '../../interface';
styleUrls: {
ios: 'radio.ios.scss',
md: 'radio.md.scss',
ionic: 'radio.md.scss',
},
shadow: true,
})
@@ -198,7 +200,7 @@ export class Radio implements ComponentInterface {
render() {
const { checked, disabled, color, el, justify, labelPlacement, hasLabel, buttonTabindex, alignment } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const inItem = hostContext('ion-item', el);
return (
@@ -207,7 +209,7 @@ export class Radio implements ComponentInterface {
onBlur={this.onBlur}
onClick={this.onClick}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
'in-item': inItem,
'radio-checked': checked,
'radio-disabled': disabled,

View File

@@ -7,7 +7,7 @@ import { printIonWarning } from '@utils/logging';
import { isRTL } from '@utils/rtl';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color, Gesture, GestureDetail } from '../../interface';
import { roundToMaxDecimalPlaces } from '../../utils/floating-point';
@@ -23,7 +23,8 @@ import type {
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot label - The label text to associate with the range. Use the "labelPlacement" property to control where the label is placed relative to the range.
* @slot start - Content is placed to the left of the range slider in LTR, and to the right in RTL.
@@ -42,6 +43,7 @@ import type {
styleUrls: {
ios: 'range.ios.scss',
md: 'range.md.scss',
ionic: 'range.md.scss',
},
shadow: true,
})
@@ -817,7 +819,7 @@ export class Range implements ComponentInterface {
const needsEndAdjustment = inItem && !hasEndContent;
const mode = getIonMode(this);
const theme = getIonTheme(this);
renderHiddenInput(true, el, this.name, JSON.stringify(this.getValue()), disabled);
@@ -827,7 +829,7 @@ export class Range implements ComponentInterface {
onFocusout={this.onBlur}
id={rangeId}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'in-item': inItem,
'range-disabled': disabled,
'range-pressed': pressedKnob !== undefined,

View File

@@ -5,12 +5,16 @@ import { sanitizeDOMString } from '@utils/sanitization';
import { arrowDown, caretBackSharp } from 'ionicons/icons';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { IonicSafeString } from '../../utils/sanitization';
import { supportsRubberBandScrolling } from '../refresher/refresher.utils';
import type { SpinnerTypes } from '../spinner/spinner-configs';
import { SPINNERS } from '../spinner/spinner-configs';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-refresher-content',
})
@@ -62,6 +66,8 @@ export class RefresherContent implements ComponentInterface {
@Prop() refreshingText?: string | IonicSafeString;
componentWillLoad() {
const theme = getIonTheme(this);
if (this.pullingIcon === undefined) {
/**
* The native iOS refresher uses a spinner instead of
@@ -69,18 +75,16 @@ export class RefresherContent implements ComponentInterface {
* the native iOS refresher.
*/
const hasRubberBandScrolling = supportsRubberBandScrolling();
const mode = getIonMode(this);
const overflowRefresher = hasRubberBandScrolling ? 'lines' : arrowDown;
this.pullingIcon = config.get(
'refreshingIcon',
mode === 'ios' && hasRubberBandScrolling ? config.get('spinner', overflowRefresher) : 'circular'
theme === 'ios' && hasRubberBandScrolling ? config.get('spinner', overflowRefresher) : 'circular'
);
}
if (this.refreshingSpinner === undefined) {
const mode = getIonMode(this);
this.refreshingSpinner = config.get(
'refreshingSpinner',
config.get('spinner', mode === 'ios' ? 'lines' : 'circular')
config.get('spinner', theme === 'ios' ? 'lines' : 'circular')
);
}
}
@@ -106,16 +110,20 @@ export class RefresherContent implements ComponentInterface {
render() {
const pullingIcon = this.pullingIcon;
const hasSpinner = pullingIcon != null && (SPINNERS[pullingIcon] as any) !== undefined;
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host class={mode}>
<Host
class={{
[theme]: true,
}}
>
<div class="refresher-pulling">
{this.pullingIcon && hasSpinner && (
<div class="refresher-pulling-icon">
<div class="spinner-arrow-container">
<ion-spinner name={this.pullingIcon as SpinnerTypes} paused></ion-spinner>
{mode === 'md' && this.pullingIcon === 'circular' && (
{theme === 'md' && this.pullingIcon === 'circular' && (
<div class="arrow-container">
<ion-icon icon={caretBackSharp} aria-hidden="true"></ion-icon>
</div>

View File

@@ -10,7 +10,7 @@ import {
import { clamp, componentOnReady, getElementRoot, raf, transitionEndAsync } from '@utils/helpers';
import { ImpactStyle, hapticImpact } from '@utils/native/haptic';
import { getIonMode } from '../../global/ionic-global';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { Animation, Gesture, GestureDetail } from '../../interface';
import type { RefresherEventDetail } from './refresher-interface';
@@ -26,13 +26,15 @@ import {
} from './refresher.utils';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-refresher',
styleUrls: {
ios: 'refresher.ios.scss',
md: 'refresher.md.scss',
ionic: 'refresher.md.scss',
},
})
export class Refresher implements ComponentInterface {
@@ -801,15 +803,15 @@ export class Refresher implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
slot="fixed"
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`refresher-${mode}`]: true,
[`refresher-${theme}`]: true,
'refresher-native': this.nativeRefresher,
'refresher-active': this.state !== RefresherState.Inactive,
'refresher-pulling': this.state === RefresherState.Pulling,

View File

@@ -4,7 +4,7 @@ import { findClosestIonContent, getScrollElement } from '@utils/content';
import { raf } from '@utils/helpers';
import { hapticSelectionChanged, hapticSelectionEnd, hapticSelectionStart } from '@utils/native/haptic';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Gesture, GestureDetail } from '../../interface';
import type { ItemReorderEventDetail } from './reorder-group-interface';
@@ -17,6 +17,10 @@ const enum ReorderGroupState {
Complete = 2,
}
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-reorder-group',
styleUrl: 'reorder-group.scss',
@@ -301,11 +305,11 @@ export class ReorderGroup implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'reorder-enabled': !this.disabled,
'reorder-list-active': this.state !== ReorderGroupState.Idle,
}}

View File

@@ -2,9 +2,12 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Listen, h } from '@stencil/core';
import { reorderThreeOutline, reorderTwoSharp } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part icon - The icon of the reorder handle (uses ion-icon).
*/
@Component({
@@ -12,6 +15,7 @@ import { getIonMode } from '../../global/ionic-global';
styleUrls: {
ios: 'reorder.ios.scss',
md: 'reorder.md.scss',
ionic: 'reorder.md.scss',
},
shadow: true,
})
@@ -32,10 +36,14 @@ export class Reorder implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const reorderIcon = mode === 'ios' ? reorderThreeOutline : reorderTwoSharp;
const theme = getIonTheme(this);
const reorderIcon = theme === 'ios' ? reorderThreeOutline : reorderTwoSharp;
return (
<Host class={mode}>
<Host
class={{
[theme]: true,
}}
>
<slot>
<ion-icon icon={reorderIcon} lazy={false} class="reorder-icon" part="icon" aria-hidden="true" />
</slot>

View File

@@ -1,8 +1,12 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Method, Prop, h, readTask, writeTask } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-ripple-effect',
styleUrl: 'ripple-effect.scss',
@@ -78,12 +82,12 @@ export class RippleEffect implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
role="presentation"
class={{
[mode]: true,
[theme]: true,
unbounded: this.unbounded,
}}
></Host>

View File

@@ -5,6 +5,10 @@ import type { NavigationHookCallback } from './route-interface';
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-route',
})

View File

@@ -2,10 +2,14 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses, openURL } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
import type { RouterDirection } from '../router/utils/interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-router-link',
styleUrl: 'router-link.scss',
@@ -55,7 +59,7 @@ export class RouterLink implements ComponentInterface {
};
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const attrs = {
href: this.href,
rel: this.rel,
@@ -65,7 +69,7 @@ export class RouterLink implements ComponentInterface {
<Host
onClick={this.onClick}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'ion-activatable': true,
})}
>

View File

@@ -19,6 +19,9 @@ import type {
import type { RouterOutletOptions, SwipeGestureHandler } from '../nav/nav-interface';
import type { RouteID, RouterDirection, RouteWrite, NavOutlet } from '../router/utils/interface';
/**
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-router-outlet',
styleUrl: 'router-outlet.scss',
@@ -37,7 +40,7 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
@Element() el!: HTMLElement;
/**
* The mode determines which platform styles to use.
* The mode determines the platform behaviors of the component.
*/
@Prop({ mutable: true }) mode = getIonMode(this);

View File

@@ -14,6 +14,10 @@ import { findChainForIDs, findChainForSegments, findRouteRedirect } from './util
import { readRedirects, readRoutes } from './utils/parser';
import { chainToSegments, generatePath, parsePath, readSegments, writeSegments } from './utils/path';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-router',
})

View File

@@ -1,8 +1,12 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-row',
styleUrl: 'row.scss',
@@ -10,8 +14,14 @@ import { getIonMode } from '../../global/ionic-global';
})
export class Row implements ComponentInterface {
render() {
const theme = getIonTheme(this);
return (
<Host class={getIonMode(this)}>
<Host
class={{
[theme]: true,
}}
>
<slot></slot>
</Host>
);

View File

@@ -7,19 +7,21 @@ import { createColorClasses } from '@utils/theme';
import { arrowBackSharp, closeCircle, closeSharp, searchOutline, searchSharp } from 'ionicons/icons';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { AutocompleteTypes, Color, StyleEventDetail } from '../../interface';
import type { SearchbarChangeEventDetail, SearchbarInputEventDetail } from './searchbar-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-searchbar',
styleUrls: {
ios: 'searchbar.ios.scss',
md: 'searchbar.md.scss',
ionic: 'searchbar.md.scss',
},
scoped: true,
})
@@ -110,18 +112,18 @@ export class Searchbar implements ComponentInterface {
@Prop() autocorrect: 'on' | 'off' = 'off';
/**
* Set the cancel button icon. Only applies to `md` mode.
* Defaults to `arrow-back-sharp`.
* Set the cancel button icon. Only available when the theme is `"md"`.
* Defaults to `"arrow-back-sharp"`.
*/
@Prop() cancelButtonIcon = config.get('backButtonIcon', arrowBackSharp) as string;
/**
* Set the the cancel button text. Only applies to `ios` mode.
* Set the the cancel button text. Only available when the theme is `"ios"`.
*/
@Prop() cancelButtonText = 'Cancel';
/**
* Set the clear icon. Defaults to `close-circle` for `ios` and `close-sharp` for `md`.
* Set the clear icon. Defaults to `"close-circle"` for `"ios"` theme and `"close-sharp"` for `"md"` and `"ionic"` theme.
*/
@Prop() clearIcon?: string;
@@ -187,8 +189,8 @@ export class Searchbar implements ComponentInterface {
@Prop() placeholder = 'Search';
/**
* The icon to use as the search icon. Defaults to `search-outline` in
* `ios` mode and `search-sharp` in `md` mode.
* The icon to use as the search icon. Defaults to `"search-outline"` in
* the `"ios"` theme and `"search-sharp"` in the `"md"` and `"ionic"` themes.
*/
@Prop() searchIcon?: string;
@@ -487,11 +489,11 @@ export class Searchbar implements ComponentInterface {
private positionElements() {
const value = this.getValue();
const prevAlignLeft = this.shouldAlignLeft;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const shouldAlignLeft = !this.animated || value.trim() !== '' || !!this.focused;
this.shouldAlignLeft = shouldAlignLeft;
if (mode !== 'ios') {
if (theme !== 'ios') {
return;
}
@@ -623,9 +625,9 @@ export class Searchbar implements ComponentInterface {
render() {
const { cancelButtonText } = this;
const animated = this.animated && config.getBoolean('animated', true);
const mode = getIonMode(this);
const clearIcon = this.clearIcon || (mode === 'ios' ? closeCircle : closeSharp);
const searchIcon = this.searchIcon || (mode === 'ios' ? searchOutline : searchSharp);
const theme = getIonTheme(this);
const clearIcon = this.clearIcon || (theme === 'ios' ? closeCircle : closeSharp);
const searchIcon = this.searchIcon || (theme === 'ios' ? searchOutline : searchSharp);
const shouldShowCancelButton = this.shouldShowCancelButton();
const cancelButton = this.showCancelButton !== 'never' && (
@@ -634,14 +636,14 @@ export class Searchbar implements ComponentInterface {
// Screen readers should not announce button if it is not visible on screen
aria-hidden={shouldShowCancelButton ? undefined : 'true'}
type="button"
tabIndex={mode === 'ios' && !shouldShowCancelButton ? -1 : undefined}
tabIndex={theme === 'ios' && !shouldShowCancelButton ? -1 : undefined}
onMouseDown={this.onCancelSearchbar}
onTouchStart={this.onCancelSearchbar}
class="searchbar-cancel-button"
>
<div aria-hidden="true">
{mode === 'md' ? (
<ion-icon aria-hidden="true" mode={mode} icon={this.cancelButtonIcon} lazy={false}></ion-icon>
{theme === 'md' ? (
<ion-icon aria-hidden="true" icon={this.cancelButtonIcon} lazy={false}></ion-icon>
) : (
cancelButtonText
)}
@@ -654,7 +656,7 @@ export class Searchbar implements ComponentInterface {
role="search"
aria-disabled={this.disabled ? 'true' : null}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'searchbar-animated': animated,
'searchbar-disabled': this.disabled,
'searchbar-no-animate': animated && this.noAnimate,
@@ -690,15 +692,9 @@ export class Searchbar implements ComponentInterface {
{...this.inheritedAttributes}
/>
{mode === 'md' && cancelButton}
{theme === 'md' && cancelButton}
<ion-icon
aria-hidden="true"
mode={mode}
icon={searchIcon}
lazy={false}
class="searchbar-search-icon"
></ion-icon>
<ion-icon aria-hidden="true" icon={searchIcon} lazy={false} class="searchbar-search-icon"></ion-icon>
<button
aria-label="reset"
@@ -715,16 +711,10 @@ export class Searchbar implements ComponentInterface {
}}
onClick={() => this.onClearInput(true)}
>
<ion-icon
aria-hidden="true"
mode={mode}
icon={clearIcon}
lazy={false}
class="searchbar-clear-icon"
></ion-icon>
<ion-icon aria-hidden="true" icon={clearIcon} lazy={false} class="searchbar-clear-icon"></ion-icon>
</button>
</div>
{mode === 'ios' && cancelButton}
{theme === 'ios' && cancelButton}
</Host>
);
}

View File

@@ -5,7 +5,7 @@ import type { Attributes } from '@utils/helpers';
import { addEventListener, removeEventListener, inheritAttributes } from '@utils/helpers';
import { hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { SegmentValue } from '../segment/segment-interface';
import type { SegmentButtonLayout } from './segment-button-interface';
@@ -13,7 +13,8 @@ import type { SegmentButtonLayout } from './segment-button-interface';
let ids = 0;
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part native - The native HTML button element that wraps all child elements.
* @part indicator - The indicator displayed on the checked segment button.
@@ -24,6 +25,7 @@ let ids = 0;
styleUrls: {
ios: 'segment-button.ios.scss',
md: 'segment-button.md.scss',
ionic: 'segment-button.md.scss',
},
shadow: true,
})
@@ -124,12 +126,12 @@ export class SegmentButton implements ComponentInterface, ButtonInterface {
render() {
const { checked, type, disabled, hasIcon, hasLabel, layout, segmentEl } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const hasSegmentColor = () => segmentEl?.color !== undefined;
return (
<Host
class={{
[mode]: true,
[theme]: true,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'in-segment': hostContext('ion-segment', this.el),
@@ -159,7 +161,7 @@ export class SegmentButton implements ComponentInterface, ButtonInterface {
<span class="button-inner">
<slot></slot>
</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
<div
part="indicator"

View File

@@ -5,19 +5,21 @@ import { raf } from '@utils/helpers';
import { isRTL } from '@utils/rtl';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color, StyleEventDetail } from '../../interface';
import type { SegmentChangeEventDetail, SegmentValue } from './segment-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-segment',
styleUrls: {
ios: 'segment.ios.scss',
md: 'segment.md.scss',
ionic: 'segment.md.scss',
},
shadow: true,
})
@@ -558,13 +560,13 @@ export class Segment implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
role="tablist"
onClick={this.onClick}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'segment-activated': this.activated,

View File

@@ -1,8 +1,12 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-select-option',
shadow: true,
@@ -24,7 +28,16 @@ export class SelectOption implements ComponentInterface {
@Prop() value?: any | null;
render() {
return <Host role="option" id={this.inputId} class={getIonMode(this)}></Host>;
const theme = getIonTheme(this);
return (
<Host
class={{
[theme]: true,
}}
role="option"
id={this.inputId}
></Host>
);
}
}

View File

@@ -3,13 +3,16 @@ import { Element, Component, Host, Prop, h, forceUpdate } from '@stencil/core';
import { safeCall } from '@utils/overlays';
import { getClassMap } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { CheckboxCustomEvent } from '../checkbox/checkbox-interface';
import type { RadioGroupCustomEvent } from '../radio-group/radio-group-interface';
import type { SelectPopoverOption } from './select-popover-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @internal
*/
@Component({
@@ -17,6 +20,7 @@ import type { SelectPopoverOption } from './select-popover-interface';
styleUrls: {
ios: 'select-popover.ios.scss',
md: 'select-popover.md.scss',
ionic: 'select-popover.md.scss',
},
scoped: true,
})
@@ -181,9 +185,14 @@ export class SelectPopover implements ComponentInterface {
render() {
const { header, message, options, subHeader } = this;
const hasSubHeaderOrMessage = subHeader !== undefined || message !== undefined;
const theme = getIonTheme(this);
return (
<Host class={getIonMode(this)}>
<Host
class={{
[theme]: true,
}}
>
<ion-list>
{header !== undefined && <ion-list-header>{header}</ion-list-header>}
{hasSubHeaderOrMessage && (

View File

@@ -11,7 +11,7 @@ import { createColorClasses, hostContext } from '@utils/theme';
import { watchForOptions } from '@utils/watch-options';
import { caretDownSharp, chevronExpand } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type {
ActionSheetOptions,
AlertOptions,
@@ -29,7 +29,8 @@ import type { SelectChangeEventDetail, SelectInterface, SelectCompareFn } from '
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot label - The label text to associate with the select. Use the `labelPlacement` property to control where the label is placed relative to the select. Use this if you need to render a label with custom HTML.
* @slot start - Content to display at the leading edge of the select.
@@ -46,6 +47,7 @@ import type { SelectChangeEventDetail, SelectInterface, SelectCompareFn } from '
styleUrls: {
ios: 'select.ios.scss',
md: 'select.md.scss',
ionic: 'select.md.scss',
},
shadow: true,
})
@@ -93,7 +95,7 @@ export class Select implements ComponentInterface {
/**
* 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 in `md` mode.
* `"outline"` the item will be transparent with a border. Only available in the `"md"` theme.
*/
@Prop() fill?: 'outline' | 'solid';
@@ -173,14 +175,14 @@ export class Select implements ComponentInterface {
@Prop() selectedText?: string | null;
/**
* The toggle icon to use. Defaults to `chevronExpand` for `ios` mode,
* or `caretDownSharp` for `md` mode.
* The toggle icon to use. Defaults to `"chevronExpand"` for the `"ios"` theme,
* or `"caretDownSharp"` for the `"md"` and `"ionic"` themes.
*/
@Prop() toggleIcon?: string;
/**
* The toggle icon to show when the select is open. If defined, the icon
* rotation behavior in `md` mode will be disabled. If undefined, `toggleIcon`
* rotation behavior in `"md"` theme will be disabled. If undefined, `toggleIcon`
* will be used for when the select is both open and closed.
*/
@Prop() expandedIcon?: string;
@@ -490,8 +492,8 @@ export class Select implements ComponentInterface {
private async openPopover(ev: UIEvent) {
const { fill, labelPlacement } = this;
const interfaceOptions = this.interfaceOptions;
const mode = getIonMode(this);
const showBackdrop = mode === 'md' ? false : true;
const theme = getIonTheme(this);
const showBackdrop = theme === 'md' ? false : true;
const multiple = this.multiple;
const value = this.value;
@@ -504,7 +506,7 @@ export class Select implements ComponentInterface {
* when using a fill in MD mode or if the
* label is floating/stacked.
*/
if (hasFloatingOrStackedLabel || (mode === 'md' && fill !== undefined)) {
if (hasFloatingOrStackedLabel || (theme === 'md' && fill !== undefined)) {
size = 'cover';
/**
@@ -522,7 +524,7 @@ export class Select implements ComponentInterface {
}
const popoverOpts: PopoverOptions = {
mode,
theme,
event,
alignment: 'center',
size,
@@ -558,10 +560,10 @@ export class Select implements ComponentInterface {
}
private async openActionSheet() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const interfaceOptions = this.interfaceOptions;
const actionSheetOpts: ActionSheetOptions = {
mode,
theme,
...interfaceOptions,
buttons: this.createActionSheetButtons(this.childOpts, this.value),
@@ -586,10 +588,10 @@ export class Select implements ComponentInterface {
private async openAlert() {
const interfaceOptions = this.interfaceOptions;
const inputType = this.multiple ? 'checkbox' : 'radio';
const mode = getIonMode(this);
const theme = getIonTheme(this);
const alertOpts: AlertOptions = {
mode,
theme,
...interfaceOptions,
header: interfaceOptions.header ? interfaceOptions.header : this.labelText,
@@ -786,8 +788,8 @@ export class Select implements ComponentInterface {
* when fill="outline".
*/
private renderLabelContainer() {
const mode = getIonMode(this);
const hasOutlineFill = mode === 'md' && this.fill === 'outline';
const theme = getIonTheme(this);
const hasOutlineFill = theme === 'md' && this.fill === 'outline';
if (hasOutlineFill) {
/**
@@ -859,14 +861,14 @@ export class Select implements ComponentInterface {
* next to the select text.
*/
private renderSelectIcon() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const { isExpanded, toggleIcon, expandedIcon } = this;
let icon: string;
if (isExpanded && expandedIcon !== undefined) {
icon = expandedIcon;
} else {
const defaultIcon = mode === 'ios' ? chevronExpand : caretDownSharp;
const defaultIcon = theme === 'ios' ? chevronExpand : caretDownSharp;
icon = toggleIcon ?? defaultIcon;
}
@@ -924,12 +926,12 @@ export class Select implements ComponentInterface {
render() {
const { disabled, el, isExpanded, expandedIcon, labelPlacement, justify, placeholder, fill, shape, name, value } =
this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const hasFloatingOrStackedLabel = labelPlacement === 'floating' || labelPlacement === 'stacked';
const justifyEnabled = !hasFloatingOrStackedLabel;
const rtl = isRTL(el) ? 'rtl' : 'ltr';
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
const shouldRenderHighlight = theme === 'md' && fill !== 'outline' && !inItem;
const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
@@ -960,7 +962,7 @@ export class Select implements ComponentInterface {
<Host
onClick={this.onClick}
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'in-item': inItem,
'in-item-color': hostContext('ion-item.ion-color', el),
'select-disabled': disabled,

View File

@@ -3,9 +3,13 @@ import { Component, Element, Event, Host, Prop, h } from '@stencil/core';
import { hostContext } from '@utils/theme';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { StyleEventDetail } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-skeleton-text',
styleUrl: 'skeleton-text.scss',
@@ -43,12 +47,12 @@ export class SkeletonText implements ComponentInterface {
render() {
const animated = this.animated && config.getBoolean('animated', true);
const inMedia = hostContext('ion-avatar', this.el) || hostContext('ion-thumbnail', this.el);
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
'skeleton-text-animated': animated,
'in-media': inMedia,
}}

View File

@@ -3,13 +3,17 @@ import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
import type { SpinnerTypes } from './spinner-configs';
import { SPINNERS } from './spinner-configs';
import type { SpinnerConfig } from './spinner-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-spinner',
styleUrl: 'spinner.scss',
@@ -41,16 +45,16 @@ export class Spinner implements ComponentInterface {
private getName(): SpinnerTypes {
const spinnerName = this.name || config.get('spinner');
const mode = getIonMode(this);
const theme = getIonTheme(this);
if (spinnerName) {
return spinnerName;
}
return mode === 'ios' ? 'lines' : 'circular';
return theme === 'ios' ? 'lines' : 'circular';
}
render() {
const self = this;
const mode = getIonMode(self);
const theme = getIonTheme(self);
const spinnerName = self.getName();
const spinner = SPINNERS[spinnerName] ?? SPINNERS['lines'];
const duration = typeof self.duration === 'number' && self.duration > 10 ? self.duration : spinner.dur;
@@ -69,7 +73,7 @@ export class Spinner implements ComponentInterface {
return (
<Host
class={createColorClasses(self.color, {
[mode]: true,
[theme]: true,
[`spinner-${spinnerName}`]: true,
'spinner-paused': self.paused || config.getBoolean('_testing'),
})}

View File

@@ -1,7 +1,7 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Build, Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
// TODO(FW-2832): types
@@ -16,11 +16,16 @@ const QUERY: { [key: string]: string } = {
never: '',
};
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-split-pane',
styleUrls: {
ios: 'split-pane.ios.scss',
md: 'split-pane.md.scss',
ionic: 'split-pane.md.scss',
},
shadow: true,
})
@@ -168,14 +173,14 @@ export class SplitPane implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={{
[mode]: true,
[theme]: true,
// Used internally for styling
[`split-pane-${mode}`]: true,
[`split-pane-${theme}`]: true,
'split-pane-visible': this.visible,
}}

View File

@@ -4,19 +4,21 @@ import type { KeyboardController } from '@utils/keyboard/keyboard-controller';
import { createKeyboardController } from '@utils/keyboard/keyboard-controller';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
import type { TabBarChangedEventDetail } from './tab-bar-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-tab-bar',
styleUrls: {
ios: 'tab-bar.ios.scss',
md: 'tab-bar.md.scss',
ionic: 'tab-bar.md.scss',
},
shadow: true,
})
@@ -49,7 +51,7 @@ export class TabBar implements ComponentInterface {
/**
* If `true`, the tab bar will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* Only applies when the theme is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
@Prop() translucent = false;
@@ -96,7 +98,7 @@ export class TabBar implements ComponentInterface {
render() {
const { color, translucent, keyboardVisible } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const shouldHide = keyboardVisible && this.el.getAttribute('slot') !== 'top';
return (
@@ -104,7 +106,7 @@ export class TabBar implements ComponentInterface {
role="tablist"
aria-hidden={shouldHide ? 'true' : null}
class={createColorClasses(color, {
[mode]: true,
[theme]: true,
'tab-bar-translucent': translucent,
'tab-bar-hidden': shouldHide,
})}

View File

@@ -5,7 +5,7 @@ import type { Attributes } from '@utils/helpers';
import { inheritAttributes } from '@utils/helpers';
import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type {
TabBarChangedEventDetail,
TabButtonClickEventDetail,
@@ -13,7 +13,8 @@ import type {
} from '../tab-bar/tab-bar-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @part native - The native HTML anchor element that wraps all child elements.
*/
@@ -22,6 +23,7 @@ import type {
styleUrls: {
ios: 'tab-button.ios.scss',
md: 'tab-button.md.scss',
ionic: 'tab-button.md.scss',
},
shadow: true,
})
@@ -138,7 +140,7 @@ export class TabButton implements ComponentInterface, AnchorInterface {
render() {
const { disabled, hasIcon, hasLabel, href, rel, target, layout, selected, tab, inheritedAttributes } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const attrs = {
download: this.download,
href,
@@ -152,7 +154,7 @@ export class TabButton implements ComponentInterface, AnchorInterface {
onKeyup={this.onKeyUp}
id={tab !== undefined ? `tab-button-${tab}` : null}
class={{
[mode]: true,
[theme]: true,
'tab-selected': selected,
'tab-disabled': disabled,
'tab-has-label': hasLabel,
@@ -178,7 +180,7 @@ export class TabButton implements ComponentInterface, AnchorInterface {
<span class="button-inner">
<slot></slot>
</span>
{mode === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
{theme === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
</a>
</Host>
);

View File

@@ -4,6 +4,10 @@ import { attachComponent } from '@utils/framework-delegate';
import type { ComponentRef, FrameworkDelegate } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-tab',
styleUrl: 'tab.scss',

View File

@@ -5,6 +5,9 @@ import type { NavOutlet, RouteID, RouteWrite } from '../router/utils/interface';
import type { TabButtonClickEventDetail } from '../tab-bar/tab-bar-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot top - Content is placed at the top of the screen.
* @slot bottom - Content is placed at the bottom of the screen.

View File

@@ -2,11 +2,12 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-text',
@@ -22,11 +23,11 @@ export class Text implements ComponentInterface {
@Prop({ reflect: true }) color?: Color;
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
})}
>
<slot></slot>

View File

@@ -21,14 +21,15 @@ import { createSlotMutationController } from '@utils/slot-mutation-controller';
import type { SlotMutationController } from '@utils/slot-mutation-controller';
import { createColorClasses, hostContext } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color } from '../../interface';
import { getCounterText } from '../input/input.utils';
import type { TextareaChangeEventDetail, TextareaInputEventDetail } from './textarea-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot label - The label text to associate with the textarea. Use the `labelPlacement` property to control where the label is placed relative to the textarea. Use this if you need to render a label with custom HTML. (EXPERIMENTAL)
* @slot start - Content to display at the leading edge of the textarea. (EXPERIMENTAL)
@@ -39,6 +40,7 @@ import type { TextareaChangeEventDetail, TextareaInputEventDetail } from './text
styleUrls: {
ios: 'textarea.ios.scss',
md: 'textarea.md.scss',
ionic: 'textarea.md.scss',
},
scoped: true,
})
@@ -118,7 +120,7 @@ export class Textarea implements ComponentInterface {
/**
* 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 in `md` mode.
* `"outline"` the item will be transparent with a border. Only available when the theme is `"md"`.
*/
@Prop() fill?: 'outline' | 'solid';
@@ -534,8 +536,8 @@ export class Textarea implements ComponentInterface {
* Renders the border container when fill="outline".
*/
private renderLabelContainer() {
const mode = getIonMode(this);
const hasOutlineFill = mode === 'md' && this.fill === 'outline';
const theme = getIonTheme(this);
const hasOutlineFill = theme === 'md' && this.fill === 'outline';
if (hasOutlineFill) {
/**
@@ -616,10 +618,10 @@ export class Textarea implements ComponentInterface {
render() {
const { inputId, disabled, fill, shape, labelPlacement, el, hasFocus } = this;
const mode = getIonMode(this);
const theme = getIonTheme(this);
const value = this.getValue();
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
const shouldRenderHighlight = theme === 'md' && fill !== 'outline' && !inItem;
const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
@@ -647,7 +649,7 @@ export class Textarea implements ComponentInterface {
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
'has-value': hasValue,
'has-focus': hasFocus,
'label-floating': labelShouldFloat,

View File

@@ -1,8 +1,12 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, h } from '@stencil/core';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-thumbnail',
styleUrl: 'thumbnail.scss',
@@ -10,8 +14,13 @@ import { getIonMode } from '../../global/ionic-global';
})
export class Thumbnail implements ComponentInterface {
render() {
const theme = getIonTheme(this);
return (
<Host class={getIonMode(this)}>
<Host
class={{
[theme]: true,
}}
>
<slot></slot>
</Host>
);

View File

@@ -2,14 +2,19 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, Watch, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
import { getIonTheme } from '../../global/ionic-global';
import type { Color, StyleEventDetail } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-title',
styleUrls: {
ios: 'title.ios.scss',
md: 'title.md.scss',
ionic: 'title.md.scss',
},
shadow: true,
})
@@ -56,13 +61,13 @@ export class ToolbarTitle implements ComponentInterface {
}
render() {
const mode = getIonMode(this);
const theme = getIonTheme(this);
const size = this.getSize();
return (
<Host
class={createColorClasses(this.color, {
[mode]: true,
[theme]: true,
[`title-${size}`]: true,
'title-rtl': document.dir === 'rtl',
})}

View File

@@ -1,7 +1,7 @@
import { win } from '@utils/browser';
import { printIonWarning } from '@utils/logging';
import type { Mode } from 'src/interface';
import type { Mode } from '../../../interface';
import type { ToastAnimationPosition, ToastPosition } from '../toast-interface';
/**
@@ -18,7 +18,7 @@ import type { ToastAnimationPosition, ToastPosition } from '../toast-interface';
* @param position The value of the toast's position prop.
* @param positionAnchor The element the toast should be anchored to,
* if applicable.
* @param mode The toast component's mode (md, ios, etc).
* @param mode The toast component's platform (md or ios).
* @param toast A reference to the toast element itself.
*/
export function getAnimationPosition(

Some files were not shown because too many files have changed in this diff Show More