@iyulab/flex-table 0.15.0 → 0.16.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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Minimal XLSX reader — no external dependencies.
3
+ * Reads OOXML (.xlsx) files using ZIP central directory + DOMParser.
4
+ * Handles STORE (no compression) and DEFLATE compression.
5
+ * Supports string, number, boolean, and date cell types.
6
+ */
7
+ /** Parsed sheet data from an XLSX file */
8
+ export interface ImportedSheet {
9
+ /** Column header strings from the first row */
10
+ headers: string[];
11
+ /** Data rows as raw string values (one string per cell) */
12
+ rows: string[][];
13
+ }
14
+ /**
15
+ * Parse an XLSX file buffer into a structured ImportedSheet.
16
+ * The first row is treated as headers; subsequent rows are data.
17
+ * All values are returned as raw strings — type coercion is left to the consumer.
18
+ */
19
+ export declare function readXlsx(buffer: ArrayBuffer): Promise<ImportedSheet>;
@@ -0,0 +1 @@
1
+ export {};
@@ -288,6 +288,39 @@ var s = t`
288
288
  color: var(--ft-empty-color);
289
289
  }
290
290
 
291
+ .ft-has-comment {
292
+ position: relative;
293
+ }
294
+
295
+ .ft-comment-indicator {
296
+ position: absolute;
297
+ top: 0;
298
+ right: 0;
299
+ width: 0;
300
+ height: 0;
301
+ border-style: solid;
302
+ border-width: 0 7px 7px 0;
303
+ border-color: transparent #f59e0b transparent transparent;
304
+ pointer-events: none;
305
+ z-index: 1;
306
+ }
307
+
308
+ .ft-import-overlay {
309
+ position: absolute;
310
+ inset: 0;
311
+ z-index: 100;
312
+ background: rgba(59, 130, 246, 0.15);
313
+ border: 2px dashed rgba(59, 130, 246, 0.8);
314
+ display: flex;
315
+ align-items: center;
316
+ justify-content: center;
317
+ font-size: 14px;
318
+ font-weight: 500;
319
+ color: rgb(37, 99, 235);
320
+ pointer-events: none;
321
+ border-radius: 4px;
322
+ }
323
+
291
324
  .ft-row-num-header,
292
325
  .ft-row-num {
293
326
  position: absolute;
@@ -955,13 +988,13 @@ function S(e, t, n) {
955
988
  if (c && l) continue;
956
989
  if (c) return 1;
957
990
  if (l) return -1;
958
- let u = ee(t, s, i.get(a) ?? "text");
991
+ let u = C(t, s, i.get(a) ?? "text");
959
992
  if (u !== 0) return o === "asc" ? u : -u;
960
993
  }
961
994
  return n - r;
962
995
  }), r;
963
996
  }
964
- function ee(e, t, n) {
997
+ function C(e, t, n) {
965
998
  switch (n) {
966
999
  case "number": {
967
1000
  let n = Number(e), r = Number(t);
@@ -976,7 +1009,7 @@ function ee(e, t, n) {
976
1009
  default: return String(e).localeCompare(String(t));
977
1010
  }
978
1011
  }
979
- function te(e, t, n) {
1012
+ function w(e, t, n) {
980
1013
  let r = e.find((e) => e.key === t);
981
1014
  return n ? r ? r.direction === "asc" ? e.map((e) => e.key === t ? {
982
1015
  ...e,
@@ -994,7 +1027,7 @@ function te(e, t, n) {
994
1027
  }
995
1028
  //#endregion
996
1029
  //#region src/core/filtering.ts
997
- function ne(e, t, n) {
1030
+ function T(e, t, n) {
998
1031
  if (t.length === 0) return Array.from({ length: e.length }, (e, t) => t);
999
1032
  let r = [];
1000
1033
  for (let i = 0; i < e.length; i++) {
@@ -1013,9 +1046,9 @@ function ne(e, t, n) {
1013
1046
  }
1014
1047
  //#endregion
1015
1048
  //#region src/core/undo.ts
1016
- var C = 100, w = class {
1049
+ var E = 100, D = class {
1017
1050
  constructor() {
1018
- this._undoStack = [], this._redoStack = [], this._maxSize = C;
1051
+ this._undoStack = [], this._redoStack = [], this._maxSize = E;
1019
1052
  }
1020
1053
  get maxSize() {
1021
1054
  return this._maxSize;
@@ -1052,7 +1085,7 @@ var C = 100, w = class {
1052
1085
  };
1053
1086
  //#endregion
1054
1087
  //#region src/clipboard/clipboard.ts
1055
- function T(e, t, n) {
1088
+ function ee(e, t, n) {
1056
1089
  let r = [];
1057
1090
  for (let i = n.startRow; i <= n.endRow; i++) {
1058
1091
  let a = e[i], o = [];
@@ -1064,7 +1097,7 @@ function T(e, t, n) {
1064
1097
  }
1065
1098
  return r.join("\n");
1066
1099
  }
1067
- function E(e) {
1100
+ function O(e) {
1068
1101
  let t = e.replace(/\r\n/g, "\n").replace(/\r/g, "\n"), n = [], r = [], i = 0, a = t.length;
1069
1102
  for (; i <= a;) {
1070
1103
  if (i === a) {
@@ -1093,7 +1126,7 @@ function E(e) {
1093
1126
  }
1094
1127
  return n;
1095
1128
  }
1096
- function D(e, t) {
1129
+ function k(e, t) {
1097
1130
  if (e === "") return null;
1098
1131
  switch (t.type) {
1099
1132
  case "number": {
@@ -1106,7 +1139,7 @@ function D(e, t) {
1106
1139
  }
1107
1140
  //#endregion
1108
1141
  //#region src/export/xlsx-writer.ts
1109
- var re = (() => {
1142
+ var te = (() => {
1110
1143
  let e = new Uint32Array(256);
1111
1144
  for (let t = 0; t < 256; t++) {
1112
1145
  let n = t;
@@ -1115,56 +1148,56 @@ var re = (() => {
1115
1148
  }
1116
1149
  return e;
1117
1150
  })();
1118
- function ie(e) {
1151
+ function A(e) {
1119
1152
  let t = 4294967295;
1120
- for (let n = 0; n < e.length; n++) t = re[(t ^ e[n]) & 255] ^ t >>> 8;
1153
+ for (let n = 0; n < e.length; n++) t = te[(t ^ e[n]) & 255] ^ t >>> 8;
1121
1154
  return (t ^ 4294967295) >>> 0;
1122
1155
  }
1123
- var O = new TextEncoder();
1124
- function k(e) {
1156
+ var j = new TextEncoder();
1157
+ function ne(e) {
1125
1158
  let t = [], n = [], r = 0;
1126
1159
  for (let i of e) {
1127
- let e = O.encode(i.name), a = ie(i.data), o = i.data.length, s = new ArrayBuffer(30 + e.length), c = new DataView(s);
1160
+ let e = j.encode(i.name), a = A(i.data), o = i.data.length, s = new ArrayBuffer(30 + e.length), c = new DataView(s);
1128
1161
  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);
1129
1162
  let l = new ArrayBuffer(46 + e.length), u = new DataView(l);
1130
1163
  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;
1131
1164
  }
1132
- let i = A(n), a = /* @__PURE__ */ new ArrayBuffer(22), o = new DataView(a);
1133
- 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), A([
1165
+ let i = M(n), a = /* @__PURE__ */ new ArrayBuffer(22), o = new DataView(a);
1166
+ 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), M([
1134
1167
  ...t,
1135
1168
  i,
1136
1169
  new Uint8Array(a)
1137
1170
  ]);
1138
1171
  }
1139
- function A(e) {
1172
+ function M(e) {
1140
1173
  let t = e.reduce((e, t) => e + t.length, 0), n = new Uint8Array(t), r = 0;
1141
1174
  for (let t of e) n.set(t, r), r += t.length;
1142
1175
  return n;
1143
1176
  }
1144
- function j(e) {
1177
+ function N(e) {
1145
1178
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1146
1179
  }
1147
- function ae(e) {
1180
+ function P(e) {
1148
1181
  let t = "";
1149
1182
  for (e++; e > 0;) t = String.fromCharCode(64 + (e % 26 || 26)) + t, e = Math.floor((e - 1) / 26);
1150
1183
  return t;
1151
1184
  }
1152
- function M(e, t) {
1153
- return ae(t) + (e + 1);
1185
+ function F(e, t) {
1186
+ return P(t) + (e + 1);
1154
1187
  }
1155
- function N(e) {
1188
+ function I(e) {
1156
1189
  let t = Date.UTC(1899, 11, 30);
1157
1190
  return (e.getTime() - t) / 864e5;
1158
1191
  }
1159
- var P = "<?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>", F = "<?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>", I = "<?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>", L = "<?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>", R = "<?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>";
1160
- function z(e, t) {
1161
- let n = [], r = t.map((e, t) => `<c r="${M(0, t)}" t="str" s="2"><v>${j(e.header)}</v></c>`);
1192
+ var L = "<?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>", R = "<?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>", re = "<?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>", ie = "<?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>", ae = "<?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>";
1193
+ function oe(e, t) {
1194
+ let n = [], r = t.map((e, t) => `<c r="${F(0, t)}" t="str" s="2"><v>${N(e.header)}</v></c>`);
1162
1195
  return n.push(`<row r="1">${r.join("")}</row>`), e.forEach((e, r) => {
1163
1196
  let i = t.map((t, n) => {
1164
- let i = M(r + 1, n), a = e[t.key];
1197
+ let i = F(r + 1, n), a = e[t.key];
1165
1198
  if (a == null) return `<c r="${i}" t="str"><v></v></c>`;
1166
1199
  let o = t.type ?? "text";
1167
- 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>${N(a).toFixed(6)}</v></c>` : o === "boolean" ? `<c r="${i}" t="b"><v>${+!!a}</v></c>` : `<c r="${i}" t="str"><v>${j(String(a))}</v></c>`;
1200
+ 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>${I(a).toFixed(6)}</v></c>` : o === "boolean" ? `<c r="${i}" t="b"><v>${+!!a}</v></c>` : `<c r="${i}" t="str"><v>${N(String(a))}</v></c>`;
1168
1201
  });
1169
1202
  n.push(`<row r="${r + 2}">${i.join("")}</row>`);
1170
1203
  }), `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -1172,55 +1205,55 @@ function z(e, t) {
1172
1205
  <sheetData>${n.join("")}</sheetData>
1173
1206
  </worksheet>`;
1174
1207
  }
1175
- function B(e, t) {
1176
- let n = z(e, t);
1177
- return k([
1208
+ function z(e, t) {
1209
+ let n = oe(e, t);
1210
+ return ne([
1178
1211
  {
1179
1212
  name: "[Content_Types].xml",
1180
- data: O.encode(P)
1213
+ data: j.encode(L)
1181
1214
  },
1182
1215
  {
1183
1216
  name: "_rels/.rels",
1184
- data: O.encode(F)
1217
+ data: j.encode(R)
1185
1218
  },
1186
1219
  {
1187
1220
  name: "xl/workbook.xml",
1188
- data: O.encode(I)
1221
+ data: j.encode(re)
1189
1222
  },
1190
1223
  {
1191
1224
  name: "xl/_rels/workbook.xml.rels",
1192
- data: O.encode(L)
1225
+ data: j.encode(ie)
1193
1226
  },
1194
1227
  {
1195
1228
  name: "xl/worksheets/sheet1.xml",
1196
- data: O.encode(n)
1229
+ data: j.encode(n)
1197
1230
  },
1198
1231
  {
1199
1232
  name: "xl/styles.xml",
1200
- data: O.encode(R)
1233
+ data: j.encode(ae)
1201
1234
  }
1202
1235
  ]);
1203
1236
  }
1204
1237
  //#endregion
1205
1238
  //#region src/export/export.ts
1206
- function V(e, t, n) {
1239
+ function B(e, t, n) {
1207
1240
  switch (n) {
1208
- case "csv": return U(e, t, ",");
1209
- case "tsv": return U(e, t, " ");
1210
- case "json": return G(e, t);
1211
- case "xlsx": return B(e, t);
1241
+ case "csv": return H(e, t, ",");
1242
+ case "tsv": return H(e, t, " ");
1243
+ case "json": return W(e, t);
1244
+ case "xlsx": return z(e, t);
1212
1245
  }
1213
1246
  }
1214
- function H(e, t) {
1247
+ function V(e, t) {
1215
1248
  return e == null ? "" : (t.type === "date" || t.type === "datetime") && e instanceof Date ? e.toISOString() : String(e);
1216
1249
  }
1217
- function U(e, t, n) {
1218
- return [t.map((e) => W(e.header, n)).join(n), ...e.map((e) => t.map((t) => W(H(e[t.key], t), n)).join(n))].join("\n");
1250
+ function H(e, t, n) {
1251
+ return [t.map((e) => U(e.header, n)).join(n), ...e.map((e) => t.map((t) => U(V(e[t.key], t), n)).join(n))].join("\n");
1219
1252
  }
1220
- function W(e, t) {
1253
+ function U(e, t) {
1221
1254
  return e.includes(t) || e.includes("\"") || e.includes("\n") || e.includes("\r") ? "\"" + e.replace(/"/g, "\"\"") + "\"" : e;
1222
1255
  }
1223
- function G(e, t) {
1256
+ function W(e, t) {
1224
1257
  let n = e.map((e) => {
1225
1258
  let n = {};
1226
1259
  for (let r of t) {
@@ -1231,26 +1264,138 @@ function G(e, t) {
1231
1264
  });
1232
1265
  return JSON.stringify(n, null, 2);
1233
1266
  }
1234
- function K(e, t, n) {
1267
+ function G(e, t, n) {
1235
1268
  let r = new Blob([e], { type: n }), i = URL.createObjectURL(r), a = document.createElement("a");
1236
1269
  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);
1237
1270
  }
1238
- var q = {
1271
+ var K = {
1239
1272
  csv: "text/csv;charset=utf-8",
1240
1273
  tsv: "text/tab-separated-values;charset=utf-8",
1241
1274
  json: "application/json;charset=utf-8",
1242
1275
  xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1243
- }, oe = {
1276
+ }, se = {
1244
1277
  csv: ".csv",
1245
1278
  tsv: ".tsv",
1246
1279
  json: ".json",
1247
1280
  xlsx: ".xlsx"
1248
1281
  };
1249
- function se(e) {
1250
- return q[e];
1251
- }
1252
1282
  function ce(e) {
1253
- return oe[e];
1283
+ return K[e];
1284
+ }
1285
+ function le(e) {
1286
+ return se[e];
1287
+ }
1288
+ //#endregion
1289
+ //#region src/export/xlsx-reader.ts
1290
+ function ue(e) {
1291
+ for (let t = e.byteLength - 22; t >= 0; t--) if (e.getUint32(t, !0) === 101010256) return t;
1292
+ throw Error("XLSX: End of central directory not found — not a valid ZIP file");
1293
+ }
1294
+ function de(e) {
1295
+ let t = ue(e), n = e.getUint32(t + 16, !0), r = e.getUint32(t + 12, !0), i = new TextDecoder("utf-8"), a = [], o = n, s = n + r;
1296
+ for (; o < s && e.getUint32(o, !0) === 33639248;) {
1297
+ 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));
1298
+ a.push({
1299
+ name: d,
1300
+ compressionMethod: t,
1301
+ compressedSize: n,
1302
+ uncompressedSize: r,
1303
+ localHeaderOffset: u
1304
+ }), o += 46 + s + c + l;
1305
+ }
1306
+ return a;
1307
+ }
1308
+ async function fe(e) {
1309
+ let t = new DecompressionStream("deflate-raw"), n = t.writable.getWriter(), r = t.readable.getReader();
1310
+ n.write(e), n.close();
1311
+ let i = [];
1312
+ for (;;) {
1313
+ let { done: e, value: t } = await r.read();
1314
+ if (e) break;
1315
+ i.push(t);
1316
+ }
1317
+ let a = i.reduce((e, t) => e + t.length, 0), o = new Uint8Array(a), s = 0;
1318
+ for (let e of i) o.set(e, s), s += e.length;
1319
+ return o;
1320
+ }
1321
+ async function pe(e, t) {
1322
+ 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);
1323
+ if (t.compressionMethod === 0) return o.slice();
1324
+ if (t.compressionMethod === 8) return fe(o);
1325
+ throw Error(`XLSX: Unsupported compression method ${t.compressionMethod}`);
1326
+ }
1327
+ async function me(e) {
1328
+ let t = new DataView(e), n = de(t), r = /* @__PURE__ */ new Map();
1329
+ for (let e of n) e.compressedSize === 0 && e.name.endsWith("/") || r.set(e.name, await pe(t, e));
1330
+ return r;
1331
+ }
1332
+ var he = new TextDecoder("utf-8");
1333
+ function q(e) {
1334
+ let t = he.decode(e);
1335
+ return new DOMParser().parseFromString(t, "application/xml");
1336
+ }
1337
+ function ge(e) {
1338
+ if (!e) return [];
1339
+ let t = q(e);
1340
+ return Array.from(t.querySelectorAll("si")).map((e) => Array.from(e.querySelectorAll("t")).map((e) => e.textContent ?? "").join(""));
1341
+ }
1342
+ function _e(e) {
1343
+ let t = (e - 1) * 864e5 + Date.UTC(1899, 11, 30);
1344
+ return new Date(t).toISOString().slice(0, 10);
1345
+ }
1346
+ function ve(e, t) {
1347
+ let n = q(e).querySelectorAll("row");
1348
+ if (n.length === 0) return [];
1349
+ let r = 0, i = /* @__PURE__ */ new Map();
1350
+ for (let e of n) {
1351
+ let n = parseInt(e.getAttribute("r") ?? "1", 10) - 1, a = /* @__PURE__ */ new Map();
1352
+ i.set(n, a);
1353
+ for (let n of e.querySelectorAll("c")) {
1354
+ let e = ye(n.getAttribute("r") ?? "");
1355
+ e > r && (r = e);
1356
+ let i = n.getAttribute("t") ?? "", o = n.getAttribute("s") ?? "", s = n.querySelector("v")?.textContent ?? "", c = n.querySelector("is > t")?.textContent ?? null, l;
1357
+ if (i === "s") l = t[parseInt(s, 10)] ?? "";
1358
+ else if (i === "str" || i === "inlineStr") l = c ?? s;
1359
+ else if (i === "b") l = s === "1" ? "true" : "false";
1360
+ else if (s === "") l = "";
1361
+ else {
1362
+ let e = parseFloat(s);
1363
+ l = !isNaN(e) && o !== "" && parseInt(o, 10) > 0 && e >= 1 && e <= 73050 ? _e(e) : s;
1364
+ }
1365
+ a.set(e, l);
1366
+ }
1367
+ }
1368
+ if (i.size === 0) return [];
1369
+ let a = Math.max(...i.keys()), o = [];
1370
+ for (let e = 0; e <= a; e++) {
1371
+ let t = i.get(e) ?? /* @__PURE__ */ new Map(), n = [];
1372
+ for (let e = 0; e <= r; e++) n.push(t.get(e) ?? "");
1373
+ o.push(n);
1374
+ }
1375
+ return o;
1376
+ }
1377
+ function ye(e) {
1378
+ let t = 0, n = 0;
1379
+ for (; n < e.length && e[n] >= "A" && e[n] <= "Z";) t = t * 26 + (e.charCodeAt(n) - 64), n++;
1380
+ return t - 1;
1381
+ }
1382
+ async function be(e) {
1383
+ let t = await me(e), n = ge(t.get("xl/sharedStrings.xml")), r = t.get("xl/worksheets/sheet1.xml");
1384
+ if (!r) {
1385
+ for (let [e, n] of t) if (e.toLowerCase().includes("worksheets/sheet")) {
1386
+ r = n;
1387
+ break;
1388
+ }
1389
+ }
1390
+ if (!r) throw Error("XLSX: No worksheet found");
1391
+ let i = ve(r, n);
1392
+ return i.length === 0 ? {
1393
+ headers: [],
1394
+ rows: []
1395
+ } : {
1396
+ headers: i[0],
1397
+ rows: i.slice(1)
1398
+ };
1254
1399
  }
1255
1400
  //#endregion
1256
1401
  //#region \0@oxc-project+runtime@0.130.0/helpers/decorate.js
@@ -1269,9 +1414,9 @@ var Y = {
1269
1414
  lt: "<",
1270
1415
  gte: "≥",
1271
1416
  lte: "≤"
1272
- }, X = 120, Z = 40, le = 32, Q = 5, $ = class extends e {
1417
+ }, X = 120, Z = 40, xe = 32, Q = 5, $ = class extends e {
1273
1418
  constructor(...e) {
1274
- super(...e), this.columns = [], this.data = [], this.rowHeight = le, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.selectable = !1, this.dataMode = "client", this.footerData = null, this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new y(), this._editing = new b(), this._rowSelection = new x(), this._undo = new w(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._autocompleteState = null, this._headerMenu = null, this._bodyContextMenu = null, this._viewDirty = !0, this._isDragging = !1, this._wasDrag = !1, this._resizing = null, this._resizeCleanup = null, 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._invalidCells = /* @__PURE__ */ new Map(), this._textFilterState = /* @__PURE__ */ new Map(), this._numberFilterState = /* @__PURE__ */ new Map(), this._dateFilterState = /* @__PURE__ */ new Map(), this._emptyFilterState = /* @__PURE__ */ new Map();
1419
+ super(...e), this.columns = [], this.data = [], this.rowHeight = xe, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new y(), this._editing = new b(), this._rowSelection = new x(), this._undo = new D(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, this._autocompleteState = null, this._headerMenu = null, this._bodyContextMenu = null, this._viewDirty = !0, this._isDragging = !1, this._wasDrag = !1, this._resizing = null, this._resizeCleanup = null, 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._invalidCells = /* @__PURE__ */ new Map(), this._textFilterState = /* @__PURE__ */ new Map(), this._numberFilterState = /* @__PURE__ */ new Map(), this._dateFilterState = /* @__PURE__ */ new Map(), this._emptyFilterState = /* @__PURE__ */ new Map();
1275
1420
  }
1276
1421
  static {
1277
1422
  this.styles = s;
@@ -1580,12 +1725,111 @@ var Y = {
1580
1725
  if (!t) return "";
1581
1726
  let n = this.visibleColumns.slice(t.startCol, t.endCol + 1), r = [];
1582
1727
  for (let e = t.startRow; e <= t.endRow; e++) r.push(this.data[this._toDataIndex(e)]);
1583
- return V(r, n, e);
1728
+ return B(r, n, e);
1584
1729
  }
1585
- return V(this._sortedIndices.map((e) => this.data[e]), this.visibleColumns, e);
1730
+ return B(this._sortedIndices.map((e) => this.data[e]), this.visibleColumns, e);
1586
1731
  }
1587
1732
  exportToFile(e, t) {
1588
- K(this.exportToString(e), t ?? `export${ce(e)}`, se(e));
1733
+ G(this.exportToString(e), t ?? `export${le(e)}`, ce(e));
1734
+ }
1735
+ setComment(e, t, n) {
1736
+ if (n) this._comments.has(e) || this._comments.set(e, /* @__PURE__ */ new Map()), this._comments.get(e).set(t, n);
1737
+ else {
1738
+ let n = this._comments.get(e);
1739
+ n && (n.delete(t), n.size === 0 && this._comments.delete(e));
1740
+ }
1741
+ this.dispatchEvent(new CustomEvent("comment-change", {
1742
+ detail: {
1743
+ dataIndex: e,
1744
+ colKey: t,
1745
+ text: n ?? null
1746
+ },
1747
+ bubbles: !0,
1748
+ composed: !0
1749
+ })), this.requestUpdate();
1750
+ }
1751
+ getComment(e, t) {
1752
+ return this._comments.get(e)?.get(t) ?? null;
1753
+ }
1754
+ getAllComments() {
1755
+ let e = [];
1756
+ for (let [t, n] of this._comments) for (let [r, i] of n) e.push({
1757
+ dataIndex: t,
1758
+ colKey: r,
1759
+ text: i
1760
+ });
1761
+ return e;
1762
+ }
1763
+ clearComments() {
1764
+ this._comments.clear(), this.requestUpdate();
1765
+ }
1766
+ async importFromFile(e) {
1767
+ let t = e.name.toLowerCase();
1768
+ if (t.endsWith(".xlsx")) {
1769
+ let t = await be(await e.arrayBuffer());
1770
+ this._applyImportedSheet(t);
1771
+ } else if (t.endsWith(".csv") || t.endsWith(".tsv")) {
1772
+ let t = O(await e.text());
1773
+ this._applyImportedRows(t);
1774
+ } else console.warn(`flex-table importFromFile: unsupported file type "${e.name}"`);
1775
+ }
1776
+ _applyImportedSheet(e) {
1777
+ let t = this._buildHeaderColumnMap(e.headers), n = e.rows.map((n) => {
1778
+ let r = {};
1779
+ return e.headers.forEach((e, i) => {
1780
+ let a = t.get(e);
1781
+ if (!a) return;
1782
+ let o = this.columns.find((e) => e.key === a);
1783
+ r[a] = o ? k(n[i] ?? "", o) : n[i] ?? null;
1784
+ }), r;
1785
+ });
1786
+ this.data = n, this.dispatchEvent(new CustomEvent("data-import", {
1787
+ detail: { count: n.length },
1788
+ bubbles: !0,
1789
+ composed: !0
1790
+ }));
1791
+ }
1792
+ _applyImportedRows(e) {
1793
+ if (e.length === 0) return;
1794
+ let t = e[0], n = this._buildHeaderColumnMap(t), r = e.slice(1).map((e) => {
1795
+ let r = {};
1796
+ return t.forEach((t, i) => {
1797
+ let a = n.get(t);
1798
+ if (!a) return;
1799
+ let o = this.columns.find((e) => e.key === a);
1800
+ r[a] = o ? k(e[i] ?? "", o) : e[i] ?? null;
1801
+ }), r;
1802
+ });
1803
+ this.data = r, this.dispatchEvent(new CustomEvent("data-import", {
1804
+ detail: { count: r.length },
1805
+ bubbles: !0,
1806
+ composed: !0
1807
+ }));
1808
+ }
1809
+ _buildHeaderColumnMap(e) {
1810
+ let t = /* @__PURE__ */ new Map();
1811
+ for (let n of e) {
1812
+ let e = this.columns.find((e) => e.header === n);
1813
+ if (e) {
1814
+ t.set(n, e.key);
1815
+ continue;
1816
+ }
1817
+ let r = this.columns.find((e) => e.header.toLowerCase() === n.toLowerCase());
1818
+ r && t.set(n, r.key);
1819
+ }
1820
+ return t;
1821
+ }
1822
+ _onDragover(e) {
1823
+ this.importEnabled && (e.dataTransfer?.types.includes("Files") ?? !1) && (e.preventDefault(), e.dataTransfer.dropEffect = "copy", this._isDragOver = !0);
1824
+ }
1825
+ _onDragleave() {
1826
+ this._isDragOver = !1;
1827
+ }
1828
+ async _onDrop(e) {
1829
+ if (this._isDragOver = !1, !this.importEnabled) return;
1830
+ e.preventDefault();
1831
+ let t = e.dataTransfer?.files[0];
1832
+ t && await this.importFromFile(t);
1589
1833
  }
1590
1834
  _getSelectedDataRows() {
1591
1835
  let e = this._selection.getEffectiveRange();
@@ -1624,10 +1868,10 @@ var Y = {
1624
1868
  };
1625
1869
  }
1626
1870
  connectedCallback() {
1627
- super.connectedCallback(), this._onScroll = this._onScroll.bind(this), this._onKeyDown = this._onKeyDown.bind(this), this._onDocumentClick = this._onDocumentClick.bind(this), this._onContextMenu = this._onContextMenu.bind(this), this.addEventListener("scroll", this._onScroll, { passive: !0 }), this.addEventListener("keydown", this._onKeyDown), this.addEventListener("contextmenu", this._onContextMenu), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "grid"), typeof ResizeObserver < "u" && (this._hostResizeObserver = new ResizeObserver(() => this._measureViewport()), this._hostResizeObserver.observe(this));
1871
+ super.connectedCallback(), this._onScroll = this._onScroll.bind(this), this._onKeyDown = this._onKeyDown.bind(this), this._onDocumentClick = this._onDocumentClick.bind(this), this._onContextMenu = this._onContextMenu.bind(this), this._onDragover = this._onDragover.bind(this), this._onDragleave = this._onDragleave.bind(this), this._onDrop = this._onDrop.bind(this), this.addEventListener("scroll", this._onScroll, { passive: !0 }), this.addEventListener("keydown", this._onKeyDown), this.addEventListener("contextmenu", this._onContextMenu), this.addEventListener("dragover", this._onDragover), this.addEventListener("dragleave", this._onDragleave), this.addEventListener("drop", this._onDrop), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "grid"), typeof ResizeObserver < "u" && (this._hostResizeObserver = new ResizeObserver(() => this._measureViewport()), this._hostResizeObserver.observe(this));
1628
1872
  }
1629
1873
  disconnectedCallback() {
1630
- super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("contextmenu", this._onContextMenu), document.removeEventListener("click", this._onDocumentClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
1874
+ super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("dragover", this._onDragover), this.removeEventListener("dragleave", this._onDragleave), this.removeEventListener("drop", this._onDrop), document.removeEventListener("click", this._onDocumentClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
1631
1875
  }
1632
1876
  firstUpdated() {
1633
1877
  this._measureViewport();
@@ -1675,7 +1919,7 @@ var Y = {
1675
1919
  this._filteredIndices = Array.from({ length: this.data.length }, (e, t) => t), this._sortedIndices = this._filteredIndices;
1676
1920
  return;
1677
1921
  }
1678
- if (this._filteredIndices = ne(this.data, this._filters, (e, t, n) => {
1922
+ if (this._filteredIndices = T(this.data, this._filters, (e, t, n) => {
1679
1923
  this.dispatchEvent(new CustomEvent("filter-error", {
1680
1924
  detail: {
1681
1925
  error: e,
@@ -1814,7 +2058,7 @@ var Y = {
1814
2058
  }
1815
2059
  let t = this.shadowRoot?.querySelector(".ft-editor");
1816
2060
  if (t) {
1817
- let n = D(t.value, e);
2061
+ let n = k(t.value, e);
1818
2062
  this._applyEdit(n);
1819
2063
  } else this._cancelEdit();
1820
2064
  }
@@ -2036,7 +2280,7 @@ var Y = {
2036
2280
  async _handleCopy(e) {
2037
2281
  let t = this._selection.getEffectiveRange();
2038
2282
  if (!t) return;
2039
- let n = this.visibleColumns, r = T(this._sortedIndices.map((e) => this.data[e]), n, t);
2283
+ let n = this.visibleColumns, r = ee(this._sortedIndices.map((e) => this.data[e]), n, t);
2040
2284
  try {
2041
2285
  await navigator.clipboard.writeText(r);
2042
2286
  } catch (e) {
@@ -2062,7 +2306,7 @@ var Y = {
2062
2306
  if (!this._activeCell) return;
2063
2307
  let e = await this._readClipboardText();
2064
2308
  if (e == null) return;
2065
- let t = E(e);
2309
+ let t = O(e);
2066
2310
  if (t.length === 0) return;
2067
2311
  let n = this._expandRowsForPaste(this._activeCell.row, t.length), r = this._applyPasteData(this._activeCell, t);
2068
2312
  if (r.length > 0 || n.length > 0) {
@@ -2120,7 +2364,7 @@ var Y = {
2120
2364
  for (let a = 0; a < t[i].length; a++) {
2121
2365
  let s = e.col + a;
2122
2366
  if (s >= n.length) break;
2123
- let c = n[s], l = this.data[o][c.key], u = D(t[i][a], c);
2367
+ let c = n[s], l = this.data[o][c.key], u = k(t[i][a], c);
2124
2368
  this.data[o][c.key] = u, r.push({
2125
2369
  row: o,
2126
2370
  col: s,
@@ -2185,7 +2429,7 @@ var Y = {
2185
2429
  for (let r = e.startCol + 1; r <= e.endCol; r++) {
2186
2430
  let e = t[r];
2187
2431
  if (!e || !this._isCellEditable(e)) continue;
2188
- let a = D(o == null ? "" : String(o), e);
2432
+ let a = k(o == null ? "" : String(o), e);
2189
2433
  n.push({
2190
2434
  row: i,
2191
2435
  key: e.key,
@@ -2276,7 +2520,7 @@ var Y = {
2276
2520
  this._selectColumn(n);
2277
2521
  return;
2278
2522
  }
2279
- t.sortable !== !1 && (this._sortCriteria = te(this._sortCriteria, t.key, e.shiftKey), this.dataMode !== "server" && this._recomputeView(), this.requestUpdate(), this.dispatchEvent(new CustomEvent("sort-change", {
2523
+ t.sortable !== !1 && (this._sortCriteria = w(this._sortCriteria, t.key, e.shiftKey), this.dataMode !== "server" && this._recomputeView(), this.requestUpdate(), this.dispatchEvent(new CustomEvent("sort-change", {
2280
2524
  detail: { criteria: [...this._sortCriteria] },
2281
2525
  bubbles: !0,
2282
2526
  composed: !0
@@ -3232,12 +3476,12 @@ var Y = {
3232
3476
  `;
3233
3477
  }
3234
3478
  render() {
3235
- let e = this.visibleColumns;
3236
- if (e.length === 0) return n`<div class="ft-empty">No columns defined</div>`;
3237
- let t = this.headerHeight, r = this._totalRowWidth, { start: i, end: a } = this.visibleColRange, o = [];
3238
- for (let t = 0; t < e.length; t++) (e[t].pinned === "left" || e[t].pinned === "right") && (t < i || t >= a) && o.push(t);
3239
- let s = 0, c = this._scrollLeft, l = this.selectable ? n`<div class="ft-checkbox-header"
3240
- style="position: absolute; top: 0; left: ${c + s}px; width: 36px; height: ${t}px; z-index: 4;">
3479
+ let e = this.visibleColumns, t = this.importEnabled && this._isDragOver ? n`<div class="ft-import-overlay">Drop file to import (.xlsx / .csv)</div>` : r;
3480
+ if (e.length === 0) return n`${t}<div class="ft-empty">No columns defined</div>`;
3481
+ let i = this.headerHeight, a = this._totalRowWidth, { start: o, end: s } = this.visibleColRange, c = [];
3482
+ for (let t = 0; t < e.length; t++) (e[t].pinned === "left" || e[t].pinned === "right") && (t < o || t >= s) && c.push(t);
3483
+ let l = 0, u = this._scrollLeft, d = this.selectable ? n`<div class="ft-checkbox-header"
3484
+ style="position: absolute; top: 0; left: ${u + l}px; width: 36px; height: ${i}px; z-index: 4;">
3241
3485
  ${this._rowSelection.mode === "multi" ? n`
3242
3486
  <input type="checkbox"
3243
3487
  .checked=${this._rowSelection.isAllSelected}
@@ -3245,37 +3489,38 @@ var Y = {
3245
3489
  @change=${this._onSelectAllChange}>
3246
3490
  ` : ""}
3247
3491
  </div>` : "";
3248
- this.selectable && (s += 36);
3249
- let u = this.showRowNumbers ? n`<div class="ft-row-num-header"
3250
- style="position: absolute; top: 0; left: ${c + s}px; width: 48px; height: ${t}px; z-index: 4;">#</div>` : "", d = [];
3251
- for (let t of o) d.push(this._renderHeaderCell(e[t], t));
3252
- for (let t = i; t < a; t++) d.push(this._renderHeaderCell(e[t], t));
3253
- let f = this._colDragIndicatorLeft == null ? "" : n`<div class="ft-drop-indicator" style="left:${this._colDragIndicatorLeft}px"></div>`;
3492
+ this.selectable && (l += 36);
3493
+ let f = this.showRowNumbers ? n`<div class="ft-row-num-header"
3494
+ style="position: absolute; top: 0; left: ${u + l}px; width: 48px; height: ${i}px; z-index: 4;">#</div>` : "", p = [];
3495
+ for (let t of c) p.push(this._renderHeaderCell(e[t], t));
3496
+ for (let t = o; t < s; t++) p.push(this._renderHeaderCell(e[t], t));
3497
+ let m = this._colDragIndicatorLeft == null ? "" : n`<div class="ft-drop-indicator" style="left:${this._colDragIndicatorLeft}px"></div>`;
3254
3498
  if (this.data.length === 0 || this._visibleRowCount === 0) return n`
3255
- <div class="ft-header" role="row" style="width: ${r}px; height: ${t}px;">
3256
- ${l}${u}
3257
- ${d}
3258
- ${f}
3499
+ <div class="ft-header" role="row" style="width: ${a}px; height: ${i}px;">
3500
+ ${d}${f}
3501
+ ${p}
3502
+ ${m}
3259
3503
  </div>
3260
3504
  <div class="ft-empty">${this.data.length === 0 ? "No data" : "No matching data"}</div>
3261
3505
  `;
3262
- let { start: p, end: m } = this.visibleRange, h = this._frozenRowCount, g = [];
3263
- for (let e = p; e < m; e++) g.push(this._renderRow(e, i, a, o, (e - h) * this.rowHeight));
3264
- let _ = this._renderFillHandle(), v = this._rowDragIndicatorY == null ? "" : n`<div class="ft-row-drop-indicator" style="top:${this._rowDragIndicatorY}px;width:${r + this._prefixWidth}px;"></div>`;
3506
+ let { start: h, end: g } = this.visibleRange, _ = this._frozenRowCount, v = [];
3507
+ for (let e = h; e < g; e++) v.push(this._renderRow(e, o, s, c, (e - _) * this.rowHeight));
3508
+ let y = this._renderFillHandle(), b = this._rowDragIndicatorY == null ? "" : n`<div class="ft-row-drop-indicator" style="top:${this._rowDragIndicatorY}px;width:${a + this._prefixWidth}px;"></div>`;
3265
3509
  return n`
3510
+ ${t}
3266
3511
  ${this._renderFindPanel()}
3267
- <div class="ft-header" role="row" style="width: ${r}px; height: ${t}px;">
3268
- ${l}${u}
3269
- ${d}
3270
- ${f}
3512
+ <div class="ft-header" role="row" style="width: ${a}px; height: ${i}px;">
3513
+ ${d}${f}
3514
+ ${p}
3515
+ ${m}
3271
3516
  </div>
3272
- ${this._renderFrozenRows(i, a, o)}
3273
- <div class="ft-body" style="height: ${this.totalBodyHeight}px; width: ${r}px;">
3274
- ${g}
3517
+ ${this._renderFrozenRows(o, s, c)}
3518
+ <div class="ft-body" style="height: ${this.totalBodyHeight}px; width: ${a}px;">
3519
+ ${v}
3275
3520
  </div>
3276
- ${this.footerData ? this._renderFooter(i, a, o) : ""}
3277
- ${v}
3278
- ${_}
3521
+ ${this.footerData ? this._renderFooter(o, s, c) : ""}
3522
+ ${b}
3523
+ ${y}
3279
3524
  ${this._renderHeaderContextMenu()}
3280
3525
  ${this._renderBodyContextMenu()}
3281
3526
  `;
@@ -3370,9 +3615,7 @@ var Y = {
3370
3615
  ${this._renderEditor(e, t)}
3371
3616
  </div>
3372
3617
  `;
3373
- let v = o || c, y = this._isCellInvalid(i, a), b = (this._findState?.results ?? []).findIndex((e) => e.row === i && e.col === a), x = b >= 0, S = x && b === this._findState.currentIndex;
3374
- return n`
3375
- <div class=${[
3618
+ let v = o || c, y = this._isCellInvalid(i, a), b = (this._findState?.results ?? []).findIndex((e) => e.row === i && e.col === a), x = b >= 0, S = x && b === this._findState.currentIndex, C = [
3376
3619
  "ft-cell",
3377
3620
  `ft-type-${t.type ?? "text"}`,
3378
3621
  o ? "ft-active" : "",
@@ -3380,7 +3623,9 @@ var Y = {
3380
3623
  d ? "ft-pinned" : "",
3381
3624
  y ? "ft-invalid" : "",
3382
3625
  S ? "ft-find-current" : x ? "ft-find-match" : ""
3383
- ].filter(Boolean).join(" ")}
3626
+ ].filter(Boolean).join(" "), w = this._toDataIndex(i), T = this._comments.get(w)?.get(t.key) ?? null, E = T !== null, D = E ? n`<div class="ft-comment-indicator" title=${T}></div>` : r;
3627
+ return n`
3628
+ <div class=${E ? C + " ft-has-comment" : C}
3384
3629
  role="gridcell"
3385
3630
  data-col-index=${a}
3386
3631
  aria-selected=${v ? "true" : "false"}
@@ -3392,6 +3637,7 @@ var Y = {
3392
3637
  @mouseenter=${() => this._onCellMouseEnter(i, a)}
3393
3638
  @click=${(e) => this._onCellClickEvent(e, i, a)}
3394
3639
  @dblclick=${() => this._onCellDblClick(i, a)}>
3640
+ ${D}
3395
3641
  ${f(e[t.key], e, t)}
3396
3642
  </div>
3397
3643
  `;
@@ -3492,7 +3738,10 @@ J([a({ type: Array })], $.prototype, "columns", void 0), J([a({
3492
3738
  })], $.prototype, "showContextMenu", void 0), J([a({
3493
3739
  type: Number,
3494
3740
  attribute: "frozen-rows"
3495
- })], $.prototype, "frozenRows", void 0), J([a({ type: Boolean })], $.prototype, "selectable", void 0), J([a({
3741
+ })], $.prototype, "frozenRows", void 0), J([a({
3742
+ type: Boolean,
3743
+ attribute: "import-enabled"
3744
+ })], $.prototype, "importEnabled", void 0), J([a({ type: Boolean })], $.prototype, "selectable", void 0), J([a({
3496
3745
  type: String,
3497
3746
  attribute: "selection-mode"
3498
3747
  })], $.prototype, "selectionMode", null), J([a({
@@ -3504,6 +3753,6 @@ J([a({ type: Array })], $.prototype, "columns", void 0), J([a({
3504
3753
  })], $.prototype, "footerData", void 0), J([a({
3505
3754
  type: Number,
3506
3755
  attribute: "max-undo-size"
3507
- })], $.prototype, "maxUndoSize", null), J([o()], $.prototype, "_scrollTop", void 0), J([o()], $.prototype, "_scrollLeft", void 0), J([o()], $.prototype, "_viewportHeight", void 0), J([o()], $.prototype, "_viewportWidth", void 0), J([o()], $.prototype, "_activeCell", void 0), J([o()], $.prototype, "_editingCell", void 0), J([o()], $.prototype, "_sortCriteria", void 0), J([o()], $.prototype, "_openFilterKey", void 0), J([o()], $.prototype, "_rowSelectionVersion", void 0), J([o()], $.prototype, "_autocompleteState", void 0), J([o()], $.prototype, "_headerMenu", void 0), J([o()], $.prototype, "_bodyContextMenu", void 0), $ = J([i("flex-table")], $);
3756
+ })], $.prototype, "maxUndoSize", null), J([o()], $.prototype, "_scrollTop", void 0), J([o()], $.prototype, "_scrollLeft", void 0), J([o()], $.prototype, "_viewportHeight", void 0), J([o()], $.prototype, "_viewportWidth", void 0), J([o()], $.prototype, "_activeCell", void 0), J([o()], $.prototype, "_editingCell", void 0), J([o()], $.prototype, "_sortCriteria", void 0), J([o()], $.prototype, "_openFilterKey", void 0), J([o()], $.prototype, "_rowSelectionVersion", void 0), J([o()], $.prototype, "_autocompleteState", void 0), J([o()], $.prototype, "_headerMenu", void 0), J([o()], $.prototype, "_bodyContextMenu", void 0), J([o()], $.prototype, "_isDragOver", void 0), $ = J([i("flex-table")], $);
3508
3757
  //#endregion
3509
- export { f as a, x as i, V as n, w as r, $ as t };
3758
+ export { f as a, x as i, B as n, D as r, $ as t };
@@ -19,6 +19,8 @@ export declare class FlexTable extends LitElement {
19
19
  showContextMenu: boolean;
20
20
  /** Number of rows to freeze at the top (always visible during vertical scroll). */
21
21
  frozenRows: number;
22
+ /** Enable file drag-and-drop import (.xlsx, .csv). */
23
+ importEnabled: boolean;
22
24
  /** Enable row-level checkbox selection. */
23
25
  selectable: boolean;
24
26
  /** Row selection mode: 'single' or 'multi' (default: 'multi'). */
@@ -64,6 +66,9 @@ export declare class FlexTable extends LitElement {
64
66
  private _findState;
65
67
  private _columnWidths;
66
68
  private _hostResizeObserver;
69
+ /** Keyed by dataIndex → colKey → comment text */
70
+ private _comments;
71
+ private _isDragOver;
67
72
  get visibleColumns(): ColumnDefinition[];
68
73
  private get _prefixWidth();
69
74
  /** Whether an undo operation is available. */
@@ -162,6 +167,39 @@ export declare class FlexTable extends LitElement {
162
167
  * Export table data and trigger file download.
163
168
  */
164
169
  exportToFile(format: ExportFormat, filename?: string): void;
170
+ /**
171
+ * Set a comment on the cell at the given data index and column key.
172
+ * Pass an empty string or null to remove the comment.
173
+ */
174
+ setComment(dataIndex: number, colKey: string, text: string | null): void;
175
+ /**
176
+ * Get the comment for a cell (by data index and column key). Returns null if none.
177
+ */
178
+ getComment(dataIndex: number, colKey: string): string | null;
179
+ /**
180
+ * Get all comments as a flat array.
181
+ */
182
+ getAllComments(): Array<{
183
+ dataIndex: number;
184
+ colKey: string;
185
+ text: string;
186
+ }>;
187
+ /**
188
+ * Clear all comments.
189
+ */
190
+ clearComments(): void;
191
+ /**
192
+ * Import data from an xlsx or csv File.
193
+ * Dispatches 'data-import' event with { count } on success.
194
+ */
195
+ importFromFile(file: File): Promise<void>;
196
+ private _applyImportedSheet;
197
+ private _applyImportedRows;
198
+ /** Map header text → column key using exact header match (case-insensitive fallback). */
199
+ private _buildHeaderColumnMap;
200
+ private _onDragover;
201
+ private _onDragleave;
202
+ private _onDrop;
165
203
  private _getSelectedDataRows;
166
204
  /**
167
205
  * Get the effective width for a column, checking internal overrides first.
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, n, r, t as i } from "./flex-table-BVzjrFBP.js";
1
+ import { a as e, i as t, n, r, t as i } from "./flex-table-B6dOkF56.js";
2
2
  export { i as FlexTable, t as RowSelectionState, r as UndoStack, n as exportData, e as renderCell };
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./flex-table-BVzjrFBP.js";
1
+ import { t as e } from "./flex-table-B6dOkF56.js";
2
2
  import t from "react";
3
3
  import { createComponent as n } from "@lit/react";
4
4
  //#region src/react.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",