diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/data-value-write-events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/data-value-write-events.mdx
index bbf36931b0e..adcbec6e393 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/data-value-write-events.mdx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/data-value-write-events.mdx
@@ -1,5 +1,5 @@
-| Event | Description |
-| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `onChange` | _(optional)_ Will be called on value changes made by the user, with the new value as argument. |
-| `onFocus` | _(optional)_ Will be called when the component gets into focus. Like clicking inside a text input or opening a dropdown. Called with active value as argument. |
-| `onBlur` | _(optional)_ Will be called when the component stop being in focus. Like when going to next field, or closing a dropdown. Called with active value as argument. |
+| Event | Description |
+| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `onChange` | _(optional)_ Will be called on value changes made by the user, with the new value e.g. `+47 99999999`. The second parameter is an object: `{ countryCode, phoneNumber }`. |
+| `onFocus` | _(optional)_ Will be called when the component gets into focus. Like clicking inside a text input or opening a dropdown. Called with active value as argument. |
+| `onBlur` | _(optional)_ Will be called when the component stop being in focus. Like when going to next field, or closing a dropdown. Called with active value as argument. |
diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/Examples.tsx
index 46bbbf75597..95656ea94d1 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/Examples.tsx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/Examples.tsx
@@ -110,6 +110,19 @@ export const ValidationRequired = () => {
)
}
+export const ValidationPattern = () => {
+ return (
+
+ console.log('onChange', ...args)}
+ pattern="((?=\\+47)^\\+47 [49]\\d{7}$)|((?!\\+47)^\\+\\d{2} \\d{6})"
+ />
+
+ )
+}
+
export const WithFilter = () => {
return (
diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/demos.mdx
index 7f7176cd134..82ac57c1c52 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/demos.mdx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/demos.mdx
@@ -42,6 +42,12 @@ import * as Examples from './Examples'
+### Validation - Pattern
+
+This pattern will strictly match Norwegian mobile numbers, which are defined as having a "+47" country code, followed by a number starting with 4 or 9, and exactly 7 more digits. If the country code is set to any other two-digit code, the pattern will match witch 6 digits after the country code.
+
+
+
diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/PhoneNumber.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/PhoneNumber.tsx
index 7f55de307a4..37fbcb998d3 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/PhoneNumber.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/PhoneNumber.tsx
@@ -6,7 +6,7 @@ import countries, { CountryType } from '../../constants/countries'
import StringField, { Props as StringFieldProps } from '../String'
import FieldBlock from '../../FieldBlock'
import { useDataValue } from '../../hooks'
-import { FieldHelpProps, FieldProps } from '../../types'
+import { FieldHelpProps, FieldProps, JSONSchema } from '../../types'
import { pickSpacingProps } from '../../../../components/flex/utils'
import SharedContext from '../../../../shared/Context'
import {
@@ -103,12 +103,21 @@ function PhoneNumber(props: Props) {
[]
)
+ const schema = useMemo(
+ () =>
+ props.schema ?? {
+ type: 'string',
+ pattern: props.pattern,
+ },
+ [props.schema, props.pattern]
+ )
const defaultProps: Partial = {
+ schema,
errorMessages,
}
const preparedProps: Props = {
- ...defaultProps,
...props,
+ ...defaultProps,
validateRequired,
fromExternal,
toEvent,
@@ -133,7 +142,6 @@ function PhoneNumber(props: Props) {
disabled,
width = 'large',
help,
- pattern,
required,
validateInitially,
continuousValidation,
@@ -349,7 +357,6 @@ function PhoneNumber(props: Props) {
width={omitCountryCodeField ? 'medium' : 'stretch'}
help={help}
required={required}
- pattern={pattern}
errorMessages={errorMessages}
validateInitially={validateInitially}
continuousValidation={continuousValidation}
diff --git a/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/__tests__/PhoneNumber.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/__tests__/PhoneNumber.test.tsx
index b8f39f321a9..2f617ed43c2 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/__tests__/PhoneNumber.test.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/Field/PhoneNumber/__tests__/PhoneNumber.test.tsx
@@ -1,9 +1,9 @@
import React from 'react'
import { wait, axeComponent } from '../../../../../core/jest/jestSetup'
-import { fireEvent, render } from '@testing-library/react'
+import { fireEvent, render, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Provider } from '../../../../../shared'
-import { Field, Form, JSONSchema } from '../../..'
+import { Field, Form, FormError, JSONSchema } from '../../..'
describe('Field.PhoneNumber', () => {
it('should default to 47', () => {
@@ -481,10 +481,10 @@ describe('Field.PhoneNumber', () => {
).not.toBeInTheDocument()
})
- it('should handle "pattern" property', async () => {
+ it('should handle simple "pattern" property', async () => {
render(
-
+
)
@@ -497,7 +497,7 @@ describe('Field.PhoneNumber', () => {
expect(document.querySelector('[role="alert"]')).toBeInTheDocument()
expect(document.querySelector('[role="alert"]').textContent).toContain(
- 'valid number'
+ 'You must enter a valid number'
)
await userEvent.type(numberElement, '{Backspace>8}89')
@@ -522,6 +522,64 @@ describe('Field.PhoneNumber', () => {
).not.toBeInTheDocument()
})
+ it('should handle "pattern" property with country code', () => {
+ const props = {
+ validateInitially: true,
+ pattern:
+ '((?=\\+47)^\\+47 [49]\\d{7}$)|((?!\\+47)^\\+\\d{2} \\d{6})',
+ }
+ const { rerender } = render(
+
+ )
+
+ expect(
+ document.querySelector('[role="alert"]')
+ ).not.toBeInTheDocument()
+
+ rerender()
+
+ expect(document.querySelector('[role="alert"]')).toBeInTheDocument()
+
+ rerender()
+
+ expect(
+ document.querySelector('[role="alert"]')
+ ).not.toBeInTheDocument()
+
+ rerender()
+
+ expect(document.querySelector('[role="alert"]')).toBeInTheDocument()
+ })
+
+ it('should handle "validator" property with country code', async () => {
+ const validator = jest.fn(() => {
+ return new FormError('some error')
+ })
+
+ render(
+
+
+
+ )
+
+ expect(validator).toHaveBeenCalledTimes(1)
+ expect(validator).toHaveBeenCalledWith('+41 9999', {
+ pattern: 'You must enter a valid number',
+ required: 'You must enter a valid number',
+ })
+
+ await waitFor(() => {
+ expect(document.querySelector('[role="alert"]')).toBeInTheDocument()
+ expect(
+ document.querySelector('[role="alert"]').textContent
+ ).toContain('some error')
+ })
+ })
+
it('should filter countries list with given filterCountries', () => {
render(
{
- // update('+41 1')
- update('+45')
- }, [])
+ const { update } = Form.useData('uniqueId')
+
+ React.useLayoutEffect(() => {
+ update('/phone', () => '+41 123')
+ }, [update])
+
return (
- {
- console.log('onChange', value)
- update(value)
- }}
- />
+
+
+ {
+ console.log('onChange', value)
+ update('/phone', () => value)
+ }}
+ />
+
+
+
+
+
+
)
}