@pixerate/editor 0.22.0 → 0.23.0

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.
Files changed (83) hide show
  1. package/README.md +80 -2
  2. package/THIRD_PARTY_NOTICES.md +88 -0
  3. package/dist/agent/index.cjs +83 -108
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +69 -211
  6. package/dist/agent/index.d.ts +69 -211
  7. package/dist/agent/index.js +76 -101
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/arrangeShortcuts-B8O3f8-P.d.cts +184 -0
  10. package/dist/arrangeShortcuts-sLlD2rSX.d.ts +184 -0
  11. package/dist/canvas/index.cjs +879 -83
  12. package/dist/canvas/index.cjs.map +1 -1
  13. package/dist/canvas/index.d.cts +291 -186
  14. package/dist/canvas/index.d.ts +291 -186
  15. package/dist/canvas/index.js +865 -69
  16. package/dist/canvas/index.js.map +1 -1
  17. package/dist/chunk-26BVFKHU.cjs +453 -0
  18. package/dist/chunk-26BVFKHU.cjs.map +1 -0
  19. package/dist/chunk-2H7ZHPEJ.js +762 -0
  20. package/dist/chunk-2H7ZHPEJ.js.map +1 -0
  21. package/dist/chunk-7DWMJCAT.js +453 -0
  22. package/dist/chunk-7DWMJCAT.js.map +1 -0
  23. package/dist/chunk-ARRTP33I.js +101 -0
  24. package/dist/chunk-ARRTP33I.js.map +1 -0
  25. package/dist/chunk-CPOKFNBG.cjs +101 -0
  26. package/dist/chunk-CPOKFNBG.cjs.map +1 -0
  27. package/dist/chunk-G2I4QJOT.cjs +762 -0
  28. package/dist/chunk-G2I4QJOT.cjs.map +1 -0
  29. package/dist/{chunk-RU52I7QO.js → chunk-K3R5NG2D.js} +147 -42
  30. package/dist/chunk-K3R5NG2D.js.map +1 -0
  31. package/dist/{chunk-DENSCKFC.js → chunk-QBJ22YZR.js} +423 -30
  32. package/dist/chunk-QBJ22YZR.js.map +1 -0
  33. package/dist/{chunk-SAZRENEZ.cjs → chunk-RIKBJLS2.cjs} +424 -31
  34. package/dist/chunk-RIKBJLS2.cjs.map +1 -0
  35. package/dist/{chunk-6M3BCTBD.cjs → chunk-XDMXXC4Z.cjs} +230 -125
  36. package/dist/chunk-XDMXXC4Z.cjs.map +1 -0
  37. package/dist/commands/index.cjs +860 -0
  38. package/dist/commands/index.cjs.map +1 -0
  39. package/dist/commands/index.d.cts +592 -0
  40. package/dist/commands/index.d.ts +592 -0
  41. package/dist/commands/index.js +860 -0
  42. package/dist/commands/index.js.map +1 -0
  43. package/dist/{controller-B7GIybc4.d.cts → controller-pePCJLT1.d.cts} +78 -5
  44. package/dist/{controller-B7GIybc4.d.ts → controller-pePCJLT1.d.ts} +78 -5
  45. package/dist/history/index.cjs +12 -2
  46. package/dist/history/index.cjs.map +1 -1
  47. package/dist/history/index.d.cts +211 -7
  48. package/dist/history/index.d.ts +211 -7
  49. package/dist/history/index.js +13 -3
  50. package/dist/image-editor/index.cjs +418 -13
  51. package/dist/image-editor/index.cjs.map +1 -1
  52. package/dist/image-editor/index.d.cts +154 -3
  53. package/dist/image-editor/index.d.ts +154 -3
  54. package/dist/image-editor/index.js +417 -12
  55. package/dist/image-editor/index.js.map +1 -1
  56. package/dist/index.cjs +34 -76
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/index.d.cts +5 -42
  59. package/dist/index.d.ts +5 -42
  60. package/dist/index.js +27 -69
  61. package/dist/index.js.map +1 -1
  62. package/dist/registry-D5-R90p0.d.cts +209 -0
  63. package/dist/registry-D5-R90p0.d.ts +209 -0
  64. package/dist/spreadsheet/index.cjs +19 -3
  65. package/dist/spreadsheet/index.cjs.map +1 -1
  66. package/dist/spreadsheet/index.d.cts +67 -9
  67. package/dist/spreadsheet/index.d.ts +67 -9
  68. package/dist/spreadsheet/index.js +18 -2
  69. package/dist/{types-CJ4U-HHI.d.cts → types-DX4Mh4SL.d.cts} +1 -1
  70. package/dist/{types-CJ4U-HHI.d.ts → types-DX4Mh4SL.d.ts} +1 -1
  71. package/dist/types-GT5a5YAX.d.cts +86 -0
  72. package/dist/types-GT5a5YAX.d.ts +86 -0
  73. package/package.json +8 -2
  74. package/dist/chunk-2TWGLC5K.cjs +0 -262
  75. package/dist/chunk-2TWGLC5K.cjs.map +0 -1
  76. package/dist/chunk-6M3BCTBD.cjs.map +0 -1
  77. package/dist/chunk-DENSCKFC.js.map +0 -1
  78. package/dist/chunk-KAADNAPF.js +0 -262
  79. package/dist/chunk-KAADNAPF.js.map +0 -1
  80. package/dist/chunk-RU52I7QO.js.map +0 -1
  81. package/dist/chunk-SAZRENEZ.cjs.map +0 -1
  82. package/dist/types-BZgcDsC5.d.cts +0 -42
  83. package/dist/types-BZgcDsC5.d.ts +0 -42
@@ -414,9 +414,7 @@ function toNumber(value) {
414
414
  if (isBlank(value)) return 0;
415
415
  if (typeof value === "boolean") return value ? 1 : 0;
416
416
  if (typeof value === "number") return value;
417
- const trimmed = String(value).trim();
418
- const num = trimmed === "" ? NaN : Number(trimmed);
419
- return isNaN(num) ? "#VALUE!" : num;
417
+ return _nullishCoalesce(parseNumberText(String(value)), () => ( "#VALUE!"));
420
418
  }
421
419
  function toBoolean(value) {
422
420
  if (isFormulaError(value)) return value;
@@ -428,7 +426,26 @@ function toBoolean(value) {
428
426
  if (upper === "FALSE") return false;
429
427
  return "#VALUE!";
430
428
  }
431
- var toText = (value) => isBlank(value) ? "" : typeof value === "boolean" ? value ? "TRUE" : "FALSE" : String(value);
429
+ var toText = (value) => isBlank(value) ? "" : typeof value === "boolean" ? value ? "TRUE" : "FALSE" : typeof value === "number" ? numberToText(value) : String(value);
430
+ function numberToText(n) {
431
+ if (n === 0 || !Number.isFinite(n)) return "0";
432
+ const a = Math.abs(n);
433
+ if ((a < 1e-9 || a >= 1e15) && Math.round(a) !== a || a >= 1e15) return sciText(n, 15);
434
+ let mag = Math.floor(Math.log10(a));
435
+ if (a >= Math.pow(10, mag + 1)) mag++;
436
+ const decimals = Math.min(Math.max(14 - mag, 0), 30);
437
+ return trimDecimal(n.toFixed(decimals));
438
+ }
439
+ function trimDecimal(s) {
440
+ if (!s.includes(".")) return s;
441
+ const t = s.replace(/0+$/, "").replace(/\.$/, "");
442
+ return t === "-0" ? "0" : t;
443
+ }
444
+ function sciText(n, sig) {
445
+ const [mantissa, exp] = n.toExponential(Math.max(sig - 1, 0)).split("e");
446
+ const e = Number(exp);
447
+ return `${trimDecimal(mantissa)}E${e < 0 ? "-" : "+"}${String(Math.abs(e)).padStart(2, "0")}`;
448
+ }
432
449
  function numericValue(value) {
433
450
  if (typeof value === "number") return Number.isFinite(value) ? value : null;
434
451
  if (typeof value !== "string" || FORMULA_ERRORS.has(value)) return null;
@@ -441,22 +458,68 @@ function normalizeValue(value) {
441
458
  const num = typeof value === "string" ? numericValue(value) : null;
442
459
  return num === null ? value : num;
443
460
  }
461
+ var ERROR_ORDER = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A", "#SPILL!", "#CALC!", "#CYCLE!", "#ERROR!"];
462
+ function valueRank(value) {
463
+ if (isBlank(value)) return 4;
464
+ if (typeof value === "number") return 0;
465
+ if (typeof value === "boolean") return 2;
466
+ if (typeof value === "string" && FORMULA_ERRORS.has(value)) return 3;
467
+ return 1;
468
+ }
469
+ function compareNumbers(a, b) {
470
+ if (a === b) return 0;
471
+ if (Math.abs(a - b) > Math.max(Math.abs(a), Math.abs(b)) * 1e-13) return a < b ? -1 : 1;
472
+ const round15 = (x2) => !Number.isFinite(x2) || x2 === 0 ? x2 : Number(x2.toExponential(14));
473
+ const x = round15(a);
474
+ const y = round15(b);
475
+ return x < y ? -1 : x > y ? 1 : 0;
476
+ }
477
+ function compareText(a, b) {
478
+ const x = a.toLowerCase();
479
+ const y = b.toLowerCase();
480
+ return x < y ? -1 : x > y ? 1 : 0;
481
+ }
444
482
  function compareValues(left, right) {
445
- if (typeof left === "string" && typeof right === "string") {
446
- const a = isoDateTime(left);
447
- const b = a === null ? null : isoDateTime(right);
448
- if (a !== null && b !== null) return a - b;
449
- }
450
- const rank = (v) => typeof v === "boolean" ? 2 : typeof v === "string" ? 1 : 0;
451
- const l = isBlank(left) ? typeof right === "string" ? "" : 0 : left;
452
- const r = isBlank(right) ? typeof l === "string" ? "" : 0 : right;
453
- if (rank(l) !== rank(r)) return rank(l) - rank(r);
454
- if (typeof l === "string") {
455
- const a = l.toLowerCase();
456
- const b = r.toLowerCase();
457
- return a < b ? -1 : a > b ? 1 : 0;
458
- }
459
- return Number(l) - Number(r);
483
+ const lRank = valueRank(left);
484
+ const rRank = valueRank(right);
485
+ if (lRank === 4 || rRank === 4) {
486
+ if (lRank === rRank) return 0;
487
+ const blankFirst = lRank === 4;
488
+ const other = blankFirst ? right : left;
489
+ const otherRank = blankFirst ? rRank : lRank;
490
+ let cmp;
491
+ if (otherRank === 0) cmp = compareNumbers(0, other);
492
+ else if (otherRank === 1) cmp = String(other) === "" ? 0 : -1;
493
+ else if (otherRank === 2) cmp = other ? -1 : 0;
494
+ else return lRank - rRank;
495
+ return blankFirst ? cmp : -cmp;
496
+ }
497
+ if (lRank === 1 && rRank === 1) {
498
+ const a = String(left);
499
+ const b = String(right);
500
+ const ta = isoDateTime(a);
501
+ const tb = ta === null ? null : isoDateTime(b);
502
+ if (ta !== null && tb !== null) return Math.sign(ta - tb);
503
+ return compareText(a, b);
504
+ }
505
+ if (lRank === 0 && rRank === 1 || lRank === 1 && rRank === 0) {
506
+ const date = parseIsoDate(lRank === 1 ? left : right);
507
+ if (date) {
508
+ const serial = dateToSerial(date);
509
+ return lRank === 0 ? compareNumbers(left, serial) : compareNumbers(serial, right);
510
+ }
511
+ }
512
+ if (lRank !== rRank) return lRank - rRank;
513
+ if (lRank === 0) return compareNumbers(left, right);
514
+ if (lRank === 2) return Number(left) - Number(right);
515
+ return Math.sign(ERROR_ORDER.indexOf(left) - ERROR_ORDER.indexOf(right));
516
+ }
517
+ function sortCompareValues(left, right) {
518
+ const lBlank = isBlank(left);
519
+ const rBlank = isBlank(right);
520
+ if (lBlank || rBlank) return lBlank === rBlank ? 0 : lBlank ? 1 : -1;
521
+ if (isFormulaError(left) && isFormulaError(right)) return 0;
522
+ return compareValues(left, right);
460
523
  }
461
524
  function roundHalfAwayFromZero(value, decimals) {
462
525
  const factor = Math.pow(10, decimals);
@@ -565,6 +628,282 @@ var daysBetween = (start, end) => Math.round(
565
628
  (Date.UTC(end.getFullYear(), end.getMonth(), end.getDate()) - Date.UTC(start.getFullYear(), start.getMonth(), start.getDate())) / MS_PER_DAY
566
629
  );
567
630
 
631
+ // src/spreadsheet/formula/parse-input.ts
632
+ var MONTH_NAMES = [
633
+ "January",
634
+ "February",
635
+ "March",
636
+ "April",
637
+ "May",
638
+ "June",
639
+ "July",
640
+ "August",
641
+ "September",
642
+ "October",
643
+ "November",
644
+ "December"
645
+ ];
646
+ function daysFromCivil(year, month, day) {
647
+ const y = month <= 2 ? year - 1 : year;
648
+ const era = Math.floor((y >= 0 ? y : y - 399) / 400);
649
+ const yoe = y - era * 400;
650
+ const doy = Math.floor((153 * (month > 2 ? month - 3 : month + 9) + 2) / 5) + day - 1;
651
+ const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
652
+ return era * 146097 + doe - 719468;
653
+ }
654
+ var isLeapYear = (y) => y % 4 === 0 && y % 100 !== 0 || y % 400 === 0;
655
+ function daysInMonth(year, month) {
656
+ if (month === 2) return isLeapYear(year) ? 29 : 28;
657
+ if ([4, 6, 9, 11].includes(month)) return 30;
658
+ return month >= 1 && month <= 12 ? 31 : 0;
659
+ }
660
+ var daysInMonth1900 = (year, month) => year === 1900 && month === 2 ? 29 : daysInMonth(year, month);
661
+ var UNIX_1899_12_30 = -25569;
662
+ var MAX_SERIAL_1900 = 2958465;
663
+ function serialFromYmd(year, month, day) {
664
+ if (![year, month, day].every(Number.isSafeInteger)) return null;
665
+ let y = year >= 0 && year < 1900 ? year + 1900 : year;
666
+ const m0 = month - 1;
667
+ y += Math.floor(m0 / 12);
668
+ const m = (m0 % 12 + 12) % 12 + 1;
669
+ if (y < 1900 || y > 9999) return null;
670
+ const first = daysFromCivil(y, m, 1) - UNIX_1899_12_30 - (y === 1900 && m <= 2 ? 1 : 0);
671
+ const serial = first + day - 1;
672
+ return serial >= 0 && serial <= MAX_SERIAL_1900 ? serial : null;
673
+ }
674
+ var timeFraction = (h, m, s) => (h * 3600 + m * 60 + s) / 86400;
675
+ var currentYear = () => (/* @__PURE__ */ new Date()).getFullYear();
676
+ function parseCellInput(input) {
677
+ if (input === "") return { value: "", type: "empty" };
678
+ if (input.startsWith("'")) return { value: input.slice(1), type: "text" };
679
+ const t = input.trim();
680
+ const upper = t.toUpperCase();
681
+ if (upper === "TRUE") return { value: true, type: "boolean" };
682
+ if (upper === "FALSE") return { value: false, type: "boolean" };
683
+ if (FORMULA_ERRORS.has(upper)) return { value: upper, type: "error" };
684
+ const numeric = parseNumeric(t);
685
+ if (numeric) {
686
+ if (numeric.kind === "date") {
687
+ const iso = isoText(numeric.date);
688
+ if (iso !== null) {
689
+ return { value: iso, type: "date", numberFormat: numeric.format, formatKind: "date", cellFormat: "date" };
690
+ }
691
+ } else {
692
+ const formatKind = numeric.kind === "time" ? "time" : formatKindOf(numeric.format);
693
+ return {
694
+ value: normalizeZero(numeric.value),
695
+ type: "number",
696
+ ...numeric.format ? { numberFormat: numeric.format } : {},
697
+ ...formatKind ? { formatKind } : {},
698
+ ...formatKind && formatKind !== "time" ? { cellFormat: formatKind } : {}
699
+ };
700
+ }
701
+ }
702
+ return { value: input, type: "text" };
703
+ }
704
+ function parseNumberText(text) {
705
+ const numeric = parseNumeric(text.trim());
706
+ if (!numeric) return null;
707
+ if (numeric.kind !== "date") return normalizeZero(numeric.value);
708
+ const { year, month, day, time = 0 } = numeric.date;
709
+ const serial = serialFromYmd(year, month, day);
710
+ return serial === null ? null : serial + time;
711
+ }
712
+ var normalizeZero = (n) => n === 0 ? 0 : n;
713
+ function formatKindOf(format) {
714
+ if (!format) return void 0;
715
+ if (format.includes("$")) return "currency";
716
+ if (format.includes("%")) return "percentage";
717
+ return "number";
718
+ }
719
+ var pad2 = (n, width = 2) => String(n).padStart(width, "0");
720
+ function isoText({ year, month, day, time }) {
721
+ if (day > daysInMonth(year, month)) return null;
722
+ const date = `${pad2(year, 4)}-${pad2(month)}-${pad2(day)}`;
723
+ if (time === void 0) return date;
724
+ let seconds = Math.round(time * 86400);
725
+ if (seconds >= 86400) seconds = 86399;
726
+ return `${date} ${pad2(Math.floor(seconds / 3600))}:${pad2(Math.floor(seconds / 60) % 60)}:${pad2(seconds % 60)}`;
727
+ }
728
+ function parseNumeric(t) {
729
+ if (t === "") return null;
730
+ if (t.startsWith("(") && t.endsWith(")") && t.length >= 2) {
731
+ const inner = parseNumeric(t.slice(1, -1).trim());
732
+ if (!inner || inner.kind === "date") return null;
733
+ return { ...inner, value: -inner.value };
734
+ }
735
+ const plain = parsePlain(t);
736
+ if (plain) return plain;
737
+ const fraction = parseFraction(t);
738
+ if (fraction !== null) return { kind: "number", value: fraction, format: "# ?/?" };
739
+ return parseDateTime(t);
740
+ }
741
+ var startsWithDigitOrDot = (s) => /^[0-9.]/.test(s);
742
+ function parsePlain(t) {
743
+ let s = t;
744
+ let neg = false;
745
+ let currency = false;
746
+ let percent = false;
747
+ if (s.startsWith("-")) {
748
+ neg = true;
749
+ s = s.slice(1).trimStart();
750
+ } else if (s.startsWith("+")) {
751
+ s = s.slice(1).trimStart();
752
+ }
753
+ if (s.startsWith("$")) {
754
+ currency = true;
755
+ s = s.slice(1).trimStart();
756
+ if (!neg && s.startsWith("-")) {
757
+ neg = true;
758
+ s = s.slice(1);
759
+ }
760
+ }
761
+ if (s.endsWith("%")) {
762
+ percent = true;
763
+ s = s.slice(0, -1).trimEnd();
764
+ }
765
+ if (s === "") return null;
766
+ const hasSep = s.includes(",");
767
+ let digits;
768
+ if (hasSep) {
769
+ const dot = s.indexOf(".");
770
+ const int = dot === -1 ? s : s.slice(0, dot);
771
+ const frac = dot === -1 ? null : s.slice(dot + 1);
772
+ const groups = int.split(",");
773
+ const first = groups[0];
774
+ if (first === "" || first.length > 3 || groups.slice(1).some((g) => g.length !== 3)) return null;
775
+ digits = groups.join("") + (frac !== null ? `.${frac}` : "");
776
+ } else {
777
+ digits = s;
778
+ }
779
+ if (!/^[0-9.eE+-]+$/.test(digits) || !startsWithDigitOrDot(digits)) return null;
780
+ if (!/^(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(digits)) return null;
781
+ let n = Number(digits);
782
+ if (!Number.isFinite(n)) return null;
783
+ const sci = /[eE]/.test(digits);
784
+ if (percent) n /= 100;
785
+ if (neg) n = -n;
786
+ const hasDot = digits.includes(".");
787
+ const format = currency ? hasDot ? '"$"#,##0.00' : '"$"#,##0' : percent ? hasDot ? "0.00%" : "0%" : sci ? "0.00E+00" : hasSep ? hasDot ? "#,##0.00" : "#,##0" : void 0;
788
+ return { kind: "number", value: n, ...format ? { format } : {} };
789
+ }
790
+ var parseDecimal = (s) => /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(s) ? Number(s) : null;
791
+ function parseFraction(t) {
792
+ const space = t.indexOf(" ");
793
+ if (space === -1) return null;
794
+ const whole = t.slice(0, space);
795
+ const frac = t.slice(space + 1).trim();
796
+ const neg = whole.startsWith("-");
797
+ const w = parseDecimal(whole.replace(/^-+/, ""));
798
+ const slash = frac.indexOf("/");
799
+ if (w === null || slash === -1) return null;
800
+ const a = parseDecimal(frac.slice(0, slash));
801
+ const b = parseDecimal(frac.slice(slash + 1));
802
+ if (a === null || b === null || b === 0 || !Number.isFinite(w)) return null;
803
+ const v = w + a / b;
804
+ return neg ? -v : v;
805
+ }
806
+ function monthFromName(s) {
807
+ const l = s.toLowerCase();
808
+ if (l.length < 3) return null;
809
+ const index = MONTH_NAMES.findIndex((m) => m.toLowerCase().startsWith(l));
810
+ return index === -1 ? null : index + 1;
811
+ }
812
+ function parseTime(input) {
813
+ const lower = input.trim().toLowerCase();
814
+ let body = lower;
815
+ let pm = null;
816
+ for (const [suffix, isPm] of [["am", false], ["a", false], ["pm", true], ["p", true]]) {
817
+ if (lower.endsWith(suffix)) {
818
+ body = lower.slice(0, -suffix.length).trim();
819
+ pm = isPm;
820
+ break;
821
+ }
822
+ }
823
+ const parts = body.split(":");
824
+ if (parts.length === 1 && pm === null) return null;
825
+ if (parts.length > 3 || parts.some((p) => p === "")) return null;
826
+ const num = (p) => p === void 0 ? 0 : parseDecimal(p);
827
+ let h = num(parts[0]);
828
+ const m = num(parts[1]);
829
+ const s = num(parts[2]);
830
+ if (h === null || m === null || s === null) return null;
831
+ if (m >= 60 || s >= 60 || h < 0 || m < 0 || s < 0) return null;
832
+ if (pm !== null) {
833
+ if (h > 12) return null;
834
+ if (h === 12) h = 0;
835
+ if (pm) h += 12;
836
+ } else if (h >= 1e4) {
837
+ return null;
838
+ }
839
+ return { fraction: timeFraction(h, m, s), seconds: parts.length === 3, ampm: pm !== null };
840
+ }
841
+ var expandYear = (text, y) => text.length <= 2 ? y < 30 ? 2e3 + y : 1900 + y : y;
842
+ function validYmd(year, month, day) {
843
+ if (month < 1 || month > 12 || day < 1 || year < 1900 || year > 9999) return null;
844
+ if (day > daysInMonth1900(year, month)) return null;
845
+ return { year, month, day };
846
+ }
847
+ function parseDate(input) {
848
+ const t = input.trim().replace(/,+$/, "");
849
+ const num = (s) => /^[+-]?\d+$/.test(s.trim()) ? Number(s.trim()) : null;
850
+ const withFormat = (date, format) => date ? { date, format } : null;
851
+ const parts = t.split(/[/.-]/);
852
+ if (parts.length === 3) {
853
+ const [a, b, c] = parts.map((p) => p.trim());
854
+ if (a.length === 4) {
855
+ const [y2, m2, d2] = [num(a), num(b), num(c)];
856
+ if (y2 !== null && m2 !== null && d2 !== null) return withFormat(validYmd(y2, m2, d2), "yyyy-mm-dd");
857
+ }
858
+ {
859
+ const [m2, d2, y2] = [num(a), num(b), num(c)];
860
+ if (m2 !== null && d2 !== null && y2 !== null) return withFormat(validYmd(expandYear(c, y2), m2, d2), "m/d/yyyy");
861
+ }
862
+ const [d, m, y] = [num(a), monthFromName(b), num(c)];
863
+ if (d !== null && m !== null && y !== null) return withFormat(validYmd(expandYear(c, y), m, d), "d-mmm-yy");
864
+ }
865
+ if (parts.length === 2) {
866
+ const [a, b] = parts.map((p) => p.trim());
867
+ const [x, y] = [num(a), num(b)];
868
+ if (x !== null && y !== null) {
869
+ if (x >= 1 && x <= 12 && y >= 1 && y <= 31) return withFormat(validYmd(currentYear(), x, y), "d-mmm");
870
+ if (x >= 1 && x <= 12 && b.length === 4) return withFormat(validYmd(y, x, 1), "mmm-yy");
871
+ }
872
+ const dayA = num(a);
873
+ const monthB = monthFromName(b);
874
+ if (dayA !== null && monthB !== null) return withFormat(validYmd(currentYear(), monthB, dayA), "d-mmm");
875
+ const monthA = monthFromName(a);
876
+ const yearB = num(b);
877
+ if (monthA !== null && yearB !== null) return withFormat(validYmd(expandYear(b, yearB), monthA, 1), "mmm-yy");
878
+ }
879
+ const words = t.split(/[ ,]/).filter((w) => w !== "");
880
+ if (words.length === 3) {
881
+ const [w0, w1, w2] = words;
882
+ let [m, d, y] = [monthFromName(w0), num(w1), num(w2)];
883
+ if (m !== null && d !== null && y !== null) return withFormat(validYmd(expandYear(w2, y), m, d), "d-mmm-yy");
884
+ [d, m, y] = [num(w0), monthFromName(w1), num(w2)];
885
+ if (d !== null && m !== null && y !== null) return withFormat(validYmd(expandYear(w2, y), m, d), "d-mmm-yy");
886
+ }
887
+ return null;
888
+ }
889
+ function parseDateTime(t) {
890
+ const time = parseTime(t);
891
+ if (time) {
892
+ const format = time.fraction >= 1 ? "[h]:mm:ss" : time.seconds ? time.ampm ? "h:mm:ss AM/PM" : "h:mm:ss" : time.ampm ? "h:mm AM/PM" : "h:mm";
893
+ return { kind: "time", value: time.fraction, format };
894
+ }
895
+ const date = parseDate(t);
896
+ if (date) return { kind: "date", date: date.date, format: date.format };
897
+ for (let i = t.indexOf(" "); i !== -1; i = t.indexOf(" ", i + 1)) {
898
+ const d = parseDate(t.slice(0, i));
899
+ const tm = d ? parseTime(t.slice(i + 1)) : null;
900
+ if (d && tm && tm.fraction < 1) {
901
+ return { kind: "date", date: { ...d.date, time: tm.fraction }, format: "m/d/yyyy h:mm" };
902
+ }
903
+ }
904
+ return null;
905
+ }
906
+
568
907
  // src/spreadsheet/formula/criteria.ts
569
908
  function wildcardToRegExp(pattern) {
570
909
  let source = "";
@@ -601,12 +940,17 @@ function parseCriteria(criterion) {
601
940
  if (op === "<>") return (value) => !isBlank(value);
602
941
  return () => false;
603
942
  }
604
- const operandNumber = numericValue(operand);
943
+ const parsed = parseCellInput(operand.trim());
944
+ const operandNumber = _nullishCoalesce(numericValue(operand), () => ( (parsed.type === "number" ? parsed.value : null)));
945
+ const operandDate = parsed.type === "date" ? parsed.value : null;
946
+ const isDateValue = (value) => typeof value === "number" || parseIsoDate(value) !== null;
605
947
  const operandUpper = operand.trim().toUpperCase();
606
948
  const operandBoolean = operandUpper === "TRUE" ? true : operandUpper === "FALSE" ? false : null;
607
949
  if (op === "=" || op === "<>") {
608
950
  let equals;
609
- if (operandNumber !== null) {
951
+ if (operandDate !== null) {
952
+ equals = (value) => isDateValue(value) && compareValues(value, operandDate) === 0;
953
+ } else if (operandNumber !== null) {
610
954
  equals = (value) => numericValue(value) === operandNumber;
611
955
  } else if (operandBoolean !== null) {
612
956
  equals = (value) => value === operandBoolean || typeof value === "string" && value.trim().toUpperCase() === operandUpper;
@@ -619,6 +963,9 @@ function parseCriteria(criterion) {
619
963
  return op === "=" ? (value) => !isFormulaError(value) && equals(value) : (value) => !isFormulaError(value) && !equals(value);
620
964
  }
621
965
  const test = (cmp) => op === "<" ? cmp < 0 : op === "<=" ? cmp <= 0 : op === ">" ? cmp > 0 : cmp >= 0;
966
+ if (operandDate !== null) {
967
+ return (value) => isDateValue(value) && test(compareValues(value, operandDate));
968
+ }
622
969
  if (operandNumber !== null) {
623
970
  return (value) => {
624
971
  const num = numericValue(value);
@@ -636,6 +983,42 @@ function parseCriteria(criterion) {
636
983
  }
637
984
 
638
985
  // src/spreadsheet/formula/format.ts
986
+ function formatCellDisplay(cell) {
987
+ if (!cell) return "";
988
+ if (cell.error) return cell.error;
989
+ const { value, numberFormat } = cell;
990
+ if (numberFormat && value !== "" && value !== null && value !== void 0 && typeof value !== "boolean") {
991
+ if (/^\[h\]/i.test(numberFormat) && typeof value === "number") return formatElapsedHours(value);
992
+ if (numberFormat === "# ?/?" && typeof value === "number") return formatFraction(value);
993
+ const formatted = formatValueWithCode(value, numberFormat);
994
+ if (formatted !== null) return formatted;
995
+ }
996
+ return toText(value);
997
+ }
998
+ function formatFraction(value) {
999
+ const sign = value < 0 ? "-" : "";
1000
+ const abs = Math.abs(value);
1001
+ let whole = Math.floor(abs);
1002
+ const frac = abs - whole;
1003
+ let best = { num: 0, den: 1, err: frac };
1004
+ for (let den = 2; den <= 9; den++) {
1005
+ const num = Math.round(frac * den);
1006
+ const err = Math.abs(frac - num / den);
1007
+ if (err < best.err - 1e-12) best = { num, den, err };
1008
+ }
1009
+ if (best.num === best.den) {
1010
+ whole += 1;
1011
+ best = { num: 0, den: 1, err: 0 };
1012
+ }
1013
+ if (best.num === 0) return `${sign}${whole}`;
1014
+ return `${sign}${whole === 0 ? "" : `${whole} `}${best.num}/${best.den}`;
1015
+ }
1016
+ function formatElapsedHours(days) {
1017
+ const total = Math.round(Math.abs(days) * 86400);
1018
+ const p = (n) => String(n).padStart(2, "0");
1019
+ const text = `${Math.floor(total / 3600)}:${p(Math.floor(total / 60) % 60)}:${p(total % 60)}`;
1020
+ return days < 0 ? `-${text}` : text;
1021
+ }
639
1022
  function formatValueWithCode(value, format) {
640
1023
  if (isDateFormat(format)) {
641
1024
  const date = toDate(value);
@@ -750,7 +1133,7 @@ function splitSections(format) {
750
1133
  }
751
1134
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
752
1135
  var DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
753
- var pad2 = (n) => String(n).padStart(2, "0");
1136
+ var pad3 = (n) => String(n).padStart(2, "0");
754
1137
  function formatDate(date, format) {
755
1138
  const parts = [];
756
1139
  for (const token of tokenize(format)) {
@@ -777,30 +1160,30 @@ function formatDate(date, format) {
777
1160
  return code[0] === code[0].toLowerCase() ? text.toLowerCase() : text;
778
1161
  }
779
1162
  if (lower.startsWith("y")) {
780
- return lower.length <= 2 ? pad2(date.getFullYear() % 100) : String(date.getFullYear());
1163
+ return lower.length <= 2 ? pad3(date.getFullYear() % 100) : String(date.getFullYear());
781
1164
  }
782
1165
  if (lower.startsWith("d")) {
783
1166
  if (lower.length >= 4) return DAYS[date.getDay()];
784
1167
  if (lower.length === 3) return DAYS[date.getDay()].slice(0, 3);
785
- return lower.length === 2 ? pad2(date.getDate()) : String(date.getDate());
1168
+ return lower.length === 2 ? pad3(date.getDate()) : String(date.getDate());
786
1169
  }
787
1170
  if (lower.startsWith("h")) {
788
1171
  let hours = date.getHours();
789
1172
  if (twelveHour) hours = hours % 12 || 12;
790
- return lower.length >= 2 ? pad2(hours) : String(hours);
1173
+ return lower.length >= 2 ? pad3(hours) : String(hours);
791
1174
  }
792
1175
  if (lower.startsWith("s")) {
793
- return lower.length >= 2 ? pad2(date.getSeconds()) : String(date.getSeconds());
1176
+ return lower.length >= 2 ? pad3(date.getSeconds()) : String(date.getSeconds());
794
1177
  }
795
1178
  const position = codes.findIndex((c) => c.i === index);
796
1179
  const prev = _nullishCoalesce(_optionalChain([codes, 'access', _5 => _5[position - 1], 'optionalAccess', _6 => _6.text, 'access', _7 => _7.toLowerCase, 'call', _8 => _8()]), () => ( ""));
797
1180
  const next = _nullishCoalesce(_optionalChain([codes, 'access', _9 => _9[position + 1], 'optionalAccess', _10 => _10.text, 'access', _11 => _11.toLowerCase, 'call', _12 => _12()]), () => ( ""));
798
1181
  if (lower.length <= 2 && (prev.startsWith("h") || next.startsWith("s"))) {
799
- return lower.length === 2 ? pad2(date.getMinutes()) : String(date.getMinutes());
1182
+ return lower.length === 2 ? pad3(date.getMinutes()) : String(date.getMinutes());
800
1183
  }
801
1184
  if (lower.length >= 4) return MONTHS[date.getMonth()];
802
1185
  if (lower.length === 3) return MONTHS[date.getMonth()].slice(0, 3);
803
- return lower.length === 2 ? pad2(date.getMonth() + 1) : String(date.getMonth() + 1);
1186
+ return lower.length === 2 ? pad3(date.getMonth() + 1) : String(date.getMonth() + 1);
804
1187
  }).join("");
805
1188
  }
806
1189
 
@@ -1806,7 +2189,7 @@ var TEXT_FUNCTIONS = [
1806
2189
  if (isFormulaError(value)) return value;
1807
2190
  if (typeof value === "number") return value;
1808
2191
  if (isBlank(value)) return 0;
1809
- const num = parseNumericText(toText(value));
2192
+ const num = _nullishCoalesce(parseNumericText(toText(value)), () => ( parseNumberText(toText(value))));
1810
2193
  if (num === null) return ctx.argError(0, "#VALUE!", `("${toText(value)}") can't be converted to a number.`);
1811
2194
  return num;
1812
2195
  }
@@ -3226,5 +3609,15 @@ var FormulaEvaluator = (_class2 = class {
3226
3609
 
3227
3610
 
3228
3611
 
3229
- exports.tokenizeFormula = tokenizeFormula; exports.WHOLE_COLUMN_END_ROW = WHOLE_COLUMN_END_ROW; exports.parseCellReference = parseCellReference; exports.parseRange = parseRange; exports.FormulaParser = FormulaParser; exports.parseFormula = parseFormula; exports.FORMULA_ERRORS = FORMULA_ERRORS; exports.isFormulaError = isFormulaError; exports.colNameToIndex = colNameToIndex; exports.indexToColName = indexToColName; exports.wildcardToRegExp = wildcardToRegExp; exports.parseCriteria = parseCriteria; exports.formatValueWithCode = formatValueWithCode; exports.registerFormulaFunction = registerFormulaFunction; exports.unregisterFormulaFunction = unregisterFormulaFunction; exports.getFormulaFunction = getFormulaFunction; exports.listFormulaFunctions = listFormulaFunctions; exports.searchFormulaFunctions = searchFormulaFunctions; exports.getFormulaArgumentSpecIndex = getFormulaArgumentSpecIndex; exports.checkFormulaArgumentCount = checkFormulaArgumentCount; exports.getFormulaSignatureParts = getFormulaSignatureParts; exports.getFormulaSignature = getFormulaSignature; exports.describeFormulaError = describeFormulaError; exports.MAX_FORMULA_ARRAY_SIZE = MAX_FORMULA_ARRAY_SIZE; exports.FormulaEvaluator = FormulaEvaluator;
3230
- //# sourceMappingURL=chunk-SAZRENEZ.cjs.map
3612
+
3613
+
3614
+
3615
+
3616
+
3617
+
3618
+
3619
+
3620
+
3621
+
3622
+ exports.tokenizeFormula = tokenizeFormula; exports.WHOLE_COLUMN_END_ROW = WHOLE_COLUMN_END_ROW; exports.parseCellReference = parseCellReference; exports.parseRange = parseRange; exports.FormulaParser = FormulaParser; exports.parseFormula = parseFormula; exports.serialFromYmd = serialFromYmd; exports.parseCellInput = parseCellInput; exports.parseNumberText = parseNumberText; exports.FORMULA_ERRORS = FORMULA_ERRORS; exports.isFormulaError = isFormulaError; exports.numberToText = numberToText; exports.numericValue = numericValue; exports.compareNumbers = compareNumbers; exports.compareValues = compareValues; exports.sortCompareValues = sortCompareValues; exports.colNameToIndex = colNameToIndex; exports.indexToColName = indexToColName; exports.parseIsoDate = parseIsoDate; exports.wildcardToRegExp = wildcardToRegExp; exports.parseCriteria = parseCriteria; exports.formatCellDisplay = formatCellDisplay; exports.formatValueWithCode = formatValueWithCode; exports.registerFormulaFunction = registerFormulaFunction; exports.unregisterFormulaFunction = unregisterFormulaFunction; exports.getFormulaFunction = getFormulaFunction; exports.listFormulaFunctions = listFormulaFunctions; exports.searchFormulaFunctions = searchFormulaFunctions; exports.getFormulaArgumentSpecIndex = getFormulaArgumentSpecIndex; exports.checkFormulaArgumentCount = checkFormulaArgumentCount; exports.getFormulaSignatureParts = getFormulaSignatureParts; exports.getFormulaSignature = getFormulaSignature; exports.describeFormulaError = describeFormulaError; exports.MAX_FORMULA_ARRAY_SIZE = MAX_FORMULA_ARRAY_SIZE; exports.FormulaEvaluator = FormulaEvaluator;
3623
+ //# sourceMappingURL=chunk-RIKBJLS2.cjs.map