diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts
index 5938d3fb748..62888e05926 100644
--- a/angular/src/directives/proxies.ts
+++ b/angular/src/directives/proxies.ts
@@ -278,8 +278,8 @@ export class IonHeader {
}
export declare interface IonIcon extends Components.IonIcon {
}
-@ProxyCmp({ inputs: ["ariaLabel", "color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "size", "src"] })
-@Component({ selector: "ion-icon", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["ariaLabel", "color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "size", "src"] })
+@ProxyCmp({ inputs: ["ariaHidden", "ariaLabel", "color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] })
+@Component({ selector: "ion-icon", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["ariaHidden", "ariaLabel", "color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] })
export class IonIcon {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
diff --git a/core/src/components/progress-bar/progress-bar.scss b/core/src/components/progress-bar/progress-bar.scss
index 2f70b8d6656..ae90bc52448 100644
--- a/core/src/components/progress-bar/progress-bar.scss
+++ b/core/src/components/progress-bar/progress-bar.scss
@@ -10,7 +10,7 @@
* @prop --progress-background: Color of the progress bar
* @prop --buffer-background: Color of the buffer bar
*/
- --background: #{ion-color(primary, base, 0.2)};
+ --background: #{ion-color(primary, base, 0.3)};
--progress-background: #{ion-color(primary, base)};
--buffer-background: var(--background);
display: block;
@@ -27,7 +27,7 @@
:host(.ion-color) {
--progress-background: #{current-color(base)};
- --buffer-background: #{current-color(base, 0.2)};
+ --buffer-background: #{current-color(base, 0.3)};
}
// indeterminate has no progress-buffer-bar, so it will be added to the host
@@ -72,17 +72,10 @@
}
.progress-buffer-bar {
- // It's currently here because --buffer-background has an alpha
- // Otherwise the buffer circles would be seen through
- background: #fff;
-
- z-index: 1; // Make it behind the progress
-
- &:before {
- background: var(--buffer-background);
+ background: var(--buffer-background);
- content: "";
- }
+ // Make it behind the progress
+ z-index: 1;
}
// MD based animation on indeterminate type
@@ -109,7 +102,7 @@
top: 0;
right: 0;
bottom: 0;
- left: -54.888891%;
+ left: -54.888891%;
/* stylelint-enable property-blacklist */
animation: secondary-indeterminate-translate 2s infinite linear;
@@ -123,8 +116,26 @@
// Buffer style
// --------------------------------------------------
+.buffer-circles.buffer-circles-reversed {
+ /* stylelint-disable property-blacklist */
+ right: unset;
+ left: 0;
+
+ background-position: right;
+ /* stylelint-enable property-blacklist */
+}
+
.buffer-circles {
- background: radial-gradient(ellipse at center, var(--buffer-background) 0%, var(--buffer-background) 30%, transparent 30%) repeat-x 5px center;
+ /* stylelint-disable property-blacklist */
+ right: 0;
+
+ left: unset;
+ /* stylelint-enable property-blacklist */
+
+ background: radial-gradient(ellipse at center, var(--buffer-background) 0%, var(--buffer-background) 30%, transparent 30%) repeat-x 5px;
+
+ /* stylelint-disable-next-line property-blacklist */
+ background-position: left;
background-size: 10px 10px;
z-index: 0;
diff --git a/core/src/components/progress-bar/progress-bar.tsx b/core/src/components/progress-bar/progress-bar.tsx
index ee952e64ab2..902ab2b621e 100644
--- a/core/src/components/progress-bar/progress-bar.tsx
+++ b/core/src/components/progress-bar/progress-bar.tsx
@@ -54,6 +54,7 @@ export class ProgressBar implements ComponentInterface {
const { color, type, reversed, value, buffer } = this;
const paused = config.getBoolean('_testing');
const mode = getIonMode(this);
+ const isReversed = document.dir === 'rtl' ? !reversed : reversed;
return (
{type === 'indeterminate'
? renderIndeterminate()
- : renderProgress(value, buffer)
+ : renderProgress(value, buffer, isReversed)
}
);
@@ -83,13 +84,13 @@ const renderIndeterminate = () => {
];
};
-const renderProgress = (value: number, buffer: number) => {
+const renderProgress = (value: number, buffer: number, reversed: boolean) => {
const finalValue = clamp(0, value, 1);
const finalBuffer = clamp(0, buffer, 1);
return [
,
- finalBuffer !== 1 && ,
+ finalBuffer !== 1 && ,
,
];
};
diff --git a/core/src/components/progress-bar/test/basic/index.html b/core/src/components/progress-bar/test/basic/index.html
index 688296cf98a..b428a315c6b 100644
--- a/core/src/components/progress-bar/test/basic/index.html
+++ b/core/src/components/progress-bar/test/basic/index.html
@@ -9,7 +9,9 @@
-
@@ -619,10 +622,6 @@ Street Fighter II
-
- Default
-
-
@@ -759,6 +758,18 @@ Street Fighter II
Dark
+
+
+
+
+
+
+
+
+
+
+
+
@@ -921,22 +932,31 @@ Street Fighter II
// create component to open
const element = document.createElement('div');
element.innerHTML = `
-
+
Super Modal
-
- Content of doom
- Here's some more content
- Dismiss Modal
+
+
+
+ Super Modal
+
+
+
+
Content of doom
+
Here's some more content
+
Dismiss Modal
+
`;
// present the modal
const modalElement = Object.assign(document.createElement('ion-modal'), {
- component: element
+ component: element,
+ swipeToClose: true,
+ presentingElement: document.querySelector('ion-tabs')
});
// listen for close event
diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts
index aea7e41a41c..8ee4fdd52fb 100644
--- a/packages/vue/src/proxies.ts
+++ b/packages/vue/src/proxies.ts
@@ -3,7 +3,7 @@
/* auto-generated vue proxies */
import { defineContainer } from './vue-component-lib/utils';
-import { JSX } from '@ionic/core';
+import type { JSX } from '@ionic/core';
@@ -42,10 +42,7 @@ export const IonButton = /*@__PURE__*/ defineContainer('ion-butto
'type',
'ionFocus',
'ionBlur'
-],
-{
- "routerLinkComponent": true
-});
+]);
export const IonButtons = /*@__PURE__*/ defineContainer('ion-buttons', [
@@ -64,10 +61,7 @@ export const IonCard = /*@__PURE__*/ defineContainer('ion-card', [
'routerDirection',
'routerAnimation',
'target'
-],
-{
- "routerLinkComponent": true
-});
+]);
export const IonCardContent = /*@__PURE__*/ defineContainer('ion-card-content');
@@ -103,7 +97,8 @@ export const IonCheckbox = /*@__PURE__*/ defineContainer('ion-c
],
{
"modelProp": "checked",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -186,7 +181,8 @@ export const IonDatetime = /*@__PURE__*/ defineContainer('ion-d
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -195,10 +191,7 @@ export const IonFab = /*@__PURE__*/ defineContainer('ion-fab', [
'vertical',
'edge',
'activated'
-],
-{
- "routerLinkComponent": true
-});
+]);
export const IonFabButton = /*@__PURE__*/ defineContainer('ion-fab-button', [
@@ -218,10 +211,7 @@ export const IonFabButton = /*@__PURE__*/ defineContainer('ion
'closeIcon',
'ionFocus',
'ionBlur'
-],
-{
- "routerLinkComponent": true
-});
+]);
export const IonFabList = /*@__PURE__*/ defineContainer('ion-fab-list', [
@@ -306,7 +296,8 @@ export const IonInput = /*@__PURE__*/ defineContainer('ion-input',
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -324,10 +315,7 @@ export const IonItem = /*@__PURE__*/ defineContainer('ion-item', [
'routerDirection',
'target',
'type'
-],
-{
- "routerLinkComponent": true
-});
+]);
export const IonItemDivider = /*@__PURE__*/ defineContainer('ion-item-divider', [
@@ -460,7 +448,8 @@ export const IonRadio = /*@__PURE__*/ defineContainer('ion-radio',
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -472,7 +461,8 @@ export const IonRadioGroup = /*@__PURE__*/ defineContainer('i
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -496,7 +486,8 @@ export const IonRange = /*@__PURE__*/ defineContainer('ion-range',
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -566,7 +557,8 @@ export const IonSearchbar = /*@__PURE__*/ defineContainer('ion
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -582,7 +574,8 @@ export const IonSegment = /*@__PURE__*/ defineContainer('ion-seg
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -594,7 +587,8 @@ export const IonSegmentButton = /*@__PURE__*/ defineContainer('ion-selec
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -710,7 +705,8 @@ export const IonTextarea = /*@__PURE__*/ defineContainer('ion-t
],
{
"modelProp": "value",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
@@ -737,7 +733,8 @@ export const IonToggle = /*@__PURE__*/ defineContainer('ion-toggl
],
{
"modelProp": "checked",
- "modelUpdateEvent": "ionChange"
+ "modelUpdateEvent": "ionChange",
+ "externalModelUpdateEvent": "ionChange"
});
diff --git a/packages/vue/src/vue-component-lib/utils.ts b/packages/vue/src/vue-component-lib/utils.ts
index 37d388f54f8..e9a994c9a41 100644
--- a/packages/vue/src/vue-component-lib/utils.ts
+++ b/packages/vue/src/vue-component-lib/utils.ts
@@ -1,4 +1,4 @@
-import { VNode, defineComponent, h, inject, ref, Ref } from 'vue';
+import { VNode, defineComponent, getCurrentInstance, h, inject, ref, Ref } from 'vue';
export interface InputProps extends Object {
modelValue: string | boolean;
@@ -17,7 +17,7 @@ interface NavManager {
interface ComponentOptions {
modelProp?: string;
modelUpdateEvent?: string;
- routerLinkComponent?: boolean;
+ externalModelUpdateEvent?: string;
}
const getComponentClasses = (classes: unknown) => {
@@ -41,7 +41,7 @@ const getElementClasses = (ref: Ref, componentClasses:
* integrations.
*/
export const defineContainer = (name: string, componentProps: string[] = [], componentOptions: ComponentOptions = {}) => {
- const { modelProp, modelUpdateEvent, routerLinkComponent } = componentOptions;
+ const { modelProp, modelUpdateEvent, externalModelUpdateEvent } = componentOptions;
/**
* Create a Vue component wrapper around a Web Component.
@@ -49,29 +49,46 @@ export const defineContainer = (name: string, componentProps: string[] =
* They refer to whatever properties are set on an instance of a component.
*/
const Container = defineComponent((props, { attrs, slots, emit }) => {
+ let modelPropValue = (props as any)[modelProp];
const containerRef = ref();
const classes = new Set(getComponentClasses(attrs.class));
const onVnodeBeforeMount = (vnode: VNode) => {
// Add a listener to tell Vue to update the v-model
if (vnode.el) {
vnode.el.addEventListener(modelUpdateEvent.toLowerCase(), (e: Event) => {
- emit(UPDATE_VALUE_EVENT, (e?.target as any)[modelProp]);
+ modelPropValue = (e?.target as any)[modelProp];
+ emit(UPDATE_VALUE_EVENT, modelPropValue);
+
+ /**
+ * We need to emit the change event here
+ * rather than on the web component to ensure
+ * that any v-model bindings have been updated.
+ * Otherwise, the developer will listen on the
+ * native web component, but the v-model will
+ * not have been updated yet.
+ */
+ emit(externalModelUpdateEvent, e);
});
}
};
- let handleClick: (ev: Event) => void;
- if (routerLinkComponent) {
- const navManager: NavManager = inject(NAV_MANAGER);
- handleClick = (ev: Event) => {
- const routerProps = Object.keys(props).filter(p => p.startsWith(ROUTER_PROP_REFIX));
- if (routerProps.length === 0) return;
+ const currentInstance = getCurrentInstance();
+ const hasRouter = currentInstance?.appContext?.provides[NAV_MANAGER];
+ const navManager: NavManager | undefined = hasRouter ? inject(NAV_MANAGER) : undefined;
+ const handleRouterLink = (ev: Event) => {
+ const { routerLink } = props as any;
+ if (!routerLink) return;
+ const routerProps = Object.keys(props).filter(p => p.startsWith(ROUTER_PROP_REFIX));
+
+ if (navManager !== undefined) {
let navigationPayload: any = { event: ev };
routerProps.forEach(prop => {
navigationPayload[prop] = (props as any)[prop];
});
navManager.navigate(navigationPayload);
+ } else {
+ console.warn('Tried to navigate, but no router was found. Make sure you have mounted Vue Router.');
}
}
@@ -80,28 +97,28 @@ export const defineContainer = (name: string, componentProps: string[] =
classes.add(value);
});
+ const oldClick = (props as any).onClick;
+ const handleClick = (ev: Event) => {
+ if (oldClick !== undefined) {
+ oldClick(ev);
+ }
+ if (!ev.defaultPrevented) {
+ handleRouterLink(ev);
+ }
+ }
+
let propsToAdd = {
...props,
ref: containerRef,
class: getElementClasses(containerRef, classes),
- onClick: (routerLinkComponent) ? handleClick : (props as any).onClick,
- onVnodeBeforeMount: (modelUpdateEvent) ? onVnodeBeforeMount : undefined
+ onClick: handleClick,
+ onVnodeBeforeMount: (modelUpdateEvent && externalModelUpdateEvent) ? onVnodeBeforeMount : undefined
};
- if ((props as any).onClick) {
- const oldClick = (props as any).onClick;
- propsToAdd.onClick = (ev: Event) => {
- oldClick(ev);
- if (!ev.defaultPrevented) {
- handleClick(ev);
- }
- };
- }
-
if (modelProp) {
propsToAdd = {
...propsToAdd,
- [modelProp]: props.hasOwnProperty('modelValue') ? props.modelValue : (props as any)[modelProp]
+ [modelProp]: props.hasOwnProperty('modelValue') ? props.modelValue : modelPropValue
}
}
@@ -110,13 +127,10 @@ export const defineContainer = (name: string, componentProps: string[] =
});
Container.displayName = name;
- Container.props = componentProps;
+ Container.props = [...componentProps, ROUTER_LINK_VALUE];
if (modelProp) {
Container.props.push(MODEL_VALUE);
- Container.emits = [UPDATE_VALUE_EVENT];
- }
- if (routerLinkComponent) {
- Container.props.push(ROUTER_LINK_VALUE);
+ Container.emits = [UPDATE_VALUE_EVENT, externalModelUpdateEvent];
}
return Container;