@rowsncolumns/spreadsheet-state 29.1.6 → 29.1.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"datatype.d.ts","sourceRoot":"","sources":["../../../api/datatype.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"datatype.d.ts","sourceRoot":"","sources":["../../../api/datatype.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { __read, __values } from "tslib";
2
- import { getDefaultDateFormat, getDefaultDateTimeFormat, isAFormula, isNil, ssfFormat, ssfFormatColor, toDate, toSerial, } from "@rowsncolumns/utils";
2
+ import { getDefaultDateFormat, getDefaultDateTimeFormat, isAFormula, isNil, ssfFormat, ssfFormatColor, toDate, toSerial, toSerialFromParts, } from "@rowsncolumns/utils";
3
3
  import { detectDateFormatPattern, detectDateTimeFormatPattern, isValidDate, isValidDateTime, toTimeSerial, validateDate, validateDateTime, } from "./date";
4
4
  import { changeDecimals, detectDecimalPattern, getDecimalPlaces, hasThousandsGrouping, pattern_number_thousands, } from "./decimals";
5
5
  import { buildGroupRegex, getGroupingInfo, getLocaleDigitMap, getLocaleSeparators, getPercentSignInfo, getSignInfo, } from "./intl";
@@ -434,11 +434,12 @@ export var createNumberValue = function (value, numFormatType, locale, use1904,
434
434
  var isDate = numFormatType === "DATE";
435
435
  var isDateTime = numFormatType === "DATE_TIME";
436
436
  if (typeof value !== "boolean" && (isDate || isDateTime)) {
437
+ // A number is already a serial: applying the Date type only changes the
438
+ // format. Round-tripping it through `toDate`/`toSerial` moved Excel's
439
+ // phantom 1900-02-29 (60) onto the 28th (59) because no `Date` holds the
440
+ // 29th (rowsncolumns/spreadsheet#1026).
437
441
  if (typeof value === "number") {
438
- var dateValue_1 = createDateValueFromNumber(value, use1904);
439
- if (!isNil(dateValue_1) && dateValue_1 instanceof Date) {
440
- return toSerial(dateValue_1, use1904);
441
- }
442
+ return value;
442
443
  }
443
444
  var dateValue = isDate
444
445
  ? validateDate(value, locale)
@@ -448,7 +449,7 @@ export var createNumberValue = function (value, numFormatType, locale, use1904,
448
449
  if (isTimeOnly) {
449
450
  return toTimeSerial(hour !== null && hour !== void 0 ? hour : 0, minute !== null && minute !== void 0 ? minute : 0, second !== null && second !== void 0 ? second : 0);
450
451
  }
451
- return toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
452
+ return toSerialFromParts(year, month, day, hour, minute, second, use1904);
452
453
  }
453
454
  }
454
455
  return convertToNumber(value, locale, lenientGrouping);
@@ -648,14 +649,16 @@ export var detectValueTypeAndPattern = function (value, locale, lenientGrouping,
648
649
  var _a = dateTimeValue.parts, year = _a.year, month = _a.month, day = _a.day, hour = _a.hour, minute = _a.minute, second = _a.second, isTimeOnly = dateTimeValue.isTimeOnly;
649
650
  var numberValue = isTimeOnly
650
651
  ? toTimeSerial(hour !== null && hour !== void 0 ? hour : 0, minute !== null && minute !== void 0 ? minute : 0, second !== null && second !== void 0 ? second : 0)
651
- : toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
652
+ : toSerialFromParts(year, month, day, hour, minute, second, use1904);
652
653
  return ["numberValue", "DATE_TIME", numberValue, dateTimeValue.format];
653
654
  }
654
655
  // Dates
655
656
  var dateValue = validateDate(value, locale);
656
657
  if (dateValue) {
657
658
  var _b = dateValue.parts, year = _b.year, month = _b.month, day = _b.day, hour = _b.hour, minute = _b.minute, second = _b.second;
658
- var numberValue = toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
659
+ // Parts, not a `Date`: Excel's phantom 1900-02-29 must land on serial 60
660
+ // rather than roll over to March 1 (rowsncolumns/spreadsheet#1026).
661
+ var numberValue = toSerialFromParts(year, month, day, hour, minute, second, use1904);
659
662
  return ["numberValue", "DATE", numberValue, dateValue.format];
660
663
  }
661
664
  return ["stringValue"];
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../api/date.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAYD,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,eAAe,GAAG,SAiCpB,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,eAAe,GAAG,SAoEpB,CAAC;AA6CF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM,WAGxE,CAAC;AAwBF,eAAO,MAAM,WAAW,GACtB,OAAO,GAAG,EACV,QAAQ,MAAM,GAAG,SAAS,KACzB,OAKF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,GAAG,KAAG,OAK5C,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,MAAM,GAAG,SAKX,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,MAAM,GAAG,SAKX,CAAC;AAYF,eAAO,MAAM,cAAc,cAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe,cAAgC,CAAC;AAC7D,eAAO,MAAM,aAAa,cAA8B,CAAC"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../api/date.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAYD,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,eAAe,GAAG,SAsCpB,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,eAAe,GAAG,SAsEpB,CAAC;AA6CF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM,WAGxE,CAAC;AAwBF,eAAO,MAAM,WAAW,GACtB,OAAO,GAAG,EACV,QAAQ,MAAM,GAAG,SAAS,KACzB,OAKF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,GAAG,KAAG,OAK5C,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,MAAM,GAAG,SAKX,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,MAAM,GAAG,SAKX,CAAC;AAYF,eAAO,MAAM,cAAc,cAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe,cAAgC,CAAC;AAC7D,eAAO,MAAM,aAAa,cAA8B,CAAC"}
@@ -17,14 +17,17 @@ var TIME_FORMATS = {
17
17
  FULL: "hh:mm:ss",
18
18
  SHORT_WITH_MERIDIAN: "hh:mm AM/PM",
19
19
  SHORT: "hh:mm",
20
- // Excel "elapsed time" patterns. The square brackets around `h` tell the
21
- // formatter to display the full elapsed-hours count without wrapping at
22
- // 24 — `[h]:mm:ss` will render a 25.5-hour duration as `25:30:00`, not
23
- // `01:30:00`. Excel auto-applies these when the user types a value with
24
- // hours > 24.
25
- FULL_ELAPSED: "[h]:mm:ss",
26
- SHORT_ELAPSED: "[h]:mm",
20
+ // Excel "elapsed time" (Duration) pattern. The square brackets around `h`
21
+ // tell the formatter to display the full elapsed-hours count without
22
+ // wrapping at 24 — `[h]:mm:ss` renders a 25.5-hour duration as `25:30:00`,
23
+ // not `01:30:00`. Excel auto-applies it when the typed hours reach 24
24
+ // (`24:00` is one day, `25:00` a duration) and always shows the seconds, so
25
+ // a typed `25:00` displays `25:00:00` (rowsncolumns/spreadsheet#1027) —
26
+ // the same pattern the Number menu's "Duration" item applies.
27
+ ELAPSED: "[h]:mm:ss",
27
28
  };
29
+ // Typed hours at or past a full day are a Duration, never a clock time.
30
+ var ELAPSED_HOURS_MIN = 24;
28
31
  // Cap elapsed-time hours at Excel's documented limit (`9999:59:59`). Beyond
29
32
  // this, treat as text rather than producing absurdly large fractional
30
33
  // serials. JS `Number.isFinite` would let `Infinity` through, so we cap
@@ -60,12 +63,17 @@ export var validateDate = function (value, locale) {
60
63
  if (year < EXCEL_DATE_MIN_YEAR || year > EXCEL_DATE_MAX_YEAR) {
61
64
  return undefined;
62
65
  }
66
+ // Excel's phantom 1900-02-29 (serial 60): the parser hands back a stand-in
67
+ // `Date` on the 28th with `excelLeapDay` set, because no `Date` can hold the
68
+ // 29th. Report the day the user typed; `toSerialFromParts` maps it to 60
69
+ // (rowsncolumns/spreadsheet#1026).
70
+ var day = "excelLeapDay" in result && result.excelLeapDay ? 29 : dateValue.getDate();
63
71
  return {
64
72
  format: result.pattern,
65
73
  parts: {
66
74
  year: year,
67
75
  month: dateValue.getMonth(),
68
- day: dateValue.getDate(),
76
+ day: day,
69
77
  hour: dateValue.getHours(),
70
78
  minute: dateValue.getMinutes(),
71
79
  second: dateValue.getSeconds(),
@@ -94,10 +102,10 @@ export var validateDateTime = function (value) {
94
102
  var minute = parseInt(match[2], 10);
95
103
  var second = parseInt(match[3], 10);
96
104
  if (isValidTimeComponents(hour, minute, second)) {
97
- // Excel parity: hour > 24 is an elapsed-time entry (e.g. `25:30:00`,
98
- // `48:00:00`). Auto-apply `[h]:mm:ss` so the cell displays the full
99
- // hours count instead of wrapping to `01:30:00`.
100
- var format = hour > 24 ? TIME_FORMATS.FULL_ELAPSED : TIME_FORMATS.FULL;
105
+ // Excel parity: hours >= 24 are an elapsed-time entry (`24:00:00`,
106
+ // `25:30:00`, `48:00:00`). Auto-apply `[h]:mm:ss` so the cell displays
107
+ // the full hours count instead of wrapping to `01:30:00`.
108
+ var format = hour >= ELAPSED_HOURS_MIN ? TIME_FORMATS.ELAPSED : TIME_FORMATS.FULL;
101
109
  return createTimeResult(format, hour, minute, second);
102
110
  }
103
111
  }
@@ -115,8 +123,9 @@ export var validateDateTime = function (value) {
115
123
  var hour = parseInt(match[1], 10);
116
124
  var minute = parseInt(match[2], 10);
117
125
  if (isValidTimeComponents(hour, minute, 0)) {
118
- // Same elapsed-time auto-pattern logic as the full form above.
119
- var format = hour > 24 ? TIME_FORMATS.SHORT_ELAPSED : TIME_FORMATS.SHORT;
126
+ // Same elapsed-time rule as the full form: a duration typed without
127
+ // seconds still gets `[h]:mm:ss` (`25:00` → `25:00:00`, as Excel).
128
+ var format = hour >= ELAPSED_HOURS_MIN ? TIME_FORMATS.ELAPSED : TIME_FORMATS.SHORT;
120
129
  return createTimeResult(format, hour, minute, 0);
121
130
  }
122
131
  }
@@ -1 +1 @@
1
- {"version":3,"file":"datatype.d.ts","sourceRoot":"","sources":["../../../api/datatype.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"datatype.d.ts","sourceRoot":"","sources":["../../../api/datatype.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { getDefaultDateFormat, getDefaultDateTimeFormat, isAFormula, isNil, ssfFormat, ssfFormatColor, toDate, toSerial, } from "@rowsncolumns/utils";
1
+ import { getDefaultDateFormat, getDefaultDateTimeFormat, isAFormula, isNil, ssfFormat, ssfFormatColor, toDate, toSerial, toSerialFromParts, } from "@rowsncolumns/utils";
2
2
  import { detectDateFormatPattern, detectDateTimeFormatPattern, isValidDate, isValidDateTime, toTimeSerial, validateDate, validateDateTime, } from "./date";
3
3
  import { changeDecimals, detectDecimalPattern, getDecimalPlaces, hasThousandsGrouping, pattern_number_thousands, } from "./decimals";
4
4
  import { buildGroupRegex, getGroupingInfo, getLocaleDigitMap, getLocaleSeparators, getPercentSignInfo, getSignInfo, } from "./intl";
@@ -408,11 +408,12 @@ export const createNumberValue = (value, numFormatType, locale, use1904, lenient
408
408
  const isDate = numFormatType === "DATE";
409
409
  const isDateTime = numFormatType === "DATE_TIME";
410
410
  if (typeof value !== "boolean" && (isDate || isDateTime)) {
411
+ // A number is already a serial: applying the Date type only changes the
412
+ // format. Round-tripping it through `toDate`/`toSerial` moved Excel's
413
+ // phantom 1900-02-29 (60) onto the 28th (59) because no `Date` holds the
414
+ // 29th (rowsncolumns/spreadsheet#1026).
411
415
  if (typeof value === "number") {
412
- const dateValue = createDateValueFromNumber(value, use1904);
413
- if (!isNil(dateValue) && dateValue instanceof Date) {
414
- return toSerial(dateValue, use1904);
415
- }
416
+ return value;
416
417
  }
417
418
  const dateValue = isDate
418
419
  ? validateDate(value, locale)
@@ -422,7 +423,7 @@ export const createNumberValue = (value, numFormatType, locale, use1904, lenient
422
423
  if (isTimeOnly) {
423
424
  return toTimeSerial(hour ?? 0, minute ?? 0, second ?? 0);
424
425
  }
425
- return toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
426
+ return toSerialFromParts(year, month, day, hour, minute, second, use1904);
426
427
  }
427
428
  }
428
429
  return convertToNumber(value, locale, lenientGrouping);
@@ -617,14 +618,16 @@ export const detectValueTypeAndPattern = (value, locale, lenientGrouping = true,
617
618
  const { parts: { year, month, day, hour, minute, second }, isTimeOnly, } = dateTimeValue;
618
619
  const numberValue = isTimeOnly
619
620
  ? toTimeSerial(hour ?? 0, minute ?? 0, second ?? 0)
620
- : toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
621
+ : toSerialFromParts(year, month, day, hour, minute, second, use1904);
621
622
  return ["numberValue", "DATE_TIME", numberValue, dateTimeValue.format];
622
623
  }
623
624
  // Dates
624
625
  const dateValue = validateDate(value, locale);
625
626
  if (dateValue) {
626
627
  const { parts: { year, month, day, hour, minute, second }, } = dateValue;
627
- const numberValue = toSerial(new Date(year, month, day, hour, minute, second, 0), use1904);
628
+ // Parts, not a `Date`: Excel's phantom 1900-02-29 must land on serial 60
629
+ // rather than roll over to March 1 (rowsncolumns/spreadsheet#1026).
630
+ const numberValue = toSerialFromParts(year, month, day, hour, minute, second, use1904);
628
631
  return ["numberValue", "DATE", numberValue, dateValue.format];
629
632
  }
630
633
  return ["stringValue"];
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../api/date.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAYD,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,eAAe,GAAG,SAiCpB,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,eAAe,GAAG,SAoEpB,CAAC;AA6CF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM,WAGxE,CAAC;AAwBF,eAAO,MAAM,WAAW,GACtB,OAAO,GAAG,EACV,QAAQ,MAAM,GAAG,SAAS,KACzB,OAKF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,GAAG,KAAG,OAK5C,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,MAAM,GAAG,SAKX,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,MAAM,GAAG,SAKX,CAAC;AAYF,eAAO,MAAM,cAAc,cAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe,cAAgC,CAAC;AAC7D,eAAO,MAAM,aAAa,cAA8B,CAAC"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../api/date.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAYD,eAAO,MAAM,YAAY,GACvB,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,eAAe,GAAG,SAsCpB,CAAC;AAGF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,eAAe,GAAG,SAsEpB,CAAC;AA6CF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,QAAQ,MAAM,EAAE,QAAQ,MAAM,WAGxE,CAAC;AAwBF,eAAO,MAAM,WAAW,GACtB,OAAO,GAAG,EACV,QAAQ,MAAM,GAAG,SAAS,KACzB,OAKF,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,GAAG,KAAG,OAK5C,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EACnD,QAAQ,MAAM,GAAG,SAAS,KACzB,MAAM,GAAG,SAKX,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,KAClD,MAAM,GAAG,SAKX,CAAC;AAYF,eAAO,MAAM,cAAc,cAA+B,CAAC;AAC3D,eAAO,MAAM,eAAe,cAAgC,CAAC;AAC7D,eAAO,MAAM,aAAa,cAA8B,CAAC"}
@@ -17,14 +17,17 @@ const TIME_FORMATS = {
17
17
  FULL: "hh:mm:ss",
18
18
  SHORT_WITH_MERIDIAN: "hh:mm AM/PM",
19
19
  SHORT: "hh:mm",
20
- // Excel "elapsed time" patterns. The square brackets around `h` tell the
21
- // formatter to display the full elapsed-hours count without wrapping at
22
- // 24 — `[h]:mm:ss` will render a 25.5-hour duration as `25:30:00`, not
23
- // `01:30:00`. Excel auto-applies these when the user types a value with
24
- // hours > 24.
25
- FULL_ELAPSED: "[h]:mm:ss",
26
- SHORT_ELAPSED: "[h]:mm",
20
+ // Excel "elapsed time" (Duration) pattern. The square brackets around `h`
21
+ // tell the formatter to display the full elapsed-hours count without
22
+ // wrapping at 24 — `[h]:mm:ss` renders a 25.5-hour duration as `25:30:00`,
23
+ // not `01:30:00`. Excel auto-applies it when the typed hours reach 24
24
+ // (`24:00` is one day, `25:00` a duration) and always shows the seconds, so
25
+ // a typed `25:00` displays `25:00:00` (rowsncolumns/spreadsheet#1027) —
26
+ // the same pattern the Number menu's "Duration" item applies.
27
+ ELAPSED: "[h]:mm:ss",
27
28
  };
29
+ // Typed hours at or past a full day are a Duration, never a clock time.
30
+ const ELAPSED_HOURS_MIN = 24;
28
31
  // Cap elapsed-time hours at Excel's documented limit (`9999:59:59`). Beyond
29
32
  // this, treat as text rather than producing absurdly large fractional
30
33
  // serials. JS `Number.isFinite` would let `Infinity` through, so we cap
@@ -60,12 +63,17 @@ export const validateDate = (value, locale) => {
60
63
  if (year < EXCEL_DATE_MIN_YEAR || year > EXCEL_DATE_MAX_YEAR) {
61
64
  return undefined;
62
65
  }
66
+ // Excel's phantom 1900-02-29 (serial 60): the parser hands back a stand-in
67
+ // `Date` on the 28th with `excelLeapDay` set, because no `Date` can hold the
68
+ // 29th. Report the day the user typed; `toSerialFromParts` maps it to 60
69
+ // (rowsncolumns/spreadsheet#1026).
70
+ const day = "excelLeapDay" in result && result.excelLeapDay ? 29 : dateValue.getDate();
63
71
  return {
64
72
  format: result.pattern,
65
73
  parts: {
66
74
  year,
67
75
  month: dateValue.getMonth(),
68
- day: dateValue.getDate(),
76
+ day,
69
77
  hour: dateValue.getHours(),
70
78
  minute: dateValue.getMinutes(),
71
79
  second: dateValue.getSeconds(),
@@ -94,10 +102,10 @@ export const validateDateTime = (value) => {
94
102
  const minute = parseInt(match[2], 10);
95
103
  const second = parseInt(match[3], 10);
96
104
  if (isValidTimeComponents(hour, minute, second)) {
97
- // Excel parity: hour > 24 is an elapsed-time entry (e.g. `25:30:00`,
98
- // `48:00:00`). Auto-apply `[h]:mm:ss` so the cell displays the full
99
- // hours count instead of wrapping to `01:30:00`.
100
- const format = hour > 24 ? TIME_FORMATS.FULL_ELAPSED : TIME_FORMATS.FULL;
105
+ // Excel parity: hours >= 24 are an elapsed-time entry (`24:00:00`,
106
+ // `25:30:00`, `48:00:00`). Auto-apply `[h]:mm:ss` so the cell displays
107
+ // the full hours count instead of wrapping to `01:30:00`.
108
+ const format = hour >= ELAPSED_HOURS_MIN ? TIME_FORMATS.ELAPSED : TIME_FORMATS.FULL;
101
109
  return createTimeResult(format, hour, minute, second);
102
110
  }
103
111
  }
@@ -115,8 +123,9 @@ export const validateDateTime = (value) => {
115
123
  const hour = parseInt(match[1], 10);
116
124
  const minute = parseInt(match[2], 10);
117
125
  if (isValidTimeComponents(hour, minute, 0)) {
118
- // Same elapsed-time auto-pattern logic as the full form above.
119
- const format = hour > 24 ? TIME_FORMATS.SHORT_ELAPSED : TIME_FORMATS.SHORT;
126
+ // Same elapsed-time rule as the full form: a duration typed without
127
+ // seconds still gets `[h]:mm:ss` (`25:00` → `25:00:00`, as Excel).
128
+ const format = hour >= ELAPSED_HOURS_MIN ? TIME_FORMATS.ELAPSED : TIME_FORMATS.SHORT;
120
129
  return createTimeResult(format, hour, minute, 0);
121
130
  }
122
131
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowsncolumns/spreadsheet-state",
3
- "version": "29.1.6",
3
+ "version": "29.1.7",
4
4
  "main": "./dist/cjs/index.js",
5
5
  "module": "./dist/esm/index.js",
6
6
  "types": "./dist/esm/index.d.ts",
@@ -78,15 +78,15 @@
78
78
  "@rowsncolumns/fast-formula-parser": ">=6.2.42",
79
79
  "@rowsncolumns/grid": ">=13.2.35",
80
80
  "@rowsncolumns/icons": ">=7.2.33",
81
- "@rowsncolumns/spreadsheet": ">=10.4.4",
81
+ "@rowsncolumns/spreadsheet": ">=10.4.5",
82
82
  "@rowsncolumns/ui": ">=16.0.4",
83
- "@rowsncolumns/utils": ">=9.5.3"
83
+ "@rowsncolumns/utils": ">=9.5.4"
84
84
  },
85
85
  "dependencies": {
86
86
  "@rowsncolumns/calculation-worker": ">=10.0.1",
87
- "@rowsncolumns/date-parser": ">=13.0.3",
87
+ "@rowsncolumns/date-parser": ">=13.0.4",
88
88
  "@rowsncolumns/functions": ">=15.0.2",
89
- "@rowsncolumns/toolkit": ">=24.5.5",
89
+ "@rowsncolumns/toolkit": ">=24.5.6",
90
90
  "formik": "^2.4.6",
91
91
  "immer": "^10.1.1",
92
92
  "jotai": "^2.12.4",