@iyulab/flex-table 0.38.0 → 0.38.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.38.1] - 2026-09-23
4
+
5
+ ### Fixed
6
+
7
+ - 🔴 **XLSX import no longer turns styled numbers into dates.** A number was read as a date whenever
8
+ its cell had any non-default style and its value fell between 1 and 73050 — so bold figures,
9
+ thousands separators, currency and percentage formats (most numbers in a real business
10
+ spreadsheet) came in as dates: a price of 12,450 became `1934-01-30`. Whether a number is a date
11
+ is now decided by the cell style's number format, read from `styles.xml`: the built-in date
12
+ formats, and custom formats whose code draws a day or a year (text in quotes, escaped characters
13
+ and bracketed sections such as `[Red]` or `[$-409]` are not counted). Time-only formats stay
14
+ numbers.
15
+ - 🔴 **Imported dates are no longer one day early.** The serial-to-date conversion subtracted a day,
16
+ so a date exported by the table and imported back came in as the day before.
17
+ - **Row drag and the fill handle hit the frozen row under the pointer while the table is
18
+ scrolled.** Frozen rows stay put as a sticky band, but both gestures added the scroll offset to
19
+ the pointer position everywhere, so over the band they pointed at the body row hidden behind
20
+ it: a row dropped onto a frozen row landed further down, and a fill dragged up into the band
21
+ stopped short of it. The drop indicator is drawn at the right place too.
22
+ - **XLSX import honors the 1904 date system** (`workbookPr date1904`, used by workbooks created on
23
+ a Mac), which otherwise shifts every date by four years.
24
+
3
25
  ## [0.38.0] - 2026-09-23
4
26
 
5
27
  ### Fixed
@@ -4,6 +4,12 @@
4
4
  * Supports string, number, boolean, and date cell types.
5
5
  */
6
6
  import type { ColumnDefinition, DataRow } from '../models/types.js';
7
+ export interface ZipFile {
8
+ name: string;
9
+ data: Uint8Array;
10
+ }
11
+ /** @internal 테스트가 실물에 가까운 통합 문서(스타일·1904 날짜 체계)를 조립하는 데 쓴다. */
12
+ export declare function buildZip(files: ZipFile[]): Uint8Array<ArrayBuffer>;
7
13
  /**
8
14
  * Build an XLSX file as a Uint8Array.
9
15
  */
@@ -946,7 +946,9 @@ var l = r`
946
946
  alertMessage: "رسالة",
947
947
  remove: "إزالة",
948
948
  closeTab: "إغلاق علامة التبويب",
949
- breadcrumb: "مسار التنقل"
949
+ breadcrumb: "مسار التنقل",
950
+ confirm: "تأكيد",
951
+ cancel: "إلغاء"
950
952
  },
951
953
  "../assets/locales/de.json": {
952
954
  valueMissing: "Dieses Feld ist erforderlich",
@@ -987,7 +989,9 @@ var l = r`
987
989
  alertMessage: "Nachricht",
988
990
  remove: "Entfernen",
989
991
  closeTab: "Tab schließen",
990
- breadcrumb: "Navigationspfad"
992
+ breadcrumb: "Navigationspfad",
993
+ confirm: "Bestätigen",
994
+ cancel: "Abbrechen"
991
995
  },
992
996
  "../assets/locales/en.json": {
993
997
  valueMissing: "This field is required",
@@ -1028,7 +1032,9 @@ var l = r`
1028
1032
  alertMessage: "Message",
1029
1033
  remove: "Remove",
1030
1034
  closeTab: "Close tab",
1031
- breadcrumb: "Breadcrumb"
1035
+ breadcrumb: "Breadcrumb",
1036
+ confirm: "Confirm",
1037
+ cancel: "Cancel"
1032
1038
  },
1033
1039
  "../assets/locales/es.json": {
1034
1040
  valueMissing: "Este campo es obligatorio",
@@ -1069,7 +1075,9 @@ var l = r`
1069
1075
  alertMessage: "Mensaje",
1070
1076
  remove: "Quitar",
1071
1077
  closeTab: "Cerrar pestaña",
1072
- breadcrumb: "Ruta de navegación"
1078
+ breadcrumb: "Ruta de navegación",
1079
+ confirm: "Confirmar",
1080
+ cancel: "Cancelar"
1073
1081
  },
1074
1082
  "../assets/locales/fr.json": {
1075
1083
  valueMissing: "Ce champ est obligatoire",
@@ -1110,7 +1118,9 @@ var l = r`
1110
1118
  alertMessage: "Message",
1111
1119
  remove: "Supprimer",
1112
1120
  closeTab: "Fermer l'onglet",
1113
- breadcrumb: "Fil d'Ariane"
1121
+ breadcrumb: "Fil d'Ariane",
1122
+ confirm: "Confirmer",
1123
+ cancel: "Annuler"
1114
1124
  },
1115
1125
  "../assets/locales/id.json": {
1116
1126
  valueMissing: "Kolom ini wajib diisi",
@@ -1151,7 +1161,9 @@ var l = r`
1151
1161
  alertMessage: "Pesan",
1152
1162
  remove: "Hapus",
1153
1163
  closeTab: "Tutup tab",
1154
- breadcrumb: "Navigasi remah roti"
1164
+ breadcrumb: "Navigasi remah roti",
1165
+ confirm: "Konfirmasi",
1166
+ cancel: "Batal"
1155
1167
  },
1156
1168
  "../assets/locales/ja.json": {
1157
1169
  valueMissing: "この項目は必須です",
@@ -1192,7 +1204,9 @@ var l = r`
1192
1204
  alertMessage: "メッセージ",
1193
1205
  remove: "削除",
1194
1206
  closeTab: "タブを閉じる",
1195
- breadcrumb: "パンくずリスト"
1207
+ breadcrumb: "パンくずリスト",
1208
+ confirm: "OK",
1209
+ cancel: "キャンセル"
1196
1210
  },
1197
1211
  "../assets/locales/ko.json": {
1198
1212
  valueMissing: "필수 항목입니다",
@@ -1233,7 +1247,9 @@ var l = r`
1233
1247
  alertMessage: "메시지",
1234
1248
  remove: "제거",
1235
1249
  closeTab: "탭 닫기",
1236
- breadcrumb: "탐색 경로"
1250
+ breadcrumb: "탐색 경로",
1251
+ confirm: "확인",
1252
+ cancel: "취소"
1237
1253
  },
1238
1254
  "../assets/locales/pt-BR.json": {
1239
1255
  valueMissing: "Este campo é obrigatório",
@@ -1274,7 +1290,9 @@ var l = r`
1274
1290
  alertMessage: "Mensagem",
1275
1291
  remove: "Remover",
1276
1292
  closeTab: "Fechar aba",
1277
- breadcrumb: "Trilha de navegação"
1293
+ breadcrumb: "Trilha de navegação",
1294
+ confirm: "Confirmar",
1295
+ cancel: "Cancelar"
1278
1296
  },
1279
1297
  "../assets/locales/ru.json": {
1280
1298
  valueMissing: "Это поле обязательно для заполнения",
@@ -1315,7 +1333,9 @@ var l = r`
1315
1333
  alertMessage: "Сообщение",
1316
1334
  remove: "Удалить",
1317
1335
  closeTab: "Закрыть вкладку",
1318
- breadcrumb: "Навигационная цепочка"
1336
+ breadcrumb: "Навигационная цепочка",
1337
+ confirm: "Подтвердить",
1338
+ cancel: "Отмена"
1319
1339
  },
1320
1340
  "../assets/locales/th.json": {
1321
1341
  valueMissing: "จำเป็นต้องกรอกข้อมูลนี้",
@@ -1356,7 +1376,9 @@ var l = r`
1356
1376
  alertMessage: "ข้อความ",
1357
1377
  remove: "ลบ",
1358
1378
  closeTab: "ปิดแท็บ",
1359
- breadcrumb: "เส้นทางการนำทาง"
1379
+ breadcrumb: "เส้นทางการนำทาง",
1380
+ confirm: "ยืนยัน",
1381
+ cancel: "ยกเลิก"
1360
1382
  },
1361
1383
  "../assets/locales/vi.json": {
1362
1384
  valueMissing: "Trường này là bắt buộc",
@@ -1397,7 +1419,9 @@ var l = r`
1397
1419
  alertMessage: "Thông báo",
1398
1420
  remove: "Xóa",
1399
1421
  closeTab: "Đóng tab",
1400
- breadcrumb: "Đường dẫn điều hướng"
1422
+ breadcrumb: "Đường dẫn điều hướng",
1423
+ confirm: "Xác nhận",
1424
+ cancel: "Hủy"
1401
1425
  },
1402
1426
  "../assets/locales/zh-CN.json": {
1403
1427
  valueMissing: "此项为必填项",
@@ -1438,7 +1462,9 @@ var l = r`
1438
1462
  alertMessage: "消息",
1439
1463
  remove: "移除",
1440
1464
  closeTab: "关闭标签页",
1441
- breadcrumb: "面包屑导航"
1465
+ breadcrumb: "面包屑导航",
1466
+ confirm: "确定",
1467
+ cancel: "取消"
1442
1468
  },
1443
1469
  "../assets/locales/zh-TW.json": {
1444
1470
  valueMissing: "此欄位為必填",
@@ -1479,7 +1505,9 @@ var l = r`
1479
1505
  alertMessage: "訊息",
1480
1506
  remove: "移除",
1481
1507
  closeTab: "關閉分頁",
1482
- breadcrumb: "麵包屑導覽"
1508
+ breadcrumb: "麵包屑導覽",
1509
+ confirm: "確定",
1510
+ cancel: "取消"
1483
1511
  }
1484
1512
  })).map(([e, t]) => [(e.split("/").pop()?.replace(".json", "") || "").toLowerCase(), t])), d = /* @__PURE__ */ new Map();
1485
1513
  function f() {
@@ -1600,7 +1628,7 @@ function ee(e, t) {
1600
1628
  case "number": return re(e);
1601
1629
  case "boolean": return i`<span class="ft-bool">${e ? "✔" : ""}</span>`;
1602
1630
  case "date": return ie(e);
1603
- case "datetime": return O(e);
1631
+ case "datetime": return ae(e);
1604
1632
  case "select": return te(e, t);
1605
1633
  default: return String(e);
1606
1634
  }
@@ -1624,13 +1652,13 @@ function re(e) {
1624
1652
  function ie(e) {
1625
1653
  return e instanceof Date || typeof e == "string" ? E(e) : String(e);
1626
1654
  }
1627
- function O(e) {
1655
+ function ae(e) {
1628
1656
  return e instanceof Date || typeof e == "string" ? E(e, ne) : String(e);
1629
1657
  }
1630
1658
  //#endregion
1631
1659
  //#region src/locale.ts
1632
- var k = v.namespace("flex-table");
1633
- k.register("en", {
1660
+ var O = v.namespace("flex-table");
1661
+ O.register("en", {
1634
1662
  showHiddenColumns: "Show hidden column(s)",
1635
1663
  columnMenu: "Column menu",
1636
1664
  cellActions: "Cell actions",
@@ -1683,7 +1711,7 @@ k.register("en", {
1683
1711
  booleanTrue: "True",
1684
1712
  booleanFalse: "False",
1685
1713
  dropFileToImport: "Drop file to import (.xlsx / .csv)"
1686
- }), k.register("ko", {
1714
+ }), O.register("ko", {
1687
1715
  showHiddenColumns: "숨긴 열 보기",
1688
1716
  columnMenu: "열 메뉴",
1689
1717
  cellActions: "셀 작업",
@@ -1737,10 +1765,10 @@ k.register("en", {
1737
1765
  booleanFalse: "거짓",
1738
1766
  dropFileToImport: "가져올 파일을 놓으세요 (.xlsx / .csv)"
1739
1767
  });
1740
- var A = (e, t) => k.text(e, t);
1768
+ var k = (e, t) => O.text(e, t);
1741
1769
  //#endregion
1742
1770
  //#region src/core/selection.ts
1743
- function ae(e) {
1771
+ function oe(e) {
1744
1772
  return {
1745
1773
  startRow: Math.min(e.startRow, e.endRow),
1746
1774
  startCol: Math.min(e.startCol, e.endCol),
@@ -1748,7 +1776,7 @@ function ae(e) {
1748
1776
  endCol: Math.max(e.startCol, e.endCol)
1749
1777
  };
1750
1778
  }
1751
- var oe = class {
1779
+ var se = class {
1752
1780
  constructor() {
1753
1781
  this.activeCell = null, this.rangeAnchor = null, this.range = null, this.extraRanges = [], this._rowCount = 0, this._colCount = 0;
1754
1782
  }
@@ -1775,7 +1803,7 @@ var oe = class {
1775
1803
  return e < 0 || e >= this._rowCount || t < 0 || t >= this._colCount ? this.activeCell : (!this.rangeAnchor && this.activeCell && (this.rangeAnchor = { ...this.activeCell }), this.activeCell = {
1776
1804
  row: e,
1777
1805
  col: t
1778
- }, this.rangeAnchor && (this.range = ae({
1806
+ }, this.rangeAnchor && (this.range = oe({
1779
1807
  startRow: this.rangeAnchor.row,
1780
1808
  startCol: this.rangeAnchor.col,
1781
1809
  endRow: e,
@@ -1846,7 +1874,7 @@ var oe = class {
1846
1874
  shiftMoveRight() {
1847
1875
  return this.activeCell ? this.setActiveWithRange(this.activeCell.row, this.activeCell.col + 1) : null;
1848
1876
  }
1849
- }, se = class {
1877
+ }, A = class {
1850
1878
  constructor() {
1851
1879
  this.current = null;
1852
1880
  }
@@ -1986,7 +2014,7 @@ var le = 100, M = class {
1986
2014
  };
1987
2015
  //#endregion
1988
2016
  //#region src/clipboard/clipboard.ts
1989
- function N(e, t, n) {
2017
+ function ue(e, t, n) {
1990
2018
  let r = [];
1991
2019
  for (let i = n.startRow; i <= n.endRow; i++) {
1992
2020
  let a = e[i], o = [];
@@ -1998,7 +2026,7 @@ function N(e, t, n) {
1998
2026
  }
1999
2027
  return r.join("\n");
2000
2028
  }
2001
- function P(e) {
2029
+ function N(e) {
2002
2030
  let t = e.replace(/\r\n/g, "\n").replace(/\r/g, "\n"), n = [], r = [], i = 0, a = t.length;
2003
2031
  for (; i <= a;) {
2004
2032
  if (i === a) {
@@ -2028,7 +2056,7 @@ function P(e) {
2028
2056
  }
2029
2057
  return n;
2030
2058
  }
2031
- function F(e, t) {
2059
+ function P(e, t) {
2032
2060
  if (e === "") return null;
2033
2061
  switch (t.type) {
2034
2062
  case "number": {
@@ -2041,7 +2069,7 @@ function F(e, t) {
2041
2069
  }
2042
2070
  //#endregion
2043
2071
  //#region src/export/xlsx-writer.ts
2044
- var ue = (() => {
2072
+ var de = (() => {
2045
2073
  let e = /* @__PURE__ */ new Uint32Array(256);
2046
2074
  for (let t = 0; t < 256; t++) {
2047
2075
  let n = t;
@@ -2050,56 +2078,56 @@ var ue = (() => {
2050
2078
  }
2051
2079
  return e;
2052
2080
  })();
2053
- function de(e) {
2081
+ function fe(e) {
2054
2082
  let t = 4294967295;
2055
- for (let n = 0; n < e.length; n++) t = ue[(t ^ e[n]) & 255] ^ t >>> 8;
2083
+ for (let n = 0; n < e.length; n++) t = de[(t ^ e[n]) & 255] ^ t >>> 8;
2056
2084
  return (t ^ 4294967295) >>> 0;
2057
2085
  }
2058
- var I = new TextEncoder();
2059
- function fe(e) {
2086
+ var F = new TextEncoder();
2087
+ function pe(e) {
2060
2088
  let t = [], n = [], r = 0;
2061
2089
  for (let i of e) {
2062
- let e = I.encode(i.name), a = de(i.data), o = i.data.length, s = new ArrayBuffer(30 + e.length), c = new DataView(s);
2090
+ let e = F.encode(i.name), a = fe(i.data), o = i.data.length, s = new ArrayBuffer(30 + e.length), c = new DataView(s);
2063
2091
  c.setUint32(0, 67324752, !0), c.setUint16(4, 20, !0), c.setUint16(6, 0, !0), c.setUint16(8, 0, !0), c.setUint16(10, 0, !0), c.setUint16(12, 33, !0), c.setUint32(14, a, !0), c.setUint32(18, o, !0), c.setUint32(22, o, !0), c.setUint16(26, e.length, !0), c.setUint16(28, 0, !0), new Uint8Array(s, 30).set(e), t.push(new Uint8Array(s)), t.push(i.data);
2064
2092
  let l = new ArrayBuffer(46 + e.length), u = new DataView(l);
2065
2093
  u.setUint32(0, 33639248, !0), u.setUint16(4, 20, !0), u.setUint16(6, 20, !0), u.setUint16(8, 0, !0), u.setUint16(10, 0, !0), u.setUint16(12, 0, !0), u.setUint16(14, 33, !0), u.setUint32(16, a, !0), u.setUint32(20, o, !0), u.setUint32(24, o, !0), u.setUint16(28, e.length, !0), u.setUint16(30, 0, !0), u.setUint16(32, 0, !0), u.setUint16(34, 0, !0), u.setUint16(36, 0, !0), u.setUint32(38, 0, !0), u.setUint32(42, r, !0), new Uint8Array(l, 46).set(e), n.push(new Uint8Array(l)), r += 30 + e.length + o;
2066
2094
  }
2067
- let i = L(n), a = /* @__PURE__ */ new ArrayBuffer(22), o = new DataView(a);
2068
- return o.setUint32(0, 101010256, !0), o.setUint16(4, 0, !0), o.setUint16(6, 0, !0), o.setUint16(8, e.length, !0), o.setUint16(10, e.length, !0), o.setUint32(12, i.length, !0), o.setUint32(16, r, !0), o.setUint16(20, 0, !0), L([
2095
+ let i = I(n), a = /* @__PURE__ */ new ArrayBuffer(22), o = new DataView(a);
2096
+ return o.setUint32(0, 101010256, !0), o.setUint16(4, 0, !0), o.setUint16(6, 0, !0), o.setUint16(8, e.length, !0), o.setUint16(10, e.length, !0), o.setUint32(12, i.length, !0), o.setUint32(16, r, !0), o.setUint16(20, 0, !0), I([
2069
2097
  ...t,
2070
2098
  i,
2071
2099
  new Uint8Array(a)
2072
2100
  ]);
2073
2101
  }
2074
- function L(e) {
2102
+ function I(e) {
2075
2103
  let t = e.reduce((e, t) => e + t.length, 0), n = new Uint8Array(t), r = 0;
2076
2104
  for (let t of e) n.set(t, r), r += t.length;
2077
2105
  return n;
2078
2106
  }
2079
- function R(e) {
2107
+ function L(e) {
2080
2108
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2081
2109
  }
2082
- function z(e) {
2110
+ function R(e) {
2083
2111
  let t = "";
2084
2112
  for (e++; e > 0;) t = String.fromCharCode(64 + (e % 26 || 26)) + t, e = Math.floor((e - 1) / 26);
2085
2113
  return t;
2086
2114
  }
2087
- function B(e, t) {
2088
- return z(t) + (e + 1);
2115
+ function z(e, t) {
2116
+ return R(t) + (e + 1);
2089
2117
  }
2090
- function V(e) {
2118
+ function B(e) {
2091
2119
  let t = Date.UTC(1899, 11, 30);
2092
2120
  return (e.getTime() - t) / 864e5;
2093
2121
  }
2094
- var pe = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n <Default Extension=\"xml\" ContentType=\"application/xml\"/>\n <Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/>\n <Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/>\n <Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/>\n</Types>", me = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>\n</Relationships>", he = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\n <sheets><sheet name=\"Sheet1\" sheetId=\"1\" r:id=\"rId1\"/></sheets>\n</workbook>", ge = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>\n <Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>\n</Relationships>", _e = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">\n <numFmts count=\"1\"><numFmt numFmtId=\"164\" formatCode=\"yyyy-mm-dd\"/></numFmts>\n <fonts count=\"2\">\n <font><sz val=\"11\"/><name val=\"Calibri\"/></font>\n <font><sz val=\"11\"/><b/><name val=\"Calibri\"/></font>\n </fonts>\n <fills count=\"2\">\n <fill><patternFill patternType=\"none\"/></fill>\n <fill><patternFill patternType=\"gray125\"/></fill>\n </fills>\n <borders count=\"1\"><border><left/><right/><top/><bottom/><diagonal/></border></borders>\n <cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/></cellStyleXfs>\n <cellXfs count=\"3\">\n <xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/>\n <xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyNumberFormat=\"1\"/>\n <xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\"/>\n </cellXfs>\n</styleSheet>";
2095
- function ve(e, t) {
2096
- let n = [], r = t.map((e, t) => `<c r="${B(0, t)}" t="str" s="2"><v>${R(e.header)}</v></c>`);
2122
+ var me = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n <Default Extension=\"xml\" ContentType=\"application/xml\"/>\n <Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/>\n <Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/>\n <Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/>\n</Types>", he = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>\n</Relationships>", ge = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\n <sheets><sheet name=\"Sheet1\" sheetId=\"1\" r:id=\"rId1\"/></sheets>\n</workbook>", _e = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>\n <Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>\n</Relationships>", ve = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">\n <numFmts count=\"1\"><numFmt numFmtId=\"164\" formatCode=\"yyyy-mm-dd\"/></numFmts>\n <fonts count=\"2\">\n <font><sz val=\"11\"/><name val=\"Calibri\"/></font>\n <font><sz val=\"11\"/><b/><name val=\"Calibri\"/></font>\n </fonts>\n <fills count=\"2\">\n <fill><patternFill patternType=\"none\"/></fill>\n <fill><patternFill patternType=\"gray125\"/></fill>\n </fills>\n <borders count=\"1\"><border><left/><right/><top/><bottom/><diagonal/></border></borders>\n <cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/></cellStyleXfs>\n <cellXfs count=\"3\">\n <xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/>\n <xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyNumberFormat=\"1\"/>\n <xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"0\" xfId=\"0\" applyFont=\"1\"/>\n </cellXfs>\n</styleSheet>";
2123
+ function ye(e, t) {
2124
+ let n = [], r = t.map((e, t) => `<c r="${z(0, t)}" t="str" s="2"><v>${L(e.header)}</v></c>`);
2097
2125
  return n.push(`<row r="1">${r.join("")}</row>`), e.forEach((e, r) => {
2098
2126
  let i = t.map((t, n) => {
2099
- let i = B(r + 1, n), a = e[t.key];
2127
+ let i = z(r + 1, n), a = e[t.key];
2100
2128
  if (a == null) return `<c r="${i}" t="str"><v></v></c>`;
2101
2129
  let o = t.type ?? "text";
2102
- return o === "number" && typeof a == "number" ? `<c r="${i}"><v>${a}</v></c>` : (o === "date" || o === "datetime") && a instanceof Date ? `<c r="${i}" s="1"><v>${V(a).toFixed(6)}</v></c>` : o === "boolean" ? `<c r="${i}" t="b"><v>${+!!a}</v></c>` : `<c r="${i}" t="str"><v>${R(String(a))}</v></c>`;
2130
+ return o === "number" && typeof a == "number" ? `<c r="${i}"><v>${a}</v></c>` : (o === "date" || o === "datetime") && a instanceof Date ? `<c r="${i}" s="1"><v>${B(a).toFixed(6)}</v></c>` : o === "boolean" ? `<c r="${i}" t="b"><v>${+!!a}</v></c>` : `<c r="${i}" t="str"><v>${L(String(a))}</v></c>`;
2103
2131
  });
2104
2132
  n.push(`<row r="${r + 2}">${i.join("")}</row>`);
2105
2133
  }), `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -2107,55 +2135,55 @@ function ve(e, t) {
2107
2135
  <sheetData>${n.join("")}</sheetData>
2108
2136
  </worksheet>`;
2109
2137
  }
2110
- function ye(e, t) {
2111
- let n = ve(e, t);
2112
- return fe([
2138
+ function be(e, t) {
2139
+ let n = ye(e, t);
2140
+ return pe([
2113
2141
  {
2114
2142
  name: "[Content_Types].xml",
2115
- data: I.encode(pe)
2143
+ data: F.encode(me)
2116
2144
  },
2117
2145
  {
2118
2146
  name: "_rels/.rels",
2119
- data: I.encode(me)
2147
+ data: F.encode(he)
2120
2148
  },
2121
2149
  {
2122
2150
  name: "xl/workbook.xml",
2123
- data: I.encode(he)
2151
+ data: F.encode(ge)
2124
2152
  },
2125
2153
  {
2126
2154
  name: "xl/_rels/workbook.xml.rels",
2127
- data: I.encode(ge)
2155
+ data: F.encode(_e)
2128
2156
  },
2129
2157
  {
2130
2158
  name: "xl/worksheets/sheet1.xml",
2131
- data: I.encode(n)
2159
+ data: F.encode(n)
2132
2160
  },
2133
2161
  {
2134
2162
  name: "xl/styles.xml",
2135
- data: I.encode(_e)
2163
+ data: F.encode(ve)
2136
2164
  }
2137
2165
  ]);
2138
2166
  }
2139
2167
  //#endregion
2140
2168
  //#region src/export/export.ts
2141
- function H(e, t, n) {
2169
+ function V(e, t, n) {
2142
2170
  switch (n) {
2143
- case "csv": return U(e, t, ",");
2144
- case "tsv": return U(e, t, " ");
2145
- case "json": return xe(e, t);
2146
- case "xlsx": return ye(e, t);
2171
+ case "csv": return H(e, t, ",");
2172
+ case "tsv": return H(e, t, " ");
2173
+ case "json": return Se(e, t);
2174
+ case "xlsx": return be(e, t);
2147
2175
  }
2148
2176
  }
2149
- function be(e, t) {
2177
+ function xe(e, t) {
2150
2178
  return e == null ? "" : (t.type === "date" || t.type === "datetime") && e instanceof Date ? e.toISOString() : String(e);
2151
2179
  }
2152
- function U(e, t, n) {
2153
- return [t.map((e) => W(e.header, n)).join(n), ...e.map((e) => t.map((t) => W(be(e[t.key], t), n)).join(n))].join("\n");
2180
+ function H(e, t, n) {
2181
+ return [t.map((e) => U(e.header, n)).join(n), ...e.map((e) => t.map((t) => U(xe(e[t.key], t), n)).join(n))].join("\n");
2154
2182
  }
2155
- function W(e, t) {
2183
+ function U(e, t) {
2156
2184
  return e.includes(t) || e.includes("\"") || e.includes("\n") || e.includes("\r") ? "\"" + e.replace(/"/g, "\"\"") + "\"" : e;
2157
2185
  }
2158
- function xe(e, t) {
2186
+ function Se(e, t) {
2159
2187
  let n = e.map((e) => {
2160
2188
  let n = {};
2161
2189
  for (let r of t) {
@@ -2166,35 +2194,35 @@ function xe(e, t) {
2166
2194
  });
2167
2195
  return JSON.stringify(n, null, 2);
2168
2196
  }
2169
- function Se(e, t, n) {
2197
+ function Ce(e, t, n) {
2170
2198
  let r = new Blob([e], { type: n }), i = URL.createObjectURL(r), a = document.createElement("a");
2171
2199
  a.href = i, a.download = t, a.style.display = "none", document.body.appendChild(a), a.click(), document.body.removeChild(a), setTimeout(() => URL.revokeObjectURL(i), 100);
2172
2200
  }
2173
- var Ce = {
2201
+ var we = {
2174
2202
  csv: "text/csv;charset=utf-8",
2175
2203
  tsv: "text/tab-separated-values;charset=utf-8",
2176
2204
  json: "application/json;charset=utf-8",
2177
2205
  xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
2178
- }, we = {
2206
+ }, Te = {
2179
2207
  csv: ".csv",
2180
2208
  tsv: ".tsv",
2181
2209
  json: ".json",
2182
2210
  xlsx: ".xlsx"
2183
2211
  };
2184
- function Te(e) {
2185
- return Ce[e];
2186
- }
2187
2212
  function Ee(e) {
2188
2213
  return we[e];
2189
2214
  }
2215
+ function De(e) {
2216
+ return Te[e];
2217
+ }
2190
2218
  //#endregion
2191
2219
  //#region src/export/xlsx-reader.ts
2192
- function De(e) {
2220
+ function Oe(e) {
2193
2221
  for (let t = e.byteLength - 22; t >= 0; t--) if (e.getUint32(t, !0) === 101010256) return t;
2194
2222
  throw Error("XLSX: End of central directory not found — not a valid ZIP file");
2195
2223
  }
2196
- function Oe(e) {
2197
- let t = De(e), n = e.getUint32(t + 16, !0), r = e.getUint32(t + 12, !0), i = new TextDecoder("utf-8"), a = [], o = n, s = n + r;
2224
+ function ke(e) {
2225
+ let t = Oe(e), n = e.getUint32(t + 16, !0), r = e.getUint32(t + 12, !0), i = new TextDecoder("utf-8"), a = [], o = n, s = n + r;
2198
2226
  for (; o < s && e.getUint32(o, !0) === 33639248;) {
2199
2227
  let t = e.getUint16(o + 10, !0), n = e.getUint32(o + 20, !0), r = e.getUint32(o + 24, !0), s = e.getUint16(o + 28, !0), c = e.getUint16(o + 30, !0), l = e.getUint16(o + 32, !0), u = e.getUint32(o + 42, !0), d = i.decode(new Uint8Array(e.buffer, o + 46, s));
2200
2228
  a.push({
@@ -2207,7 +2235,7 @@ function Oe(e) {
2207
2235
  }
2208
2236
  return a;
2209
2237
  }
2210
- async function ke(e) {
2238
+ async function Ae(e) {
2211
2239
  let t = new DecompressionStream("deflate-raw"), n = t.writable.getWriter(), r = t.readable.getReader();
2212
2240
  n.write(e), n.close();
2213
2241
  let i = [];
@@ -2220,69 +2248,107 @@ async function ke(e) {
2220
2248
  for (let e of i) o.set(e, s), s += e.length;
2221
2249
  return o;
2222
2250
  }
2223
- async function Ae(e, t) {
2251
+ async function je(e, t) {
2224
2252
  let n = t.localHeaderOffset, r = e.getUint16(n + 26, !0), i = e.getUint16(n + 28, !0), a = n + 30 + r + i, o = new Uint8Array(e.buffer, a, t.compressedSize);
2225
2253
  if (t.compressionMethod === 0) return o.slice();
2226
- if (t.compressionMethod === 8) return ke(o);
2254
+ if (t.compressionMethod === 8) return Ae(o);
2227
2255
  throw Error(`XLSX: Unsupported compression method ${t.compressionMethod}`);
2228
2256
  }
2229
- async function je(e) {
2230
- let t = new DataView(e), n = Oe(t), r = /* @__PURE__ */ new Map();
2231
- for (let e of n) e.compressedSize === 0 && e.name.endsWith("/") || r.set(e.name, await Ae(t, e));
2257
+ async function Me(e) {
2258
+ let t = new DataView(e), n = ke(t), r = /* @__PURE__ */ new Map();
2259
+ for (let e of n) e.compressedSize === 0 && e.name.endsWith("/") || r.set(e.name, await je(t, e));
2232
2260
  return r;
2233
2261
  }
2234
- var Me = new TextDecoder("utf-8");
2235
- function G(e) {
2236
- let t = Me.decode(e);
2262
+ var Ne = new TextDecoder("utf-8");
2263
+ function W(e) {
2264
+ let t = Ne.decode(e);
2237
2265
  return new DOMParser().parseFromString(t, "application/xml");
2238
2266
  }
2239
- function Ne(e) {
2267
+ function Pe(e) {
2240
2268
  if (!e) return [];
2241
- let t = G(e);
2269
+ let t = W(e);
2242
2270
  return Array.from(t.querySelectorAll("si")).map((e) => Array.from(e.querySelectorAll("t")).map((e) => e.textContent ?? "").join(""));
2243
2271
  }
2244
- function Pe(e) {
2245
- let t = (e - 1) * 864e5 + Date.UTC(1899, 11, 30);
2246
- return new Date(t).toISOString().slice(0, 10);
2272
+ var Fe = /* @__PURE__ */ new Set([
2273
+ 14,
2274
+ 15,
2275
+ 16,
2276
+ 17,
2277
+ 22,
2278
+ 27,
2279
+ 28,
2280
+ 29,
2281
+ 30,
2282
+ 31,
2283
+ 36,
2284
+ 50,
2285
+ 51,
2286
+ 52,
2287
+ 53,
2288
+ 54,
2289
+ 57,
2290
+ 58
2291
+ ]);
2292
+ function Ie(e) {
2293
+ let t = e.replace(/"[^"]*"/g, "").replace(/\\./g, "").replace(/\[[^\]]*\]/g, "").split(";")[0];
2294
+ return /[dy]/i.test(t);
2295
+ }
2296
+ function Le(e) {
2297
+ let t = /* @__PURE__ */ new Set();
2298
+ if (!e) return t;
2299
+ let n = W(e), r = /* @__PURE__ */ new Map();
2300
+ for (let e of Array.from(n.querySelectorAll("numFmts > numFmt"))) r.set(parseInt(e.getAttribute("numFmtId") ?? "", 10), e.getAttribute("formatCode") ?? "");
2301
+ return Array.from(n.querySelectorAll("cellXfs > xf")).forEach((e, n) => {
2302
+ let i = parseInt(e.getAttribute("numFmtId") ?? "0", 10), a = r.get(i);
2303
+ (a === void 0 ? Fe.has(i) : Ie(a)) && t.add(n);
2304
+ }), t;
2305
+ }
2306
+ function Re(e) {
2307
+ if (!e) return !1;
2308
+ let t = W(e).querySelector("workbookPr")?.getAttribute("date1904");
2309
+ return t === "1" || t === "true";
2310
+ }
2311
+ function ze(e, t) {
2312
+ return new Date((t ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30)) + Math.floor(e) * 864e5).toISOString().slice(0, 10);
2247
2313
  }
2248
- function Fe(e, t) {
2249
- let n = G(e).querySelectorAll("row");
2250
- if (n.length === 0) return [];
2251
- let r = 0, i = /* @__PURE__ */ new Map();
2252
- for (let e of n) {
2253
- let n = parseInt(e.getAttribute("r") ?? "1", 10) - 1, a = /* @__PURE__ */ new Map();
2254
- i.set(n, a);
2255
- for (let n of e.querySelectorAll("c")) {
2256
- let e = Ie(n.getAttribute("r") ?? "");
2257
- e > r && (r = e);
2258
- let i = n.getAttribute("t") ?? "", o = n.getAttribute("s") ?? "", s = n.querySelector("v")?.textContent ?? "", c = n.querySelector("is > t")?.textContent ?? null, l;
2259
- if (i === "s") l = t[parseInt(s, 10)] ?? "";
2260
- else if (i === "str" || i === "inlineStr") l = c ?? s;
2261
- else if (i === "b") l = s === "1" ? "true" : "false";
2262
- else if (s === "") l = "";
2314
+ function Be(e, t, n, r) {
2315
+ let i = W(e).querySelectorAll("row");
2316
+ if (i.length === 0) return [];
2317
+ let a = 0, o = /* @__PURE__ */ new Map();
2318
+ for (let e of i) {
2319
+ let i = parseInt(e.getAttribute("r") ?? "1", 10) - 1, s = /* @__PURE__ */ new Map();
2320
+ o.set(i, s);
2321
+ for (let i of e.querySelectorAll("c")) {
2322
+ let e = Ve(i.getAttribute("r") ?? "");
2323
+ e > a && (a = e);
2324
+ let o = i.getAttribute("t") ?? "", c = i.getAttribute("s") ?? "", l = i.querySelector("v")?.textContent ?? "", u = i.querySelector("is > t")?.textContent ?? null, d;
2325
+ if (o === "s") d = t[parseInt(l, 10)] ?? "";
2326
+ else if (o === "str" || o === "inlineStr") d = u ?? l;
2327
+ else if (o === "b") d = l === "1" ? "true" : "false";
2328
+ else if (l === "") d = "";
2263
2329
  else {
2264
- let e = parseFloat(s);
2265
- l = !isNaN(e) && o !== "" && parseInt(o, 10) > 0 && e >= 1 && e <= 73050 ? Pe(e) : s;
2330
+ let e = parseFloat(l);
2331
+ d = c !== "" && n.has(parseInt(c, 10)) && !isNaN(e) && e >= 0 ? ze(e, r) : l;
2266
2332
  }
2267
- a.set(e, l);
2333
+ s.set(e, d);
2268
2334
  }
2269
2335
  }
2270
- if (i.size === 0) return [];
2271
- let a = Math.max(...i.keys()), o = [];
2272
- for (let e = 0; e <= a; e++) {
2273
- let t = i.get(e) ?? /* @__PURE__ */ new Map(), n = [];
2274
- for (let e = 0; e <= r; e++) n.push(t.get(e) ?? "");
2275
- o.push(n);
2336
+ if (o.size === 0) return [];
2337
+ let s = Math.max(...o.keys()), c = [];
2338
+ for (let e = 0; e <= s; e++) {
2339
+ let t = o.get(e) ?? /* @__PURE__ */ new Map(), n = [];
2340
+ for (let e = 0; e <= a; e++) n.push(t.get(e) ?? "");
2341
+ c.push(n);
2276
2342
  }
2277
- return o;
2343
+ return c;
2278
2344
  }
2279
- function Ie(e) {
2345
+ function Ve(e) {
2280
2346
  let t = 0, n = 0;
2281
2347
  for (; n < e.length && e[n] >= "A" && e[n] <= "Z";) t = t * 26 + (e.charCodeAt(n) - 64), n++;
2282
2348
  return t - 1;
2283
2349
  }
2284
- async function Le(e) {
2285
- let t = await je(e), n = Ne(t.get("xl/sharedStrings.xml")), r = t.get("xl/worksheets/sheet1.xml");
2350
+ async function G(e) {
2351
+ let t = await Me(e), n = Pe(t.get("xl/sharedStrings.xml")), r = t.get("xl/worksheets/sheet1.xml");
2286
2352
  if (!r) {
2287
2353
  for (let [e, n] of t) if (e.toLowerCase().includes("worksheets/sheet")) {
2288
2354
  r = n;
@@ -2290,13 +2356,13 @@ async function Le(e) {
2290
2356
  }
2291
2357
  }
2292
2358
  if (!r) throw Error("XLSX: No worksheet found");
2293
- let i = Fe(r, n);
2294
- return i.length === 0 ? {
2359
+ let i = Le(t.get("xl/styles.xml")), a = Re(t.get("xl/workbook.xml")), o = Be(r, n, i, a);
2360
+ return o.length === 0 ? {
2295
2361
  headers: [],
2296
2362
  rows: []
2297
2363
  } : {
2298
- headers: i[0],
2299
- rows: i.slice(1)
2364
+ headers: o[0],
2365
+ rows: o.slice(1)
2300
2366
  };
2301
2367
  }
2302
2368
  //#endregion
@@ -2316,9 +2382,9 @@ var q = {
2316
2382
  lt: "<",
2317
2383
  gte: "≥",
2318
2384
  lte: "≤"
2319
- }, J = 120, Y = 40, X = 20, Z = 32, Q = 5, Re = 200, $ = class extends n {
2385
+ }, J = 120, Y = 40, X = 20, Z = 32, Q = 5, He = 200, $ = class extends n {
2320
2386
  constructor(...e) {
2321
- super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = Z, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.emptyMessage = "No data", this.noMatchingMessage = "No matching data", this.loading = !1, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this.stylesheets = [], this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._baseStyleSheets = [], this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new oe(), this._editing = new se(), this._rowSelection = new j(), this._undo = new M(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._lastCheckboxRowIndex = null, this._checkboxShiftPending = !1, this._autocompleteState = null, this._headerMenu = null, this._bodyContextMenu = null, this._commentPopup = null, this._viewDirty = !0, this._isDragging = !1, this._wasDrag = !1, this._resizing = null, this._resizeCleanup = null, this._wasHeaderDrag = !1, this._wasRowDrag = !1, this._colDrag = null, this._colDragIndicatorLeft = null, this._fillDrag = null, this._rowDrag = null, this._rowDragIndicatorY = null, this._findState = null, this._columnWidths = /* @__PURE__ */ new Map(), this._hostResizeObserver = null, this._comments = /* @__PURE__ */ new Map(), this._isDragOver = !1, this._warnedUnconstrained = !1, this._onCommentPopupOutsideClick = () => {
2387
+ super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = Z, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.emptyMessage = "No data", this.noMatchingMessage = "No matching data", this.loading = !1, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this.stylesheets = [], this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._baseStyleSheets = [], this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new se(), this._editing = new A(), this._rowSelection = new j(), this._undo = new M(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._lastCheckboxRowIndex = null, this._checkboxShiftPending = !1, this._autocompleteState = null, this._headerMenu = null, this._bodyContextMenu = null, this._commentPopup = null, this._viewDirty = !0, this._isDragging = !1, this._wasDrag = !1, this._resizing = null, this._resizeCleanup = null, this._wasHeaderDrag = !1, this._wasRowDrag = !1, this._colDrag = null, this._colDragIndicatorLeft = null, this._fillDrag = null, this._rowDrag = null, this._rowDragIndicatorY = null, this._findState = null, this._columnWidths = /* @__PURE__ */ new Map(), this._hostResizeObserver = null, this._comments = /* @__PURE__ */ new Map(), this._isDragOver = !1, this._warnedUnconstrained = !1, this._onCommentPopupOutsideClick = () => {
2322
2388
  this._commitCommentPopup();
2323
2389
  }, this._invalidCells = /* @__PURE__ */ new Map(), this._textFilterState = /* @__PURE__ */ new Map(), this._numberFilterState = /* @__PURE__ */ new Map(), this._dateFilterState = /* @__PURE__ */ new Map(), this._emptyFilterState = /* @__PURE__ */ new Map();
2324
2390
  }
@@ -2683,12 +2749,12 @@ var q = {
2683
2749
  if (!t) return "";
2684
2750
  let n = this.visibleColumns.slice(t.startCol, t.endCol + 1), r = [];
2685
2751
  for (let e = t.startRow; e <= t.endRow; e++) r.push(this.data[this._toDataIndex(e)]);
2686
- return H(r, n, e);
2752
+ return V(r, n, e);
2687
2753
  }
2688
- return H(this._sortedIndices.map((e) => this.data[e]), this.visibleColumns, e);
2754
+ return V(this._sortedIndices.map((e) => this.data[e]), this.visibleColumns, e);
2689
2755
  }
2690
2756
  exportToFile(e, t) {
2691
- Se(this.exportToString(e), t ?? `export${Ee(e)}`, Te(e));
2757
+ Ce(this.exportToString(e), t ?? `export${De(e)}`, Ee(e));
2692
2758
  }
2693
2759
  setComment(e, t, n) {
2694
2760
  let r = this.getComment(e, t);
@@ -2745,10 +2811,10 @@ var q = {
2745
2811
  async importFromFile(e) {
2746
2812
  let t = e.name.toLowerCase();
2747
2813
  if (t.endsWith(".xlsx")) {
2748
- let t = await Le(await e.arrayBuffer());
2814
+ let t = await G(await e.arrayBuffer());
2749
2815
  this._applyImportedSheet(t);
2750
2816
  } else if (t.endsWith(".csv") || t.endsWith(".tsv")) {
2751
- let t = P(await e.text());
2817
+ let t = N(await e.text());
2752
2818
  this._applyImportedRows(t);
2753
2819
  } else console.warn(`flex-table importFromFile: unsupported file type "${e.name}"`);
2754
2820
  }
@@ -2759,7 +2825,7 @@ var q = {
2759
2825
  let a = t.get(e);
2760
2826
  if (!a) return;
2761
2827
  let o = this.columns.find((e) => e.key === a);
2762
- r[a] = o ? F(n[i] ?? "", o) : n[i] ?? null;
2828
+ r[a] = o ? P(n[i] ?? "", o) : n[i] ?? null;
2763
2829
  }), r;
2764
2830
  }), r = [...this.data];
2765
2831
  this.data = n, this._undo.push({
@@ -2784,7 +2850,7 @@ var q = {
2784
2850
  let a = n.get(t);
2785
2851
  if (!a) return;
2786
2852
  let o = this.columns.find((e) => e.key === a);
2787
- r[a] = o ? F(e[i] ?? "", o) : e[i] ?? null;
2853
+ r[a] = o ? P(e[i] ?? "", o) : e[i] ?? null;
2788
2854
  }), r;
2789
2855
  }), i = [...this.data];
2790
2856
  this.data = r, this._undo.push({
@@ -2852,6 +2918,14 @@ var q = {
2852
2918
  get frozenRowsHeight() {
2853
2919
  return this._frozenRowCount * this.rowHeight;
2854
2920
  }
2921
+ _rowSpaceY(e) {
2922
+ let t = e - this.getBoundingClientRect().top - this.headerHeight;
2923
+ return t < this.frozenRowsHeight ? t : t + this._scrollTop;
2924
+ }
2925
+ _rowBoundaryViewportY(e) {
2926
+ let t = this.headerHeight + e * this.rowHeight;
2927
+ return e <= this._frozenRowCount ? t : Math.max(this.headerHeight + this.frozenRowsHeight, t - this._scrollTop);
2928
+ }
2855
2929
  get totalBodyHeight() {
2856
2930
  return Math.max(0, this._visibleRowCount - this._frozenRowCount) * this.rowHeight;
2857
2931
  }
@@ -2960,7 +3034,7 @@ var q = {
2960
3034
  e !== this._viewportHeight && (this._viewportHeight = e), t !== this._viewportWidth && (this._viewportWidth = t), this._warnIfUnconstrained();
2961
3035
  }
2962
3036
  _warnIfUnconstrained() {
2963
- this._warnedUnconstrained || process.env.NODE_ENV === "production" || this._visibleRowCount < Re || this.scrollHeight > this.clientHeight + 1 || (this._warnedUnconstrained = !0, console.warn(`[@iyulab/flex-table] ${this._visibleRowCount} rows but the host has no height constraint — it grew to fit every row, so virtual scrolling is off and all rows are rendered. Give the host a height (e.g. height: 400px, or flex: 1 1 auto with min-height: 0 inside a sized parent) so it becomes the scroll container.`));
3037
+ this._warnedUnconstrained || process.env.NODE_ENV === "production" || this._visibleRowCount < He || this.scrollHeight > this.clientHeight + 1 || (this._warnedUnconstrained = !0, console.warn(`[@iyulab/flex-table] ${this._visibleRowCount} rows but the host has no height constraint — it grew to fit every row, so virtual scrolling is off and all rows are rendered. Give the host a height (e.g. height: 400px, or flex: 1 1 auto with min-height: 0 inside a sized parent) so it becomes the scroll container.`));
2964
3038
  }
2965
3039
  _onScroll() {
2966
3040
  this._scrollTop = this.scrollTop, this._scrollLeft = this.scrollLeft;
@@ -3090,7 +3164,7 @@ var q = {
3090
3164
  }
3091
3165
  let t = this.shadowRoot?.querySelector(".ft-editor");
3092
3166
  if (t) {
3093
- let n = F(t.value, e);
3167
+ let n = P(t.value, e);
3094
3168
  this._applyEdit(n);
3095
3169
  } else this._cancelEdit();
3096
3170
  }
@@ -3318,7 +3392,7 @@ var q = {
3318
3392
  async _handleCopy(e) {
3319
3393
  let t = this._selection.getEffectiveRange();
3320
3394
  if (!t) return;
3321
- let n = this.visibleColumns, r = N(this._sortedIndices.map((e) => this.data[e]), n, t);
3395
+ let n = this.visibleColumns, r = ue(this._sortedIndices.map((e) => this.data[e]), n, t);
3322
3396
  try {
3323
3397
  await navigator.clipboard.writeText(r);
3324
3398
  } catch (e) {
@@ -3344,7 +3418,7 @@ var q = {
3344
3418
  if (!this._activeCell) return;
3345
3419
  let e = await this._readClipboardText();
3346
3420
  if (e == null) return;
3347
- let t = P(e);
3421
+ let t = N(e);
3348
3422
  if (t.length === 0) return;
3349
3423
  let n = this._expandRowsForPaste(this._activeCell.row, t.length), r = this._applyPasteData(this._activeCell, t);
3350
3424
  if (r.length > 0 || n.length > 0) {
@@ -3402,7 +3476,7 @@ var q = {
3402
3476
  for (let a = 0; a < t[i].length; a++) {
3403
3477
  let s = e.col + a;
3404
3478
  if (s >= n.length) break;
3405
- let c = n[s], l = this.data[o][c.key], u = F(t[i][a], c);
3479
+ let c = n[s], l = this.data[o][c.key], u = P(t[i][a], c);
3406
3480
  this.data[o][c.key] = u, r.push({
3407
3481
  row: o,
3408
3482
  col: s,
@@ -3467,7 +3541,7 @@ var q = {
3467
3541
  for (let r = e.startCol + 1; r <= e.endCol; r++) {
3468
3542
  let e = t[r];
3469
3543
  if (!e || !this._isCellEditable(e)) continue;
3470
- let a = F(o == null ? "" : String(o), e);
3544
+ let a = P(o == null ? "" : String(o), e);
3471
3545
  n.push({
3472
3546
  row: i,
3473
3547
  key: e.key,
@@ -3626,7 +3700,7 @@ var q = {
3626
3700
  @click=${n ? (t) => this._onHeaderClick(t, e) : void 0}>
3627
3701
  ${x ? i`
3628
3702
  <button class="ft-hidden-col-indicator"
3629
- title=${A("showHiddenColumns")}
3703
+ title=${k("showHiddenColumns")}
3630
3704
  @click=${(t) => {
3631
3705
  t.stopPropagation(), this._showHiddenBefore(e);
3632
3706
  }}>&#x276F;</button>
@@ -3636,8 +3710,8 @@ var q = {
3636
3710
  ${o >= 0 ? i`<span class="ft-sort-order">${o + 1}</span>` : ""}
3637
3711
  <button class="ft-column-menu-btn ${s ? "ft-filter-active" : ""}"
3638
3712
  type="button"
3639
- title=${A("columnMenu")}
3640
- aria-label=${A("columnMenuFor", { header: e.header })}
3713
+ title=${k("columnMenu")}
3714
+ aria-label=${k("columnMenuFor", { header: e.header })}
3641
3715
  aria-haspopup="menu"
3642
3716
  aria-expanded=${this._headerMenu?.key === e.key ? "true" : "false"}
3643
3717
  @mousedown=${(e) => e.stopPropagation()}
@@ -3756,26 +3830,26 @@ var q = {
3756
3830
  }}>${t}</button>
3757
3831
  `;
3758
3832
  return i`
3759
- <div class="ft-header-menu" role="menu" aria-label=${A("columnMenuRegion", { header: o.header })}
3833
+ <div class="ft-header-menu" role="menu" aria-label=${k("columnMenuRegion", { header: o.header })}
3760
3834
  style="position: fixed; left: ${t}px; top: ${n}px; z-index: 200;"
3761
3835
  @mousedown=${(e) => e.stopPropagation()}
3762
3836
  @keydown=${(e) => this._onHeaderMenuKeydown(e)}>
3763
3837
  ${o.sortable === !1 ? a : i`
3764
- ${c("sort-asc", A("sortAscending"), () => this._applySortFromMenu(e, "asc"))}
3765
- ${c("sort-desc", A("sortDescending"), () => this._applySortFromMenu(e, "desc"))}
3838
+ ${c("sort-asc", k("sortAscending"), () => this._applySortFromMenu(e, "asc"))}
3839
+ ${c("sort-desc", k("sortDescending"), () => this._applySortFromMenu(e, "desc"))}
3766
3840
  <div class="ft-header-menu-separator" role="separator"></div>
3767
3841
  `}
3768
3842
  ${this.showFilters ? i`
3769
- ${c("filter", A("filter"), () => this._openFilterFromMenu(e))}
3770
- ${s ? c("clear-filter", A("clearFilter"), () => this._clearColumnFilter(e)) : a}
3843
+ ${c("filter", k("filter"), () => this._openFilterFromMenu(e))}
3844
+ ${s ? c("clear-filter", k("clearFilter"), () => this._clearColumnFilter(e)) : a}
3771
3845
  <div class="ft-header-menu-separator" role="separator"></div>
3772
3846
  ` : a}
3773
- ${c("hide", A("hideColumn"), () => this._setColumnHidden(e, !0))}
3774
- ${r.map((e) => c("show", A("showColumn", { header: e.header }), () => this._setColumnHidden(e.key, !1)))}
3847
+ ${c("hide", k("hideColumn"), () => this._setColumnHidden(e, !0))}
3848
+ ${r.map((e) => c("show", k("showColumn", { header: e.header }), () => this._setColumnHidden(e.key, !1)))}
3775
3849
  <div class="ft-header-menu-separator" role="separator"></div>
3776
- ${c("autofit", A("autoFitWidth"), () => this._autoFitColumn(e))}
3777
- ${c("wider", A("wider"), () => this._resizeColumnBy(e, X), !0)}
3778
- ${c("narrower", A("narrower"), () => this._resizeColumnBy(e, -20), !0)}
3850
+ ${c("autofit", k("autoFitWidth"), () => this._autoFitColumn(e))}
3851
+ ${c("wider", k("wider"), () => this._resizeColumnBy(e, X), !0)}
3852
+ ${c("narrower", k("narrower"), () => this._resizeColumnBy(e, -20), !0)}
3779
3853
  </div>
3780
3854
  `;
3781
3855
  }
@@ -3793,26 +3867,26 @@ var q = {
3793
3867
  }}>${e}</button>
3794
3868
  `, f = i`<div class="ft-context-menu-separator" role="separator"></div>`;
3795
3869
  return i`
3796
- <div class="ft-body-context-menu" role="menu" aria-label=${A("cellActions")}
3870
+ <div class="ft-body-context-menu" role="menu" aria-label=${k("cellActions")}
3797
3871
  style="position: fixed; left: ${n}px; top: ${r}px; z-index: 200;"
3798
3872
  @mousedown=${(e) => e.stopPropagation()}
3799
3873
  @keydown=${(e) => this._onMenuKeydown(e, ".ft-body-context-menu", l)}>
3800
- ${d(A("copy"), () => this._handleCopy(!1))}
3874
+ ${d(k("copy"), () => this._handleCopy(!1))}
3801
3875
  ${f}
3802
- ${d(A("insertRowAbove"), () => this.addRow(void 0, t))}
3803
- ${d(A("insertRowBelow"), () => this.addRow(void 0, t + 1))}
3804
- ${d(A("deleteRow"), () => this.deleteRows([t]), !0)}
3876
+ ${d(k("insertRowAbove"), () => this.addRow(void 0, t))}
3877
+ ${d(k("insertRowBelow"), () => this.addRow(void 0, t + 1))}
3878
+ ${d(k("deleteRow"), () => this.deleteRows([t]), !0)}
3805
3879
  ${f}
3806
- ${d(A("hideColumn"), () => this._setColumnHidden(o.key, !0))}
3880
+ ${d(k("hideColumn"), () => this._setColumnHidden(o.key, !0))}
3807
3881
  ${f}
3808
- ${d(`${A("sortAscending")} ↑`, () => this._applySortFromMenu(o.key, "asc"))}
3809
- ${d(`${A("sortDescending")} ↓`, () => this._applySortFromMenu(o.key, "desc"))}
3882
+ ${d(`${k("sortAscending")} ↑`, () => this._applySortFromMenu(o.key, "asc"))}
3883
+ ${d(`${k("sortDescending")} ↓`, () => this._applySortFromMenu(o.key, "desc"))}
3810
3884
  ${f}
3811
- ${d(A("filterByThisValue"), () => this.setFilter(o.key, (e) => e === s))}
3812
- ${c ? d(A("clearFilter"), () => this.removeFilter(o.key)) : a}
3885
+ ${d(k("filterByThisValue"), () => this.setFilter(o.key, (e) => e === s))}
3886
+ ${c ? d(k("clearFilter"), () => this.removeFilter(o.key)) : a}
3813
3887
  ${f}
3814
- ${d(A(u ? "editComment" : "addComment"), () => this._openCommentPopup(t, o.key, n, r))}
3815
- ${u ? d(A("deleteComment"), () => this.setComment(t, o.key, null), !0) : a}
3888
+ ${d(k(u ? "editComment" : "addComment"), () => this._openCommentPopup(t, o.key, n, r))}
3889
+ ${u ? d(k("deleteComment"), () => this.setComment(t, o.key, null), !0) : a}
3816
3890
  </div>
3817
3891
  `;
3818
3892
  }
@@ -3844,13 +3918,13 @@ var q = {
3844
3918
  @mousedown=${(e) => e.stopPropagation()}>
3845
3919
  <textarea class="ft-comment-popup-textarea"
3846
3920
  rows="4"
3847
- placeholder=${A("addCommentPlaceholder")}
3921
+ placeholder=${k("addCommentPlaceholder")}
3848
3922
  @keydown=${(e) => {
3849
3923
  e.key === "Escape" && (e.preventDefault(), this._cancelCommentPopup()), e.key === "Enter" && (e.ctrlKey || e.metaKey) && (e.preventDefault(), this._commitCommentPopup());
3850
3924
  }}></textarea>
3851
3925
  <div class="ft-comment-popup-buttons">
3852
- <button class="ft-comment-popup-cancel" @click=${() => this._cancelCommentPopup()}>${A("cancel")}</button>
3853
- <button class="ft-comment-popup-save" @click=${() => this._commitCommentPopup()}>${A("save")}</button>
3926
+ <button class="ft-comment-popup-cancel" @click=${() => this._cancelCommentPopup()}>${k("cancel")}</button>
3927
+ <button class="ft-comment-popup-save" @click=${() => this._commitCommentPopup()}>${k("save")}</button>
3854
3928
  </div>
3855
3929
  </div>
3856
3930
  `;
@@ -3886,7 +3960,7 @@ var q = {
3886
3960
  <div class="ft-filter-dropdown" @click=${(e) => e.stopPropagation()}>
3887
3961
  ${t === "boolean" ? this._renderBooleanFilter(e) : t === "number" ? this._renderNumberFilter(e) : t === "date" || t === "datetime" ? this._renderDateFilter(e) : this._renderTextFilter(e)}
3888
3962
  <div class="ft-filter-actions">
3889
- <button class="ft-filter-clear" @click=${() => this._clearColumnFilter(e.key)}>${A("clear")}</button>
3963
+ <button class="ft-filter-clear" @click=${() => this._clearColumnFilter(e.key)}>${k("clear")}</button>
3890
3964
  </div>
3891
3965
  </div>
3892
3966
  `;
@@ -3919,7 +3993,7 @@ var q = {
3919
3993
  let n = this._emptyFilterState.get(e) ?? "";
3920
3994
  return i`
3921
3995
  <div class="ft-filter-empty-row">
3922
- <label>${A("blankCells")}</label>
3996
+ <label>${k("blankCells")}</label>
3923
3997
  <select class="ft-filter-mode-select"
3924
3998
  .value=${n}
3925
3999
  @change=${(n) => {
@@ -3929,9 +4003,9 @@ var q = {
3929
4003
  @keydown=${(e) => {
3930
4004
  e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
3931
4005
  }}>
3932
- <option value="">${A("blankAll")}</option>
3933
- <option value="empty">${A("emptyOnly")}</option>
3934
- <option value="non-empty">${A("nonEmptyOnly")}</option>
4006
+ <option value="">${k("blankAll")}</option>
4007
+ <option value="empty">${k("emptyOnly")}</option>
4008
+ <option value="non-empty">${k("nonEmptyOnly")}</option>
3935
4009
  </select>
3936
4010
  </div>
3937
4011
  `;
@@ -4007,13 +4081,13 @@ var q = {
4007
4081
  @keydown=${(e) => {
4008
4082
  e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
4009
4083
  }}>
4010
- <option value="contains">${A("contains")}</option>
4011
- <option value="starts">${A("startsWith")}</option>
4012
- <option value="ends">${A("endsWith")}</option>
4013
- <option value="wildcard">${A("wildcard")}</option>
4084
+ <option value="contains">${k("contains")}</option>
4085
+ <option value="starts">${k("startsWith")}</option>
4086
+ <option value="ends">${k("endsWith")}</option>
4087
+ <option value="wildcard">${k("wildcard")}</option>
4014
4088
  </select>
4015
4089
  </div>
4016
- <input class="ft-filter-input" type="text" placeholder=${A("searchPlaceholder")}
4090
+ <input class="ft-filter-input" type="text" placeholder=${k("searchPlaceholder")}
4017
4091
  .value=${t.value}
4018
4092
  @input=${(t) => {
4019
4093
  let n = t.target.value, r = this._textFilterState.get(e.key) ?? {
@@ -4064,7 +4138,7 @@ var q = {
4064
4138
  }}>
4065
4139
  ${Object.keys(q).map((e) => i`<option value=${e}>${q[e]}</option>`)}
4066
4140
  </select>
4067
- <input class="ft-filter-input ft-num-cond-input" type="number" placeholder=${A("valuePlaceholder")}
4141
+ <input class="ft-filter-input ft-num-cond-input" type="number" placeholder=${k("valuePlaceholder")}
4068
4142
  .value=${n.value == null ? "" : String(n.value)}
4069
4143
  @input=${(n) => {
4070
4144
  let r = n.target.value, i = this._numberFilterState.get(e) ?? this._defaultNumState();
@@ -4125,13 +4199,13 @@ var q = {
4125
4199
  let t = e.type === "datetime" ? "datetime-local" : "date", n = this._dateFilterState.get(e.key) ?? {};
4126
4200
  return i`
4127
4201
  <div class="ft-filter-range">
4128
- <input class="ft-filter-input" type=${t} placeholder=${A("fromPlaceholder")}
4202
+ <input class="ft-filter-input" type=${t} placeholder=${k("fromPlaceholder")}
4129
4203
  .value=${n.from ?? ""}
4130
4204
  @input=${(t) => this._applyDateFilter(e.key, t, "from")}
4131
4205
  @keydown=${(e) => {
4132
4206
  e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
4133
4207
  }}>
4134
- <input class="ft-filter-input" type=${t} placeholder=${A("toPlaceholder")}
4208
+ <input class="ft-filter-input" type=${t} placeholder=${k("toPlaceholder")}
4135
4209
  .value=${n.to ?? ""}
4136
4210
  @input=${(t) => this._applyDateFilter(e.key, t, "to")}
4137
4211
  @keydown=${(e) => {
@@ -4157,9 +4231,9 @@ var q = {
4157
4231
  @keydown=${(e) => {
4158
4232
  e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
4159
4233
  }}>
4160
- <option value="all">${A("all")}</option>
4161
- <option value="true">\u2714 ${A("booleanTrue")}</option>
4162
- <option value="false">\u2718 ${A("booleanFalse")}</option>
4234
+ <option value="all">${k("all")}</option>
4235
+ <option value="true">\u2714 ${k("booleanTrue")}</option>
4236
+ <option value="false">\u2718 ${k("booleanFalse")}</option>
4163
4237
  </select>
4164
4238
  ${this._renderEmptyFilterRow(e.key)}
4165
4239
  `;
@@ -4286,7 +4360,7 @@ var q = {
4286
4360
  }
4287
4361
  _updateFillDrag(e) {
4288
4362
  if (!this._fillDrag) return;
4289
- let t = this.getBoundingClientRect(), n = e.clientX - t.left + this._scrollLeft - this._prefixWidth, r = e.clientY - t.top + this._scrollTop - this.headerHeight, i = this.visibleColumns, a = 0;
4363
+ let t = this.getBoundingClientRect(), n = e.clientX - t.left + this._scrollLeft - this._prefixWidth, r = this._rowSpaceY(e.clientY), i = this.visibleColumns, a = 0;
4290
4364
  for (let e = 0; e < i.length; e++) (this._colLeftOffsets[e] ?? 0) <= n && (a = e);
4291
4365
  let o = Math.max(0, Math.min(this._visibleRowCount - 1, Math.floor(r / this.rowHeight))), { sourceRange: s } = this._fillDrag, c = o - s.endRow, l = a - s.endCol, u;
4292
4366
  u = Math.abs(c) >= Math.abs(l) ? c >= 0 ? {
@@ -4419,9 +4493,9 @@ var q = {
4419
4493
  _updateRowDrag(e) {
4420
4494
  if (!this._rowDrag) return;
4421
4495
  this._rowDrag.ghost && (this._rowDrag.ghost.style.left = `${e.clientX + 12}px`, this._rowDrag.ghost.style.top = `${e.clientY - 10}px`);
4422
- let t = this.getBoundingClientRect(), n = e.clientY - t.top + this._scrollTop - this.headerHeight, r = this.rowHeight, i = Math.round(n / r);
4496
+ let t = this.getBoundingClientRect(), n = this._rowSpaceY(e.clientY), r = this.rowHeight, i = Math.round(n / r);
4423
4497
  i = Math.max(0, Math.min(this._visibleRowCount, i)), this._rowDrag.rowIndex < i && i--, this._rowDrag.targetIndex = i;
4424
- let a = this.headerHeight + i * r - this._scrollTop;
4498
+ let a = this._rowBoundaryViewportY(i);
4425
4499
  this._rowDragIndicatorY = Math.max(this.headerHeight, Math.min(a, t.height)), this.requestUpdate();
4426
4500
  }
4427
4501
  _finishRowDrag() {
@@ -4579,39 +4653,39 @@ var q = {
4579
4653
  e.key === "Enter" && e.target instanceof HTMLInputElement && e.target.classList.contains("ft-find-input") && (e.shiftKey ? this._findPrev() : this._findNext());
4580
4654
  }}>
4581
4655
  <div class="ft-find-row">
4582
- <input class="ft-find-input" type="text" placeholder=${A("findPlaceholder")}
4656
+ <input class="ft-find-input" type="text" placeholder=${k("findPlaceholder")}
4583
4657
  .value=${t}
4584
4658
  @input=${(e) => {
4585
4659
  this._findState.query = e.target.value, this._findSearch();
4586
4660
  }}>
4587
4661
  <span class="ft-find-count">${c > 0 ? `${l}/${c}` : t ? "0 results" : ""}</span>
4588
- <button @click=${() => this._findPrev()} title=${A("findPrevious")}>◀</button>
4589
- <button @click=${() => this._findNext()} title=${A("findNext")}>▶</button>
4590
- <label title=${A("matchCase")}><input type="checkbox" ?checked=${r} @change=${(e) => {
4662
+ <button @click=${() => this._findPrev()} title=${k("findPrevious")}>◀</button>
4663
+ <button @click=${() => this._findNext()} title=${k("findNext")}>▶</button>
4664
+ <label title=${k("matchCase")}><input type="checkbox" ?checked=${r} @change=${(e) => {
4591
4665
  this._findState.matchCase = e.target.checked, this._findSearch();
4592
4666
  }}> Aa</label>
4593
- <label title=${A("wholeCell")}><input type="checkbox" ?checked=${a} @change=${(e) => {
4667
+ <label title=${k("wholeCell")}><input type="checkbox" ?checked=${a} @change=${(e) => {
4594
4668
  this._findState.wholeCell = e.target.checked, this._findSearch();
4595
4669
  }}> [ ]</label>
4596
- <button @click=${() => this._closeFindPanel()} title=${A("closeFind")}>✕</button>
4670
+ <button @click=${() => this._closeFindPanel()} title=${k("closeFind")}>✕</button>
4597
4671
  </div>
4598
4672
  ${e === "replace" ? i`
4599
4673
  <div class="ft-find-row">
4600
- <input class="ft-find-replace-input" type="text" placeholder=${A("replaceWithPlaceholder")}
4674
+ <input class="ft-find-replace-input" type="text" placeholder=${k("replaceWithPlaceholder")}
4601
4675
  .value=${n}
4602
4676
  @input=${(e) => {
4603
4677
  this._findState.replaceWith = e.target.value;
4604
4678
  }}>
4605
- <button @click=${() => this._replaceOne()} ?disabled=${c === 0}>${A("replace")}</button>
4606
- <button @click=${() => this._replaceAll()} ?disabled=${c === 0}>${A("replaceAll")}</button>
4679
+ <button @click=${() => this._replaceOne()} ?disabled=${c === 0}>${k("replace")}</button>
4680
+ <button @click=${() => this._replaceAll()} ?disabled=${c === 0}>${k("replaceAll")}</button>
4607
4681
  </div>
4608
4682
  ` : ""}
4609
4683
  </div>
4610
4684
  `;
4611
4685
  }
4612
4686
  render() {
4613
- let e = this.visibleColumns, t = this.importEnabled && this._isDragOver ? i`<div class="ft-import-overlay">${A("dropFileToImport")}</div>` : a, n = this.loading ? i`<div class="ft-loading-overlay"></div>` : a;
4614
- if (e.length === 0) return i`${t}${n}<div class="ft-empty">${A("noColumnsDefined")}</div>`;
4687
+ let e = this.visibleColumns, t = this.importEnabled && this._isDragOver ? i`<div class="ft-import-overlay">${k("dropFileToImport")}</div>` : a, n = this.loading ? i`<div class="ft-loading-overlay"></div>` : a;
4688
+ if (e.length === 0) return i`${t}${n}<div class="ft-empty">${k("noColumnsDefined")}</div>`;
4615
4689
  let r = this.headerHeight, o = this._totalRowWidth, { start: s, end: c } = this.visibleColRange, l = [];
4616
4690
  for (let t = 0; t < e.length; t++) (e[t].pinned === "left" || e[t].pinned === "right") && (t < s || t >= c) && l.push(t);
4617
4691
  let u = 0, d = this._scrollLeft, f = this.selectable ? i`<div class="ft-checkbox-header"
@@ -4920,4 +4994,4 @@ K([s({ type: Array })], $.prototype, "columns", void 0), K([s({
4920
4994
  attribute: "max-undo-size"
4921
4995
  })], $.prototype, "maxUndoSize", null), K([c()], $.prototype, "_scrollTop", void 0), K([c()], $.prototype, "_scrollLeft", void 0), K([c()], $.prototype, "_viewportHeight", void 0), K([c()], $.prototype, "_viewportWidth", void 0), K([c()], $.prototype, "_activeCell", void 0), K([c()], $.prototype, "_editingCell", void 0), K([c()], $.prototype, "_sortCriteria", void 0), K([c()], $.prototype, "_openFilterKey", void 0), K([c()], $.prototype, "_rowSelectionVersion", void 0), K([c()], $.prototype, "_autocompleteState", void 0), K([c()], $.prototype, "_headerMenu", void 0), K([c()], $.prototype, "_bodyContextMenu", void 0), K([c()], $.prototype, "_commentPopup", void 0), K([c()], $.prototype, "_isDragOver", void 0), $ = K([o("flex-table")], $);
4922
4996
  //#endregion
4923
- export { k as a, j as i, H as n, D as o, M as r, $ as t };
4997
+ export { O as a, j as i, V as n, D as o, M as r, $ as t };
@@ -306,6 +306,14 @@ export declare class FlexTable extends LitElement {
306
306
  private get _visibleRowCount();
307
307
  private get _frozenRowCount();
308
308
  private get frozenRowsHeight();
309
+ /**
310
+ * 포인터의 뷰포트 y → 행 좌표(행 영역 맨 위 = 0, 픽셀). 고정 행 띠는 `position: sticky` 라
311
+ * 스크롤해도 제자리이므로, 그 띠 위에서는 스크롤 양을 더하지 않는다 — 더하면 띠 뒤에 가려진
312
+ * 본문 행을 가리킨다. 행 끌기·채우기 핸들이 같은 식을 쓴다.
313
+ */
314
+ private _rowSpaceY;
315
+ /** 행 경계 `index`(행 `index` 의 위 선)의 뷰포트 y(호스트 기준). 고정 띠 뒤로 가려지는 본문 경계는 띠 아래 선에 붙인다. */
316
+ private _rowBoundaryViewportY;
309
317
  private get totalBodyHeight();
310
318
  private get visibleRange();
311
319
  connectedCallback(): void;
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, n, o as r, r as i, t as a } from "./flex-table-DcIjmfEK.js";
1
+ import { a as e, i as t, n, o as r, r as i, t as a } from "./flex-table-DbbqD5Jn.js";
2
2
  export { a as FlexTable, t as RowSelectionState, i as UndoStack, n as exportData, e as flexTableLocale, r as renderCell };
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./flex-table-DcIjmfEK.js";
1
+ import { t as e } from "./flex-table-DbbqD5Jn.js";
2
2
  import t from "react";
3
3
  import { createComponent as n } from "@lit/react";
4
4
  var r = n({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.38.0",
3
+ "version": "0.38.1",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",