Compare commits
1 Commits
v7.5.4
...
v7.5.3-nig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e29690b589 |
17
CHANGELOG.md
@@ -3,30 +3,15 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.5.4](https://github.com/ionic-team/ionic-framework/compare/v7.5.3...v7.5.4) (2023-11-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **inputs:** remove invalid legacy warnings in input, textarea, and select ([#28484](https://github.com/ionic-team/ionic-framework/issues/28484)) ([c765dcb](https://github.com/ionic-team/ionic-framework/commit/c765dcbac4148762768d8c2bea9103e7d38c510b))
|
||||
* **item:** apply safe area to proper side regardless of direction ([#28403](https://github.com/ionic-team/ionic-framework/issues/28403)) ([ed040b0](https://github.com/ionic-team/ionic-framework/commit/ed040b09e9cbd4246864e690542132defc6a6578))
|
||||
* **list:** remove border from last item with item-sliding ([#28439](https://github.com/ionic-team/ionic-framework/issues/28439)) ([cafafcc](https://github.com/ionic-team/ionic-framework/commit/cafafcc9d166ef536dcb73edd522c8f2a0fb95b6)), closes [#28435](https://github.com/ionic-team/ionic-framework/issues/28435)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.5.3](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3) (2023-11-01)
|
||||
## [7.5.3-nightly.20231031](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3-nightly.20231031) (2023-10-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** long words wrap to next line ([#28408](https://github.com/ionic-team/ionic-framework/issues/28408)) ([34257d6](https://github.com/ionic-team/ionic-framework/commit/34257d681e9034b0a001aa45e17222f3aab5ed76)), closes [#28406](https://github.com/ionic-team/ionic-framework/issues/28406)
|
||||
* **angular:** inputs on standalone form controls are reactive ([#28434](https://github.com/ionic-team/ionic-framework/issues/28434)) ([3b6e631](https://github.com/ionic-team/ionic-framework/commit/3b6e6318bf94125b3f8305b4d072a5945ceb3730)), closes [#28431](https://github.com/ionic-team/ionic-framework/issues/28431)
|
||||
* **angular:** NavController works with nested outlets ([#28421](https://github.com/ionic-team/ionic-framework/issues/28421)) ([90acad1](https://github.com/ionic-team/ionic-framework/commit/90acad1837b117542830ec0083389a35c5b4ee76)), closes [#28417](https://github.com/ionic-team/ionic-framework/issues/28417)
|
||||
* **angular:** run platform subscriptions inside zone ([#28404](https://github.com/ionic-team/ionic-framework/issues/28404)) ([a4b303e](https://github.com/ionic-team/ionic-framework/commit/a4b303e1338a35756a9cf7f67508d24d2f8537a2)), closes [#19539](https://github.com/ionic-team/ionic-framework/issues/19539)
|
||||
* **angular:** standalone form components do not error when multiple are used ([#28423](https://github.com/ionic-team/ionic-framework/issues/28423)) ([89698b3](https://github.com/ionic-team/ionic-framework/commit/89698b338fb05cde427c98720c238d2365abdaa7)), closes [#28418](https://github.com/ionic-team/ionic-framework/issues/28418)
|
||||
* **datetime:** allow calendar navigation in readonly mode; disallow keyboard navigation when disabled ([#28336](https://github.com/ionic-team/ionic-framework/issues/28336)) ([f6a6877](https://github.com/ionic-team/ionic-framework/commit/f6a6877044a6d912a92aab00c3c78897da09415d)), closes [#28121](https://github.com/ionic-team/ionic-framework/issues/28121)
|
||||
* **input, textarea, select:** use consistent sizes ([#28390](https://github.com/ionic-team/ionic-framework/issues/28390)) ([b31ecbb](https://github.com/ionic-team/ionic-framework/commit/b31ecbbfe8deb87604686d752e92e672dd9b277a)), closes [#28388](https://github.com/ionic-team/ionic-framework/issues/28388)
|
||||
* **list-header:** apply safe area to proper side regardless of direction ([#28371](https://github.com/ionic-team/ionic-framework/issues/28371)) ([f99d530](https://github.com/ionic-team/ionic-framework/commit/f99d5305fb4b1607b42e34a0b7653d8e1b5bf23f))
|
||||
* **segment:** avoid scrolling webkit bug ([#28376](https://github.com/ionic-team/ionic-framework/issues/28376)) ([8e2f818](https://github.com/ionic-team/ionic-framework/commit/8e2f81867175e9980e6d072b0a4414baae571223)), closes [#28373](https://github.com/ionic-team/ionic-framework/issues/28373)
|
||||
|
||||
@@ -3,27 +3,13 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.5.4](https://github.com/ionic-team/ionic-framework/compare/v7.5.3...v7.5.4) (2023-11-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **inputs:** remove invalid legacy warnings in input, textarea, and select ([#28484](https://github.com/ionic-team/ionic-framework/issues/28484)) ([c765dcb](https://github.com/ionic-team/ionic-framework/commit/c765dcbac4148762768d8c2bea9103e7d38c510b))
|
||||
* **item:** apply safe area to proper side regardless of direction ([#28403](https://github.com/ionic-team/ionic-framework/issues/28403)) ([ed040b0](https://github.com/ionic-team/ionic-framework/commit/ed040b09e9cbd4246864e690542132defc6a6578))
|
||||
* **list:** remove border from last item with item-sliding ([#28439](https://github.com/ionic-team/ionic-framework/issues/28439)) ([cafafcc](https://github.com/ionic-team/ionic-framework/commit/cafafcc9d166ef536dcb73edd522c8f2a0fb95b6)), closes [#28435](https://github.com/ionic-team/ionic-framework/issues/28435)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.5.3](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3) (2023-11-01)
|
||||
## [7.5.3-nightly.20231031](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3-nightly.20231031) (2023-10-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **alert:** long words wrap to next line ([#28408](https://github.com/ionic-team/ionic-framework/issues/28408)) ([34257d6](https://github.com/ionic-team/ionic-framework/commit/34257d681e9034b0a001aa45e17222f3aab5ed76)), closes [#28406](https://github.com/ionic-team/ionic-framework/issues/28406)
|
||||
* **angular:** standalone form components do not error when multiple are used ([#28423](https://github.com/ionic-team/ionic-framework/issues/28423)) ([89698b3](https://github.com/ionic-team/ionic-framework/commit/89698b338fb05cde427c98720c238d2365abdaa7)), closes [#28418](https://github.com/ionic-team/ionic-framework/issues/28418)
|
||||
* **datetime:** allow calendar navigation in readonly mode; disallow keyboard navigation when disabled ([#28336](https://github.com/ionic-team/ionic-framework/issues/28336)) ([f6a6877](https://github.com/ionic-team/ionic-framework/commit/f6a6877044a6d912a92aab00c3c78897da09415d)), closes [#28121](https://github.com/ionic-team/ionic-framework/issues/28121)
|
||||
* **input, textarea, select:** use consistent sizes ([#28390](https://github.com/ionic-team/ionic-framework/issues/28390)) ([b31ecbb](https://github.com/ionic-team/ionic-framework/commit/b31ecbbfe8deb87604686d752e92e672dd9b277a)), closes [#28388](https://github.com/ionic-team/ionic-framework/issues/28388)
|
||||
* **list-header:** apply safe area to proper side regardless of direction ([#28371](https://github.com/ionic-team/ionic-framework/issues/28371)) ([f99d530](https://github.com/ionic-team/ionic-framework/commit/f99d5305fb4b1607b42e34a0b7653d8e1b5bf23f))
|
||||
* **segment:** avoid scrolling webkit bug ([#28376](https://github.com/ionic-team/ionic-framework/issues/28376)) ([8e2f818](https://github.com/ionic-team/ionic-framework/commit/8e2f81867175e9980e6d072b0a4414baae571223)), closes [#28373](https://github.com/ionic-team/ionic-framework/issues/28373)
|
||||
|
||||
18
core/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.7.1",
|
||||
"@stencil/core": "^4.6.0",
|
||||
"ionicons": "^7.2.1",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
@@ -1653,9 +1653,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.7.1.tgz",
|
||||
"integrity": "sha512-KDWA/3qDiABA5LqtHCmTVwORuzgu/YdC0FpSBwVmwlw6K8jUjbTA5JB6Q03da2F+EQlDHOVgbW0TNtHCm54uXQ==",
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.6.0.tgz",
|
||||
"integrity": "sha512-5Y6/fP28aspPDRB+Tz5GuB1jRVGuUEk5/rnyE8ACGcuzEOG+zR0A/IHRJSU3XmCxUlVDKfKoO6St5W84oUCVMA==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
@@ -11586,9 +11586,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.7.1.tgz",
|
||||
"integrity": "sha512-KDWA/3qDiABA5LqtHCmTVwORuzgu/YdC0FpSBwVmwlw6K8jUjbTA5JB6Q03da2F+EQlDHOVgbW0TNtHCm54uXQ=="
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.6.0.tgz",
|
||||
"integrity": "sha512-5Y6/fP28aspPDRB+Tz5GuB1jRVGuUEk5/rnyE8ACGcuzEOG+zR0A/IHRJSU3XmCxUlVDKfKoO6St5W84oUCVMA=="
|
||||
},
|
||||
"@stencil/react-output-target": {
|
||||
"version": "0.5.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -31,7 +31,7 @@
|
||||
"loader/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.7.1",
|
||||
"@stencil/core": "^4.6.0",
|
||||
"ionicons": "^7.2.1",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
@@ -86,11 +86,13 @@
|
||||
"lint.sass.fix": "npm run lint.sass -- --fix",
|
||||
"lint.ts": "npm run eslint",
|
||||
"lint.ts.fix": "npm run eslint -- --fix",
|
||||
"prerelease": "npm run validate && np prerelease --yolo --any-branch --tag next",
|
||||
"prerender.e2e": "node scripts/testing/prerender.js",
|
||||
"prettier": "prettier \"./src/**/*.{html,ts,tsx,js,jsx}\"",
|
||||
"start": "npm run build.css && stencil build --dev --watch --serve",
|
||||
"test": "npm run test.spec && npm run test.e2e",
|
||||
"test.spec": "stencil test --spec --max-workers=2",
|
||||
"test.spec.debug": "npx --node-arg=\"--inspect-brk\" stencil test --spec",
|
||||
"test.e2e": "npx playwright test",
|
||||
"test.e2e.update-snapshots": "npm run test.e2e -- --update-snapshots",
|
||||
"test.watch": "jest --watch --no-cache",
|
||||
|
||||
4
core/src/components.d.ts
vendored
@@ -915,7 +915,7 @@ export namespace Components {
|
||||
*/
|
||||
"presentation": DatetimePresentation;
|
||||
/**
|
||||
* If `true`, the datetime appears normal but the selected date cannot be changed.
|
||||
* If `true`, the datetime appears normal but is not interactive.
|
||||
*/
|
||||
"readonly": boolean;
|
||||
/**
|
||||
@@ -5595,7 +5595,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"presentation"?: DatetimePresentation;
|
||||
/**
|
||||
* If `true`, the datetime appears normal but the selected date cannot be changed.
|
||||
* If `true`, the datetime appears normal but is not interactive.
|
||||
*/
|
||||
"readonly"?: boolean;
|
||||
/**
|
||||
|
||||
@@ -185,37 +185,13 @@ ion-picker-column-internal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host(.datetime-readonly),
|
||||
:host(.datetime-disabled) {
|
||||
pointer-events: none;
|
||||
|
||||
.calendar-days-of-week,
|
||||
.datetime-time {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
:host(.datetime-readonly) {
|
||||
pointer-events: none;
|
||||
|
||||
/**
|
||||
* Allow user to navigate months
|
||||
* while in readonly mode
|
||||
*/
|
||||
.calendar-action-buttons,
|
||||
.calendar-body,
|
||||
.datetime-year {
|
||||
pointer-events: initial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disabled buttons should have full opacity
|
||||
* in readonly mode
|
||||
*/
|
||||
|
||||
.calendar-day[disabled]:not(.calendar-day-constrained),
|
||||
.datetime-action-buttons ion-button[disabled] {
|
||||
opacity: 1;
|
||||
}
|
||||
:host(.datetime-disabled) {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -172,7 +172,7 @@ export class Datetime implements ComponentInterface {
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* If `true`, the datetime appears normal but the selected date cannot be changed.
|
||||
* If `true`, the datetime appears normal but is not interactive.
|
||||
*/
|
||||
@Prop() readonly = false;
|
||||
|
||||
@@ -599,14 +599,6 @@ export class Datetime implements ComponentInterface {
|
||||
};
|
||||
|
||||
private setActiveParts = (parts: DatetimeParts, removeDate = false) => {
|
||||
/** if the datetime component is in readonly mode,
|
||||
* allow browsing of the calendar without changing
|
||||
* the set value
|
||||
*/
|
||||
if (this.readonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { multiple, minParts, maxParts, activeParts } = this;
|
||||
|
||||
/**
|
||||
@@ -1422,13 +1414,7 @@ export class Datetime implements ComponentInterface {
|
||||
*/
|
||||
|
||||
private renderFooter() {
|
||||
const { disabled, readonly, showDefaultButtons, showClearButton } = this;
|
||||
/**
|
||||
* The cancel, clear, and confirm buttons
|
||||
* should not be interactive if the datetime
|
||||
* is disabled or readonly.
|
||||
*/
|
||||
const isButtonDisabled = disabled || readonly;
|
||||
const { showDefaultButtons, showClearButton } = this;
|
||||
const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
|
||||
if (!hasSlottedButtons && !showDefaultButtons && !showClearButton) {
|
||||
return;
|
||||
@@ -1458,33 +1444,18 @@ export class Datetime implements ComponentInterface {
|
||||
<slot name="buttons">
|
||||
<ion-buttons>
|
||||
{showDefaultButtons && (
|
||||
<ion-button
|
||||
id="cancel-button"
|
||||
color={this.color}
|
||||
onClick={() => this.cancel(true)}
|
||||
disabled={isButtonDisabled}
|
||||
>
|
||||
<ion-button id="cancel-button" color={this.color} onClick={() => this.cancel(true)}>
|
||||
{this.cancelText}
|
||||
</ion-button>
|
||||
)}
|
||||
<div class="datetime-action-buttons-container">
|
||||
{showClearButton && (
|
||||
<ion-button
|
||||
id="clear-button"
|
||||
color={this.color}
|
||||
onClick={() => clearButtonClick()}
|
||||
disabled={isButtonDisabled}
|
||||
>
|
||||
<ion-button id="clear-button" color={this.color} onClick={() => clearButtonClick()}>
|
||||
{this.clearText}
|
||||
</ion-button>
|
||||
)}
|
||||
{showDefaultButtons && (
|
||||
<ion-button
|
||||
id="confirm-button"
|
||||
color={this.color}
|
||||
onClick={() => this.confirm(true)}
|
||||
disabled={isButtonDisabled}
|
||||
>
|
||||
<ion-button id="confirm-button" color={this.color} onClick={() => this.confirm(true)}>
|
||||
{this.doneText}
|
||||
</ion-button>
|
||||
)}
|
||||
@@ -1986,12 +1957,11 @@ export class Datetime implements ComponentInterface {
|
||||
*/
|
||||
|
||||
private renderCalendarHeader(mode: Mode) {
|
||||
const { disabled } = this;
|
||||
const expandedIcon = mode === 'ios' ? chevronDown : caretUpSharp;
|
||||
const collapsedIcon = mode === 'ios' ? chevronForward : caretDownSharp;
|
||||
|
||||
const prevMonthDisabled = disabled || isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
|
||||
const nextMonthDisabled = disabled || isNextMonthDisabled(this.workingParts, this.maxParts);
|
||||
const prevMonthDisabled = isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
|
||||
const nextMonthDisabled = isNextMonthDisabled(this.workingParts, this.maxParts);
|
||||
|
||||
// don't use the inheritAttributes util because it removes dir from the host, and we still need that
|
||||
const hostDir = this.el.getAttribute('dir') || undefined;
|
||||
@@ -2007,7 +1977,6 @@ export class Datetime implements ComponentInterface {
|
||||
aria-label="Show year picker"
|
||||
detail={false}
|
||||
lines="none"
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
this.toggleMonthAndYearView();
|
||||
/**
|
||||
@@ -2074,28 +2043,23 @@ export class Datetime implements ComponentInterface {
|
||||
);
|
||||
}
|
||||
private renderMonth(month: number, year: number) {
|
||||
const { disabled, readonly } = this;
|
||||
|
||||
const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year);
|
||||
const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month);
|
||||
const isCalMonthDisabled = !yearAllowed || !monthAllowed;
|
||||
const isDatetimeDisabled = disabled || readonly;
|
||||
const swipeDisabled =
|
||||
disabled ||
|
||||
isMonthDisabled(
|
||||
{
|
||||
month,
|
||||
year,
|
||||
day: null,
|
||||
},
|
||||
{
|
||||
// The day is not used when checking if a month is disabled.
|
||||
// Users should be able to access the min or max month, even if the
|
||||
// min/max date is out of bounds (e.g. min is set to Feb 15, Feb should not be disabled).
|
||||
minParts: { ...this.minParts, day: null },
|
||||
maxParts: { ...this.maxParts, day: null },
|
||||
}
|
||||
);
|
||||
const swipeDisabled = isMonthDisabled(
|
||||
{
|
||||
month,
|
||||
year,
|
||||
day: null,
|
||||
},
|
||||
{
|
||||
// The day is not used when checking if a month is disabled.
|
||||
// Users should be able to access the min or max month, even if the
|
||||
// min/max date is out of bounds (e.g. min is set to Feb 15, Feb should not be disabled).
|
||||
minParts: { ...this.minParts, day: null },
|
||||
maxParts: { ...this.maxParts, day: null },
|
||||
}
|
||||
);
|
||||
// The working month should never have swipe disabled.
|
||||
// Otherwise the CSS scroll snap will not work and the user
|
||||
// can free-scroll the calendar.
|
||||
@@ -2119,14 +2083,7 @@ export class Datetime implements ComponentInterface {
|
||||
const { el, highlightedDates, isDateEnabled, multiple } = this;
|
||||
const referenceParts = { month, day, year };
|
||||
const isCalendarPadding = day === null;
|
||||
const {
|
||||
isActive,
|
||||
isToday,
|
||||
ariaLabel,
|
||||
ariaSelected,
|
||||
disabled: isDayDisabled,
|
||||
text,
|
||||
} = getCalendarDayState(
|
||||
const { isActive, isToday, ariaLabel, ariaSelected, disabled, text } = getCalendarDayState(
|
||||
this.locale,
|
||||
referenceParts,
|
||||
this.activeParts,
|
||||
@@ -2137,8 +2094,7 @@ export class Datetime implements ComponentInterface {
|
||||
);
|
||||
|
||||
const dateIsoString = convertDataToISO(referenceParts);
|
||||
|
||||
let isCalDayDisabled = isCalMonthDisabled || isDayDisabled;
|
||||
let isCalDayDisabled = isCalMonthDisabled || disabled;
|
||||
|
||||
if (!isCalDayDisabled && isDateEnabled !== undefined) {
|
||||
try {
|
||||
@@ -2157,15 +2113,6 @@ export class Datetime implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Some days are constrained through max & min or allowed dates
|
||||
* and also disabled because the component is readonly or disabled.
|
||||
* These need to be displayed differently.
|
||||
*/
|
||||
const isCalDayConstrained = isCalDayDisabled && isDatetimeDisabled;
|
||||
|
||||
const isButtonDisabled = isCalDayDisabled || isDatetimeDisabled;
|
||||
|
||||
let dateStyle: DatetimeHighlightStyle | undefined = undefined;
|
||||
|
||||
/**
|
||||
@@ -2211,12 +2158,11 @@ export class Datetime implements ComponentInterface {
|
||||
data-year={year}
|
||||
data-index={index}
|
||||
data-day-of-week={dayOfWeek}
|
||||
disabled={isButtonDisabled}
|
||||
disabled={isCalDayDisabled}
|
||||
class={{
|
||||
'calendar-day-padding': isCalendarPadding,
|
||||
'calendar-day': true,
|
||||
'calendar-day-active': isActive,
|
||||
'calendar-day-constrained': isCalDayConstrained,
|
||||
'calendar-day-today': isToday,
|
||||
}}
|
||||
part={dateParts}
|
||||
@@ -2291,7 +2237,7 @@ export class Datetime implements ComponentInterface {
|
||||
}
|
||||
|
||||
private renderTimeOverlay() {
|
||||
const { disabled, hourCycle, isTimePopoverOpen, locale } = this;
|
||||
const { hourCycle, isTimePopoverOpen, locale } = this;
|
||||
const computedHourCycle = getHourCycle(locale, hourCycle);
|
||||
const activePart = this.getActivePartsWithFallback();
|
||||
|
||||
@@ -2305,7 +2251,6 @@ export class Datetime implements ComponentInterface {
|
||||
part={`time-button${isTimePopoverOpen ? ' active' : ''}`}
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
disabled={disabled}
|
||||
onClick={async (ev) => {
|
||||
const { popoverRef } = this;
|
||||
|
||||
|
||||
@@ -30,102 +30,3 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This behavior does not differ across
|
||||
* modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('datetime: a11y'), () => {
|
||||
test('datetime should be keyboard navigable', async ({ page, browserName }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-22T16:30:00"></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
|
||||
|
||||
const datetime = page.locator('ion-datetime');
|
||||
const monthYearButton = page.locator('.calendar-month-year ion-item');
|
||||
const prevButton = page.locator('.calendar-next-prev ion-button:nth-child(1)');
|
||||
const nextButton = page.locator('.calendar-next-prev ion-button:nth-child(2)');
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await expect(monthYearButton).toBeFocused();
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await expect(prevButton).toBeFocused();
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await expect(nextButton).toBeFocused();
|
||||
|
||||
// check value before & after selecting via keyboard
|
||||
const initialValue = await datetime.evaluate((el: HTMLIonDatetimeElement) => el.value);
|
||||
expect(initialValue).toBe('2022-02-22T16:30:00');
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await page.waitForChanges();
|
||||
|
||||
await page.keyboard.press('ArrowLeft');
|
||||
await page.waitForChanges();
|
||||
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
const newValue = await datetime.evaluate((el: HTMLIonDatetimeElement) => el.value);
|
||||
expect(newValue).not.toBe('2022-02-22T16:30:00');
|
||||
});
|
||||
|
||||
test('buttons should be keyboard navigable', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
|
||||
<ion-datetime value="2022-02-22T16:30:00" show-default-buttons="true" show-clear-button="true"></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const clearButton = page.locator('#clear-button button');
|
||||
const selectedDay = page.locator('.calendar-day-active');
|
||||
|
||||
await expect(selectedDay).toHaveText('22');
|
||||
|
||||
await clearButton.focus();
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(clearButton).toBeFocused();
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(selectedDay).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('should navigate through months via right arrow key', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
|
||||
<ion-datetime value="2022-02-28"></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||
const calendarBody = page.locator('.calendar-body');
|
||||
await expect(calendarMonthYear).toHaveText('February 2022');
|
||||
|
||||
await calendarBody.focus();
|
||||
await page.waitForChanges();
|
||||
|
||||
await page.keyboard.press('ArrowRight');
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(calendarMonthYear).toHaveText('March 2022');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not differ across
|
||||
* modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config, screenshot }) => {
|
||||
test.describe(title('datetime: disabled'), () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-05T00:00:00" min="2022-01-01T00:00:00" max="2022-02-20T23:59:59" day-values="5,6,10,11,15,16,20" show-default-buttons disabled></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const datetime = page.locator('ion-datetime');
|
||||
await expect(datetime).toHaveScreenshot(screenshot(`datetime-disabled`));
|
||||
});
|
||||
|
||||
test('date should be disabled', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const febFirstButton = page.locator(`.calendar-day[data-day='1'][data-month='2']`);
|
||||
|
||||
await expect(febFirstButton).toBeDisabled();
|
||||
});
|
||||
|
||||
test('month-year button should be disabled', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||
await expect(calendarMonthYear.locator('button')).toBeDisabled();
|
||||
});
|
||||
|
||||
test('next and prev buttons should be disabled', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const prevMonthButton = page.locator('ion-datetime .calendar-next-prev ion-button:first-of-type button');
|
||||
const nextMonthButton = page.locator('ion-datetime .calendar-next-prev ion-button:last-of-type button');
|
||||
|
||||
await expect(prevMonthButton).toBeDisabled();
|
||||
await expect(nextMonthButton).toBeDisabled();
|
||||
});
|
||||
|
||||
test('clear button should be disabled', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
|
||||
<ion-datetime value="2022-02-22T16:30:00" show-default-buttons="true" show-clear-button="true" disabled></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const clearButton = page.locator('#clear-button button');
|
||||
|
||||
await expect(clearButton).toBeDisabled();
|
||||
});
|
||||
|
||||
test('should not navigate through months via right arrow key', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-28" disabled></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||
const calendarBody = page.locator('.calendar-body');
|
||||
await expect(calendarMonthYear).toHaveText('February 2022');
|
||||
|
||||
await calendarBody.focus();
|
||||
await page.waitForChanges();
|
||||
|
||||
await page.keyboard.press('ArrowRight');
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(calendarMonthYear).toHaveText('February 2022');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,77 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Datetime - Disabled</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<style>
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(250px, 1fr));
|
||||
grid-row-gap: 20px;
|
||||
grid-column-gap: 20px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
|
||||
color: #6f7378;
|
||||
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
ion-datetime {
|
||||
width: 350px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Datetime - Disabled</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Inline - Default Value</h2>
|
||||
<ion-datetime id="inline-datetime-value" disabled value="2022-04-21T00:00:00"></ion-datetime>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Inline</h2>
|
||||
<ion-datetime
|
||||
id="inline-datetime"
|
||||
presentation="date"
|
||||
disabled
|
||||
show-default-buttons="true"
|
||||
show-clear-button="true"
|
||||
multiple="true"
|
||||
></ion-datetime>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Inline - No Default Value</h2>
|
||||
<ion-datetime id="inline-datetime-no-value" disabled></ion-datetime>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
<script>
|
||||
const firstDatetime = document.querySelector('#inline-datetime');
|
||||
firstDatetime.value = ['2023-08-03', '2023-08-13', '2023-08-29'];
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,167 +0,0 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not differ across
|
||||
* modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config, screenshot }) => {
|
||||
test.describe(title('datetime: readonly'), () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-05T00:00:00" min="2022-01-01T00:00:00" max="2022-02-20T23:59:59" day-values="5,6,10,11,15,16,20" show-default-buttons readonly></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const datetime = page.locator('ion-datetime');
|
||||
await expect(datetime).toHaveScreenshot(screenshot(`datetime-readonly`));
|
||||
});
|
||||
|
||||
test('date should be disabled', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-28" readonly></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const febFirstButton = page.locator(`.calendar-day[data-day='1'][data-month='2']`);
|
||||
|
||||
await expect(febFirstButton).toBeDisabled();
|
||||
});
|
||||
|
||||
test('should navigate months via month-year button', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||
await expect(calendarMonthYear).toHaveText('February 2022');
|
||||
|
||||
await calendarMonthYear.click();
|
||||
await page.waitForChanges();
|
||||
await page.locator('.month-column .picker-item[data-value="3"]').click();
|
||||
await page.waitForChanges();
|
||||
await expect(calendarMonthYear).toHaveText('March 2022');
|
||||
|
||||
await expect(ionChange).not.toHaveReceivedEvent();
|
||||
});
|
||||
|
||||
test('should open picker using keyboard navigation', async ({ page, browserName }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||
const monthYearButton = page.locator('.calendar-month-year ion-item');
|
||||
await expect(calendarMonthYear).toHaveText('February 2022');
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await expect(monthYearButton).toBeFocused();
|
||||
await page.waitForChanges();
|
||||
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForChanges();
|
||||
|
||||
const marchPickerItem = page.locator('.month-column .picker-item[data-value="3"]');
|
||||
await expect(marchPickerItem).toBeVisible();
|
||||
});
|
||||
|
||||
test('should view next month via next button', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
|
||||
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||
await expect(calendarMonthYear).toHaveText('February 2022');
|
||||
|
||||
const nextMonthButton = page.locator('ion-datetime .calendar-next-prev ion-button + ion-button');
|
||||
await nextMonthButton.click();
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(calendarMonthYear).toHaveText('March 2022');
|
||||
await expect(ionChange).not.toHaveReceivedEvent();
|
||||
});
|
||||
|
||||
test('should not change value when the month is changed via keyboard navigation', async ({ page, browserName }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-datetime value="2022-02-22T16:30:00" readonly></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const tabKey = browserName === 'webkit' ? 'Alt+Tab' : 'Tab';
|
||||
|
||||
const datetime = page.locator('ion-datetime');
|
||||
const monthYearButton = page.locator('.calendar-month-year ion-item');
|
||||
const prevButton = page.locator('.calendar-next-prev ion-button:nth-child(1)');
|
||||
const nextButton = page.locator('.calendar-next-prev ion-button:nth-child(2)');
|
||||
const calendarMonthYear = page.locator('ion-datetime .calendar-month-year');
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await expect(monthYearButton).toBeFocused();
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await expect(prevButton).toBeFocused();
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await expect(nextButton).toBeFocused();
|
||||
|
||||
// check value before & after selecting via keyboard
|
||||
const initialValue = await datetime.evaluate((el: HTMLIonDatetimeElement) => el.value);
|
||||
expect(initialValue).toBe('2022-02-22T16:30:00');
|
||||
await expect(calendarMonthYear).toHaveText('February 2022');
|
||||
|
||||
await page.keyboard.press(tabKey);
|
||||
await page.waitForChanges();
|
||||
|
||||
await page.keyboard.press('ArrowLeft');
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(calendarMonthYear).toHaveText('January 2022');
|
||||
await page.keyboard.press('Enter');
|
||||
await page.waitForChanges();
|
||||
|
||||
const newValue = await datetime.evaluate((el: HTMLIonDatetimeElement) => el.value);
|
||||
// should not have changed
|
||||
expect(newValue).toBe('2022-02-22T16:30:00');
|
||||
});
|
||||
|
||||
test('clear button should be disabled', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
|
||||
<ion-datetime value="2022-02-22T16:30:00" show-default-buttons="true" show-clear-button="true" readonly></ion-datetime>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await page.waitForSelector('.datetime-ready');
|
||||
|
||||
const clearButton = page.locator('#clear-button button');
|
||||
|
||||
await expect(clearButton).toBeDisabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 19 KiB |
@@ -1,83 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Datetime - Readonly</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<style>
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(250px, 1fr));
|
||||
grid-row-gap: 20px;
|
||||
grid-column-gap: 20px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
|
||||
color: #6f7378;
|
||||
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
ion-datetime {
|
||||
width: 350px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>Datetime - Readonly</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<div class="grid">
|
||||
<div class="grid-item">
|
||||
<h2>Inline</h2>
|
||||
<ion-datetime
|
||||
id="inline-datetime"
|
||||
presentation="date"
|
||||
readonly
|
||||
show-default-buttons="true"
|
||||
show-clear-button="true"
|
||||
multiple="true"
|
||||
></ion-datetime>
|
||||
</div>
|
||||
|
||||
<div class="grid-item">
|
||||
<h2>Inline - No Default Value</h2>
|
||||
<ion-datetime id="inline-datetime-no-value" readonly></ion-datetime>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
<script>
|
||||
const firstDatetime = document.querySelector('#inline-datetime');
|
||||
firstDatetime.value = ['2023-08-03', '2023-08-13', '2023-08-29'];
|
||||
|
||||
firstDatetime.isDateEnabled = (dateString) => {
|
||||
const date = new Date(dateString);
|
||||
const utcDay = date.getUTCDay();
|
||||
|
||||
/**
|
||||
* Date will be enabled if it is not
|
||||
* Sunday or Saturday
|
||||
*/
|
||||
return utcDay !== 0 && utcDay !== 6;
|
||||
};
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -203,21 +203,14 @@
|
||||
.item-native {
|
||||
@include border-radius(var(--border-radius));
|
||||
@include margin(0);
|
||||
@include padding(var(--padding-top), null, var(--padding-bottom));
|
||||
@include padding(
|
||||
var(--padding-top),
|
||||
var(--padding-end),
|
||||
var(--padding-bottom),
|
||||
calc(var(--padding-start) + var(--ion-safe-area-left, 0px))
|
||||
);
|
||||
@include text-inherit();
|
||||
|
||||
/* stylelint-disable */
|
||||
@include ltr() {
|
||||
padding-right: var(--padding-end);
|
||||
padding-left: calc(var(--padding-start) + var(--ion-safe-area-left, 0px));
|
||||
}
|
||||
|
||||
@include rtl() {
|
||||
padding-right: calc(var(--padding-start) + var(--ion-safe-area-right, 0px));
|
||||
padding-left: var(--padding-end);
|
||||
}
|
||||
/* stylelint-enable */
|
||||
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
@@ -268,19 +261,12 @@ button, a {
|
||||
|
||||
.item-inner {
|
||||
@include margin(0);
|
||||
@include padding(var(--inner-padding-top), null, var(--inner-padding-bottom));
|
||||
|
||||
/* stylelint-disable */
|
||||
@include ltr() {
|
||||
padding-right: calc(var(--ion-safe-area-right, 0px) + var(--inner-padding-end));
|
||||
padding-left: var(--inner-padding-start);
|
||||
}
|
||||
|
||||
@include rtl() {
|
||||
padding-right: var(--inner-padding-start);
|
||||
padding-left: calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end));
|
||||
}
|
||||
/* stylelint-enable */
|
||||
@include padding(
|
||||
var(--inner-padding-top),
|
||||
calc(var(--ion-safe-area-right, 0px) + var(--inner-padding-end)),
|
||||
var(--inner-padding-bottom),
|
||||
var(--inner-padding-start)
|
||||
);
|
||||
|
||||
display: flex;
|
||||
|
||||
@@ -309,19 +295,12 @@ button, a {
|
||||
|
||||
.item-bottom {
|
||||
@include margin(0);
|
||||
@include padding(0, null);
|
||||
|
||||
/* stylelint-disable */
|
||||
@include ltr() {
|
||||
padding-left: calc(var(--padding-start) + var(--ion-safe-area-left, 0px));
|
||||
padding-right: calc(var(--inner-padding-end) + var(--ion-safe-area-right, 0px));
|
||||
}
|
||||
|
||||
@include rtl() {
|
||||
padding-left: calc(var(--inner-padding-end) + var(--ion-safe-area-left, 0px));
|
||||
padding-right: calc(var(--padding-start) + var(--ion-safe-area-right, 0px));
|
||||
}
|
||||
/* stylelint-enable */
|
||||
@include padding(
|
||||
0,
|
||||
var(--inner-padding-end),
|
||||
0,
|
||||
calc(var(--padding-start) + var(--ion-safe-area-left, 0px))
|
||||
);
|
||||
|
||||
display: flex;
|
||||
|
||||
|
||||
@@ -10,37 +10,5 @@ configs().forEach(({ title, screenshot, config }) => {
|
||||
|
||||
await expect(page).toHaveScreenshot(screenshot(`item-diff`));
|
||||
});
|
||||
|
||||
/**
|
||||
* This behavior needs to be tested for all modes & directions
|
||||
* Safe padding should stay on the same side when the direction changes
|
||||
*/
|
||||
test('should have safe area padding', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
:root {
|
||||
--ion-safe-area-left: 40px;
|
||||
--ion-safe-area-right: 20px;
|
||||
}
|
||||
</style>
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Item with helper</ion-label>
|
||||
<div slot="helper">Helper</div>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label> Single line text that should have ellipses when it doesn't all fit in the item</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const list = page.locator('ion-list');
|
||||
|
||||
await expect(list).toHaveScreenshot(screenshot('item-safe-area'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
@@ -19,25 +19,12 @@
|
||||
@include border-radius($list-inset-ios-border-radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* These selectors ensure the last item in the list
|
||||
* has the correct border.
|
||||
* We need to consider the following scenarios:
|
||||
1. The only item in a list.
|
||||
2. The last item in a list as long as it is not the only item.
|
||||
3. The item in the last item-sliding in a list.
|
||||
* Note that we do not select ion-item:last-of-type
|
||||
* because that will cause the borders to disappear on
|
||||
* items in an item-sliding when the item is the last
|
||||
* element in the item-sliding container.
|
||||
*/
|
||||
.list-ios.list-inset ion-item:only-child,
|
||||
.list-ios.list-inset ion-item:not(:only-of-type):last-of-type,
|
||||
.list-ios.list-inset ion-item-sliding:last-of-type ion-item {
|
||||
.list-ios.list-inset ion-item:last-child {
|
||||
--border-width: 0;
|
||||
--inner-border-width: 0;
|
||||
}
|
||||
|
||||
|
||||
.list-ios.list-inset + ion-list.list-inset {
|
||||
@include margin(0, null, null, null);
|
||||
}
|
||||
|
||||
@@ -23,50 +23,12 @@
|
||||
@include border-radius($list-inset-md-border-radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* These selectors ensure the first item in the list
|
||||
* has the correct radius.
|
||||
* We need to consider the following scenarios:
|
||||
1. The first item in a list as long as it is not the only item.
|
||||
2. The item in the first item-sliding in a list.
|
||||
* Note that we do not select "ion-item-sliding ion-item:first-of-type"
|
||||
* because that will cause the borders to disappear on
|
||||
* items in an item-sliding when the item is the first
|
||||
* element in the item-sliding container.
|
||||
*/
|
||||
.list-md.list-inset ion-item:not(:only-of-type):first-of-type,
|
||||
.list-md.list-inset ion-item-sliding:first-of-type ion-item {
|
||||
.list-md.list-inset ion-item:first-child {
|
||||
--border-radius: #{$list-inset-md-border-radius $list-inset-md-border-radius 0 0};
|
||||
}
|
||||
|
||||
/**
|
||||
* These selectors ensure the last item in the list
|
||||
* has the correct radius and border.
|
||||
* We need to consider the following scenarios:
|
||||
1. The last item in a list as long as it is not the only item.
|
||||
2. The item in the last item-sliding in a list.
|
||||
* Note that we do not select "ion-item-sliding ion-item:last-of-type"
|
||||
* because that will cause the borders to disappear on
|
||||
* items in an item-sliding when the item is the last
|
||||
* element in the item-sliding container.
|
||||
*/
|
||||
.list-md.list-inset ion-item:not(:only-of-type):last-of-type,
|
||||
.list-md.list-inset ion-item-sliding:last-of-type ion-item {
|
||||
--border-radius: #{0 0 $list-inset-md-border-radius $list-inset-md-border-radius};
|
||||
--border-width: 0;
|
||||
--inner-border-width: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The only item in a list should have a border radius
|
||||
* on all corners.
|
||||
* We target :only-child instead of :only-of-type
|
||||
* otherwise borders will disappear on items inside of
|
||||
* ion-item-sliding because the item will be the only
|
||||
* one of its type inside of the ion-item-sliding group.
|
||||
*/
|
||||
.list-md.list-inset ion-item:only-child {
|
||||
--border-radius: #{$list-inset-md-border-radius};
|
||||
.list-md.list-inset ion-item:last-child {
|
||||
--border-radius: #{0 0 $list-inset-md-border-radius, $list-inset-md-border-radius};
|
||||
--border-width: 0;
|
||||
--inner-border-width: 0;
|
||||
}
|
||||
|
||||
@@ -26,162 +26,3 @@ configs().forEach(({ title, screenshot, config }) => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Padding and border color ensures the bottom border can be easily seen if it regresses.
|
||||
* The background color ensures that any border radius values can be seen.
|
||||
*/
|
||||
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('list: lines with children'), () => {
|
||||
test('only item in inset list should not have line', async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/28435',
|
||||
});
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
#container {
|
||||
padding: 10px;
|
||||
background: #0088cc;
|
||||
}
|
||||
|
||||
ion-item {
|
||||
--border-color: red;
|
||||
}
|
||||
</style>
|
||||
<div id="container">
|
||||
<ion-list inset="true">
|
||||
<ion-item>
|
||||
<ion-label>Item 0</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</div>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const container = page.locator('#container');
|
||||
|
||||
await expect(container).toHaveScreenshot(screenshot('inset-list-only-item-no-lines'));
|
||||
});
|
||||
test('last item in inset list with end options should not have line', async ({ page }) => {
|
||||
test.info().annotations.push({
|
||||
type: 'issue',
|
||||
description: 'https://github.com/ionic-team/ionic-framework/issues/28435',
|
||||
});
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
#container {
|
||||
padding: 10px;
|
||||
background: #0088cc;
|
||||
}
|
||||
|
||||
ion-item {
|
||||
--border-color: red;
|
||||
}
|
||||
</style>
|
||||
<div id="container">
|
||||
<ion-list inset="true">
|
||||
<ion-item-sliding>
|
||||
<ion-item>
|
||||
<ion-label>Item 0</ion-label>
|
||||
</ion-item>
|
||||
<ion-item-options slot="end">
|
||||
<ion-item-option color="warning">
|
||||
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
|
||||
<ion-item-sliding>
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
</ion-item>
|
||||
<ion-item-options slot="end">
|
||||
<ion-item-option color="warning">
|
||||
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
|
||||
<ion-item-sliding>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
</ion-item>
|
||||
<ion-item-options slot="end">
|
||||
<ion-item-option color="warning">
|
||||
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
</ion-item-sliding>
|
||||
</ion-list>
|
||||
</div>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const container = page.locator('#container');
|
||||
|
||||
await expect(container).toHaveScreenshot(screenshot('inset-list-end-options-no-lines'));
|
||||
});
|
||||
test('last item in inset list with start options should not have line', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<style>
|
||||
#container {
|
||||
padding: 10px;
|
||||
background: #0088cc;
|
||||
}
|
||||
|
||||
ion-item {
|
||||
--border-color: red;
|
||||
}
|
||||
</style>
|
||||
<div id="container">
|
||||
<ion-list inset="true">
|
||||
<ion-item-sliding>
|
||||
<ion-item-options slot="start">
|
||||
<ion-item-option color="warning">
|
||||
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
<ion-item>
|
||||
<ion-label>Item 0</ion-label>
|
||||
</ion-item>
|
||||
</ion-item-sliding>
|
||||
|
||||
<ion-item-sliding>
|
||||
<ion-item-options slot="start">
|
||||
<ion-item-option color="warning">
|
||||
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
</ion-item>
|
||||
</ion-item-sliding>
|
||||
|
||||
<ion-item-sliding>
|
||||
<ion-item-options slot="start">
|
||||
<ion-item-option color="warning">
|
||||
<ion-icon slot="icon-only" name="pin"></ion-icon>
|
||||
</ion-item-option>
|
||||
</ion-item-options>
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
</ion-item>
|
||||
</ion-item-sliding>
|
||||
</ion-list>
|
||||
</div>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const container = page.locator('#container');
|
||||
|
||||
await expect(container).toHaveScreenshot(screenshot('inset-list-start-options-no-lines'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
@@ -9,14 +9,6 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
test('inline pickers should not have visual regression', async ({ page }) => {
|
||||
await page.goto(`/src/components/picker-internal/test/basic`, config);
|
||||
|
||||
const fullStack = page.locator('#inline button[data-value="full-stack"]');
|
||||
const onion = page.locator('#inline button[data-value="onion"]');
|
||||
|
||||
await expect(fullStack).toHaveClass(/picker-item-active/);
|
||||
await expect(onion).toHaveClass(/picker-item-active/);
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(page.locator('#inline')).toHaveScreenshot(screenshot(`picker-internal-inline-diff`));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,6 +48,11 @@ export type LegacyFormController = {
|
||||
};
|
||||
|
||||
const hasLabelSlot = (controlEl: HTMLElement) => {
|
||||
const root = controlEl.shadowRoot;
|
||||
if (root === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Components that have a named label slot
|
||||
* also have other slots, so we need to query for
|
||||
@@ -69,5 +74,5 @@ const hasLabelSlot = (controlEl: HTMLElement) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
const NAMED_LABEL_SLOT_COMPONENTS = ['ION-INPUT', 'ION-TEXTAREA', 'ION-SELECT', 'ION-RANGE'];
|
||||
const NAMED_LABEL_SLOT_COMPONENTS = ['ION-RANGE'];
|
||||
const UNNAMED_LABEL_SLOT_COMPONENTS = ['ION-TOGGLE', 'ION-CHECKBOX', 'ION-RADIO'];
|
||||
|
||||
@@ -3,15 +3,7 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.5.4](https://github.com/ionic-team/ionic-framework/compare/v7.5.3...v7.5.4) (2023-11-08)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.5.3](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3) (2023-11-01)
|
||||
## [7.5.3-nightly.20231031](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3-nightly.20231031) (2023-10-31)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
4
docs/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"description": "Pre-packaged API documentation for the Ionic docs.",
|
||||
"main": "core.json",
|
||||
"types": "core.d.ts",
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"docs",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "7.5.4"
|
||||
"version": "7.5.3-nightly.20231031"
|
||||
}
|
||||
|
||||
@@ -3,15 +3,7 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.5.4](https://github.com/ionic-team/ionic-framework/compare/v7.5.3...v7.5.4) (2023-11-08)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.5.3](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3) (2023-11-01)
|
||||
## [7.5.3-nightly.20231031](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3-nightly.20231031) (2023-10-31)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
18
packages/angular-server/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.5.4"
|
||||
"@ionic/core": "^7.5.3-nightly.20231031"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-eslint/eslint-plugin": "^14.0.0",
|
||||
@@ -1060,9 +1060,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.3.tgz",
|
||||
"integrity": "sha512-nd4NV6gSgohLvKHGmf+jAcgzI1387eKq3enjBfE574FK/ikl5CeIltv0MBVJr9lz0pNSL/y9m1tdaFg+syASuA==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.2.tgz",
|
||||
"integrity": "sha512-0O8YgaE7CzrhDLGpnNq2Ia4bR+qFE1uHJHafoNWhoTXkydNnqSMZlxMCvtSetfv9bwLic93lcXYNoZ8I8zV3XA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.6.0",
|
||||
"ionicons": "^7.2.1",
|
||||
@@ -7330,9 +7330,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.3.tgz",
|
||||
"integrity": "sha512-nd4NV6gSgohLvKHGmf+jAcgzI1387eKq3enjBfE574FK/ikl5CeIltv0MBVJr9lz0pNSL/y9m1tdaFg+syASuA==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.2.tgz",
|
||||
"integrity": "sha512-0O8YgaE7CzrhDLGpnNq2Ia4bR+qFE1uHJHafoNWhoTXkydNnqSMZlxMCvtSetfv9bwLic93lcXYNoZ8I8zV3XA==",
|
||||
"requires": {
|
||||
"@stencil/core": "^4.6.0",
|
||||
"ionicons": "^7.2.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"description": "Angular SSR Module for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -61,6 +61,6 @@
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.5.4"
|
||||
"@ionic/core": "^7.5.3-nightly.20231031"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,11 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.5.4](https://github.com/ionic-team/ionic-framework/compare/v7.5.3...v7.5.4) (2023-11-08)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [7.5.3](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3) (2023-11-01)
|
||||
## [7.5.3-nightly.20231031](https://github.com/ionic-team/ionic-framework/compare/v7.5.2...v7.5.3-nightly.20231031) (2023-10-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular:** inputs on standalone form controls are reactive ([#28434](https://github.com/ionic-team/ionic-framework/issues/28434)) ([3b6e631](https://github.com/ionic-team/ionic-framework/commit/3b6e6318bf94125b3f8305b4d072a5945ceb3730)), closes [#28431](https://github.com/ionic-team/ionic-framework/issues/28431)
|
||||
* **angular:** NavController works with nested outlets ([#28421](https://github.com/ionic-team/ionic-framework/issues/28421)) ([90acad1](https://github.com/ionic-team/ionic-framework/commit/90acad1837b117542830ec0083389a35c5b4ee76)), closes [#28417](https://github.com/ionic-team/ionic-framework/issues/28417)
|
||||
* **angular:** run platform subscriptions inside zone ([#28404](https://github.com/ionic-team/ionic-framework/issues/28404)) ([a4b303e](https://github.com/ionic-team/ionic-framework/commit/a4b303e1338a35756a9cf7f67508d24d2f8537a2)), closes [#19539](https://github.com/ionic-team/ionic-framework/issues/19539)
|
||||
* **angular:** standalone form components do not error when multiple are used ([#28423](https://github.com/ionic-team/ionic-framework/issues/28423)) ([89698b3](https://github.com/ionic-team/ionic-framework/commit/89698b338fb05cde427c98720c238d2365abdaa7)), closes [#28418](https://github.com/ionic-team/ionic-framework/issues/28418)
|
||||
|
||||
18
packages/angular/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.5.4",
|
||||
"@ionic/core": "^7.5.3-nightly.20231031",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
@@ -1227,9 +1227,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.3.tgz",
|
||||
"integrity": "sha512-nd4NV6gSgohLvKHGmf+jAcgzI1387eKq3enjBfE574FK/ikl5CeIltv0MBVJr9lz0pNSL/y9m1tdaFg+syASuA==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.2.tgz",
|
||||
"integrity": "sha512-0O8YgaE7CzrhDLGpnNq2Ia4bR+qFE1uHJHafoNWhoTXkydNnqSMZlxMCvtSetfv9bwLic93lcXYNoZ8I8zV3XA==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^4.6.0",
|
||||
"ionicons": "^7.2.1",
|
||||
@@ -8093,9 +8093,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.3.tgz",
|
||||
"integrity": "sha512-nd4NV6gSgohLvKHGmf+jAcgzI1387eKq3enjBfE574FK/ikl5CeIltv0MBVJr9lz0pNSL/y9m1tdaFg+syASuA==",
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.5.2.tgz",
|
||||
"integrity": "sha512-0O8YgaE7CzrhDLGpnNq2Ia4bR+qFE1uHJHafoNWhoTXkydNnqSMZlxMCvtSetfv9bwLic93lcXYNoZ8I8zV3XA==",
|
||||
"requires": {
|
||||
"@stencil/core": "^4.6.0",
|
||||
"ionicons": "^7.2.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.5.4",
|
||||
"version": "7.5.3-nightly.20231031",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.5.4",
|
||||
"@ionic/core": "^7.5.3-nightly.20231031",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
|
||||
@@ -7,14 +7,26 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor, setIonicClasses } from '@ionic/angular/common';
|
||||
import type { CheckboxChangeEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-checkbox.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonCheckbox = IonCheckbox_1 = class IonCheckbox extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonCheckbox extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const CHECKBOX_INPUTS = [
|
||||
'checked',
|
||||
@@ -29,42 +41,40 @@ const CHECKBOX_INPUTS = [
|
||||
'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonCheckbox),
|
||||
multi: true,
|
||||
};
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: CHECKBOX_INPUTS,
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-checkbox',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: CHECKBOX_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonCheckbox,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonCheckbox extends ValueAccessor {
|
||||
export class IonCheckbox extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonCheckbox, CHECKBOX_INPUTS);
|
||||
}
|
||||
|
||||
writeValue(value: boolean): void {
|
||||
this.elementRef.nativeElement.checked = this.lastValue = value;
|
||||
setIonicClasses(this.elementRef);
|
||||
|
||||
@@ -7,14 +7,26 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type { DatetimeChangeEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-datetime.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonDatetime = IonDatetime_1 = class IonDatetime extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonDatetime extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const DATETIME_INPUTS = [
|
||||
'cancelText',
|
||||
@@ -49,44 +61,43 @@ const DATETIME_INPUTS = [
|
||||
'yearValues',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
const DATETIME_METHODS = ['confirm', 'reset', 'cancel'];
|
||||
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonDatetime),
|
||||
multi: true,
|
||||
};
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: DATETIME_INPUTS,
|
||||
methods: ['confirm', 'reset', 'cancel'],
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-datetime',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: DATETIME_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonDatetime,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonDatetime extends ValueAccessor {
|
||||
export class IonDatetime extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionCancel', 'ionChange', 'ionFocus', 'ionBlur']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonDatetime, DATETIME_INPUTS);
|
||||
proxyMethods(IonDatetime, DATETIME_METHODS);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
handleIonChange(el: HTMLIonDatetimeElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type {
|
||||
@@ -18,7 +18,19 @@ import type {
|
||||
} from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-input.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonInput = IonInput_1 = class IonInput extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonInput extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const INPUT_INPUTS = [
|
||||
'accept',
|
||||
@@ -60,43 +72,43 @@ const INPUT_INPUTS = [
|
||||
'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonInput),
|
||||
multi: true,
|
||||
};
|
||||
const INPUT_METHODS = ['setFocus', 'getInputElement'];
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: INPUT_INPUTS,
|
||||
methods: ['setFocus', 'getInputElement'],
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-input',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: INPUT_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonInput,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonInput extends ValueAccessor {
|
||||
export class IonInput extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionBlur', 'ionFocus']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonInput, INPUT_INPUTS);
|
||||
proxyMethods(IonInput, INPUT_METHODS);
|
||||
}
|
||||
|
||||
@HostListener('ionInput', ['$event.target'])
|
||||
handleIonInput(el: HTMLIonInputElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,53 +7,63 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type { RadioGroupChangeEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-radio-group.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonRadioGroup = IonRadioGroup_1 = class IonRadioGroup extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonRadioGroup extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value'];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonRadioGroup),
|
||||
multi: true,
|
||||
};
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: RADIO_GROUP_INPUTS,
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-radio-group',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: RADIO_GROUP_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonRadioGroup,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonRadioGroup extends ValueAccessor {
|
||||
export class IonRadioGroup extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionChange']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonRadioGroup, RADIO_GROUP_INPUTS);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
handleIonChange(el: HTMLIonRadioGroupElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,53 +7,63 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type { Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-radio.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonRadio = IonRadio_1 = class IonRadio extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonRadio extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value'];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonRadio),
|
||||
multi: true,
|
||||
};
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: RADIO_INPUTS,
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-radio',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: RADIO_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonRadio,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonRadio extends ValueAccessor {
|
||||
export class IonRadio extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonRadio, RADIO_INPUTS);
|
||||
}
|
||||
|
||||
@HostListener('ionSelect', ['$event.target'])
|
||||
handleIonSelect(el: any): void {
|
||||
/**
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type {
|
||||
@@ -19,7 +19,19 @@ import type {
|
||||
} from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-range.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonRange = IonRange_1 = class IonRange extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonRange extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const RANGE_INPUTS = [
|
||||
'activeBarStart',
|
||||
@@ -42,42 +54,40 @@ const RANGE_INPUTS = [
|
||||
'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonRange),
|
||||
multi: true,
|
||||
};
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: RANGE_INPUTS,
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-range',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: RANGE_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonRange,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonRange extends ValueAccessor {
|
||||
export class IonRange extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionFocus', 'ionBlur', 'ionKnobMoveStart', 'ionKnobMoveEnd']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonRange, RANGE_INPUTS);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
handleIonChange(el: HTMLIonRangeElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,14 +7,26 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type { SearchbarInputEventDetail, SearchbarChangeEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-searchbar.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonSearchbar = IonSearchbar_1 = class IonSearchbar extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonSearchbar extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const SEARCHBAR_INPUTS = [
|
||||
'animated',
|
||||
@@ -39,43 +51,43 @@ const SEARCHBAR_INPUTS = [
|
||||
'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonSearchbar),
|
||||
multi: true,
|
||||
};
|
||||
const SEARCHBAR_METHODS = ['setFocus', 'getInputElement'];
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: SEARCHBAR_INPUTS,
|
||||
methods: ['setFocus', 'getInputElement'],
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-searchbar',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: SEARCHBAR_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonSearchbar,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonSearchbar extends ValueAccessor {
|
||||
export class IonSearchbar extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionCancel', 'ionClear', 'ionBlur', 'ionFocus']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonSearchbar, SEARCHBAR_INPUTS);
|
||||
proxyMethods(IonSearchbar, SEARCHBAR_METHODS);
|
||||
}
|
||||
|
||||
@HostListener('ionInput', ['$event.target'])
|
||||
handleIonInput(el: HTMLIonSearchbarElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,53 +7,63 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type { SegmentChangeEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-segment.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonSegment = IonSegment_1 = class IonSegment extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonSegment extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocus', 'swipeGesture', 'value'];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonSegment),
|
||||
multi: true,
|
||||
};
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: SEGMENT_INPUTS,
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-segment',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: SEGMENT_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonSegment,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonSegment extends ValueAccessor {
|
||||
export class IonSegment extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionChange']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonSegment, SEGMENT_INPUTS);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
handleIonChange(el: HTMLIonSegmentElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,14 +7,26 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type { SelectChangeEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-select.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonSelect = IonSelect_1 = class IonSelect extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonSelect extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const SELECT_INPUTS = [
|
||||
'cancelText',
|
||||
@@ -40,43 +52,43 @@ const SELECT_INPUTS = [
|
||||
'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonSelect),
|
||||
multi: true,
|
||||
};
|
||||
const SELECT_METHODS = ['open'];
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: SELECT_INPUTS,
|
||||
methods: ['open'],
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-select',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: SELECT_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonSelect,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonSelect extends ValueAccessor {
|
||||
export class IonSelect extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionChange', 'ionCancel', 'ionDismiss', 'ionFocus', 'ionBlur']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonSelect, SELECT_INPUTS);
|
||||
proxyMethods(IonSelect, SELECT_METHODS);
|
||||
}
|
||||
|
||||
@HostListener('ionChange', ['$event.target'])
|
||||
handleIonChange(el: HTMLIonSelectElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,14 +7,26 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor } from '@ionic/angular/common';
|
||||
import type { TextareaChangeEventDetail, TextareaInputEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-textarea.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonTextarea = IonTextarea_1 = class IonTextarea extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonTextarea extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const TEXTAREA_INPUTS = [
|
||||
'autoGrow',
|
||||
@@ -49,43 +61,43 @@ const TEXTAREA_INPUTS = [
|
||||
'wrap',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonTextarea),
|
||||
multi: true,
|
||||
};
|
||||
const TEXTAREA_METHODS = ['setFocus', 'getInputElement'];
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: TEXTAREA_INPUTS,
|
||||
methods: ['setFocus', 'getInputElement'],
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-textarea',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: TEXTAREA_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonTextarea,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonTextarea extends ValueAccessor {
|
||||
export class IonTextarea extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionBlur', 'ionFocus']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonTextarea, TEXTAREA_INPUTS);
|
||||
proxyMethods(IonTextarea, TEXTAREA_METHODS);
|
||||
}
|
||||
|
||||
@HostListener('ionInput', ['$event.target'])
|
||||
handleIonInput(el: HTMLIonTextareaElement): void {
|
||||
this.handleValueChange(el, el.value);
|
||||
|
||||
@@ -7,14 +7,26 @@ import {
|
||||
HostListener,
|
||||
Injector,
|
||||
NgZone,
|
||||
forwardRef,
|
||||
} from '@angular/core';
|
||||
import type { OnInit } from '@angular/core';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ValueAccessor, setIonicClasses } from '@ionic/angular/common';
|
||||
import type { ToggleChangeEventDetail, Components } from '@ionic/core/components';
|
||||
import { defineCustomElement } from '@ionic/core/components/ion-toggle.js';
|
||||
|
||||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils';
|
||||
/**
|
||||
* Value accessor components should not use ProxyCmp
|
||||
* and should call defineCustomElement and proxyInputs
|
||||
* manually instead. Using both the @ProxyCmp and @Component
|
||||
* decorators and useExisting (where useExisting refers to the
|
||||
* class) causes ng-packagr to output multiple component variables
|
||||
* which breaks treeshaking.
|
||||
* For example, the following would be generated:
|
||||
* let IonToggle = IonToggle_1 = class IonToggle extends ValueAccessor {
|
||||
* Instead, we want only want the class generated:
|
||||
* class IonToggle extends ValueAccessor {
|
||||
*/
|
||||
import { proxyInputs, proxyOutputs } from './angular-component-lib/utils';
|
||||
|
||||
const TOGGLE_INPUTS = [
|
||||
'checked',
|
||||
@@ -29,42 +41,40 @@ const TOGGLE_INPUTS = [
|
||||
'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Pulling the provider into an object and using PURE works
|
||||
* around an ng-packagr issue that causes
|
||||
* components with multiple decorators and
|
||||
* a provider to be re-assigned. This re-assignment
|
||||
* is not supported by Webpack and causes treeshaking
|
||||
* to not work on these kinds of components.
|
||||
*/
|
||||
const accessorProvider = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: /*@__PURE__*/ forwardRef(() => IonToggle),
|
||||
multi: true,
|
||||
};
|
||||
|
||||
@ProxyCmp({
|
||||
defineCustomElementFn: defineCustomElement,
|
||||
inputs: TOGGLE_INPUTS,
|
||||
})
|
||||
@Component({
|
||||
selector: 'ion-toggle',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: TOGGLE_INPUTS,
|
||||
providers: [accessorProvider],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: IonToggle,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class IonToggle extends ValueAccessor {
|
||||
export class IonToggle extends ValueAccessor implements OnInit {
|
||||
protected el: HTMLElement;
|
||||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) {
|
||||
super(injector, r);
|
||||
defineCustomElement();
|
||||
c.detach();
|
||||
this.el = r.nativeElement;
|
||||
proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
/**
|
||||
* Data-bound input properties are set
|
||||
* by Angular after the constructor, so
|
||||
* we need to run the proxy in ngOnInit.
|
||||
*/
|
||||
proxyInputs(IonToggle, TOGGLE_INPUTS);
|
||||
}
|
||||
|
||||
writeValue(value: boolean): void {
|
||||
this.elementRef.nativeElement.checked = this.lastValue = value;
|
||||
setIonicClasses(this.elementRef);
|
||||
|
||||
@@ -14,6 +14,18 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-checkbox').should('have.class', 'ion-dirty');
|
||||
cy.get('ion-checkbox').should('have.class', 'ion-valid');
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-checkbox').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Datetime', () => {
|
||||
beforeEach(() => cy.visit('/standalone/value-accessors/datetime'));
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-datetime').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Input', () => {
|
||||
@@ -48,6 +60,10 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-input[formControlName="inputNumber"]').should('have.class', 'ion-valid');
|
||||
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-input').first().should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Radio Group', () => {
|
||||
@@ -63,8 +79,21 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-radio-group').should('have.class', 'ion-dirty');
|
||||
cy.get('ion-radio-group').should('have.class', 'ion-valid');
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-radio').first().should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Range', () => {
|
||||
beforeEach(() => cy.visit('/standalone/value-accessors/range'));
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-range').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Searchbar', () => {
|
||||
beforeEach(() => cy.visit('/standalone/value-accessors/searchbar'));
|
||||
|
||||
@@ -80,6 +109,10 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-searchbar').should('have.class', 'ion-dirty');
|
||||
cy.get('ion-searchbar').should('have.class', 'ion-valid');
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-searchbar').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Segment', () => {
|
||||
@@ -95,6 +128,10 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-segment').should('have.class', 'ion-dirty');
|
||||
cy.get('ion-segment').should('have.class', 'ion-valid');
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-segment').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Select', () => {
|
||||
@@ -113,6 +150,10 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-select').should('have.class', 'ion-dirty');
|
||||
cy.get('ion-select').should('have.class', 'ion-valid');
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-select').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Textarea', () => {
|
||||
@@ -130,6 +171,10 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-textarea').should('have.class', 'ion-dirty');
|
||||
cy.get('ion-textarea').should('have.class', 'ion-valid');
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-textarea').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Toggle', () => {
|
||||
@@ -145,6 +190,10 @@ describe('Value Accessors', () => {
|
||||
cy.get('ion-toggle').should('have.class', 'ion-dirty');
|
||||
cy.get('ion-toggle').should('have.class', 'ion-valid');
|
||||
});
|
||||
|
||||
it('should proxy inputs on load', () => {
|
||||
cy.get('ion-toggle').should('have.prop', 'color', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
</p>
|
||||
|
||||
<app-value-accessor-test [formGroup]="form">
|
||||
<ion-checkbox formControlName="checkbox"></ion-checkbox>
|
||||
<ion-checkbox color="danger" formControlName="checkbox"></ion-checkbox>
|
||||
</app-value-accessor-test>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
</p>
|
||||
|
||||
<app-value-accessor-test [formGroup]="form">
|
||||
<ion-datetime formControlName="datetime"></ion-datetime>
|
||||
<ion-datetime color="danger" formControlName="datetime"></ion-datetime>
|
||||
</app-value-accessor-test>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</p>
|
||||
|
||||
<app-value-accessor-test [formGroup]="form">
|
||||
<ion-input label="String" formControlName="inputString"></ion-input>
|
||||
<ion-input color="danger" label="String" formControlName="inputString"></ion-input>
|
||||
<ion-input label="Number" type="number" formControlName="inputNumber"></ion-input>
|
||||
</app-value-accessor-test>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<app-value-accessor-test [formGroup]="form">
|
||||
<ion-radio-group formControlName="radioGroup">
|
||||
<ion-radio value="1">One</ion-radio>
|
||||
<ion-radio color="danger" value="1">One</ion-radio>
|
||||
<ion-radio value="2">Two</ion-radio>
|
||||
</ion-radio-group>
|
||||
</app-value-accessor-test>
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
This test checks the form integrations with ion-range to make sure values are correctly assigned to the form group.
|
||||
</p>
|
||||
<app-value-accessor-test [formGroup]="form">
|
||||
<ion-range formControlName="range"></ion-range>
|
||||
<ion-range color="danger" formControlName="range"></ion-range>
|
||||
</app-value-accessor-test>
|
||||
</div>
|
||||
|
||||