Fix/input tel format options (#1733)

* fix(input-tel): remove unwanted characters in parser

* feat(input-tel-dropdown): export getFlagSymbol function

* feat(input-tel): add formatCountryCodeStyle option
This commit is contained in:
gerjanvangeest 2022-06-15 08:11:40 +02:00 committed by GitHub
parent 25e8de40b7
commit 7239d60466
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 402 additions and 40 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/input-tel-dropdown': patch
---
substract and export getFlagSymbol function

View file

@ -0,0 +1,6 @@
---
'@lion/input-tel': patch
'@lion/input-tel-dropdown': patch
---
Add option to style the country-code with parentheses in the formatter

View file

@ -0,0 +1,5 @@
---
'@lion/input-tel': patch
---
Remove unwanted characters in input-tel parser

View file

@ -81,3 +81,79 @@ export const preferredRegionCodes = () => {
`; `;
}; };
``` ```
## Format
### Format strategy
Determines what the formatter output should look like.
Formatting strategies as provided by awesome-phonenumber / google-libphonenumber.
Possible values:
| strategy | output |
| :------------ | ------------------------------------: |
| e164 | `+46707123456` |
| international | `+46 70 712 34 56` |
| national | not applicable for input-tel-dropdown |
| significant | not applicable for input-tel-dropdown |
| rfc3966 | `tel:+46-70-712-34-56` |
Also see:
- [awesome-phonenumber documentation](https://www.npmjs.com/package/awesome-phonenumber)
```js preview-story
export const formatStrategy = () => {
loadDefaultFeedbackMessages();
const inputTel = createRef();
return html`
<select @change="${({ target }) => (inputTel.value.formatStrategy = target.value)}">
<option value="e164">e164</option>
<option value="international">international</option>
<option value="rfc3966">rfc3966</option>
</select>
<lion-input-tel-dropdown
${ref(inputTel)}
label="Format strategy"
help-text="Choose a strategy above"
format-strategy="e164"
name="phoneNumber"
></lion-input-tel-dropdown>
<h-output
.show="${['modelValue', 'formatStrategy']}"
.readyPromise="${PhoneUtilManager.loadComplete}"
></h-output>
`;
};
```
### Format country code style
You can style the country code with parentheses.
```js preview-story
export const formatCountryCodeStyle = () => {
loadDefaultFeedbackMessages();
const inputTel = createRef();
return html`
<select @change="${({ target }) => (inputTel.value.formatStrategy = target.value)}">
<option value="e164">e164</option>
<option value="international">international</option>
<option value="rfc3966">rfc3966</option>
</select>
<lion-input-tel-dropdown
${ref(inputTel)}
label="Format strategy"
help-text="Choose a strategy above"
format-country-code-style="parentheses"
format-strategy="e164"
name="phoneNumber"
></lion-input-tel-dropdown>
<h-output
.show="${['modelValue', 'formatStrategy']}"
.readyPromise="${PhoneUtilManager.loadComplete}"
></h-output>
`;
};
```

View file

@ -176,7 +176,9 @@ export const oneAllowedRegion = () => {
}; };
``` ```
## Format strategy ## Format
### Format strategy
Determines what the formatter output should look like. Determines what the formatter output should look like.
Formatting strategies as provided by awesome-phonenumber / google-libphonenumber. Formatting strategies as provided by awesome-phonenumber / google-libphonenumber.
@ -223,7 +225,37 @@ export const formatStrategy = () => {
}; };
``` ```
## Live format ### Format country code style
You can also style the country code with parentheses.
```js preview-story
export const formatCountryCodeStyle = () => {
loadDefaultFeedbackMessages();
const inputTel = createRef();
return html`
<select @change="${({ target }) => (inputTel.value.formatStrategy = target.value)}">
<option value="e164">e164</option>
<option value="international">international</option>
<option value="rfc3966">rfc3966</option>
</select>
<lion-input-tel
${ref(inputTel)}
label="Format strategy"
help-text="Choose a strategy above"
.modelValue=${'+46707123456'}
format-country-code-style="parentheses"
name="phoneNumber"
></lion-input-tel>
<h-output
.show="${['modelValue', 'formatStrategy']}"
.readyPromise="${PhoneUtilManager.loadComplete}"
></h-output>
`;
};
```
### Live format
Type '6' in the example below to see how the phone number is formatted during typing. Type '6' in the example below to see how the phone number is formatted during typing.

View file

@ -1 +1,2 @@
export { getFlagSymbol } from './src/getFlagSymbol.js';
export { LionInputTelDropdown } from './src/LionInputTelDropdown.js'; export { LionInputTelDropdown } from './src/LionInputTelDropdown.js';

View file

@ -2,6 +2,7 @@
import { render, html, css, ref, createRef } from '@lion/core'; import { render, html, css, ref, createRef } from '@lion/core';
import { LionInputTel } from '@lion/input-tel'; import { LionInputTel } from '@lion/input-tel';
import { localize } from '@lion/localize'; import { localize } from '@lion/localize';
import { getFlagSymbol } from './getFlagSymbol.js';
/** /**
* Note: one could consider to implement LionInputTelDropdown as a * Note: one could consider to implement LionInputTelDropdown as a
@ -31,14 +32,6 @@ import { localize } from '@lion/localize';
* @typedef {TemplateDataForDropdownInputTel & {data: {regionMetaList:RegionMeta[]}}} TemplateDataForIntlInputTel * @typedef {TemplateDataForDropdownInputTel & {data: {regionMetaList:RegionMeta[]}}} TemplateDataForIntlInputTel
*/ */
// eslint-disable-next-line prefer-destructuring
/**
* @param {string} char
*/
function getRegionalIndicatorSymbol(char) {
return String.fromCodePoint(0x1f1e6 - 65 + char.toUpperCase().charCodeAt(0));
}
/** /**
* LionInputTelDropdown renders a dropdown like element next to the text field, inside the * LionInputTelDropdown renders a dropdown like element next to the text field, inside the
* prefix slot. This could be a LionSelect, a LionSelectRich or a native select. * prefix slot. This could be a LionSelect, a LionSelectRich or a native select.
@ -288,7 +281,11 @@ export class LionInputTelDropdown extends LionInputTel {
_initModelValueBasedOnDropdown() { _initModelValueBasedOnDropdown() {
if (!this._initialModelValue && !this.dirty && this._phoneUtil) { if (!this._initialModelValue && !this.dirty && this._phoneUtil) {
const countryCode = this._phoneUtil.getCountryCodeForRegionCode(this.activeRegion); const countryCode = this._phoneUtil.getCountryCodeForRegionCode(this.activeRegion);
if (this.formatCountryCodeStyle === 'parentheses') {
this.__initializedRegionCode = `(+${countryCode})`;
} else {
this.__initializedRegionCode = `+${countryCode}`; this.__initializedRegionCode = `+${countryCode}`;
}
this.modelValue = this.__initializedRegionCode; this.modelValue = this.__initializedRegionCode;
this._initialModelValue = this.__initializedRegionCode; this._initialModelValue = this.__initializedRegionCode;
this.initInteractionState(); this.initInteractionState();
@ -335,9 +332,13 @@ export class LionInputTelDropdown extends LionInputTel {
} else { } else {
// In case of dropdown has +31, and input has only +3 // In case of dropdown has +31, and input has only +3
const valueObj = this.value.split(' '); const valueObj = this.value.split(' ');
if (this.formatCountryCodeStyle === 'parentheses' && !this.value.includes('(')) {
this.modelValue = this._callParser(this.value.replace(valueObj[0], `(+${countryCode})`));
} else {
this.modelValue = this._callParser(this.value.replace(valueObj[0], `+${countryCode}`)); this.modelValue = this._callParser(this.value.replace(valueObj[0], `+${countryCode}`));
} }
} }
}
// Put focus on text box // Put focus on text box
const overlayController = event.target._overlayCtrl; const overlayController = event.target._overlayCtrl;
@ -419,8 +420,7 @@ export class LionInputTelDropdown extends LionInputTel {
const countryCode = const countryCode =
this._phoneUtil && this._phoneUtil.getCountryCodeForRegionCode(regionCode); this._phoneUtil && this._phoneUtil.getCountryCodeForRegionCode(regionCode);
const flagSymbol = const flagSymbol = getFlagSymbol(regionCode);
getRegionalIndicatorSymbol(regionCode[0]) + getRegionalIndicatorSymbol(regionCode[1]);
const destinationList = this.preferredRegions.includes(regionCode) const destinationList = this.preferredRegions.includes(regionCode)
? this.__regionMetaListPreferred ? this.__regionMetaListPreferred

View file

@ -0,0 +1,13 @@
/**
* @param {string} char
*/
function getRegionalIndicatorSymbol(char) {
return String.fromCodePoint(0x1f1e6 - 65 + char.toUpperCase().charCodeAt(0));
}
/**
* @param {string} regionCode
*/
export function getFlagSymbol(regionCode) {
return getRegionalIndicatorSymbol(regionCode[0]) + getRegionalIndicatorSymbol(regionCode[1]);
}

View file

@ -1,17 +1,17 @@
import {
expect,
fixture as _fixture,
fixtureSync as _fixtureSync,
html,
defineCE,
unsafeStatic,
aTimeout,
} from '@open-wc/testing';
import sinon from 'sinon';
// @ts-ignore // @ts-ignore
import { PhoneUtilManager } from '@lion/input-tel'; import { PhoneUtilManager } from '@lion/input-tel';
// @ts-ignore // @ts-ignore
import { mockPhoneUtilManager, restorePhoneUtilManager } from '@lion/input-tel/test-helpers'; import { mockPhoneUtilManager, restorePhoneUtilManager } from '@lion/input-tel/test-helpers';
import {
aTimeout,
defineCE,
expect,
fixture as _fixture,
fixtureSync as _fixtureSync,
html,
unsafeStatic,
} from '@open-wc/testing';
import sinon from 'sinon';
import { LionInputTelDropdown } from '../src/LionInputTelDropdown.js'; import { LionInputTelDropdown } from '../src/LionInputTelDropdown.js';
/** /**
@ -252,17 +252,18 @@ export function runInputTelDropdownSuite({ klass } = { klass: LionInputTelDropdo
await aTimeout(0); await aTimeout(0);
expect(spy).to.have.been.calledOnce; expect(spy).to.have.been.calledOnce;
restorePhoneUtilManager(); restorePhoneUtilManager();
spy.restore();
}); });
}); });
describe('On dropdown value change', () => { describe('On dropdown value change', () => {
it('changes the currently active country code in the textbox', async () => { it('changes the currently active country code in the textbox', async () => {
const el = await fixture( const el = await fixture(html`
html` <${tag} .allowedRegions="${[ <${tag}
'NL', .allowedRegions="${['NL', 'BE']}"
'BE', .modelValue="${'+31612345678'}"
]}" .modelValue="${'+31612345678'}"></${tag}> `, ></${tag}>
); `);
// @ts-ignore // @ts-ignore
mimicUserChangingDropdown(el.refs.dropdown.value, 'BE'); mimicUserChangingDropdown(el.refs.dropdown.value, 'BE');
await el.updateComplete; await el.updateComplete;
@ -282,6 +283,21 @@ export function runInputTelDropdownSuite({ klass } = { klass: LionInputTelDropdo
expect(el.value).to.equal('+32'); expect(el.value).to.equal('+32');
}); });
it('changes the currently active country code in the textbox when empty with parentheses', async () => {
const el = await fixture(
html` <${tag} format-country-code-style="parentheses" .allowedRegions="${[
'NL',
'BE',
]}"></${tag}> `,
);
el.value = '';
// @ts-ignore
mimicUserChangingDropdown(el.refs.dropdown.value, 'BE');
await el.updateComplete;
await el.updateComplete;
expect(el.value).to.equal('(+32)');
});
it('changes the currently active country code in the textbox when invalid', async () => { it('changes the currently active country code in the textbox when invalid', async () => {
const el = await fixture(html` <${tag} .allowedRegions="${['NL', 'BE']}"></${tag}> `); const el = await fixture(html` <${tag} .allowedRegions="${['NL', 'BE']}"></${tag}> `);
el.value = '+3'; el.value = '+3';
@ -381,5 +397,19 @@ export function runInputTelDropdownSuite({ klass } = { klass: LionInputTelDropdo
); );
}); });
}); });
describe('is empthy', () => {
it('ignores initial countrycode', async () => {
const el = await fixture(html` <${tag}></${tag}> `);
// @ts-ignore
expect(el._isEmpty()).to.be.true;
});
it('ignores initial countrycode with parentheses', async () => {
const el = await fixture(html` <${tag} format-country-code-style="parentheses"></${tag}> `);
// @ts-ignore
expect(el._isEmpty()).to.be.true;
});
});
}); });
} }

View file

@ -14,7 +14,7 @@ import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
* @typedef {import('awesome-phonenumber').PhoneNumberTypes} PhoneNumberTypes * @typedef {import('awesome-phonenumber').PhoneNumberTypes} PhoneNumberTypes
* @typedef {import('@lion/form-core/types/FormatMixinTypes').FormatOptions} FormatOptions * @typedef {import('@lion/form-core/types/FormatMixinTypes').FormatOptions} FormatOptions
* @typedef {* & import('awesome-phonenumber').default} AwesomePhoneNumber * @typedef {* & import('awesome-phonenumber').default} AwesomePhoneNumber
* @typedef {FormatOptions & {regionCode: RegionCode; formatStrategy: PhoneNumberFormat}} FormatOptionsTel * @typedef {FormatOptions & {regionCode: RegionCode; formatStrategy: PhoneNumberFormat; formatCountryCodeStyle: string;}} FormatOptionsTel
*/ */
export class LionInputTel extends LocalizeMixin(LionInput) { export class LionInputTel extends LocalizeMixin(LionInput) {
@ -24,6 +24,7 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
static properties = { static properties = {
allowedRegions: { type: Array }, allowedRegions: { type: Array },
formatStrategy: { type: String, attribute: 'format-strategy' }, formatStrategy: { type: String, attribute: 'format-strategy' },
formatCountryCodeStyle: { type: String, attribute: 'format-country-code-style' },
activeRegion: { type: String }, activeRegion: { type: String },
_phoneUtil: { type: Object, state: true }, _phoneUtil: { type: Object, state: true },
_needsLightDomRender: { type: Number, state: true }, _needsLightDomRender: { type: Number, state: true },
@ -139,6 +140,13 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
*/ */
this.formatStrategy = 'international'; this.formatStrategy = 'international';
/**
* Extra styling of the format strategy
* default | parentheses
* @type {string}
*/
this.formatCountryCodeStyle = 'default';
/** /**
* The regions that should be considered when international phone numbers are detected. * The regions that should be considered when international phone numbers are detected.
* (when not configured, all regions worldwide will be considered) * (when not configured, all regions worldwide will be considered)
@ -208,6 +216,12 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
(this.formatOptions).formatStrategy = this.formatStrategy; (this.formatOptions).formatStrategy = this.formatStrategy;
} }
if (changedProperties.has('formatCountryCodeStyle')) {
this._calculateValues({ source: null });
/** @type {FormatOptionsTel} */
(this.formatOptions).formatCountryCodeStyle = this.formatCountryCodeStyle;
}
if (changedProperties.has('modelValue') || changedProperties.has('allowedRegions')) { if (changedProperties.has('modelValue') || changedProperties.has('allowedRegions')) {
this.__calculateActiveRegion(); this.__calculateActiveRegion();
} }
@ -239,6 +253,7 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
return formatPhoneNumber(modelValue, { return formatPhoneNumber(modelValue, {
regionCode: /** @type {RegionCode} */ (this.activeRegion), regionCode: /** @type {RegionCode} */ (this.activeRegion),
formatStrategy: this.formatStrategy, formatStrategy: this.formatStrategy,
formatCountryCodeStyle: this.formatCountryCodeStyle,
}); });
} }
@ -265,6 +280,7 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
return liveFormatPhoneNumber(viewValue, { return liveFormatPhoneNumber(viewValue, {
regionCode: /** @type {RegionCode} */ (this.activeRegion), regionCode: /** @type {RegionCode} */ (this.activeRegion),
formatStrategy: this.formatStrategy, formatStrategy: this.formatStrategy,
formatCountryCodeStyle: this.formatCountryCodeStyle,
currentCaretIndex, currentCaretIndex,
prevViewValue, prevViewValue,
}); });
@ -313,7 +329,10 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
} }
// 2. Try to derive action region from user value // 2. Try to derive action region from user value
const value = !(this.modelValue instanceof Unparseable) ? this.modelValue : this.value; const regex = /[+0-9]+/gi;
const value = !(this.modelValue instanceof Unparseable)
? this.modelValue
: this.value.match(regex)?.join('');
const regionDerivedFromValue = value && this._phoneUtil && this._phoneUtil(value).g?.regionCode; const regionDerivedFromValue = value && this._phoneUtil && this._phoneUtil(value).g?.regionCode;
if (regionDerivedFromValue && this._allowedOrAllRegions.includes(regionDerivedFromValue)) { if (regionDerivedFromValue && this._allowedOrAllRegions.includes(regionDerivedFromValue)) {

View file

@ -6,14 +6,37 @@ import { PhoneUtilManager } from './PhoneUtilManager.js';
* @typedef {* & import('awesome-phonenumber').default} AwesomePhoneNumber * @typedef {* & import('awesome-phonenumber').default} AwesomePhoneNumber
*/ */
/**
* @param {string} value
* @param {object} options
* @param {RegionCode} options.regionCode
* @param {string} options.formatCountryCodeStyle
*/
export function getFormatCountryCodeStyle(value, { regionCode, formatCountryCodeStyle }) {
const countryCode = PhoneUtilManager?.PhoneUtil?.getCountryCodeForRegionCode(regionCode);
if (
formatCountryCodeStyle === 'parentheses' &&
countryCode &&
value.includes(`+${countryCode}`) &&
!value.includes(`(`)
) {
return value.replace(`+${countryCode}`, `(+${countryCode})`);
}
return value;
}
/** /**
* @param {string} modelValue * @param {string} modelValue
* @param {object} options * @param {object} options
* @param {RegionCode} options.regionCode * @param {RegionCode} options.regionCode
* @param {PhoneNumberFormat} [options.formatStrategy='international'] * @param {PhoneNumberFormat} [options.formatStrategy='international']
* @param {string} [options.formatCountryCodeStyle='default']
* @returns {string} * @returns {string}
*/ */
export function formatPhoneNumber(modelValue, { regionCode, formatStrategy = 'international' }) { export function formatPhoneNumber(
modelValue,
{ regionCode, formatStrategy = 'international', formatCountryCodeStyle = 'default' },
) {
// Do not format when not loaded // Do not format when not loaded
if (!PhoneUtilManager.isLoaded) { if (!PhoneUtilManager.isLoaded) {
return modelValue; return modelValue;
@ -50,8 +73,15 @@ export function formatPhoneNumber(modelValue, { regionCode, formatStrategy = 'in
default: default:
break; break;
} }
if (formatCountryCodeStyle !== 'default') {
return getFormatCountryCodeStyle(formattedValue, { regionCode, formatCountryCodeStyle });
}
return formattedValue; return formattedValue;
} }
if (formatCountryCodeStyle !== 'default') {
return getFormatCountryCodeStyle(modelValue, { regionCode, formatCountryCodeStyle });
}
return modelValue; return modelValue;
} }

View file

@ -18,10 +18,11 @@ export function parsePhoneNumber(viewValue, { regionCode }) {
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
const PhoneNumber = /** @type {AwesomePhoneNumber} */ (PhoneUtilManager.PhoneUtil); const PhoneNumber = /** @type {AwesomePhoneNumber} */ (PhoneUtilManager.PhoneUtil);
const regex = /[+0-9]+/gi;
const strippedViewValue = viewValue.match(regex)?.join('');
let pn; let pn;
try { try {
pn = PhoneNumber(viewValue, regionCode); pn = PhoneNumber(strippedViewValue, regionCode);
// eslint-disable-next-line no-empty // eslint-disable-next-line no-empty
} catch (_) {} } catch (_) {}

View file

@ -1,5 +1,5 @@
import { formatPhoneNumber, getFormatCountryCodeStyle } from './formatters.js';
import { PhoneUtilManager } from './PhoneUtilManager.js'; import { PhoneUtilManager } from './PhoneUtilManager.js';
import { formatPhoneNumber } from './formatters.js';
/** /**
* @typedef {import('../types').RegionCode} RegionCode * @typedef {import('../types').RegionCode} RegionCode
@ -14,11 +14,12 @@ import { formatPhoneNumber } from './formatters.js';
* @param {string} options.prevViewValue * @param {string} options.prevViewValue
* @param {number} options.currentCaretIndex * @param {number} options.currentCaretIndex
* @param {PhoneNumberFormat} options.formatStrategy * @param {PhoneNumberFormat} options.formatStrategy
* @param {string?} [options.formatCountryCodeStyle='default']
* @returns {{viewValue:string; caretIndex:number;}|undefined} * @returns {{viewValue:string; caretIndex:number;}|undefined}
*/ */
export function liveFormatPhoneNumber( export function liveFormatPhoneNumber(
viewValue, viewValue,
{ regionCode, formatStrategy, prevViewValue, currentCaretIndex }, { regionCode, formatStrategy, prevViewValue, currentCaretIndex, formatCountryCodeStyle },
) { ) {
const diff = viewValue.length - prevViewValue.length; const diff = viewValue.length - prevViewValue.length;
// Do not format when not loaded // Do not format when not loaded
@ -36,7 +37,12 @@ export function liveFormatPhoneNumber(
} }
} }
const newViewValue = formatPhoneNumber(ayt.number(), { regionCode, formatStrategy }); let parenthesesAdded = false;
let newViewValue = formatPhoneNumber(ayt.number(), { regionCode, formatStrategy });
if (formatCountryCodeStyle === 'parentheses' && regionCode && !newViewValue.includes(`(`)) {
newViewValue = getFormatCountryCodeStyle(newViewValue, { regionCode, formatCountryCodeStyle });
parenthesesAdded = true;
}
/** /**
* Given following situation: * Given following situation:
@ -45,7 +51,16 @@ export function liveFormatPhoneNumber(
* - prevViewValue `+36123` (we inserted '1' at position 2) * - prevViewValue `+36123` (we inserted '1' at position 2)
* => we should get `+31 6123`, and new caretIndex should be 3, and not newViewValue.length * => we should get `+31 6123`, and new caretIndex should be 3, and not newViewValue.length
*/ */
const countryCode = PhoneUtilManager?.PhoneUtil?.getCountryCodeForRegionCode(regionCode);
const diffBetweenNewAndCurrent = newViewValue.length - viewValue.length; const diffBetweenNewAndCurrent = newViewValue.length - viewValue.length;
const newCaretIndex = currentCaretIndex + diffBetweenNewAndCurrent; let newCaretIndex = currentCaretIndex + diffBetweenNewAndCurrent;
if (
parenthesesAdded &&
countryCode &&
viewValue.length > countryCode.toString().length + 1 &&
currentCaretIndex <= countryCode.toString().length + 1
) {
newCaretIndex -= 2;
}
return newViewValue ? { viewValue: newViewValue, caretIndex: newCaretIndex } : undefined; return newViewValue ? { viewValue: newViewValue, caretIndex: newCaretIndex } : undefined;
} }

View file

@ -10,6 +10,7 @@ import {
import sinon from 'sinon'; import sinon from 'sinon';
import { mimicUserInput } from '@lion/form-core/test-helpers'; import { mimicUserInput } from '@lion/form-core/test-helpers';
import { localize } from '@lion/localize'; import { localize } from '@lion/localize';
import { Unparseable } from '@lion/form-core';
import { LionInputTel } from '../src/LionInputTel.js'; import { LionInputTel } from '../src/LionInputTel.js';
import { PhoneNumber } from '../src/validators.js'; import { PhoneNumber } from '../src/validators.js';
import { PhoneUtilManager } from '../src/PhoneUtilManager.js'; import { PhoneUtilManager } from '../src/PhoneUtilManager.js';
@ -103,6 +104,28 @@ function runActiveRegionTests({ tag, phoneUtilLoadedAfterInit }) {
expect(el.activeRegion).to.equal('NL'); expect(el.activeRegion).to.equal('NL');
}); });
it('deducts it from value when modelValue is unparseable', async () => {
const modelValue = new Unparseable('+316');
const el = await fixture(html` <${tag} .modelValue=${modelValue}></${tag}> `);
if (resolvePhoneUtilLoaded) {
resolvePhoneUtilLoaded(undefined);
await el.updateComplete;
}
// Region code for country code '31' is 'NL'
expect(el.activeRegion).to.equal('NL');
});
it('deducts it from value when modelValue is unparseable and contains parentheses', async () => {
const modelValue = new Unparseable('(+31)6');
const el = await fixture(html` <${tag} .modelValue=${modelValue}></${tag}> `);
if (resolvePhoneUtilLoaded) {
resolvePhoneUtilLoaded(undefined);
await el.updateComplete;
}
// Region code for country code '31' is 'NL'
expect(el.activeRegion).to.equal('NL');
});
// 3. **locale**: try to get the region from locale (`html[lang]` attribute) // 3. **locale**: try to get the region from locale (`html[lang]` attribute)
it('automatically bases it on current locale when nothing preconfigured', async () => { it('automatically bases it on current locale when nothing preconfigured', async () => {
const el = await fixture(html` <${tag}></${tag}> `); const el = await fixture(html` <${tag}></${tag}> `);
@ -270,6 +293,16 @@ export function runInputTelSuite({ klass = LionInputTel } = {}) {
await aTimeout(0); await aTimeout(0);
expect(el.formattedValue).to.equal('612345678'); expect(el.formattedValue).to.equal('612345678');
}); });
it('formats according to formatCountryCodeStyle', async () => {
const el = await fixture(
html` <${tag} format-country-code-style="parentheses" .modelValue="${'+31612345678'}" .allowedRegions="${[
'NL',
]}"></${tag}> `,
);
await aTimeout(0);
expect(el.formattedValue).to.equal('(+31) 6 12345678');
});
}); });
// TODO: this should be allowed for in FormatMixin => // TODO: this should be allowed for in FormatMixin =>

View file

@ -25,4 +25,42 @@ describe('formatPhoneNumber', () => {
formatPhoneNumber('+46707123456', { regionCode: 'SE', formatStrategy: 'significant' }), formatPhoneNumber('+46707123456', { regionCode: 'SE', formatStrategy: 'significant' }),
).to.equal('707123456'); ).to.equal('707123456');
}); });
it('formats a phone number according to provided formatCountryCodeStyle', () => {
expect(
formatPhoneNumber('0707123456', {
regionCode: 'SE',
formatStrategy: 'e164',
formatCountryCodeStyle: 'parentheses',
}),
).to.equal('(+46)707123456');
expect(
formatPhoneNumber('+46707123456', {
regionCode: 'SE',
formatStrategy: 'international',
formatCountryCodeStyle: 'parentheses',
}),
).to.equal('(+46) 70 712 34 56');
expect(
formatPhoneNumber('+46707123456', {
regionCode: 'SE',
formatStrategy: 'national',
formatCountryCodeStyle: 'parentheses',
}),
).to.equal('070-712 34 56');
expect(
formatPhoneNumber('+46707123456', {
regionCode: 'SE',
formatStrategy: 'rfc3966',
formatCountryCodeStyle: 'parentheses',
}),
).to.equal('tel:(+46)-70-712-34-56');
expect(
formatPhoneNumber('+46707123456', {
regionCode: 'SE',
formatStrategy: 'significant',
formatCountryCodeStyle: 'parentheses',
}),
).to.equal('707123456');
});
}); });

View file

@ -13,4 +13,12 @@ describe('parsePhoneNumber', () => {
expect(parsePhoneNumber('0707123456', { regionCode: 'NL' })).to.equal('+31707123456'); expect(parsePhoneNumber('0707123456', { regionCode: 'NL' })).to.equal('+31707123456');
expect(parsePhoneNumber('0707123456', { regionCode: 'DE' })).to.equal('+49707123456'); expect(parsePhoneNumber('0707123456', { regionCode: 'DE' })).to.equal('+49707123456');
}); });
it('removes unwanted characters', () => {
expect(parsePhoneNumber('(+31)707123456', { regionCode: 'NL' })).to.equal('+31707123456');
expect(parsePhoneNumber('+31 70 7123456', { regionCode: 'NL' })).to.equal('+31707123456');
expect(parsePhoneNumber('+31-70-7123456', { regionCode: 'NL' })).to.equal('+31707123456');
expect(parsePhoneNumber('+31|70|7123456', { regionCode: 'NL' })).to.equal('+31707123456');
expect(parsePhoneNumber('tel:+31707123456', { regionCode: 'NL' })).to.equal('+31707123456');
});
}); });

View file

@ -16,7 +16,7 @@ describe('liveFormatPhoneNumber', () => {
prevViewValue: '+36123', prevViewValue: '+36123',
currentCaretIndex: 2, currentCaretIndex: 2,
}), }),
).to.eql({ viewValue: '+31 6 123', caretIndex: 4 }); ).to.eql({ caretIndex: 4, viewValue: '+31 6 123' });
}); });
it('live formats a complete view value', () => { it('live formats a complete view value', () => {
@ -29,4 +29,54 @@ describe('liveFormatPhoneNumber', () => {
}), }),
).to.eql({ caretIndex: 12, viewValue: '+31 6 12345678' }); ).to.eql({ caretIndex: 12, viewValue: '+31 6 12345678' });
}); });
describe('with formatCountryCodeStyle is set to parantheses', () => {
it('live formats an incomplete view value', () => {
expect(
liveFormatPhoneNumber('+316123', {
regionCode: 'NL',
formatStrategy: 'international',
prevViewValue: '+31613',
currentCaretIndex: 5,
formatCountryCodeStyle: 'parentheses',
}),
).to.eql({ caretIndex: 9, viewValue: '(+31) 6 123' });
});
it('live formats a complete view value', () => {
expect(
liveFormatPhoneNumber('+31612345678', {
regionCode: 'NL',
formatStrategy: 'international',
prevViewValue: '+3161234578',
currentCaretIndex: 10,
formatCountryCodeStyle: 'parentheses',
}),
).to.eql({ caretIndex: 14, viewValue: '(+31) 6 12345678' });
});
it('does not update if parentheses are already in place', () => {
expect(
liveFormatPhoneNumber('(+31)6123', {
regionCode: 'NL',
formatStrategy: 'international',
prevViewValue: '(+31)123',
currentCaretIndex: 5,
formatCountryCodeStyle: 'parentheses',
}),
).to.eql({ caretIndex: 5, viewValue: '(+31)6123' });
});
it('sets the correct caretIndex if currentCaretIndex in between the countryCode', () => {
expect(
liveFormatPhoneNumber('+316123', {
regionCode: 'NL',
formatStrategy: 'international',
prevViewValue: '+36123',
currentCaretIndex: 2,
formatCountryCodeStyle: 'parentheses',
}),
).to.eql({ caretIndex: 4, viewValue: '(+31) 6 123' });
});
});
}); });