From b9c91d93737b3b7beaf09f4138d6a1556f956d33 Mon Sep 17 00:00:00 2001 From: Manfred Zingl Date: Fri, 22 May 2026 12:44:54 +0200 Subject: [PATCH 1/2] add column type integer --- src/getDisplayValue.test.ts | 55 +++++++++++++++++++++++++++++++++++++ src/getDisplayValue.ts | 10 ++++++- src/grud-intl.test.ts | 16 +++++++++-- src/grud-intl.ts | 14 ++++++++-- src/predicates.ts | 3 ++ src/types/cell.ts | 1 + src/types/column.ts | 19 ++++++++++++- src/types/common.ts | 2 ++ 8 files changed, 113 insertions(+), 7 deletions(-) diff --git a/src/getDisplayValue.test.ts b/src/getDisplayValue.test.ts index 63cb73e..2cef523 100644 --- a/src/getDisplayValue.test.ts +++ b/src/getDisplayValue.test.ts @@ -10,6 +10,8 @@ import type { DateTimeCellValue, DateTimeColumn, GroupColumn, + IntegerCellValue, + IntegerColumn, LinkCellValue, LinkColumn, Locale, @@ -175,6 +177,59 @@ describe("getDisplayValue()", () => { }); }); + describe("integer", () => { + it("should format single lang number values for specific langs when no user lang is given", () => { + const columnWithSeparator: IntegerColumn = { + id: 1, + kind: "integer", + multilanguage: false, + separator: true, + } as any; + + const columnWithoutSeparator: IntegerColumn = { + id: 1, + kind: "integer", + multilanguage: false, + separator: false, + } as any; + + const value: IntegerCellValue = { value: 1234 }; + const getDisplayValueWithoutUserLocale = getDisplayValue(); + expect(getDisplayValueWithoutUserLocale(columnWithSeparator, value)) + .toEqual({ + "de-DE": "1.234", + "en-GB": "1,234", + "en-US": "1,234", + }); + expect(getDisplayValueWithoutUserLocale(columnWithoutSeparator, value)) + .toEqual({ + "de-DE": "1234", + "en-GB": "1234", + "en-US": "1234", + }); + }); + it("should format single lang number values for all values to specified user Lang", () => { + const column: IntegerColumn = { + id: 1, + kind: "integer", + multilanguage: false, + } as any; + const value: IntegerCellValue = { value: 1234 }; + const getDisplayValueForGerman = getDisplayValue("de-DE"); + const getDisplayValueForGB = getDisplayValue("en-GB"); + expect(getDisplayValueForGerman(column, value)).toEqual({ + "de-DE": "1.234", + "en-GB": "1.234", + "en-US": "1.234", + }); + expect(getDisplayValueForGB(column, value)).toEqual({ + "de-DE": "1,234", + "en-GB": "1,234", + "en-US": "1,234", + }); + }); + }); + describe("date", () => { it("should format date values for specific langs when no user lang is given", () => { const column: DateColumn = { diff --git a/src/getDisplayValue.ts b/src/getDisplayValue.ts index 6243256..7cd2952 100644 --- a/src/getDisplayValue.ts +++ b/src/getDisplayValue.ts @@ -9,6 +9,7 @@ import { isDateColumn, isDateTimeColumn, isGroupColumn, + isIntegerColumn, isLinkColumn, isMultilangColumn, isNumberColumn, @@ -33,6 +34,7 @@ import type { DisplayValueForColumn, GroupColumn, grudAny, + IntegerColumn, LinkColumn, MultilangValue, NumberColumn, @@ -134,9 +136,14 @@ export const getDisplayValue = ( }; const getNumberValue: getValueT = (column, value) => { const formatNumber = (lt: Langtag, val: number) => - i.formatNumber(userLang ?? lt, val); + i.formatNumber(userLang ?? lt, column.separator, val); return mkDisplayMap(langs, column, value, formatNumber); }; + const getIntegerValue: getValueT = (column, value) => { + const formatInteger = (lt: Langtag, val: number) => + i.formatNumber(userLang ?? lt, column.separator, val); + return mkDisplayMap(langs, column, value, formatInteger); + }; const getPlainValue: getValueT = (column, value) => mkDisplayMap(langs, column, value); @@ -188,6 +195,7 @@ export const getDisplayValue = ( [isDateColumn, getDateValue], [isDateTimeColumn, getDateTimeValue], [isGroupColumn, getGroupValue], + [isIntegerColumn, getIntegerValue], [isLinkColumn, getLinkValue], [isNumberColumn, getNumberValue], [isRichtextColumn, getPlainValue], diff --git a/src/grud-intl.test.ts b/src/grud-intl.test.ts index 1482ae9..3539a05 100644 --- a/src/grud-intl.test.ts +++ b/src/grud-intl.test.ts @@ -109,7 +109,7 @@ describe("grud-intl", () => { ); }); - describe("formatNumber()", () => { + describe("formatNumber() with separator", () => { const amount = 1234.56; it.each` langtag | result @@ -119,7 +119,19 @@ describe("grud-intl", () => { ${"en-US"} | ${"1,234.56"} `("should format correctly for $langtag", ({ langtag, result }) => { // be aware of uncommon white space in the results - expect(i.formatNumber(langtag, amount)).toBe(result); + expect(i.formatNumber(langtag, true, amount)).toBe(result); + }); + }); + describe("formatNumber() without separator", () => { + const amount = 1234.56; + it.each` + langtag | result + ${"de-DE"} | ${"1234,56"} + ${"en-GB"} | ${"1234.56"} + ${"fr-CH"} | ${"1234,56"} + ${"en-US"} | ${"1234.56"} + `("should format correctly for $langtag", ({ langtag, result }) => { + expect(i.formatNumber(langtag, false, amount)).toBe(result); }); }); diff --git a/src/grud-intl.ts b/src/grud-intl.ts index 34c9e54..eeeaac6 100644 --- a/src/grud-intl.ts +++ b/src/grud-intl.ts @@ -304,13 +304,21 @@ export function formatCurrency( return arguments.length < 3 ? formatter.format : formatter.format(value); } -export function formatNumber(lt: Country | Locale, value: number): string; -export function formatNumber(lt: Country | Locale): (_: number) => string; +export function formatNumber( + lt: Country | Locale, + separator: boolean, + value: number, +): string; +export function formatNumber( + lt: Country | Locale, + separator: boolean, +): (_: number) => string; export function formatNumber( langtag: Country | Locale = DEFAULT_LOCALE, + separator: boolean = true, value: number = 0, ) { - const formatter = new Intl.NumberFormat(langtag); + const formatter = new Intl.NumberFormat(langtag, { useGrouping: separator }); return arguments.length < 2 ? formatter.format : formatter.format(value); } diff --git a/src/predicates.ts b/src/predicates.ts index 75e5d23..604f30a 100644 --- a/src/predicates.ts +++ b/src/predicates.ts @@ -6,6 +6,7 @@ import type { CurrencyColumn, DateColumn, DateTimeColumn, + IntegerColumn, LinkColumn, NumberColumn, RichTextColumn, @@ -28,6 +29,8 @@ export const isConcatColumn = (column: Column): column is ConcatColumn => column.kind === ColumnKind.concat; export const isGroupColumn = (column: Column): column is ConcatColumn => column.kind === ColumnKind.group; +export const isIntegerColumn = (column: Column): column is IntegerColumn => + column.kind === ColumnKind.integer; export const isLinkColumn = (column: Column): column is LinkColumn => column.kind === ColumnKind.link; export const isNumberColumn = (column: Column): column is NumberColumn => diff --git a/src/types/cell.ts b/src/types/cell.ts index fbc5ac3..cbc61fc 100644 --- a/src/types/cell.ts +++ b/src/types/cell.ts @@ -13,6 +13,7 @@ export type TextCellValue = BaseCellValue; export type RichTextCellValue = BaseCellValue; export type ShortTextCellValue = BaseCellValue; export type NumberCellValue = BaseCellValue; +export type IntegerCellValue = BaseCellValue; export type BooleanCellValue = BaseCellValue; export type LinkCellValue = SingleLangCellValue< Array diff --git a/src/types/column.ts b/src/types/column.ts index 9dd169e..9c5a61c 100644 --- a/src/types/column.ts +++ b/src/types/column.ts @@ -13,6 +13,7 @@ export const ColumnKind = { date: "date", datetime: "datetime", group: "group", + integer: "integer", link: "link", numeric: "numeric", richtext: "richtext", @@ -22,6 +23,14 @@ export const ColumnKind = { } as const; export type ColumnKind = (typeof ColumnKind)[keyof typeof ColumnKind]; +export const LanguageType = { + language: "language", + country: "country", + neutral: "neutral", +} as const; + +export type LanguageType = (typeof LanguageType)[keyof typeof LanguageType]; + export type ColumnAttributeString = { type: "string"; value: string }; export type ColumnAttributeNumber = { type: "number"; value: number }; export type ColumnAttributeBoolean = { type: "boolean"; value: boolean }; @@ -43,9 +52,12 @@ interface BaseColumn { format?: string; id: ColumnID; identifier: boolean; + languagetype?: LanguageType; name: string; ordering: number; separator: boolean; + minLength?: number; + maxLength?: number; } interface SingleLangColumn extends BaseColumn { @@ -56,7 +68,7 @@ interface SingleLangColumn extends BaseColumn { interface MultilangColumn extends BaseColumn { multilanguage: true; kind: Kind; - languagetype?: "language"; + languagetype: "language"; } interface MultiCountryColumn extends BaseColumn { @@ -125,6 +137,10 @@ export type AttachmentColumn = SingleOrMultilangColumn<"attachment">; export type BooleanColumn = SingleLangColumn<"boolean">; export type CurrencyColumn = MultiCountryColumn<"currency">; export type NumberColumn = SingleOrMultilangColumn<"numeric">; + +export type IntegerColumn = SingleOrMultilangColumn<"integer"> & { + separator?: boolean; +}; export type RichTextColumn = SingleOrMultilangColumn<"richtext">; export type ShortTextColumn = SingleOrMultilangColumn<"shorttext">; export type TextColumn = SingleOrMultilangColumn<"text">; @@ -139,6 +155,7 @@ export type Column = | DateColumn | DateTimeColumn | GroupColumn + | IntegerColumn | LinkColumn | NumberColumn | RichTextColumn diff --git a/src/types/common.ts b/src/types/common.ts index 517dd12..f7cb430 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -46,6 +46,7 @@ type CellValueForColumnMap = { [Col.ColumnKind.date]: Cell.DateCellValue; [Col.ColumnKind.datetime]: Cell.DateTimeCellValue; [Col.ColumnKind.group]: Cell.GroupCellValue; + [Col.ColumnKind.integer]: Cell.IntegerCellValue; [Col.ColumnKind.link]: Cell.LinkCellValue; [Col.ColumnKind.numeric]: Cell.NumberCellValue; [Col.ColumnKind.richtext]: Cell.RichTextCellValue; @@ -62,6 +63,7 @@ type CellDisplayValueForColumnMap = { [Col.ColumnKind.date]: MultilangValue; [Col.ColumnKind.datetime]: MultilangValue; [Col.ColumnKind.group]: MultilangValue; + [Col.ColumnKind.integer]: MultilangValue; [Col.ColumnKind.link]: MultilangValue[]; [Col.ColumnKind.numeric]: MultilangValue; [Col.ColumnKind.richtext]: MultilangValue; From d0785289ad57fd6b306186636d5a0c0702f44a97 Mon Sep 17 00:00:00 2001 From: Manfred Zingl Date: Fri, 22 May 2026 13:30:43 +0200 Subject: [PATCH 2/2] increase semver version (patch) --- deno.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deno.jsonc b/deno.jsonc index aad2c69..7c8c3c1 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,6 +1,6 @@ { "name": "@grud/devtools", - "version": "0.3.6", + "version": "0.3.7", "license": "Apache-2.0", "imports": { "ramda": "npm:ramda@^0.30.1",