Skip to content

Commit

Permalink
fix: fix pluralization when using full currency/unit names
Browse files Browse the repository at this point in the history
  • Loading branch information
dm4t2 committed Mar 16, 2022
1 parent 291d841 commit fab0e93
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 44 deletions.
65 changes: 46 additions & 19 deletions src/numberFormat.ts
Expand Up @@ -2,6 +2,20 @@ import { escapeRegExp, substringBefore } from './utils'
import { CurrencyDisplay, NumberFormatStyle, NumberInputOptions, UnitDisplay } from './api'
import NumberFormatOptions = Intl.NumberFormatOptions

const getPrefix = (parts: Intl.NumberFormatPart[]) =>
parts
.slice(0, parts.map((p) => p.type).indexOf('integer'))
.map((p) => p.value)
.join('')

const getSuffix = (parts: Intl.NumberFormatPart[]) => {
const types = parts.map((p) => p.type)
return parts
.slice(Math.max(types.lastIndexOf('integer'), types.indexOf('fraction')) + 1)
.map((p) => p.value)
.join('')
}

export const DECIMAL_SEPARATORS = [',', '.', '٫']
export const INTEGER_PATTERN = '(0|[1-9]\\d*)'

Expand All @@ -20,18 +34,20 @@ export class NumberFormat {
maximumFractionDigits: number
prefix: string
negativePrefix: string
suffix: string
suffix: string[]

constructor(options: NumberInputOptions) {
const createNumberFormat = (options: Intl.NumberFormatOptions) =>
new Intl.NumberFormat(locale, {
currency,
currencyDisplay,
unit,
unitDisplay,
style,
...options
})
const { formatStyle: style, currency, currencyDisplay, unit, unitDisplay, locale, precision } = options
const numberFormat = new Intl.NumberFormat(locale, {
currency,
currencyDisplay,
unit,
unitDisplay,
style,
minimumFractionDigits: style !== NumberFormatStyle.Currency ? 1 : undefined
})
const numberFormat = createNumberFormat({ minimumFractionDigits: style !== NumberFormatStyle.Currency ? 1 : undefined })
const formatParts = numberFormat.formatToParts(style === NumberFormatStyle.Percent ? 1234.56 : 123456)

this.locale = locale
Expand All @@ -58,12 +74,9 @@ export class NumberFormat {
this.maximumFractionDigits = maximumFractionDigits
}

const getPrefix = (str: string) => substringBefore(str, this.digits[1])
const getSuffix = (str: string) => str.substring(str.lastIndexOf(this.decimalSymbol ? this.digits[0] : this.digits[1]) + 1)

this.prefix = getPrefix(numberFormat.format(1))
this.suffix = getSuffix(numberFormat.format(1))
this.negativePrefix = getPrefix(numberFormat.format(-1))
this.prefix = getPrefix(numberFormat.formatToParts(1))
this.suffix = [getSuffix(createNumberFormat({ minimumFractionDigits: 0 }).formatToParts(1)), getSuffix(numberFormat.formatToParts(2))]
this.negativePrefix = getPrefix(numberFormat.formatToParts(-1))
}

parse(str: string | null): number | null {
Expand Down Expand Up @@ -99,8 +112,22 @@ export class NumberFormat {
integerNumber /= 100
}
return [
this.stripPrefixOrSuffix(this.normalizeDigits(integerNumber.toLocaleString(this.locale, { ...options, useGrouping: true }))),
this.stripPrefixOrSuffix(this.normalizeDigits(integerNumber.toLocaleString(this.locale, { ...options, useGrouping: false })))
this.stripPrefixOrSuffix(
this.normalizeDigits(
integerNumber.toLocaleString(this.locale, {
...options,
useGrouping: true
})
)
),
this.stripPrefixOrSuffix(
this.normalizeDigits(
integerNumber.toLocaleString(this.locale, {
...options,
useGrouping: false
})
)
)
].includes(formattedNumber)
}

Expand Down Expand Up @@ -136,7 +163,7 @@ export class NumberFormat {
}

insertPrefixOrSuffix(str: string, negative: boolean): string {
return `${negative ? this.negativePrefix : this.prefix}${str}${this.suffix}`
return `${negative ? this.negativePrefix : this.prefix}${str}${this.suffix[1]}`
}

stripGroupingSeparator(str: string): string {
Expand All @@ -148,7 +175,7 @@ export class NumberFormat {
}

stripPrefixOrSuffix(str: string): string {
return str.replace(this.negativePrefix, '').replace(this.prefix, '').replace(this.suffix, '')
return str.replace(this.negativePrefix, '').replace(this.prefix, '').replace(this.suffix[1], '').replace(this.suffix[0], '')
}

normalizeDecimalSeparator(str: string, from: number): string {
Expand Down
20 changes: 14 additions & 6 deletions src/numberInput.ts
Expand Up @@ -170,7 +170,8 @@ export class NumberInput {
formattedValue = formattedValue
.replace(this.numberFormat.negativePrefix, this.numberFormat.minusSymbol)
.replace(this.numberFormat.prefix, '')
.replace(this.numberFormat.suffix, '')
.replace(this.numberFormat.suffix[1], '')
.replace(this.numberFormat.suffix[0], '')
}

this.el.value = formattedValue
Expand Down Expand Up @@ -222,9 +223,15 @@ export class NumberInput {
}
}
}
return this.options.hidePrefixOrSuffixOnFocus
? newValueLength - caretPositionFromLeft
: Math.max(newValueLength - Math.max(caretPositionFromLeft, suffix.length), prefix.length)
if (this.options.hidePrefixOrSuffixOnFocus) {
return newValueLength - caretPositionFromLeft
} else {
const getSuffixLength = (str: string) => (str.includes(suffix[1]) ? suffix[1] : str.includes(suffix[0]) ? suffix[0] : '').length
const oldSuffixLength = getSuffixLength(value)
const newSuffixLength = getSuffixLength(this.formattedValue)
const suffixLengthDifference = Math.abs(newSuffixLength - oldSuffixLength)
return Math.max(newValueLength - Math.max(caretPositionFromLeft - suffixLengthDifference, newSuffixLength), prefix.length)
}
}
this.setCaretPosition(getCaretPositionAfterFormat())
}
Expand All @@ -243,8 +250,9 @@ export class NumberInput {
const getCaretPositionOnFocus = () => {
const { prefix, suffix, groupingSymbol } = this.numberFormat
if (!this.options.hidePrefixOrSuffixOnFocus) {
if (selectionStart >= value.length - suffix.length) {
return this.formattedValue.length - suffix.length
const suffixLength = suffix[this.numberValue === 1 ? 0 : 1].length
if (selectionStart >= value.length - suffixLength) {
return this.formattedValue.length - suffixLength
} else if (selectionStart < prefix.length) {
return prefix.length
}
Expand Down

0 comments on commit fab0e93

Please sign in to comment.