diff --git a/.changeset/gorgeous-pumas-sparkle.md b/.changeset/gorgeous-pumas-sparkle.md new file mode 100644 index 000000000..63621c58a --- /dev/null +++ b/.changeset/gorgeous-pumas-sparkle.md @@ -0,0 +1,5 @@ +--- +'svelte-ux': patch +--- + +[format()] Allow only passing value and determine type based on value (integer, decimal, or Date) for quick/basic formatting diff --git a/packages/svelte-ux/src/lib/utils/format.test.ts b/packages/svelte-ux/src/lib/utils/format.test.ts index 7e7b0fdf1..7017ac23e 100644 --- a/packages/svelte-ux/src/lib/utils/format.test.ts +++ b/packages/svelte-ux/src/lib/utils/format.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect } from 'vitest'; import { format } from './format.js'; import { PeriodType } from './date_types.js'; import { testDate } from './date.test.js'; +import { parseISO } from 'date-fns'; describe('format()', () => { it('returns empty string for null', () => { @@ -36,4 +37,26 @@ describe('format()', () => { const actual = format(1234.5678, (value) => Math.round(value).toString()); expect(actual).equal('1235'); }); + + // Default format based on value type + it('format based on value type (integer)', () => { + const actual = format(1234); + expect(actual).equal('1,234'); + }); + it('format based on value type (decimal)', () => { + const actual = format(1234.5678); + expect(actual).equal('1,234.57'); + }); + it('format based on value type (date string)', () => { + const actual = format(testDate); + expect(actual).equal('11/21/2023'); + }); + it('format based on value type (date)', () => { + const actual = format(parseISO(testDate)); + expect(actual).equal('11/21/2023'); + }); + it('format based on value type (string)', () => { + const actual = format('hello'); + expect(actual).equal('hello'); + }); }); diff --git a/packages/svelte-ux/src/lib/utils/format.ts b/packages/svelte-ux/src/lib/utils/format.ts index 76ae0674d..53ecbe60b 100644 --- a/packages/svelte-ux/src/lib/utils/format.ts +++ b/packages/svelte-ux/src/lib/utils/format.ts @@ -1,4 +1,9 @@ -import { formatDateWithLocale, getPeriodTypeNameWithLocale, getDayOfWeekName } from './date.js'; +import { + formatDateWithLocale, + getPeriodTypeNameWithLocale, + getDayOfWeekName, + isStringDate, +} from './date.js'; import { formatNumberWithLocale } from './number.js'; import type { FormatNumberOptions, FormatNumberStyle } from './number.js'; import { defaultLocale, type LocaleSettings } from './locale.js'; @@ -37,29 +42,28 @@ export function formatWithLocale( format?: FormatType, options?: FormatNumberOptions | FormatDateOptions ) { - let formattedValue: string | undefined; - - if (format) { - if (typeof format === 'function') { - formattedValue = format(value); - } else if (format in PeriodType) { - formattedValue = formatDateWithLocale( - settings, - value, - format as PeriodType, - options as FormatDateOptions - ); - } else if (typeof value === 'number') { - formattedValue = formatNumberWithLocale( - settings, - value, - format as FormatNumberStyle, - options as FormatNumberOptions - ); - } + if (typeof format === 'function') { + return format(value); + } else if (value instanceof Date || isStringDate(value) || (format && format in PeriodType)) { + return formatDateWithLocale( + settings, + value, + (format ?? PeriodType.Day) as PeriodType, + options as FormatDateOptions + ); + } else if (typeof value === 'number') { + return formatNumberWithLocale( + settings, + value, + format as FormatNumberStyle, + options as FormatNumberOptions + ); + } else if (typeof value === 'string') { + // Keep original value if already string + return value; + } else if (value == null) { + return ''; } - - return formattedValue ?? ''; // return empty string so Svelte doesn't render `null` string; } export type FormatFunction = (( diff --git a/packages/svelte-ux/src/lib/utils/number.ts b/packages/svelte-ux/src/lib/utils/number.ts index f9e950bbb..144e154a4 100644 --- a/packages/svelte-ux/src/lib/utils/number.ts +++ b/packages/svelte-ux/src/lib/utils/number.ts @@ -55,6 +55,11 @@ export function formatNumberWithLocale( return `${number}`; } + // Determine default style if not provided (undefined or null) + if (style == null) { + style = Number.isInteger(number) ? 'integer' : 'decimal'; + } + const defaults = getFormatNumber(settings, style); const formatter = Intl.NumberFormat(settings.locale, {