From 290699517f087642adb2825e8aa701fd3617480f Mon Sep 17 00:00:00 2001 From: Mizga Ionut-Alexandru Date: Wed, 25 Sep 2024 14:27:42 +0300 Subject: [PATCH 1/4] fix(number-field): show decimal on iPad minimized keyboard --- packages/number-field/src/NumberField.ts | 46 ++++++++++-------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/packages/number-field/src/NumberField.ts b/packages/number-field/src/NumberField.ts index c5124adf61..b425224c09 100644 --- a/packages/number-field/src/NumberField.ts +++ b/packages/number-field/src/NumberField.ts @@ -10,6 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ +import { NumberFormatter, NumberParser } from '@internationalized/number'; import { CSSResultArray, html, @@ -21,24 +22,24 @@ import { property, query, } from '@spectrum-web-components/base/src/decorators.js'; +import { streamingListener } from '@spectrum-web-components/base/src/streaming-listener.js'; import { LanguageResolutionController, languageResolverUpdatedSymbol, } from '@spectrum-web-components/reactive-controllers/src/LanguageResolution.js'; -import { streamingListener } from '@spectrum-web-components/base/src/streaming-listener.js'; -import { NumberFormatter, NumberParser } from '@internationalized/number'; -import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron50.js'; -import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron75.js'; +import chevronStyles from '@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js'; import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js'; import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron200.js'; +import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron50.js'; +import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron75.js'; import '@spectrum-web-components/infield-button/sp-infield-button.js'; import { isAndroid, + isIOS, isIPhone, } from '@spectrum-web-components/shared/src/platform.js'; import { TextfieldBase } from '@spectrum-web-components/textfield'; -import chevronStyles from '@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js'; import styles from './number-field.css.js'; export const FRAMES_PER_CHANGE = 5; @@ -241,7 +242,7 @@ export class NumberField extends TextfieldBase { const uniqueSeparators = new Set(separators); if ( - isIPhone() && + isIOS() && this.inputElement.inputMode === 'decimal' && normalizedValue !== this.valueBeforeFocus ) { @@ -802,30 +803,21 @@ export class NumberField extends TextfieldBase { } if (changes.has('min') || changes.has('formatOptions')) { - let inputMode = 'numeric'; const hasNegative = typeof this.min !== 'undefined' && this.min < 0; const { maximumFractionDigits } = this.numberFormatter.resolvedOptions(); - const hasDecimals = maximumFractionDigits > 0; - /* c8 ignore next 18 */ - if (isIPhone()) { - // iPhone doesn't have a minus sign in either numeric or decimal. - // Note this is only for iPhone, not iPad, which always has both - // minus and decimal in numeric. - if (hasNegative) { - inputMode = 'text'; - } else if (hasDecimals) { - inputMode = 'decimal'; - } - } else if (isAndroid()) { - // Android numeric has both a decimal point and minus key. - // decimal does not have a minus key. - if (hasNegative) { - inputMode = 'numeric'; - } else if (hasDecimals) { - inputMode = 'decimal'; - } - } + const hasDecimals = + maximumFractionDigits && maximumFractionDigits > 0; + + let inputMode = 'numeric'; + /* c8 ignore next 5 */ + // iPhone doesn't have a minus sign in either numeric or decimal. + if (isIPhone() && hasNegative) inputMode = 'text'; + else if (isIOS() && hasDecimals) inputMode = 'decimal'; + // Android numeric has both a decimal point and minus key. Decimal does not have a minus key. + else if (isAndroid() && hasDecimals && !hasNegative) + inputMode = 'decimal'; + this.inputElement.inputMode = inputMode; } if ( From 3fb81c98364d0e3d59811c353dea75710ad004a7 Mon Sep 17 00:00:00 2001 From: Mizga Ionut-Alexandru Date: Mon, 30 Sep 2024 20:09:06 +0300 Subject: [PATCH 2/4] test(number-field): added iPad inputMode test --- .../number-field/test/number-field.test.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/number-field/test/number-field.test.ts b/packages/number-field/test/number-field.test.ts index aff992d5a6..a3dc4a49f0 100644 --- a/packages/number-field/test/number-field.test.ts +++ b/packages/number-field/test/number-field.test.ts @@ -1228,6 +1228,25 @@ describe('NumberField', () => { expect(changeSpy.callCount).to.equal(1); expect(lastChangeValue, 'last change value').to.equal(10); }); + xit('manages `inputMode` in iPad', async () => { + // setUserAgent is not currently supported by Playwright + await setUserAgent( + 'Mozilla/5.0 (iPad; CPU OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile15E148 Safari/604.1' + ); + el.min = 0; + await elementUpdated(el); + expect(el.focusElement.inputMode).to.equal('numeric'); + el.min = -10; + await elementUpdated(el); + expect(el.focusElement.inputMode).to.equal('numeric'); + el.formatOptions = { + minimumFractionDigits: 1, + maximumFractionDigits: 2, + }; + el.min = 0; + await elementUpdated(el); + expect(el.focusElement.inputMode).to.equal('decimal'); + }); xit('manages `inputMode` in iPhone', async () => { // setUserAgent is not currently supported by Playwright await setUserAgent( @@ -1265,6 +1284,13 @@ describe('NumberField', () => { el.min = 0; await elementUpdated(el); expect(el.focusElement.inputMode).to.equal('decimal'); + el.formatOptions = { + minimumFractionDigits: 1, + maximumFractionDigits: 2, + }; + el.min = -10; + await elementUpdated(el); + expect(el.focusElement.inputMode).to.equal('numeric'); }); it('constrains `value`', async () => { el.value = 0; From f3303266485c851f8b7c4187e375265f0a1b91dc Mon Sep 17 00:00:00 2001 From: Mizga Ionut-Alexandru Date: Wed, 2 Oct 2024 09:52:46 +0300 Subject: [PATCH 3/4] fix(number-field): show minus sign when negatives can be used --- packages/number-field/src/NumberField.ts | 3 ++- packages/number-field/test/number-field.test.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/number-field/src/NumberField.ts b/packages/number-field/src/NumberField.ts index b425224c09..f92256c315 100644 --- a/packages/number-field/src/NumberField.ts +++ b/packages/number-field/src/NumberField.ts @@ -803,7 +803,8 @@ export class NumberField extends TextfieldBase { } if (changes.has('min') || changes.has('formatOptions')) { - const hasNegative = typeof this.min !== 'undefined' && this.min < 0; + const hasNegative = typeof this.min === 'undefined' || this.min < 0; + const { maximumFractionDigits } = this.numberFormatter.resolvedOptions(); const hasDecimals = diff --git a/packages/number-field/test/number-field.test.ts b/packages/number-field/test/number-field.test.ts index a3dc4a49f0..1521027c9d 100644 --- a/packages/number-field/test/number-field.test.ts +++ b/packages/number-field/test/number-field.test.ts @@ -1239,6 +1239,9 @@ describe('NumberField', () => { el.min = -10; await elementUpdated(el); expect(el.focusElement.inputMode).to.equal('numeric'); + el.min = undefined; + await elementUpdated(el); + expect(el.focusElement.inputMode).to.equal('numeric'); el.formatOptions = { minimumFractionDigits: 1, maximumFractionDigits: 2, @@ -1258,6 +1261,9 @@ describe('NumberField', () => { el.min = -10; await elementUpdated(el); expect(el.focusElement.inputMode).to.equal('text'); + el.min = undefined; + await elementUpdated(el); + expect(el.focusElement.inputMode).to.equal('text'); el.formatOptions = { minimumFractionDigits: 1, maximumFractionDigits: 2, @@ -1277,6 +1283,9 @@ describe('NumberField', () => { el.min = -10; await elementUpdated(el); expect(el.focusElement.inputMode).to.equal('numeric'); + el.min = undefined; + await elementUpdated(el); + expect(el.focusElement.inputMode).to.equal('numeric'); el.formatOptions = { minimumFractionDigits: 1, maximumFractionDigits: 2, From 43d32948aea1559c1536caefb763fa696f21ee95 Mon Sep 17 00:00:00 2001 From: Mizga Ionut-Alexandru Date: Mon, 7 Oct 2024 15:23:11 +0300 Subject: [PATCH 4/4] chore: reverse logic for hasNegative --- packages/number-field/src/NumberField.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/number-field/src/NumberField.ts b/packages/number-field/src/NumberField.ts index f92256c315..6008c7281f 100644 --- a/packages/number-field/src/NumberField.ts +++ b/packages/number-field/src/NumberField.ts @@ -803,7 +803,8 @@ export class NumberField extends TextfieldBase { } if (changes.has('min') || changes.has('formatOptions')) { - const hasNegative = typeof this.min === 'undefined' || this.min < 0; + const hasOnlyPositives = + typeof this.min !== 'undefined' && this.min >= 0; const { maximumFractionDigits } = this.numberFormatter.resolvedOptions(); @@ -813,10 +814,10 @@ export class NumberField extends TextfieldBase { let inputMode = 'numeric'; /* c8 ignore next 5 */ // iPhone doesn't have a minus sign in either numeric or decimal. - if (isIPhone() && hasNegative) inputMode = 'text'; + if (isIPhone() && !hasOnlyPositives) inputMode = 'text'; else if (isIOS() && hasDecimals) inputMode = 'decimal'; // Android numeric has both a decimal point and minus key. Decimal does not have a minus key. - else if (isAndroid() && hasDecimals && !hasNegative) + else if (isAndroid() && hasDecimals && hasOnlyPositives) inputMode = 'decimal'; this.inputElement.inputMode = inputMode;