@rowsncolumns/utils 9.2.40 → 9.2.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cell-data-helpers.d.ts +13 -0
- package/dist/cjs/cell-data-helpers.d.ts.map +1 -1
- package/dist/cjs/cell-data-helpers.js +19 -1
- package/dist/cjs/formatter.d.ts +12 -0
- package/dist/cjs/formatter.d.ts.map +1 -1
- package/dist/cjs/formatter.js +216 -2
- package/dist/cjs/locale.d.ts +15 -0
- package/dist/cjs/locale.d.ts.map +1 -1
- package/dist/cjs/locale.js +58 -6
- package/dist/esm/cell-data-helpers.d.ts +13 -0
- package/dist/esm/cell-data-helpers.d.ts.map +1 -1
- package/dist/esm/cell-data-helpers.js +14 -0
- package/dist/esm/formatter.d.ts +12 -0
- package/dist/esm/formatter.d.ts.map +1 -1
- package/dist/esm/formatter.js +211 -2
- package/dist/esm/locale.d.ts +15 -0
- package/dist/esm/locale.d.ts.map +1 -1
- package/dist/esm/locale.js +42 -5
- package/package.json +2 -2
|
@@ -31,6 +31,19 @@ export declare const getExtendedValueError: (extValue?: Record<string, any> | nu
|
|
|
31
31
|
* `getDefaultHorizontalAlignment(sheetId, rowIndex, columnIndex)` so a toolbar
|
|
32
32
|
* alignment selector reports the alignment the grid actually draws.
|
|
33
33
|
*/
|
|
34
|
+
/**
|
|
35
|
+
* Excel's `justify` and `distributed` alignments imply word wrap: the cell
|
|
36
|
+
* wraps inside its own width even without `wrapStrategy: "wrap"` (there is
|
|
37
|
+
* nothing to spread across otherwise) and the row auto-fits the wrapped
|
|
38
|
+
* lines. Shared by the canvas renderer (wrap + overflow decision) and the
|
|
39
|
+
* state hooks' row auto-height so both agree on which cells wrap.
|
|
40
|
+
*/
|
|
41
|
+
export declare const alignmentImpliesWrap: (align: HorizontalAlign | string | null | undefined) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Whether a cell format wraps its text — explicit `wrapStrategy: "wrap"` or
|
|
44
|
+
* an alignment that wraps implicitly ({@link alignmentImpliesWrap}).
|
|
45
|
+
*/
|
|
46
|
+
export declare const cellFormatWrapsText: (format: Pick<CellFormat, "wrapStrategy" | "horizontalAlignment"> | null | undefined) => boolean;
|
|
34
47
|
export declare const resolveDefaultHorizontalAlignment: ({ errorValue, userEnteredValue, effectiveValue, dataValidation, }: {
|
|
35
48
|
errorValue: unknown;
|
|
36
49
|
userEnteredValue: Record<string, any> | null | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell-data-helpers.d.ts","sourceRoot":"","sources":["../../cell-data-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,cAAc,EACf,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,uBAAuB,GAAI,CAAC,SAAS,QAAQ,EACxD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,CAAC,SAAS,QAAQ,EACzD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,QAAQ,EACvD,OAAO,CAAC,GAAG,IAAI,KACd,UAAU,GAAG,cAAc,GAAG,IAAI,GAAG,SAEvC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,MAAM,GAAG,SAAS,GAAG,IAEvB,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAE1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,OAAO,GAAG,SAEZ,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,GAAG,GAAG,SAER,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iCAAiC,GAAI,mEAK/C;IACD,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACvD,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;CAC1E,KAAG,eAAe,GAAG,SASrB,CAAC"}
|
|
1
|
+
{"version":3,"file":"cell-data-helpers.d.ts","sourceRoot":"","sources":["../../cell-data-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,cAAc,EACf,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,uBAAuB,GAAI,CAAC,SAAS,QAAQ,EACxD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,CAAC,SAAS,QAAQ,EACzD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,QAAQ,EACvD,OAAO,CAAC,GAAG,IAAI,KACd,UAAU,GAAG,cAAc,GAAG,IAAI,GAAG,SAEvC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,MAAM,GAAG,SAAS,GAAG,IAEvB,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAE1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,OAAO,GAAG,SAEZ,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,GAAG,GAAG,SAER,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,KACjD,OAAyD,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QACI,IAAI,CAAC,UAAU,EAAE,cAAc,GAAG,qBAAqB,CAAC,GACxD,IAAI,GACJ,SAAS,KACZ,OAEgD,CAAC;AAEpD,eAAO,MAAM,iCAAiC,GAAI,mEAK/C;IACD,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACvD,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;CAC1E,KAAG,eAAe,GAAG,SASrB,CAAC"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Note: These functions use generic types to avoid circular dependencies
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.resolveDefaultHorizontalAlignment = exports.getExtendedValueError = exports.getExtendedValueFormula = exports.getExtendedValueBool = exports.getExtendedValueString = exports.getExtendedValueNumber = exports.getStyleId = exports.getCellFormattedValue = exports.getCellEffectiveFormat = exports.getCellUserEnteredFormat = exports.getCellEffectiveValue = exports.getCellUserEnteredValue = void 0;
|
|
9
|
+
exports.resolveDefaultHorizontalAlignment = exports.cellFormatWrapsText = exports.alignmentImpliesWrap = exports.getExtendedValueError = exports.getExtendedValueFormula = exports.getExtendedValueBool = exports.getExtendedValueString = exports.getExtendedValueNumber = exports.getStyleId = exports.getCellFormattedValue = exports.getCellEffectiveFormat = exports.getCellUserEnteredFormat = exports.getCellEffectiveValue = exports.getCellUserEnteredValue = void 0;
|
|
10
10
|
var getCellUserEnteredValue = function (cell) {
|
|
11
11
|
var _a;
|
|
12
12
|
return (_a = cell === null || cell === void 0 ? void 0 : cell.ue) !== null && _a !== void 0 ? _a : cell === null || cell === void 0 ? void 0 : cell.userEnteredValue;
|
|
@@ -77,6 +77,24 @@ exports.getExtendedValueError = getExtendedValueError;
|
|
|
77
77
|
* `getDefaultHorizontalAlignment(sheetId, rowIndex, columnIndex)` so a toolbar
|
|
78
78
|
* alignment selector reports the alignment the grid actually draws.
|
|
79
79
|
*/
|
|
80
|
+
/**
|
|
81
|
+
* Excel's `justify` and `distributed` alignments imply word wrap: the cell
|
|
82
|
+
* wraps inside its own width even without `wrapStrategy: "wrap"` (there is
|
|
83
|
+
* nothing to spread across otherwise) and the row auto-fits the wrapped
|
|
84
|
+
* lines. Shared by the canvas renderer (wrap + overflow decision) and the
|
|
85
|
+
* state hooks' row auto-height so both agree on which cells wrap.
|
|
86
|
+
*/
|
|
87
|
+
var alignmentImpliesWrap = function (align) { return align === "justify" || align === "distributed"; };
|
|
88
|
+
exports.alignmentImpliesWrap = alignmentImpliesWrap;
|
|
89
|
+
/**
|
|
90
|
+
* Whether a cell format wraps its text — explicit `wrapStrategy: "wrap"` or
|
|
91
|
+
* an alignment that wraps implicitly ({@link alignmentImpliesWrap}).
|
|
92
|
+
*/
|
|
93
|
+
var cellFormatWrapsText = function (format) {
|
|
94
|
+
return (format === null || format === void 0 ? void 0 : format.wrapStrategy) === "wrap" ||
|
|
95
|
+
(0, exports.alignmentImpliesWrap)(format === null || format === void 0 ? void 0 : format.horizontalAlignment);
|
|
96
|
+
};
|
|
97
|
+
exports.cellFormatWrapsText = cellFormatWrapsText;
|
|
80
98
|
var resolveDefaultHorizontalAlignment = function (_a) {
|
|
81
99
|
var _b;
|
|
82
100
|
var errorValue = _a.errorValue, userEnteredValue = _a.userEnteredValue, effectiveValue = _a.effectiveValue, dataValidation = _a.dataValidation;
|
package/dist/cjs/formatter.d.ts
CHANGED
|
@@ -31,6 +31,18 @@ export declare const isStandaloneMonthPattern: (pattern: string) => boolean;
|
|
|
31
31
|
* `A`/`P` locale, or `undefined` when there is none.
|
|
32
32
|
*/
|
|
33
33
|
export declare const withShortAmPmMarker: (pattern: string) => string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Excel's `[$symbol-LCID]` token selects the currency symbol and the
|
|
36
|
+
* language of day/month names and AM/PM; digit grouping and the decimal
|
|
37
|
+
* separator follow the workbook locale (`[$€-407] #,##0.00` is
|
|
38
|
+
* `€ 1,234.50` on a US host). numfmt applies the token's locale to the whole
|
|
39
|
+
* section, separators included, so the locale part is dropped from every
|
|
40
|
+
* section that is not a date (number, scientific, fraction, text, …); a
|
|
41
|
+
* date section keeps the token for its names, re-pointed at a companion
|
|
42
|
+
* locale that carries the workbook's separators for fractional seconds.
|
|
43
|
+
* Returns `undefined` when nothing had to change.
|
|
44
|
+
*/
|
|
45
|
+
export declare const withWorkbookSeparators: (pattern: string, locale?: string) => string | undefined;
|
|
34
46
|
export declare const ssfFormat: (pattern: string, value: any, locale?: string) => string;
|
|
35
47
|
export declare const ssfFormatColor: (pattern: string, value: any) => string | undefined;
|
|
36
48
|
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../formatter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../formatter.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OASlE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KACjC,OAWF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OAWlE,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OAOlE,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,MAAM,KAAG,OA4B1D,CAAC;AA+LF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,SA4C9D,CAAC;AAiIF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GACjC,SAAS,MAAM,EACf,SAAS,MAAM,KACd,MAAM,GAAG,SAiBX,CAAC;AAiBF,eAAO,MAAM,SAAS,GACpB,SAAS,MAAM,EACf,OAAO,GAAG,EACV,SAAS,MAAM,KACd,MA0CF,CAAC;AAmLF,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,EACf,OAAO,GAAG,KACT,MAAM,GAAG,SAoBX,CAAC"}
|
package/dist/cjs/formatter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ssfFormatColor = exports.ssfFormat = exports.withShortAmPmMarker = exports.isStandaloneMonthPattern = exports.isTextPattern = exports.isTimePattern = exports.isDateTimePattern = exports.isDatePattern = void 0;
|
|
3
|
+
exports.ssfFormatColor = exports.ssfFormat = exports.withWorkbookSeparators = exports.withShortAmPmMarker = exports.isStandaloneMonthPattern = exports.isTextPattern = exports.isTimePattern = exports.isDateTimePattern = exports.isDatePattern = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var numfmt_1 = require("numfmt");
|
|
6
6
|
var colors_1 = require("./colors");
|
|
@@ -144,6 +144,69 @@ var intlMonthNames = function (locale, options) {
|
|
|
144
144
|
.find(function (part) { return part.type === "month"; })) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "";
|
|
145
145
|
});
|
|
146
146
|
};
|
|
147
|
+
var intlRegisteredLocales = new Set();
|
|
148
|
+
/**
|
|
149
|
+
* numfmt ships name tables for a fixed set of languages; a tag it does not know
|
|
150
|
+
* (et, ms, nn, …) silently renders English month/weekday names and en-US
|
|
151
|
+
* separators. Excel and `Intl.DateTimeFormat` localize every locale, so an
|
|
152
|
+
* unknown tag gets a numfmt locale built from Intl on first use: separators
|
|
153
|
+
* from `Intl.NumberFormat`, the in-date month names (numfmt's single table is
|
|
154
|
+
* the form used beside a day number — see `getStandaloneMonthLocale`), the
|
|
155
|
+
* in-date weekday names (the form `dateStyle: "full"` shows) and the AM/PM
|
|
156
|
+
* designators. Tags Intl itself does not know keep numfmt's fallback.
|
|
157
|
+
*/
|
|
158
|
+
var ensureNumfmtLocale = function (locale) {
|
|
159
|
+
var _a, _b;
|
|
160
|
+
if (intlRegisteredLocales.has(locale))
|
|
161
|
+
return;
|
|
162
|
+
intlRegisteredLocales.add(locale);
|
|
163
|
+
try {
|
|
164
|
+
if ((0, numfmt_1.getLocale)(locale))
|
|
165
|
+
return;
|
|
166
|
+
var canonical = Intl.DateTimeFormat.supportedLocalesOf([locale])[0];
|
|
167
|
+
if (!canonical)
|
|
168
|
+
return;
|
|
169
|
+
var numberParts_1 = new Intl.NumberFormat(locale).formatToParts(1234567.5);
|
|
170
|
+
var part = function (type) { var _a; return (_a = numberParts_1.find(function (p) { return p.type === type; })) === null || _a === void 0 ? void 0 : _a.value; };
|
|
171
|
+
var weekdayNames = function (weekday) {
|
|
172
|
+
// 2024-01-07 was a Sunday; numfmt indexes `dddd[0]` as Sunday.
|
|
173
|
+
var fmt = new Intl.DateTimeFormat(locale, {
|
|
174
|
+
weekday: weekday,
|
|
175
|
+
day: "numeric",
|
|
176
|
+
month: "long",
|
|
177
|
+
year: "numeric",
|
|
178
|
+
timeZone: "UTC",
|
|
179
|
+
});
|
|
180
|
+
return Array.from({ length: 7 }, function (_, i) {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
return (_b = (_a = fmt
|
|
183
|
+
.formatToParts(new Date(Date.UTC(2024, 0, 7 + i)))
|
|
184
|
+
.find(function (p) { return p.type === "weekday"; })) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "";
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
var dayPeriod = function (hour) {
|
|
188
|
+
var _a;
|
|
189
|
+
return (_a = new Intl.DateTimeFormat(locale, {
|
|
190
|
+
hour: "numeric",
|
|
191
|
+
hour12: true,
|
|
192
|
+
timeZone: "UTC",
|
|
193
|
+
})
|
|
194
|
+
.formatToParts(new Date(Date.UTC(2024, 0, 7, hour)))
|
|
195
|
+
.find(function (p) { return p.type === "dayPeriod"; })) === null || _a === void 0 ? void 0 : _a.value;
|
|
196
|
+
};
|
|
197
|
+
var dateParts = new Intl.DateTimeFormat(locale, {
|
|
198
|
+
timeZone: "UTC",
|
|
199
|
+
}).formatToParts(new Date(Date.UTC(2024, 0, 7)));
|
|
200
|
+
var monthIndex = dateParts.findIndex(function (p) { return p.type === "month"; });
|
|
201
|
+
var dayIndex = dateParts.findIndex(function (p) { return p.type === "day"; });
|
|
202
|
+
var am = dayPeriod(9);
|
|
203
|
+
var pm = dayPeriod(21);
|
|
204
|
+
(0, numfmt_1.addLocale)(tslib_1.__assign(tslib_1.__assign({ group: (_a = part("group")) !== null && _a !== void 0 ? _a : "\u00a0", decimal: (_b = part("decimal")) !== null && _b !== void 0 ? _b : ".", mmmm: intlMonthNames(locale, { day: "numeric", month: "long" }), mmm: intlMonthNames(locale, { day: "numeric", month: "short" }), dddd: weekdayNames("long"), ddd: weekdayNames("short") }, (am && pm && am !== pm ? { ampm: [am, pm] } : {})), { preferMDY: monthIndex >= 0 && dayIndex >= 0 && monthIndex < dayIndex }), locale);
|
|
205
|
+
}
|
|
206
|
+
catch (_c) {
|
|
207
|
+
// Malformed tag: numfmt keeps its own fallback.
|
|
208
|
+
}
|
|
209
|
+
};
|
|
147
210
|
var standaloneMonthLocales = new Map();
|
|
148
211
|
/**
|
|
149
212
|
* numfmt ships one month-name table per locale: the form used beside a day
|
|
@@ -316,14 +379,165 @@ var separatorsFor = function (locale) {
|
|
|
316
379
|
group: (_b = l10n.group) !== null && _b !== void 0 ? _b : ",",
|
|
317
380
|
};
|
|
318
381
|
};
|
|
382
|
+
/**
|
|
383
|
+
* Rewrite the `[$symbol-LCID]` tokens of one section through `rewrite`,
|
|
384
|
+
* which receives the bracket content (`€-407`) and returns the new content,
|
|
385
|
+
* or an empty string to drop the token. Quoted literals, escapes and other
|
|
386
|
+
* bracket directives are left as written.
|
|
387
|
+
*/
|
|
388
|
+
var rewriteSectionLocaleTokens = function (section, rewrite) {
|
|
389
|
+
var _a;
|
|
390
|
+
var out = "";
|
|
391
|
+
var inQuotes = false;
|
|
392
|
+
var inBrackets = false;
|
|
393
|
+
for (var i = 0; i < section.length; i++) {
|
|
394
|
+
var char = section[i];
|
|
395
|
+
if (inQuotes) {
|
|
396
|
+
inQuotes = char !== '"';
|
|
397
|
+
}
|
|
398
|
+
else if (inBrackets) {
|
|
399
|
+
inBrackets = char !== "]";
|
|
400
|
+
}
|
|
401
|
+
else if (char === '"') {
|
|
402
|
+
inQuotes = true;
|
|
403
|
+
}
|
|
404
|
+
else if (char === "[") {
|
|
405
|
+
var end = section[i + 1] === "$" ? section.indexOf("]", i) : -1;
|
|
406
|
+
if (end > 0) {
|
|
407
|
+
var token = rewrite(section.slice(i + 1, end));
|
|
408
|
+
if (token)
|
|
409
|
+
out += "[".concat(token, "]");
|
|
410
|
+
i = end;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
inBrackets = true;
|
|
414
|
+
}
|
|
415
|
+
else if (char === "\\" || char === "_" || char === "*") {
|
|
416
|
+
out += char + ((_a = section[i + 1]) !== null && _a !== void 0 ? _a : "");
|
|
417
|
+
i++;
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
out += char;
|
|
421
|
+
}
|
|
422
|
+
return out;
|
|
423
|
+
};
|
|
424
|
+
/** `[$€-407]` → `[$€]`; a bare `[$-407]` goes away. */
|
|
425
|
+
var currencySymbolOnly = function (token) {
|
|
426
|
+
var dash = token.indexOf("-");
|
|
427
|
+
var symbol = dash < 0 ? token : token.slice(0, dash);
|
|
428
|
+
return symbol.length > 1 ? symbol : "";
|
|
429
|
+
};
|
|
430
|
+
var separatorLocales = new Map();
|
|
431
|
+
/**
|
|
432
|
+
* Companion numfmt locale carrying `locale`'s calendar names and AM/PM with
|
|
433
|
+
* the workbook's decimal / group separators, so a date section pinned to
|
|
434
|
+
* `[$-407]` renders German names but a workbook decimal mark in `ss.00`.
|
|
435
|
+
* Returns `locale` itself when its separators already match.
|
|
436
|
+
*/
|
|
437
|
+
var getWorkbookSeparatorLocale = function (locale, separators) {
|
|
438
|
+
var key = "".concat(locale, "\0").concat(separators.decimal, "\0").concat(separators.group);
|
|
439
|
+
var cached = separatorLocales.get(key);
|
|
440
|
+
if (cached !== undefined)
|
|
441
|
+
return cached;
|
|
442
|
+
var overlay = locale;
|
|
443
|
+
try {
|
|
444
|
+
var base = (0, numfmt_1.getLocale)(locale);
|
|
445
|
+
if (base &&
|
|
446
|
+
(base.decimal !== separators.decimal || base.group !== separators.group)) {
|
|
447
|
+
// numfmt locale ids are `[a-z\d]+` with one optional `_` part.
|
|
448
|
+
var hex = function (text) {
|
|
449
|
+
return tslib_1.__spreadArray([], tslib_1.__read(text), false).map(function (c) { return c.codePointAt(0).toString(16); }).join("x");
|
|
450
|
+
};
|
|
451
|
+
overlay = "sep".concat(hex(separators.decimal), "x").concat(hex(separators.group), "_").concat(locale.replace(/[^a-z\d]/gi, ""));
|
|
452
|
+
(0, numfmt_1.addLocale)(tslib_1.__assign(tslib_1.__assign({}, base), { decimal: separators.decimal, group: separators.group }), overlay);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
catch (_a) {
|
|
456
|
+
overlay = locale;
|
|
457
|
+
}
|
|
458
|
+
separatorLocales.set(key, overlay);
|
|
459
|
+
return overlay;
|
|
460
|
+
};
|
|
461
|
+
/**
|
|
462
|
+
* Re-point a date section's `[$symbol-LCID]` token at the companion locale
|
|
463
|
+
* with the workbook's separators (`$-407` → `$-sep2ex2c_407`). An LCID numfmt
|
|
464
|
+
* does not know or one carrying calendar bits stays as written.
|
|
465
|
+
*/
|
|
466
|
+
var workbookSeparatorLocaleToken = function (separators) {
|
|
467
|
+
return function (token) {
|
|
468
|
+
var dash = token.indexOf("-");
|
|
469
|
+
if (dash < 0)
|
|
470
|
+
return token;
|
|
471
|
+
var code = token.slice(dash + 1);
|
|
472
|
+
var wincode = Number.parseInt(code, 16);
|
|
473
|
+
if (Number.isFinite(wincode) && wincode & 0xff0000)
|
|
474
|
+
return token;
|
|
475
|
+
if (!(0, numfmt_1.getLocale)(code))
|
|
476
|
+
return token;
|
|
477
|
+
return "".concat(token.slice(0, dash + 1)).concat(getWorkbookSeparatorLocale(code, separators));
|
|
478
|
+
};
|
|
479
|
+
};
|
|
480
|
+
var isDateSection = function (section) {
|
|
481
|
+
try {
|
|
482
|
+
return (0, numfmt_1.isDateFormat)(section);
|
|
483
|
+
}
|
|
484
|
+
catch (_a) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
/**
|
|
489
|
+
* Excel's `[$symbol-LCID]` token selects the currency symbol and the
|
|
490
|
+
* language of day/month names and AM/PM; digit grouping and the decimal
|
|
491
|
+
* separator follow the workbook locale (`[$€-407] #,##0.00` is
|
|
492
|
+
* `€ 1,234.50` on a US host). numfmt applies the token's locale to the whole
|
|
493
|
+
* section, separators included, so the locale part is dropped from every
|
|
494
|
+
* section that is not a date (number, scientific, fraction, text, …); a
|
|
495
|
+
* date section keeps the token for its names, re-pointed at a companion
|
|
496
|
+
* locale that carries the workbook's separators for fractional seconds.
|
|
497
|
+
* Returns `undefined` when nothing had to change.
|
|
498
|
+
*/
|
|
499
|
+
var withWorkbookSeparators = function (pattern, locale) {
|
|
500
|
+
if (!pattern.includes("[$"))
|
|
501
|
+
return undefined;
|
|
502
|
+
var sections = (0, excel_number_format_1.splitFormatSections)(pattern);
|
|
503
|
+
var changed = false;
|
|
504
|
+
var dateTokens;
|
|
505
|
+
var rewritten = sections.map(function (section) {
|
|
506
|
+
if (!section.includes("[$"))
|
|
507
|
+
return section;
|
|
508
|
+
var rewrite = currencySymbolOnly;
|
|
509
|
+
if (isDateSection(section)) {
|
|
510
|
+
dateTokens !== null && dateTokens !== void 0 ? dateTokens : (dateTokens = workbookSeparatorLocaleToken(separatorsFor(locale)));
|
|
511
|
+
rewrite = dateTokens;
|
|
512
|
+
}
|
|
513
|
+
var stripped = rewriteSectionLocaleTokens(section, rewrite);
|
|
514
|
+
changed || (changed = stripped !== section);
|
|
515
|
+
return stripped;
|
|
516
|
+
});
|
|
517
|
+
return changed ? rewritten.join(";") : undefined;
|
|
518
|
+
};
|
|
519
|
+
exports.withWorkbookSeparators = withWorkbookSeparators;
|
|
520
|
+
var workbookSeparatorPatternCache = new Map();
|
|
521
|
+
var withWorkbookSeparatorsCached = function (code, locale) {
|
|
522
|
+
var _a;
|
|
523
|
+
var key = "".concat(locale !== null && locale !== void 0 ? locale : "", "\0").concat(code);
|
|
524
|
+
var rewritten = workbookSeparatorPatternCache.get(key);
|
|
525
|
+
if (rewritten === undefined) {
|
|
526
|
+
rewritten = (_a = (0, exports.withWorkbookSeparators)(code, locale)) !== null && _a !== void 0 ? _a : code;
|
|
527
|
+
workbookSeparatorPatternCache.set(key, rewritten);
|
|
528
|
+
}
|
|
529
|
+
return rewritten;
|
|
530
|
+
};
|
|
319
531
|
var ssfFormat = function (pattern, value, locale) {
|
|
320
532
|
try {
|
|
533
|
+
if (locale)
|
|
534
|
+
ensureNumfmtLocale(locale);
|
|
321
535
|
var shortAmPm = shortAmPmPatternCache.get(pattern);
|
|
322
536
|
if (shortAmPm === undefined && !shortAmPmPatternCache.has(pattern)) {
|
|
323
537
|
shortAmPm = (0, exports.withShortAmPmMarker)(pattern);
|
|
324
538
|
shortAmPmPatternCache.set(pattern, shortAmPm);
|
|
325
539
|
}
|
|
326
|
-
var code = shortAmPm !== null && shortAmPm !== void 0 ? shortAmPm : pattern;
|
|
540
|
+
var code = withWorkbookSeparatorsCached(shortAmPm !== null && shortAmPm !== void 0 ? shortAmPm : pattern, locale);
|
|
327
541
|
var patternLocale = localeForPattern(pattern, locale);
|
|
328
542
|
if (shortAmPm !== undefined && patternLocale) {
|
|
329
543
|
patternLocale = getShortAmPmLocale(patternLocale);
|
package/dist/cjs/locale.d.ts
CHANGED
|
@@ -16,6 +16,21 @@ export declare const getLocaleDateParts: (locale: string) => [DatePartType, stri
|
|
|
16
16
|
* de-DE → `d.m.yyyy`, hu-HU → `yyyy. mm. dd.`, en-CA → `yyyy-mm-dd`.
|
|
17
17
|
*/
|
|
18
18
|
export declare const getDefaultDateFormat: (locale?: string) => string;
|
|
19
|
+
export interface DateFieldTokens {
|
|
20
|
+
day: "d" | "dd";
|
|
21
|
+
month: "m" | "mm";
|
|
22
|
+
year: "yy" | "yyyy";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The day / month / year tokens of {@link getDefaultDateFormat} for a
|
|
26
|
+
* locale, i.e. whether the locale zero-pads each numeric field — ru-RU
|
|
27
|
+
* (`dd.mm.yyyy`) → `{ day: "dd", month: "mm", year: "yyyy" }`, en-US
|
|
28
|
+
* (`m/d/yyyy`) → `{ day: "d", month: "m", year: "yyyy" }`. A date typed
|
|
29
|
+
* as digits is displayed with the locale's own padding (Excel re-renders
|
|
30
|
+
* `30.9.2025` as `30.09.2025` under ru-RU), so the date parser assigns
|
|
31
|
+
* these tokens rather than echoing the padding the user happened to type.
|
|
32
|
+
*/
|
|
33
|
+
export declare const getDefaultDateFieldTokens: (locale?: string) => DateFieldTokens;
|
|
19
34
|
/**
|
|
20
35
|
* Default time pattern for a locale, honoring its 12/24-hour convention,
|
|
21
36
|
* separators and hour padding — e.g. en-US → `h:mm:ss AM/PM`,
|
package/dist/cjs/locale.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../locale.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,cAU5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM,qCAkC3D,CAAC;AAEF,eAAO,MAAM,kBAAkB,sDAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../locale.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,cAU5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM,qCAkC3D,CAAC;AAEF,eAAO,MAAM,kBAAkB,sDAAyC,CAAC;AAiGzE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAQ,MAA2B,WAClC,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;IAChB,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAClB,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;CACrB;AAwBD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAQ,MAA2B,KAClC,eAA4D,CAAC;AAuChE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,MAA2B,EACnC,YAAW,QAAQ,GAAG,QAAmB,WACS,CAAC;AAErD,eAAO,MAAM,wBAAwB,GAAI,SAAS,MAAM,WAEvD,CAAC;AA2CF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAQ,MAA2B,WAClC,CAAC"}
|
package/dist/cjs/locale.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getLongDateFormat = exports.getDefaultDateTimeFormat = exports.getDefaultTimeFormat = exports.getDefaultDateFormat = exports.getLocaleDateParts = exports.getLocaleDatePartsNotMemoized = exports.getCurrentLocale = void 0;
|
|
3
|
+
exports.getLongDateFormat = exports.getDefaultDateTimeFormat = exports.getDefaultTimeFormat = exports.getDefaultDateFieldTokens = exports.getDefaultDateFormat = exports.getLocaleDateParts = exports.getLocaleDatePartsNotMemoized = exports.getCurrentLocale = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var memoize_1 = require("./memoize");
|
|
6
6
|
var defaultLocale;
|
|
@@ -134,9 +134,15 @@ var buildPatternFromParts = function (parts, toToken) {
|
|
|
134
134
|
// trailing fields we skipped (e.g. an era) — trim stray whitespace.
|
|
135
135
|
return pattern.trim();
|
|
136
136
|
};
|
|
137
|
-
|
|
137
|
+
/**
|
|
138
|
+
* `formatToParts` of the locale's numeric short date for the sample
|
|
139
|
+
* instant — the single source both the default pattern and its per-field
|
|
140
|
+
* tokens are read from, so they can never disagree. Empty when Intl has
|
|
141
|
+
* no data for the locale.
|
|
142
|
+
*/
|
|
143
|
+
var getDefaultDateParts = (0, memoize_1.memoize)(function (locale) {
|
|
138
144
|
try {
|
|
139
|
-
|
|
145
|
+
return new Intl.DateTimeFormat(locale, {
|
|
140
146
|
calendar: "gregory",
|
|
141
147
|
numberingSystem: "latn",
|
|
142
148
|
year: "numeric",
|
|
@@ -144,13 +150,15 @@ var getDefaultDateFormatMemoized = (0, memoize_1.memoize)(function (locale) {
|
|
|
144
150
|
day: "numeric",
|
|
145
151
|
timeZone: "UTC",
|
|
146
152
|
}).formatToParts(FORMAT_SAMPLE_DATE);
|
|
147
|
-
var pattern = buildPatternFromParts(parts, dateFieldToken);
|
|
148
|
-
return pattern || "m/d/yyyy";
|
|
149
153
|
}
|
|
150
154
|
catch (err) {
|
|
151
|
-
return
|
|
155
|
+
return [];
|
|
152
156
|
}
|
|
153
157
|
});
|
|
158
|
+
var getDefaultDateFormatMemoized = (0, memoize_1.memoize)(function (locale) {
|
|
159
|
+
var pattern = buildPatternFromParts(getDefaultDateParts(locale), dateFieldToken);
|
|
160
|
+
return pattern || "m/d/yyyy";
|
|
161
|
+
});
|
|
154
162
|
/**
|
|
155
163
|
* Default numeric (short) date pattern for a locale, preserving the
|
|
156
164
|
* locale's field order, separators, literal text and zero-padding as
|
|
@@ -162,6 +170,50 @@ var getDefaultDateFormat = function (locale) {
|
|
|
162
170
|
return getDefaultDateFormatMemoized(locale);
|
|
163
171
|
};
|
|
164
172
|
exports.getDefaultDateFormat = getDefaultDateFormat;
|
|
173
|
+
var getDefaultDateFieldTokensMemoized = (0, memoize_1.memoize)(function (locale) {
|
|
174
|
+
var e_3, _a;
|
|
175
|
+
var tokens = { day: "d", month: "m", year: "yyyy" };
|
|
176
|
+
try {
|
|
177
|
+
for (var _b = tslib_1.__values(getDefaultDateParts(locale)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
178
|
+
var part = _c.value;
|
|
179
|
+
switch (part.type) {
|
|
180
|
+
case "day":
|
|
181
|
+
tokens.day = part.value.length === 2 ? "dd" : "d";
|
|
182
|
+
break;
|
|
183
|
+
case "month":
|
|
184
|
+
tokens.month = part.value.length === 2 ? "mm" : "m";
|
|
185
|
+
break;
|
|
186
|
+
case "year":
|
|
187
|
+
tokens.year = part.value.length === 2 ? "yy" : "yyyy";
|
|
188
|
+
break;
|
|
189
|
+
default:
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
195
|
+
finally {
|
|
196
|
+
try {
|
|
197
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
198
|
+
}
|
|
199
|
+
finally { if (e_3) throw e_3.error; }
|
|
200
|
+
}
|
|
201
|
+
return tokens;
|
|
202
|
+
});
|
|
203
|
+
/**
|
|
204
|
+
* The day / month / year tokens of {@link getDefaultDateFormat} for a
|
|
205
|
+
* locale, i.e. whether the locale zero-pads each numeric field — ru-RU
|
|
206
|
+
* (`dd.mm.yyyy`) → `{ day: "dd", month: "mm", year: "yyyy" }`, en-US
|
|
207
|
+
* (`m/d/yyyy`) → `{ day: "d", month: "m", year: "yyyy" }`. A date typed
|
|
208
|
+
* as digits is displayed with the locale's own padding (Excel re-renders
|
|
209
|
+
* `30.9.2025` as `30.09.2025` under ru-RU), so the date parser assigns
|
|
210
|
+
* these tokens rather than echoing the padding the user happened to type.
|
|
211
|
+
*/
|
|
212
|
+
var getDefaultDateFieldTokens = function (locale) {
|
|
213
|
+
if (locale === void 0) { locale = (0, exports.getCurrentLocale)(); }
|
|
214
|
+
return getDefaultDateFieldTokensMemoized(locale);
|
|
215
|
+
};
|
|
216
|
+
exports.getDefaultDateFieldTokens = getDefaultDateFieldTokens;
|
|
165
217
|
var getDefaultTimeFormatMemoized = (0, memoize_1.memoize)(function (locale, precision) {
|
|
166
218
|
try {
|
|
167
219
|
var parts = new Intl.DateTimeFormat(locale, tslib_1.__assign(tslib_1.__assign({ numberingSystem: "latn", hour: "numeric", minute: "numeric" }, (precision === "second" ? { second: "numeric" } : {})), { timeZone: "UTC" })).formatToParts(FORMAT_SAMPLE_DATE);
|
|
@@ -31,6 +31,19 @@ export declare const getExtendedValueError: (extValue?: Record<string, any> | nu
|
|
|
31
31
|
* `getDefaultHorizontalAlignment(sheetId, rowIndex, columnIndex)` so a toolbar
|
|
32
32
|
* alignment selector reports the alignment the grid actually draws.
|
|
33
33
|
*/
|
|
34
|
+
/**
|
|
35
|
+
* Excel's `justify` and `distributed` alignments imply word wrap: the cell
|
|
36
|
+
* wraps inside its own width even without `wrapStrategy: "wrap"` (there is
|
|
37
|
+
* nothing to spread across otherwise) and the row auto-fits the wrapped
|
|
38
|
+
* lines. Shared by the canvas renderer (wrap + overflow decision) and the
|
|
39
|
+
* state hooks' row auto-height so both agree on which cells wrap.
|
|
40
|
+
*/
|
|
41
|
+
export declare const alignmentImpliesWrap: (align: HorizontalAlign | string | null | undefined) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Whether a cell format wraps its text — explicit `wrapStrategy: "wrap"` or
|
|
44
|
+
* an alignment that wraps implicitly ({@link alignmentImpliesWrap}).
|
|
45
|
+
*/
|
|
46
|
+
export declare const cellFormatWrapsText: (format: Pick<CellFormat, "wrapStrategy" | "horizontalAlignment"> | null | undefined) => boolean;
|
|
34
47
|
export declare const resolveDefaultHorizontalAlignment: ({ errorValue, userEnteredValue, effectiveValue, dataValidation, }: {
|
|
35
48
|
errorValue: unknown;
|
|
36
49
|
userEnteredValue: Record<string, any> | null | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell-data-helpers.d.ts","sourceRoot":"","sources":["../../cell-data-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,cAAc,EACf,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,uBAAuB,GAAI,CAAC,SAAS,QAAQ,EACxD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,CAAC,SAAS,QAAQ,EACzD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,QAAQ,EACvD,OAAO,CAAC,GAAG,IAAI,KACd,UAAU,GAAG,cAAc,GAAG,IAAI,GAAG,SAEvC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,MAAM,GAAG,SAAS,GAAG,IAEvB,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAE1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,OAAO,GAAG,SAEZ,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,GAAG,GAAG,SAER,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iCAAiC,GAAI,mEAK/C;IACD,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACvD,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;CAC1E,KAAG,eAAe,GAAG,SASrB,CAAC"}
|
|
1
|
+
{"version":3,"file":"cell-data-helpers.d.ts","sourceRoot":"","sources":["../../cell-data-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,cAAc,EACf,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,uBAAuB,GAAI,CAAC,SAAS,QAAQ,EACxD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,CAAC,SAAS,QAAQ,EACzD,OAAO,CAAC,GAAG,IAAI,KACd,CAAC,CAAC,IAAI,CAER,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,QAAQ,EACvD,OAAO,CAAC,GAAG,IAAI,KACd,UAAU,GAAG,cAAc,GAAG,IAAI,GAAG,SAEvC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,QAAQ,EACtD,OAAO,CAAC,GAAG,IAAI,KACd,MAAM,GAAG,SAAS,GAAG,IAEvB,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,MAE1D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,OAAO,GAAG,SAEZ,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,MAAM,GAAG,SAEX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,WAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,KACpC,GAAG,GAAG,SAER,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,KACjD,OAAyD,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QACI,IAAI,CAAC,UAAU,EAAE,cAAc,GAAG,qBAAqB,CAAC,GACxD,IAAI,GACJ,SAAS,KACZ,OAEgD,CAAC;AAEpD,eAAO,MAAM,iCAAiC,GAAI,mEAK/C;IACD,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACzD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IACvD,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;CAC1E,KAAG,eAAe,GAAG,SASrB,CAAC"}
|
|
@@ -52,6 +52,20 @@ export const getExtendedValueError = (extValue) => {
|
|
|
52
52
|
* `getDefaultHorizontalAlignment(sheetId, rowIndex, columnIndex)` so a toolbar
|
|
53
53
|
* alignment selector reports the alignment the grid actually draws.
|
|
54
54
|
*/
|
|
55
|
+
/**
|
|
56
|
+
* Excel's `justify` and `distributed` alignments imply word wrap: the cell
|
|
57
|
+
* wraps inside its own width even without `wrapStrategy: "wrap"` (there is
|
|
58
|
+
* nothing to spread across otherwise) and the row auto-fits the wrapped
|
|
59
|
+
* lines. Shared by the canvas renderer (wrap + overflow decision) and the
|
|
60
|
+
* state hooks' row auto-height so both agree on which cells wrap.
|
|
61
|
+
*/
|
|
62
|
+
export const alignmentImpliesWrap = (align) => align === "justify" || align === "distributed";
|
|
63
|
+
/**
|
|
64
|
+
* Whether a cell format wraps its text — explicit `wrapStrategy: "wrap"` or
|
|
65
|
+
* an alignment that wraps implicitly ({@link alignmentImpliesWrap}).
|
|
66
|
+
*/
|
|
67
|
+
export const cellFormatWrapsText = (format) => format?.wrapStrategy === "wrap" ||
|
|
68
|
+
alignmentImpliesWrap(format?.horizontalAlignment);
|
|
55
69
|
export const resolveDefaultHorizontalAlignment = ({ errorValue, userEnteredValue, effectiveValue, dataValidation, }) => {
|
|
56
70
|
const isBoolean = getExtendedValueBool(userEnteredValue) !== undefined;
|
|
57
71
|
const isCheckbox = dataValidation?.condition?.type === "BOOLEAN";
|
package/dist/esm/formatter.d.ts
CHANGED
|
@@ -31,6 +31,18 @@ export declare const isStandaloneMonthPattern: (pattern: string) => boolean;
|
|
|
31
31
|
* `A`/`P` locale, or `undefined` when there is none.
|
|
32
32
|
*/
|
|
33
33
|
export declare const withShortAmPmMarker: (pattern: string) => string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Excel's `[$symbol-LCID]` token selects the currency symbol and the
|
|
36
|
+
* language of day/month names and AM/PM; digit grouping and the decimal
|
|
37
|
+
* separator follow the workbook locale (`[$€-407] #,##0.00` is
|
|
38
|
+
* `€ 1,234.50` on a US host). numfmt applies the token's locale to the whole
|
|
39
|
+
* section, separators included, so the locale part is dropped from every
|
|
40
|
+
* section that is not a date (number, scientific, fraction, text, …); a
|
|
41
|
+
* date section keeps the token for its names, re-pointed at a companion
|
|
42
|
+
* locale that carries the workbook's separators for fractional seconds.
|
|
43
|
+
* Returns `undefined` when nothing had to change.
|
|
44
|
+
*/
|
|
45
|
+
export declare const withWorkbookSeparators: (pattern: string, locale?: string) => string | undefined;
|
|
34
46
|
export declare const ssfFormat: (pattern: string, value: any, locale?: string) => string;
|
|
35
47
|
export declare const ssfFormatColor: (pattern: string, value: any) => string | undefined;
|
|
36
48
|
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../formatter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../formatter.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OASlE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KACjC,OAWF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OAWlE,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,OAOlE,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,MAAM,KAAG,OA4B1D,CAAC;AA+LF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,SA4C9D,CAAC;AAiIF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GACjC,SAAS,MAAM,EACf,SAAS,MAAM,KACd,MAAM,GAAG,SAiBX,CAAC;AAiBF,eAAO,MAAM,SAAS,GACpB,SAAS,MAAM,EACf,OAAO,GAAG,EACV,SAAS,MAAM,KACd,MA0CF,CAAC;AAmLF,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,EACf,OAAO,GAAG,KACT,MAAM,GAAG,SAoBX,CAAC"}
|
package/dist/esm/formatter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { addLocale, format, formatColor, getFormatDateInfo, getLocale, isDateFormat, isTextFormat, } from "numfmt";
|
|
2
2
|
import { IndexedColors } from "./colors";
|
|
3
|
-
import { excelNumberPrePass } from "./excel-number-format";
|
|
3
|
+
import { excelNumberPrePass, splitFormatSections, } from "./excel-number-format";
|
|
4
4
|
/**
|
|
5
5
|
* Pattern-based type inference (Excel parity). xlsx files routinely carry
|
|
6
6
|
* a `numberFormat.pattern` without an accompanying `type` field — these
|
|
@@ -132,6 +132,71 @@ const intlMonthNames = (locale, options) => {
|
|
|
132
132
|
.formatToParts(new Date(Date.UTC(2020, month, 1)))
|
|
133
133
|
.find((part) => part.type === "month")?.value ?? "");
|
|
134
134
|
};
|
|
135
|
+
const intlRegisteredLocales = new Set();
|
|
136
|
+
/**
|
|
137
|
+
* numfmt ships name tables for a fixed set of languages; a tag it does not know
|
|
138
|
+
* (et, ms, nn, …) silently renders English month/weekday names and en-US
|
|
139
|
+
* separators. Excel and `Intl.DateTimeFormat` localize every locale, so an
|
|
140
|
+
* unknown tag gets a numfmt locale built from Intl on first use: separators
|
|
141
|
+
* from `Intl.NumberFormat`, the in-date month names (numfmt's single table is
|
|
142
|
+
* the form used beside a day number — see `getStandaloneMonthLocale`), the
|
|
143
|
+
* in-date weekday names (the form `dateStyle: "full"` shows) and the AM/PM
|
|
144
|
+
* designators. Tags Intl itself does not know keep numfmt's fallback.
|
|
145
|
+
*/
|
|
146
|
+
const ensureNumfmtLocale = (locale) => {
|
|
147
|
+
if (intlRegisteredLocales.has(locale))
|
|
148
|
+
return;
|
|
149
|
+
intlRegisteredLocales.add(locale);
|
|
150
|
+
try {
|
|
151
|
+
if (getLocale(locale))
|
|
152
|
+
return;
|
|
153
|
+
const canonical = Intl.DateTimeFormat.supportedLocalesOf([locale])[0];
|
|
154
|
+
if (!canonical)
|
|
155
|
+
return;
|
|
156
|
+
const numberParts = new Intl.NumberFormat(locale).formatToParts(1234567.5);
|
|
157
|
+
const part = (type) => numberParts.find((p) => p.type === type)?.value;
|
|
158
|
+
const weekdayNames = (weekday) => {
|
|
159
|
+
// 2024-01-07 was a Sunday; numfmt indexes `dddd[0]` as Sunday.
|
|
160
|
+
const fmt = new Intl.DateTimeFormat(locale, {
|
|
161
|
+
weekday,
|
|
162
|
+
day: "numeric",
|
|
163
|
+
month: "long",
|
|
164
|
+
year: "numeric",
|
|
165
|
+
timeZone: "UTC",
|
|
166
|
+
});
|
|
167
|
+
return Array.from({ length: 7 }, (_, i) => fmt
|
|
168
|
+
.formatToParts(new Date(Date.UTC(2024, 0, 7 + i)))
|
|
169
|
+
.find((p) => p.type === "weekday")?.value ?? "");
|
|
170
|
+
};
|
|
171
|
+
const dayPeriod = (hour) => new Intl.DateTimeFormat(locale, {
|
|
172
|
+
hour: "numeric",
|
|
173
|
+
hour12: true,
|
|
174
|
+
timeZone: "UTC",
|
|
175
|
+
})
|
|
176
|
+
.formatToParts(new Date(Date.UTC(2024, 0, 7, hour)))
|
|
177
|
+
.find((p) => p.type === "dayPeriod")?.value;
|
|
178
|
+
const dateParts = new Intl.DateTimeFormat(locale, {
|
|
179
|
+
timeZone: "UTC",
|
|
180
|
+
}).formatToParts(new Date(Date.UTC(2024, 0, 7)));
|
|
181
|
+
const monthIndex = dateParts.findIndex((p) => p.type === "month");
|
|
182
|
+
const dayIndex = dateParts.findIndex((p) => p.type === "day");
|
|
183
|
+
const am = dayPeriod(9);
|
|
184
|
+
const pm = dayPeriod(21);
|
|
185
|
+
addLocale({
|
|
186
|
+
group: part("group") ?? "\u00a0",
|
|
187
|
+
decimal: part("decimal") ?? ".",
|
|
188
|
+
mmmm: intlMonthNames(locale, { day: "numeric", month: "long" }),
|
|
189
|
+
mmm: intlMonthNames(locale, { day: "numeric", month: "short" }),
|
|
190
|
+
dddd: weekdayNames("long"),
|
|
191
|
+
ddd: weekdayNames("short"),
|
|
192
|
+
...(am && pm && am !== pm ? { ampm: [am, pm] } : {}),
|
|
193
|
+
preferMDY: monthIndex >= 0 && dayIndex >= 0 && monthIndex < dayIndex,
|
|
194
|
+
}, locale);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Malformed tag: numfmt keeps its own fallback.
|
|
198
|
+
}
|
|
199
|
+
};
|
|
135
200
|
const standaloneMonthLocales = new Map();
|
|
136
201
|
/**
|
|
137
202
|
* numfmt ships one month-name table per locale: the form used beside a day
|
|
@@ -290,14 +355,158 @@ const separatorsFor = (locale) => {
|
|
|
290
355
|
group: l10n.group ?? ",",
|
|
291
356
|
};
|
|
292
357
|
};
|
|
358
|
+
/**
|
|
359
|
+
* Rewrite the `[$symbol-LCID]` tokens of one section through `rewrite`,
|
|
360
|
+
* which receives the bracket content (`€-407`) and returns the new content,
|
|
361
|
+
* or an empty string to drop the token. Quoted literals, escapes and other
|
|
362
|
+
* bracket directives are left as written.
|
|
363
|
+
*/
|
|
364
|
+
const rewriteSectionLocaleTokens = (section, rewrite) => {
|
|
365
|
+
let out = "";
|
|
366
|
+
let inQuotes = false;
|
|
367
|
+
let inBrackets = false;
|
|
368
|
+
for (let i = 0; i < section.length; i++) {
|
|
369
|
+
const char = section[i];
|
|
370
|
+
if (inQuotes) {
|
|
371
|
+
inQuotes = char !== '"';
|
|
372
|
+
}
|
|
373
|
+
else if (inBrackets) {
|
|
374
|
+
inBrackets = char !== "]";
|
|
375
|
+
}
|
|
376
|
+
else if (char === '"') {
|
|
377
|
+
inQuotes = true;
|
|
378
|
+
}
|
|
379
|
+
else if (char === "[") {
|
|
380
|
+
const end = section[i + 1] === "$" ? section.indexOf("]", i) : -1;
|
|
381
|
+
if (end > 0) {
|
|
382
|
+
const token = rewrite(section.slice(i + 1, end));
|
|
383
|
+
if (token)
|
|
384
|
+
out += `[${token}]`;
|
|
385
|
+
i = end;
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
inBrackets = true;
|
|
389
|
+
}
|
|
390
|
+
else if (char === "\\" || char === "_" || char === "*") {
|
|
391
|
+
out += char + (section[i + 1] ?? "");
|
|
392
|
+
i++;
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
out += char;
|
|
396
|
+
}
|
|
397
|
+
return out;
|
|
398
|
+
};
|
|
399
|
+
/** `[$€-407]` → `[$€]`; a bare `[$-407]` goes away. */
|
|
400
|
+
const currencySymbolOnly = (token) => {
|
|
401
|
+
const dash = token.indexOf("-");
|
|
402
|
+
const symbol = dash < 0 ? token : token.slice(0, dash);
|
|
403
|
+
return symbol.length > 1 ? symbol : "";
|
|
404
|
+
};
|
|
405
|
+
const separatorLocales = new Map();
|
|
406
|
+
/**
|
|
407
|
+
* Companion numfmt locale carrying `locale`'s calendar names and AM/PM with
|
|
408
|
+
* the workbook's decimal / group separators, so a date section pinned to
|
|
409
|
+
* `[$-407]` renders German names but a workbook decimal mark in `ss.00`.
|
|
410
|
+
* Returns `locale` itself when its separators already match.
|
|
411
|
+
*/
|
|
412
|
+
const getWorkbookSeparatorLocale = (locale, separators) => {
|
|
413
|
+
const key = `${locale}\u0000${separators.decimal}\u0000${separators.group}`;
|
|
414
|
+
const cached = separatorLocales.get(key);
|
|
415
|
+
if (cached !== undefined)
|
|
416
|
+
return cached;
|
|
417
|
+
let overlay = locale;
|
|
418
|
+
try {
|
|
419
|
+
const base = getLocale(locale);
|
|
420
|
+
if (base &&
|
|
421
|
+
(base.decimal !== separators.decimal || base.group !== separators.group)) {
|
|
422
|
+
// numfmt locale ids are `[a-z\d]+` with one optional `_` part.
|
|
423
|
+
const hex = (text) => [...text].map((c) => c.codePointAt(0).toString(16)).join("x");
|
|
424
|
+
overlay = `sep${hex(separators.decimal)}x${hex(separators.group)}_${locale.replace(/[^a-z\d]/gi, "")}`;
|
|
425
|
+
addLocale({ ...base, decimal: separators.decimal, group: separators.group }, overlay);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
overlay = locale;
|
|
430
|
+
}
|
|
431
|
+
separatorLocales.set(key, overlay);
|
|
432
|
+
return overlay;
|
|
433
|
+
};
|
|
434
|
+
/**
|
|
435
|
+
* Re-point a date section's `[$symbol-LCID]` token at the companion locale
|
|
436
|
+
* with the workbook's separators (`$-407` → `$-sep2ex2c_407`). An LCID numfmt
|
|
437
|
+
* does not know or one carrying calendar bits stays as written.
|
|
438
|
+
*/
|
|
439
|
+
const workbookSeparatorLocaleToken = (separators) => (token) => {
|
|
440
|
+
const dash = token.indexOf("-");
|
|
441
|
+
if (dash < 0)
|
|
442
|
+
return token;
|
|
443
|
+
const code = token.slice(dash + 1);
|
|
444
|
+
const wincode = Number.parseInt(code, 16);
|
|
445
|
+
if (Number.isFinite(wincode) && wincode & 0xff0000)
|
|
446
|
+
return token;
|
|
447
|
+
if (!getLocale(code))
|
|
448
|
+
return token;
|
|
449
|
+
return `${token.slice(0, dash + 1)}${getWorkbookSeparatorLocale(code, separators)}`;
|
|
450
|
+
};
|
|
451
|
+
const isDateSection = (section) => {
|
|
452
|
+
try {
|
|
453
|
+
return isDateFormat(section);
|
|
454
|
+
}
|
|
455
|
+
catch {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
/**
|
|
460
|
+
* Excel's `[$symbol-LCID]` token selects the currency symbol and the
|
|
461
|
+
* language of day/month names and AM/PM; digit grouping and the decimal
|
|
462
|
+
* separator follow the workbook locale (`[$€-407] #,##0.00` is
|
|
463
|
+
* `€ 1,234.50` on a US host). numfmt applies the token's locale to the whole
|
|
464
|
+
* section, separators included, so the locale part is dropped from every
|
|
465
|
+
* section that is not a date (number, scientific, fraction, text, …); a
|
|
466
|
+
* date section keeps the token for its names, re-pointed at a companion
|
|
467
|
+
* locale that carries the workbook's separators for fractional seconds.
|
|
468
|
+
* Returns `undefined` when nothing had to change.
|
|
469
|
+
*/
|
|
470
|
+
export const withWorkbookSeparators = (pattern, locale) => {
|
|
471
|
+
if (!pattern.includes("[$"))
|
|
472
|
+
return undefined;
|
|
473
|
+
const sections = splitFormatSections(pattern);
|
|
474
|
+
let changed = false;
|
|
475
|
+
let dateTokens;
|
|
476
|
+
const rewritten = sections.map((section) => {
|
|
477
|
+
if (!section.includes("[$"))
|
|
478
|
+
return section;
|
|
479
|
+
let rewrite = currencySymbolOnly;
|
|
480
|
+
if (isDateSection(section)) {
|
|
481
|
+
dateTokens ??= workbookSeparatorLocaleToken(separatorsFor(locale));
|
|
482
|
+
rewrite = dateTokens;
|
|
483
|
+
}
|
|
484
|
+
const stripped = rewriteSectionLocaleTokens(section, rewrite);
|
|
485
|
+
changed ||= stripped !== section;
|
|
486
|
+
return stripped;
|
|
487
|
+
});
|
|
488
|
+
return changed ? rewritten.join(";") : undefined;
|
|
489
|
+
};
|
|
490
|
+
const workbookSeparatorPatternCache = new Map();
|
|
491
|
+
const withWorkbookSeparatorsCached = (code, locale) => {
|
|
492
|
+
const key = `${locale ?? ""}\u0000${code}`;
|
|
493
|
+
let rewritten = workbookSeparatorPatternCache.get(key);
|
|
494
|
+
if (rewritten === undefined) {
|
|
495
|
+
rewritten = withWorkbookSeparators(code, locale) ?? code;
|
|
496
|
+
workbookSeparatorPatternCache.set(key, rewritten);
|
|
497
|
+
}
|
|
498
|
+
return rewritten;
|
|
499
|
+
};
|
|
293
500
|
export const ssfFormat = (pattern, value, locale) => {
|
|
294
501
|
try {
|
|
502
|
+
if (locale)
|
|
503
|
+
ensureNumfmtLocale(locale);
|
|
295
504
|
let shortAmPm = shortAmPmPatternCache.get(pattern);
|
|
296
505
|
if (shortAmPm === undefined && !shortAmPmPatternCache.has(pattern)) {
|
|
297
506
|
shortAmPm = withShortAmPmMarker(pattern);
|
|
298
507
|
shortAmPmPatternCache.set(pattern, shortAmPm);
|
|
299
508
|
}
|
|
300
|
-
const code = shortAmPm ?? pattern;
|
|
509
|
+
const code = withWorkbookSeparatorsCached(shortAmPm ?? pattern, locale);
|
|
301
510
|
let patternLocale = localeForPattern(pattern, locale);
|
|
302
511
|
if (shortAmPm !== undefined && patternLocale) {
|
|
303
512
|
patternLocale = getShortAmPmLocale(patternLocale);
|
package/dist/esm/locale.d.ts
CHANGED
|
@@ -16,6 +16,21 @@ export declare const getLocaleDateParts: (locale: string) => [DatePartType, stri
|
|
|
16
16
|
* de-DE → `d.m.yyyy`, hu-HU → `yyyy. mm. dd.`, en-CA → `yyyy-mm-dd`.
|
|
17
17
|
*/
|
|
18
18
|
export declare const getDefaultDateFormat: (locale?: string) => string;
|
|
19
|
+
export interface DateFieldTokens {
|
|
20
|
+
day: "d" | "dd";
|
|
21
|
+
month: "m" | "mm";
|
|
22
|
+
year: "yy" | "yyyy";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The day / month / year tokens of {@link getDefaultDateFormat} for a
|
|
26
|
+
* locale, i.e. whether the locale zero-pads each numeric field — ru-RU
|
|
27
|
+
* (`dd.mm.yyyy`) → `{ day: "dd", month: "mm", year: "yyyy" }`, en-US
|
|
28
|
+
* (`m/d/yyyy`) → `{ day: "d", month: "m", year: "yyyy" }`. A date typed
|
|
29
|
+
* as digits is displayed with the locale's own padding (Excel re-renders
|
|
30
|
+
* `30.9.2025` as `30.09.2025` under ru-RU), so the date parser assigns
|
|
31
|
+
* these tokens rather than echoing the padding the user happened to type.
|
|
32
|
+
*/
|
|
33
|
+
export declare const getDefaultDateFieldTokens: (locale?: string) => DateFieldTokens;
|
|
19
34
|
/**
|
|
20
35
|
* Default time pattern for a locale, honoring its 12/24-hour convention,
|
|
21
36
|
* separators and hour padding — e.g. en-US → `h:mm:ss AM/PM`,
|
package/dist/esm/locale.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../locale.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,cAU5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM,qCAkC3D,CAAC;AAEF,eAAO,MAAM,kBAAkB,sDAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../locale.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,cAU5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM,qCAkC3D,CAAC;AAEF,eAAO,MAAM,kBAAkB,sDAAyC,CAAC;AAiGzE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAQ,MAA2B,WAClC,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;IAChB,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAClB,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;CACrB;AAwBD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAQ,MAA2B,KAClC,eAA4D,CAAC;AAuChE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,MAA2B,EACnC,YAAW,QAAQ,GAAG,QAAmB,WACS,CAAC;AAErD,eAAO,MAAM,wBAAwB,GAAI,SAAS,MAAM,WAEvD,CAAC;AA2CF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAQ,MAA2B,WAClC,CAAC"}
|
package/dist/esm/locale.js
CHANGED
|
@@ -105,9 +105,15 @@ const buildPatternFromParts = (parts, toToken) => {
|
|
|
105
105
|
// trailing fields we skipped (e.g. an era) — trim stray whitespace.
|
|
106
106
|
return pattern.trim();
|
|
107
107
|
};
|
|
108
|
-
|
|
108
|
+
/**
|
|
109
|
+
* `formatToParts` of the locale's numeric short date for the sample
|
|
110
|
+
* instant — the single source both the default pattern and its per-field
|
|
111
|
+
* tokens are read from, so they can never disagree. Empty when Intl has
|
|
112
|
+
* no data for the locale.
|
|
113
|
+
*/
|
|
114
|
+
const getDefaultDateParts = memoize((locale) => {
|
|
109
115
|
try {
|
|
110
|
-
|
|
116
|
+
return new Intl.DateTimeFormat(locale, {
|
|
111
117
|
calendar: "gregory",
|
|
112
118
|
numberingSystem: "latn",
|
|
113
119
|
year: "numeric",
|
|
@@ -115,13 +121,15 @@ const getDefaultDateFormatMemoized = memoize((locale) => {
|
|
|
115
121
|
day: "numeric",
|
|
116
122
|
timeZone: "UTC",
|
|
117
123
|
}).formatToParts(FORMAT_SAMPLE_DATE);
|
|
118
|
-
const pattern = buildPatternFromParts(parts, dateFieldToken);
|
|
119
|
-
return pattern || "m/d/yyyy";
|
|
120
124
|
}
|
|
121
125
|
catch (err) {
|
|
122
|
-
return
|
|
126
|
+
return [];
|
|
123
127
|
}
|
|
124
128
|
});
|
|
129
|
+
const getDefaultDateFormatMemoized = memoize((locale) => {
|
|
130
|
+
const pattern = buildPatternFromParts(getDefaultDateParts(locale), dateFieldToken);
|
|
131
|
+
return pattern || "m/d/yyyy";
|
|
132
|
+
});
|
|
125
133
|
/**
|
|
126
134
|
* Default numeric (short) date pattern for a locale, preserving the
|
|
127
135
|
* locale's field order, separators, literal text and zero-padding as
|
|
@@ -129,6 +137,35 @@ const getDefaultDateFormatMemoized = memoize((locale) => {
|
|
|
129
137
|
* de-DE → `d.m.yyyy`, hu-HU → `yyyy. mm. dd.`, en-CA → `yyyy-mm-dd`.
|
|
130
138
|
*/
|
|
131
139
|
export const getDefaultDateFormat = (locale = getCurrentLocale()) => getDefaultDateFormatMemoized(locale);
|
|
140
|
+
const getDefaultDateFieldTokensMemoized = memoize((locale) => {
|
|
141
|
+
const tokens = { day: "d", month: "m", year: "yyyy" };
|
|
142
|
+
for (const part of getDefaultDateParts(locale)) {
|
|
143
|
+
switch (part.type) {
|
|
144
|
+
case "day":
|
|
145
|
+
tokens.day = part.value.length === 2 ? "dd" : "d";
|
|
146
|
+
break;
|
|
147
|
+
case "month":
|
|
148
|
+
tokens.month = part.value.length === 2 ? "mm" : "m";
|
|
149
|
+
break;
|
|
150
|
+
case "year":
|
|
151
|
+
tokens.year = part.value.length === 2 ? "yy" : "yyyy";
|
|
152
|
+
break;
|
|
153
|
+
default:
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return tokens;
|
|
158
|
+
});
|
|
159
|
+
/**
|
|
160
|
+
* The day / month / year tokens of {@link getDefaultDateFormat} for a
|
|
161
|
+
* locale, i.e. whether the locale zero-pads each numeric field — ru-RU
|
|
162
|
+
* (`dd.mm.yyyy`) → `{ day: "dd", month: "mm", year: "yyyy" }`, en-US
|
|
163
|
+
* (`m/d/yyyy`) → `{ day: "d", month: "m", year: "yyyy" }`. A date typed
|
|
164
|
+
* as digits is displayed with the locale's own padding (Excel re-renders
|
|
165
|
+
* `30.9.2025` as `30.09.2025` under ru-RU), so the date parser assigns
|
|
166
|
+
* these tokens rather than echoing the padding the user happened to type.
|
|
167
|
+
*/
|
|
168
|
+
export const getDefaultDateFieldTokens = (locale = getCurrentLocale()) => getDefaultDateFieldTokensMemoized(locale);
|
|
132
169
|
const getDefaultTimeFormatMemoized = memoize((locale, precision) => {
|
|
133
170
|
try {
|
|
134
171
|
const parts = new Intl.DateTimeFormat(locale, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rowsncolumns/utils",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.42",
|
|
4
4
|
"author": "Vinay M",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"numfmt": "^3.2.2",
|
|
45
|
-
"@rowsncolumns/common-types": ">=5.2.
|
|
45
|
+
"@rowsncolumns/common-types": ">=5.2.32"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {},
|
|
48
48
|
"peerDependencies": {}
|