Skip to content

Commit 581dfca

Browse files
committed
feat(Forms): add bankAccountType prop with formatting and input masks
Add bankAccountType prop to Field.BankAccountNumber and Value.BankAccountNumber supporting norwegianBban, swedishBban, swedishBankgiro, swedishPlusgiro, and iban. This commit adds: - Input masks and placeholders per bank account type - Type-aware display formatting in Value.BankAccountNumber - Extended formatBAN() in NumberUtils with bankAccountType parameter - inputMode switching (text for IBAN, numeric for others) Validation is only enabled for norwegianBban (default). Validation for other types will be added separately.
1 parent 6e250e6 commit 581dfca

File tree

23 files changed

+919
-118
lines changed

23 files changed

+919
-118
lines changed

packages/dnb-design-system-portal/src/docs/uilib/components/number-format/info.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ const string = cleanNumber('prefix -12 345,678 suffix') // returns -12345.678
173173
const string = cleanNumber('prefix -12.345,678 suffix') // returns -12345.678
174174
```
175175

176+
### Format bank account numbers
177+
178+
Use `formatBAN` to format bank account numbers. It supports Norwegian BBAN, Swedish BBAN, Swedish Bankgiro, Swedish Plusgiro, and IBAN.
179+
180+
```ts
181+
import { formatBAN } from '@dnb/eufemia/components/number-format/NumberUtils'
182+
183+
const { number, aria } = formatBAN('20001234567') // { number: '2000 12 34567', aria: '20 00 12 34 56 7' }
184+
const { number, aria } = formatBAN('50001234567', 'swedishBban') // { number: '5000-1234567', aria: '50 00 12 34 56 7' }
185+
const { number, aria } = formatBAN('59140129', 'swedishBankgiro') // { number: '5914-0129', aria: '59 14 01 29' }
186+
const { number, aria } = formatBAN('1263664', 'swedishPlusgiro') // { number: '126366-4', aria: '12 63 66 4' }
187+
const { number, aria } = formatBAN('NO9386011117947', 'iban') // { number: 'NO93 8601 1117 947', aria: 'N O 9 3 8 6 0 1 1 1 1 7 9 4 7' }
188+
```
189+
176190
### Element and style
177191

178192
The number component is style-independent, so it has no visual styles. By default, a `<span>` is used (with [speak-as: numbers](https://developer.mozilla.org/en-US/docs/Web/CSS/@counter-style/speak-as), even though the support is very low). However, you can easily change the element type by providing a different value to the `element="div"` property.

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/Examples.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,33 @@ export const Inline = () => {
5353
</ComponentBox>
5454
)
5555
}
56+
57+
export const SwedishBankAccountTypes = () => {
58+
return (
59+
<ComponentBox>
60+
<Value.BankAccountNumber
61+
bankAccountType="swedishBban"
62+
value="50001234567"
63+
/>
64+
<Value.BankAccountNumber
65+
bankAccountType="swedishBankgiro"
66+
value="59140129"
67+
/>
68+
<Value.BankAccountNumber
69+
bankAccountType="swedishPlusgiro"
70+
value="1263664"
71+
/>
72+
</ComponentBox>
73+
)
74+
}
75+
76+
export const IbanValue = () => {
77+
return (
78+
<ComponentBox>
79+
<Value.BankAccountNumber
80+
bankAccountType="iban"
81+
value="NO9386011117947"
82+
/>
83+
</ComponentBox>
84+
)
85+
}

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/demos.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,11 @@ import * as Examples from './Examples'
2929
### Inline
3030

3131
<Examples.Inline />
32+
33+
### Swedish bank account types
34+
35+
<Examples.SwedishBankAccountTypes />
36+
37+
### IBAN
38+
39+
<Examples.IbanValue />

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/info.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ render(<Value.BankAccountNumber />)
1313

1414
`Value.BankAccountNumber` is a wrapper component for displaying string values, with user experience tailored for bank account number values.
1515

16+
Use the `bankAccountType` prop to format different account types: `norwegianBban` (default), `swedishBban`, `swedishBankgiro`, `swedishPlusgiro`, or `iban`.
17+
1618
There is a corresponding [Field.BankAccountNumber](/uilib/extensions/forms/feature-fields/BankAccountNumber) component.
1719

1820
```jsx

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/properties.mdx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@ showTabs: true
55
import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable'
66
import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable'
77
import { ValueProperties } from '@dnb/eufemia/src/extensions/forms/Value/ValueDocs'
8+
import { BankAccountNumberValueProperties } from '@dnb/eufemia/src/extensions/forms/Value/BankAccountNumber/BankAccountNumberDocs'
89

910
## Properties
1011

12+
### BankAccountNumber-specific properties
13+
14+
<PropertiesTable props={BankAccountNumberValueProperties} />
15+
16+
### General properties
17+
1118
<PropertiesTable props={ValueProperties} />
1219

1320
## Translations
1421

15-
<TranslationsTable localeKey={['BankAccountNumber.label']} />
22+
<TranslationsTable localeKey={['BankAccountNumber']} />

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/changelog.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Get more [details about releases](/uilib/releases) or have a look on all [releas
1717

1818
## v11.0.0
1919

20+
- Added `bankAccountType` prop to [Field.BankAccountNumber](/uilib/extensions/forms/feature-fields/BankAccountNumber/) and [Value.BankAccountNumber](/uilib/extensions/forms/Value/BankAccountNumber/) with support for Swedish BBAN, Swedish Bankgiro, Swedish Plusgiro, and IBAN.
2021
- Added `preventDefaultOnSubmit` to [Form.Handler](/uilib/extensions/forms/Form/Handler/), allowing native browser form submission such as `POST` to a form `action`.
2122
- Removed automatic horizontal card-coupled outset alignment for [Form.MainHeading](/uilib/extensions/forms/Form/MainHeading/), [Form.SubHeading](/uilib/extensions/forms/Form/SubHeading/), [Form.SubmitButton](/uilib/extensions/forms/Form/SubmitButton/) and [Form.ButtonRow](/uilib/extensions/forms/Form/ButtonRow/).
2223
- [Form.Card](/uilib/extensions/forms/Form/Card/) no longer enables `outset` by default.

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/Examples.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,37 @@ export const ValidationExtendValidator = () => {
145145
</ComponentBox>
146146
)
147147
}
148+
149+
export const SwedishBankAccountTypes = () => {
150+
return (
151+
<ComponentBox>
152+
<Field.BankAccountNumber
153+
bankAccountType="swedishBban"
154+
value="50001234567"
155+
onChange={(value) => console.log('onChange', value)}
156+
/>
157+
<Field.BankAccountNumber
158+
bankAccountType="swedishBankgiro"
159+
value="59140129"
160+
onChange={(value) => console.log('onChange', value)}
161+
/>
162+
<Field.BankAccountNumber
163+
bankAccountType="swedishPlusgiro"
164+
value="1263664"
165+
onChange={(value) => console.log('onChange', value)}
166+
/>
167+
</ComponentBox>
168+
)
169+
}
170+
171+
export const Iban = () => {
172+
return (
173+
<ComponentBox>
174+
<Field.BankAccountNumber
175+
bankAccountType="iban"
176+
value="NO9386011117947"
177+
onChange={(value) => console.log('onChange', value)}
178+
/>
179+
</ComponentBox>
180+
)
181+
}

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/demos.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,11 @@ import * as Examples from './Examples'
4747
You can [extend the existing validation](/uilib/extensions/forms/create-component/useFieldProps/info/#validators) (`bankAccountNumberValidator`) with your own validation function.
4848

4949
<Examples.ValidationExtendValidator />
50+
51+
### Swedish bank account types
52+
53+
<Examples.SwedishBankAccountTypes />
54+
55+
### IBAN
56+
57+
<Examples.Iban />

packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/info.mdx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,16 @@ render(<Field.BankAccountNumber />)
1313

1414
`Field.BankAccountNumber` is a wrapper component for [string input](/uilib/extensions/forms/base-fields/String), with user experience tailored for bank account values.
1515

16-
This field is meant for Norwegian bank account numbers and therefore takes an 11-digit string as a value. A Norwegian bank account number can have a leading zero, which is why this value is a string and not a number. In addition, we validate `0000 00 00000` as invalid.
17-
More information can be found at [Wikipedia](https://no.wikipedia.org/wiki/Kontonummer).
16+
By default, this field handles Norwegian bank account numbers (BBAN) — an 11-digit string with a mod-11 checksum. Use the `bankAccountType` prop to switch between formats:
17+
18+
- `norwegianBban` (default): 11-digit Norwegian account number. Validated with mod-11 checksum.
19+
- `swedishBban`: Swedish account number with 4-digit clearing number + account number (up to 14 digits).
20+
- `swedishBankgiro`: Swedish Bankgiro number (7–8 digits).
21+
- `swedishPlusgiro`: Swedish Plusgiro number (2–8 digits).
22+
- `iban`: International Bank Account Number (up to 34 alphanumeric characters).
23+
24+
The value is always a string since account numbers (e.g. Norwegian BBAN) can have leading zeros.
25+
More information about Norwegian bank account numbers can be found at [Wikipedia](https://no.wikipedia.org/wiki/Kontonummer).
1826

1927
There is a corresponding [Value.BankAccountNumber](/uilib/extensions/forms/Value/BankAccountNumber) component.
2028

packages/dnb-eufemia/src/components/number-format/NumberUtils.ts

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ export const format = (
214214
aria = _aria
215215
} else if (ban) {
216216
type = 'ban' // Bank Account Number
217-
const { number: _number, aria: _aria } = formatBAN(value, locale)
217+
const { number: _number, aria: _aria } = formatBAN(value)
218218

219219
display = _number
220220
aria = _aria
@@ -755,35 +755,104 @@ export const formatPhone = (number, locale = null) => {
755755
return { number: display, aria }
756756
}
757757

758+
// Keep in sync with BankAccountType in Field/BankAccountNumber/validators.ts.
759+
// Duplicated here to avoid cross-layer imports in this @ts-nocheck file.
760+
type FormatBANType =
761+
| 'norwegianBban'
762+
| 'swedishBban'
763+
| 'swedishBankgiro'
764+
| 'swedishPlusgiro'
765+
| 'iban'
766+
758767
/**
759768
* Use this function to format Bank Account Numbers
760769
*
761770
* @param {string|number} number a Bank Account Number
762-
* @param {string} locale locale as a string
771+
* @param {FormatBANType} bankAccountType the type of bank account number
763772
* @returns A formatted Bank Account Number
764773
*/
765-
export const formatBAN = (number, locale = null) => {
774+
export const formatBAN = (
775+
number: string | number,
776+
bankAccountType: FormatBANType = 'norwegianBban'
777+
) => {
766778
if (isAbsent(number)) {
767779
return { number: ABSENT_VALUE_FORMAT, aria: ABSENT_VALUE_FORMAT }
768780
}
769-
// cleanup
770-
number = String(number).replace(/[^0-9]/g, '')
771781

772-
let display = number
773-
let aria = null
782+
const cleanDigits = (val: string | number) =>
783+
String(val).replace(/[^0-9]/g, '')
774784

775-
switch (locale) {
785+
const cleanAlphanumeric = (val: string | number) =>
786+
String(val).replace(/[^A-Za-z0-9]/g, '')
787+
788+
const pairwiseAria = (digits: string) =>
789+
digits
790+
.split(/([0-9]{2})/)
791+
.filter((s) => s)
792+
.join(' ')
793+
794+
let display: string
795+
let aria: string = null
796+
797+
switch (bankAccountType) {
798+
case 'iban': {
799+
const cleaned = cleanAlphanumeric(number)
800+
// Group in blocks of 4
801+
display = cleaned.match(/.{1,4}/g)?.join(' ') ?? cleaned
802+
aria = cleaned.split('').join(' ')
803+
break
804+
}
805+
806+
case 'swedishBban': {
807+
const cleaned = cleanDigits(number)
808+
// Clearing number (4 digits) + account number
809+
display =
810+
cleaned.length > 4
811+
? cleaned.slice(0, 4) + '-' + cleaned.slice(4)
812+
: cleaned
813+
aria = pairwiseAria(cleaned)
814+
break
815+
}
816+
817+
case 'swedishBankgiro': {
818+
const cleaned = cleanDigits(number)
819+
// Format: XXXX-XXXX (8 digits) or XXX-XXXX (7 digits)
820+
if (cleaned.length === 8) {
821+
display = cleaned.slice(0, 4) + '-' + cleaned.slice(4)
822+
} else if (cleaned.length === 7) {
823+
display = cleaned.slice(0, 3) + '-' + cleaned.slice(3)
824+
} else {
825+
display = cleaned
826+
}
827+
aria = pairwiseAria(cleaned)
828+
break
829+
}
830+
831+
case 'swedishPlusgiro': {
832+
const cleaned = cleanDigits(number)
833+
// Last digit is check digit, separated by dash
834+
if (cleaned.length >= 2) {
835+
display =
836+
cleaned.slice(0, cleaned.length - 1) +
837+
'-' +
838+
cleaned.slice(cleaned.length - 1)
839+
} else {
840+
display = cleaned
841+
}
842+
aria = pairwiseAria(cleaned)
843+
break
844+
}
845+
846+
case 'norwegianBban':
776847
default: {
848+
const cleaned = cleanDigits(number)
777849
// Get 2000 12 34567
778-
display = number
850+
display = cleaned
779851
.split(/([0-9]{4})([0-9]{2})([0-9]{1,})/)
780852
.filter((s) => s)
781853
.join(' ')
782-
783-
aria = number
784-
.split(/([0-9]{2})/)
785-
.filter((s) => s)
786-
.join(' ')
854+
aria = pairwiseAria(cleaned)
855+
break
787856
}
788857
}
789858

0 commit comments

Comments
 (0)