@iyulab/flex-table 0.41.1 → 0.41.2

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,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.41.2] - 2026-10-03
4
+
5
+ ### Fixed
6
+
7
+ - **The `datetime` cell editor shows and takes `YYYY-MM-DD HH:mm` in every browser language.** It was the
8
+ native `datetime-local` input, which follows the browser's UI language. It is now a text box in local
9
+ time that reads `2026-10-02 14:05` (`9:05`, a date alone is midnight), stores the local
10
+ `YYYY-MM-DDTHH:mm` string as before, and rejects text it cannot read with `validation-error`
11
+ ("Enter a date and time as YYYY-MM-DD HH:mm", new `flexTableLocale` key `notADateTime`).
12
+ - **Pasting `2026-10-02 14:05` into a datetime column stores `2026-10-02T14:05`.** Other text stays text.
13
+
14
+ ### Changed
15
+
16
+ - **The `@iyulab/components` peer is `>=1.56.0`** — date-times are read with its `parseDateTime`.
17
+
3
18
  ## [0.41.1] - 2026-10-03
4
19
 
5
20
  ### Fixed
package/README.md CHANGED
@@ -160,7 +160,7 @@ The `validator` callback returns `null` if valid, or an error message string. On
160
160
 
161
161
  A `number` column's built-in editor reads numbers the way people type them in the active `Locale` — `1,5` on a comma-decimal page is 1.5, `1.234,5` is 1234.5 — and shows the value with that locale's decimal separator. Text that is not a number is rejected the same way as a validator failure (`error` is the localized "Enter a number"). The number filter's conditions and pasted values are read the same way; pasted text that is not a number stays text.
162
162
 
163
- A `date` column's built-in editor is a text box that shows and takes `YYYY-MM-DD` in every browser language (the native date input would show the browser's UI language, e.g. `10/02/2026`). It also reads `2026/10/2`, `20261002` and `10-02` (this year), stores the ISO date string, and rejects text that is not a date (`error` is the localized "Enter a date as YYYY-MM-DD"). Pasted dates are read the same way.
163
+ A `date` column's built-in editor is a text box that shows and takes `YYYY-MM-DD` in every browser language (the native date input would show the browser's UI language, e.g. `10/02/2026`). It also reads `2026/10/2`, `20261002` and `10-02` (this year), stores the ISO date string, and rejects text that is not a date (`error` is the localized "Enter a date as YYYY-MM-DD"). Pasted dates are read the same way. A `datetime` column's editor works the same with a time: it shows `YYYY-MM-DD HH:mm` in local time, reads `2026-10-02 14:05` (a date alone is midnight), and stores the local `YYYY-MM-DDTHH:mm` string.
164
164
 
165
165
  ### `format` vs `render`
166
166
 
@@ -17,3 +17,9 @@ export declare function editableNumber(value: number): string;
17
17
  * negative offsets); a `Date` uses its local day. Anything else is shown as it is.
18
18
  */
19
19
  export declare function editableDate(value: unknown): string;
20
+ /**
21
+ * A `datetime` cell's value as `YYYY-MM-DD HH:mm` (local) for editing — the form the editor reads
22
+ * back. A local date-time string (`2026-10-02T14:05`, no offset) keeps its wall-clock time; a `Date`
23
+ * or a string with an offset (`Z`, `+09:00`) is shown in local time. Anything else is shown as it is.
24
+ */
25
+ export declare function editableDateTime(value: unknown): string;
@@ -2,11 +2,11 @@ import { n as e, t } from "./sorting-CjfjRxwL.js";
2
2
  import { LitElement as n, css as r, html as i, nothing as a } from "lit";
3
3
  import { customElement as o, property as s, state as c } from "lit/decorators.js";
4
4
  import { Locale as l } from "@iyulab/components/dist/utilities/Locale.js";
5
- import { dateTextPattern as u, formatDate as d, formatNumber as f, parseDate as p, parseNumber as m } from "@iyulab/components/dist/utilities/format.js";
6
- import { decodeTsv as h, encodeTsv as g } from "@iyulab/components/dist/utilities/tsv.js";
7
- import { isImeComposing as _ } from "@iyulab/components/dist/utilities/keyboard.js";
5
+ import { dateTextPattern as u, formatDate as d, formatNumber as f, parseDate as p, parseDateTime as m, parseNumber as h } from "@iyulab/components/dist/utilities/format.js";
6
+ import { decodeTsv as g, encodeTsv as _ } from "@iyulab/components/dist/utilities/tsv.js";
7
+ import { isImeComposing as v } from "@iyulab/components/dist/utilities/keyboard.js";
8
8
  //#region src/styles/flex-table.styles.ts
9
- var v = r`
9
+ var y = r`
10
10
  /* --- Theme Variables (Light defaults) --- */
11
11
  :host {
12
12
  --ft-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
@@ -921,13 +921,13 @@ var v = r`
921
921
  `;
922
922
  //#endregion
923
923
  //#region src/renderers/format.ts
924
- function y(e, t) {
925
- return e == null ? "" : typeof t == "function" ? t(e) : b(t) ? S(e, t) : x(e, t);
924
+ function b(e, t) {
925
+ return e == null ? "" : typeof t == "function" ? t(e) : x(t) ? C(e, t) : S(e, t);
926
926
  }
927
- function b(e) {
927
+ function x(e) {
928
928
  return /[yMdHhms]/.test(e);
929
929
  }
930
- function x(e, t) {
930
+ function S(e, t) {
931
931
  let n = typeof e == "number" ? e : Number(e);
932
932
  if (isNaN(n)) return String(e);
933
933
  let r = t.endsWith("%"), i = t.match(/^([^#0.,%]+)/), a = i ? i[1] : "", o = t.replace(/^[^#0.,%]+/, "").replace(/%$/, ""), s = o.match(/\.([0#]+)$/), c = s ? s[1].length : 0, u = {
@@ -940,7 +940,7 @@ function x(e, t) {
940
940
  style: "percent"
941
941
  }).format(n) : (d = new Intl.NumberFormat(l.get(), u).format(n), a && (d = a + d)), d + "";
942
942
  }
943
- function S(e, t) {
943
+ function C(e, t) {
944
944
  let n;
945
945
  if (e instanceof Date) n = e;
946
946
  else if (typeof e == "string" || typeof e == "number") n = new Date(e);
@@ -951,26 +951,26 @@ function S(e, t) {
951
951
  }
952
952
  //#endregion
953
953
  //#region src/renderers/cell-renderer.ts
954
- function C(e, t, n) {
955
- return n.render ? n.render(e, t, n) : n.format ? typeof n.format == "function" ? n.format(e, t, n) : y(e, n.format) : w(e, n);
954
+ function w(e, t, n) {
955
+ return n.render ? n.render(e, t, n) : n.format ? typeof n.format == "function" ? n.format(e, t, n) : b(e, n.format) : T(e, n);
956
956
  }
957
- function w(e, t) {
957
+ function T(e, t) {
958
958
  if (e == null) return "";
959
959
  switch (t.type) {
960
- case "number": return D(e);
960
+ case "number": return O(e);
961
961
  case "boolean": return i`<span class="ft-bool">${e ? "✔" : ""}</span>`;
962
- case "date": return O(e);
963
- case "datetime": return ee(e);
964
- case "select": return T(e, t);
962
+ case "date": return ee(e);
963
+ case "datetime": return te(e);
964
+ case "select": return E(e, t);
965
965
  default: return String(e);
966
966
  }
967
967
  }
968
- function T(e, t) {
968
+ function E(e, t) {
969
969
  if (!t.options || t.options.length === 0 || typeof t.options[0] == "string") return e == null ? "" : String(e);
970
970
  let n = t.options.find((t) => t.value === e);
971
971
  return n ? n.label : e == null ? "" : String(e);
972
972
  }
973
- var E = {
973
+ var D = {
974
974
  year: "numeric",
975
975
  month: "numeric",
976
976
  day: "numeric",
@@ -978,14 +978,14 @@ var E = {
978
978
  minute: "numeric",
979
979
  second: "numeric"
980
980
  };
981
- function D(e) {
981
+ function O(e) {
982
982
  return typeof e == "number" ? Number.isInteger(e) ? f(e) : f(e, { minimumFractionDigits: 1 }) : String(e);
983
983
  }
984
- function O(e) {
984
+ function ee(e) {
985
985
  return e instanceof Date || typeof e == "string" ? d(e) : String(e);
986
986
  }
987
- function ee(e) {
988
- return e instanceof Date || typeof e == "string" ? d(e, E) : String(e);
987
+ function te(e) {
988
+ return e instanceof Date || typeof e == "string" ? d(e, D) : String(e);
989
989
  }
990
990
  //#endregion
991
991
  //#region src/locale.ts
@@ -1045,6 +1045,7 @@ k.register("en", {
1045
1045
  dropFileToImport: "Drop file to import (.xlsx / .csv)",
1046
1046
  notANumber: "Enter a number",
1047
1047
  notADate: "Enter a date as YYYY-MM-DD",
1048
+ notADateTime: "Enter a date and time as YYYY-MM-DD HH:mm",
1048
1049
  notInList: "Value must be from the existing list"
1049
1050
  }), k.register("ko", {
1050
1051
  showHiddenColumns: "숨긴 열 보기",
@@ -1101,12 +1102,13 @@ k.register("en", {
1101
1102
  dropFileToImport: "가져올 파일을 놓으세요 (.xlsx / .csv)",
1102
1103
  notANumber: "숫자를 입력하세요",
1103
1104
  notADate: "날짜를 YYYY-MM-DD 로 입력하세요",
1105
+ notADateTime: "날짜와 시간을 YYYY-MM-DD HH:mm 으로 입력하세요",
1104
1106
  notInList: "목록에 있는 값이어야 합니다"
1105
1107
  });
1106
1108
  var A = (e, t) => k.text(e, t);
1107
1109
  //#endregion
1108
1110
  //#region src/core/selection.ts
1109
- function te(e) {
1111
+ function ne(e) {
1110
1112
  return {
1111
1113
  startRow: Math.min(e.startRow, e.endRow),
1112
1114
  startCol: Math.min(e.startCol, e.endCol),
@@ -1114,7 +1116,7 @@ function te(e) {
1114
1116
  endCol: Math.max(e.startCol, e.endCol)
1115
1117
  };
1116
1118
  }
1117
- var ne = class {
1119
+ var re = class {
1118
1120
  constructor() {
1119
1121
  this.activeCell = null, this.rangeAnchor = null, this.range = null, this.extraRanges = [], this._rowCount = 0, this._colCount = 0;
1120
1122
  }
@@ -1141,7 +1143,7 @@ var ne = class {
1141
1143
  return e < 0 || e >= this._rowCount || t < 0 || t >= this._colCount ? this.activeCell : (!this.rangeAnchor && this.activeCell && (this.rangeAnchor = { ...this.activeCell }), this.activeCell = {
1142
1144
  row: e,
1143
1145
  col: t
1144
- }, this.rangeAnchor && (this.range = te({
1146
+ }, this.rangeAnchor && (this.range = ne({
1145
1147
  startRow: this.rangeAnchor.row,
1146
1148
  startCol: this.rangeAnchor.col,
1147
1149
  endRow: e,
@@ -1212,7 +1214,7 @@ var ne = class {
1212
1214
  shiftMoveRight() {
1213
1215
  return this.activeCell ? this.setActiveWithRange(this.activeCell.row, this.activeCell.col + 1) : null;
1214
1216
  }
1215
- }, re = class {
1217
+ }, ie = class {
1216
1218
  constructor() {
1217
1219
  this.current = null;
1218
1220
  }
@@ -1294,7 +1296,7 @@ var ne = class {
1294
1296
  };
1295
1297
  //#endregion
1296
1298
  //#region src/core/filtering.ts
1297
- function ie(e, t, n) {
1299
+ function ae(e, t, n) {
1298
1300
  if (t.length === 0) return Array.from({ length: e.length }, (e, t) => t);
1299
1301
  let r = [];
1300
1302
  for (let i = 0; i < e.length; i++) {
@@ -1313,9 +1315,9 @@ function ie(e, t, n) {
1313
1315
  }
1314
1316
  //#endregion
1315
1317
  //#region src/core/undo.ts
1316
- var ae = 100, M = class {
1318
+ var oe = 100, M = class {
1317
1319
  constructor() {
1318
- this._undoStack = [], this._redoStack = [], this._maxSize = ae;
1320
+ this._undoStack = [], this._redoStack = [], this._maxSize = oe;
1319
1321
  }
1320
1322
  get maxSize() {
1321
1323
  return this._maxSize;
@@ -1352,7 +1354,7 @@ var ae = 100, M = class {
1352
1354
  };
1353
1355
  //#endregion
1354
1356
  //#region src/clipboard/clipboard.ts
1355
- function oe(e, t, n) {
1357
+ function se(e, t, n) {
1356
1358
  let r = [];
1357
1359
  for (let i = n.startRow; i <= n.endRow; i++) {
1358
1360
  let a = e[i], o = [];
@@ -1362,19 +1364,20 @@ function oe(e, t, n) {
1362
1364
  }
1363
1365
  r.push(o);
1364
1366
  }
1365
- return g(r);
1367
+ return _(r);
1366
1368
  }
1367
1369
  function N(e, t) {
1368
1370
  if (e === "") return null;
1369
1371
  switch (t.type) {
1370
1372
  case "number": {
1371
- let t = m(e);
1373
+ let t = h(e);
1372
1374
  if (t !== null) return t;
1373
1375
  let n = Number(e.trim());
1374
1376
  return e.trim() !== "" && Number.isFinite(n) ? n : e;
1375
1377
  }
1376
1378
  case "boolean": return e.toLowerCase() === "true" || e === "1";
1377
1379
  case "date": return p(e) ?? e;
1380
+ case "datetime": return m(e) ?? e;
1378
1381
  default: return e;
1379
1382
  }
1380
1383
  }
@@ -1384,15 +1387,24 @@ function P(e) {
1384
1387
  let n = new Intl.NumberFormat(l.get()).formatToParts(1.5).find((e) => e.type === "decimal")?.value;
1385
1388
  return n && n !== "." ? t.replace(".", n) : t;
1386
1389
  }
1387
- function se(e) {
1390
+ function ce(e) {
1388
1391
  if (e == null || e === "") return "";
1389
1392
  if (e instanceof Date) return Number.isNaN(e.getTime()) ? "" : `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
1390
1393
  let t = String(e), n = /^(\d{4}-\d{2}-\d{2})(?:$|T)/.exec(t);
1391
1394
  return n ? n[1] : t;
1392
1395
  }
1396
+ function le(e) {
1397
+ if (e == null || e === "") return "";
1398
+ let t = e instanceof Date ? "" : String(e), n = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})(?::\d{2}(?:\.\d+)?)?$/.exec(t);
1399
+ if (n) return `${n[1]} ${n[2]}`;
1400
+ let r = e instanceof Date ? e : /^\d{4}-\d{2}-\d{2}T/.test(t) ? new Date(t) : null;
1401
+ if (!r || Number.isNaN(r.getTime())) return t;
1402
+ let i = (e) => String(e).padStart(2, "0");
1403
+ return `${r.getFullYear()}-${i(r.getMonth() + 1)}-${i(r.getDate())} ${i(r.getHours())}:${i(r.getMinutes())}`;
1404
+ }
1393
1405
  //#endregion
1394
1406
  //#region src/export/xlsx-writer.ts
1395
- var ce = (() => {
1407
+ var ue = (() => {
1396
1408
  let e = /* @__PURE__ */ new Uint32Array(256);
1397
1409
  for (let t = 0; t < 256; t++) {
1398
1410
  let n = t;
@@ -1401,16 +1413,16 @@ var ce = (() => {
1401
1413
  }
1402
1414
  return e;
1403
1415
  })();
1404
- function le(e) {
1416
+ function de(e) {
1405
1417
  let t = 4294967295;
1406
- for (let n = 0; n < e.length; n++) t = ce[(t ^ e[n]) & 255] ^ t >>> 8;
1418
+ for (let n = 0; n < e.length; n++) t = ue[(t ^ e[n]) & 255] ^ t >>> 8;
1407
1419
  return (t ^ 4294967295) >>> 0;
1408
1420
  }
1409
1421
  var F = new TextEncoder();
1410
- function ue(e) {
1422
+ function fe(e) {
1411
1423
  let t = [], n = [], r = 0;
1412
1424
  for (let i of e) {
1413
- let e = F.encode(i.name), a = le(i.data), o = i.data.length, s = new ArrayBuffer(30 + e.length), c = new DataView(s);
1425
+ let e = F.encode(i.name), a = de(i.data), o = i.data.length, s = new ArrayBuffer(30 + e.length), c = new DataView(s);
1414
1426
  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);
1415
1427
  let l = new ArrayBuffer(46 + e.length), u = new DataView(l);
1416
1428
  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;
@@ -1430,27 +1442,27 @@ function I(e) {
1430
1442
  function L(e) {
1431
1443
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1432
1444
  }
1433
- function de(e) {
1445
+ function pe(e) {
1434
1446
  let t = "";
1435
1447
  for (e++; e > 0;) t = String.fromCharCode(64 + (e % 26 || 26)) + t, e = Math.floor((e - 1) / 26);
1436
1448
  return t;
1437
1449
  }
1438
1450
  function R(e, t) {
1439
- return de(t) + (e + 1);
1451
+ return pe(t) + (e + 1);
1440
1452
  }
1441
- function fe(e) {
1453
+ function me(e) {
1442
1454
  let t = Date.UTC(1899, 11, 30);
1443
1455
  return (e.getTime() - t) / 864e5;
1444
1456
  }
1445
- 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>", z = "<?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>", 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/worksheet\" Target=\"worksheets/sheet1.xml\"/>\n <Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>\n</Relationships>", ge = "<?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>";
1446
- function _e(e, t) {
1457
+ var z = "<?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>";
1458
+ function ye(e, t) {
1447
1459
  let n = [], r = t.map((e, t) => `<c r="${R(0, t)}" t="str" s="2"><v>${L(e.label)}</v></c>`);
1448
1460
  return n.push(`<row r="1">${r.join("")}</row>`), e.forEach((e, r) => {
1449
1461
  let i = t.map((t, n) => {
1450
1462
  let i = R(r + 1, n), a = e[t.key];
1451
1463
  if (a == null) return `<c r="${i}" t="str"><v></v></c>`;
1452
1464
  let o = t.type ?? "text";
1453
- 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>${fe(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>`;
1465
+ 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>${me(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>`;
1454
1466
  });
1455
1467
  n.push(`<row r="${r + 2}">${i.join("")}</row>`);
1456
1468
  }), `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -1458,24 +1470,24 @@ function _e(e, t) {
1458
1470
  <sheetData>${n.join("")}</sheetData>
1459
1471
  </worksheet>`;
1460
1472
  }
1461
- function ve(e, t) {
1462
- let n = _e(e, t);
1463
- return ue([
1473
+ function be(e, t) {
1474
+ let n = ye(e, t);
1475
+ return fe([
1464
1476
  {
1465
1477
  name: "[Content_Types].xml",
1466
- data: F.encode(pe)
1478
+ data: F.encode(z)
1467
1479
  },
1468
1480
  {
1469
1481
  name: "_rels/.rels",
1470
- data: F.encode(me)
1482
+ data: F.encode(he)
1471
1483
  },
1472
1484
  {
1473
1485
  name: "xl/workbook.xml",
1474
- data: F.encode(z)
1486
+ data: F.encode(ge)
1475
1487
  },
1476
1488
  {
1477
1489
  name: "xl/_rels/workbook.xml.rels",
1478
- data: F.encode(he)
1490
+ data: F.encode(_e)
1479
1491
  },
1480
1492
  {
1481
1493
  name: "xl/worksheets/sheet1.xml",
@@ -1483,7 +1495,7 @@ function ve(e, t) {
1483
1495
  },
1484
1496
  {
1485
1497
  name: "xl/styles.xml",
1486
- data: F.encode(ge)
1498
+ data: F.encode(ve)
1487
1499
  }
1488
1500
  ]);
1489
1501
  }
@@ -1493,20 +1505,20 @@ function B(e, t, n) {
1493
1505
  switch (n) {
1494
1506
  case "csv": return V(e, t, ",");
1495
1507
  case "tsv": return V(e, t, " ");
1496
- case "json": return be(e, t);
1497
- case "xlsx": return ve(e, t);
1508
+ case "json": return Se(e, t);
1509
+ case "xlsx": return be(e, t);
1498
1510
  }
1499
1511
  }
1500
- function ye(e, t) {
1512
+ function xe(e, t) {
1501
1513
  return e == null ? "" : (t.type === "date" || t.type === "datetime") && e instanceof Date ? e.toISOString() : String(e);
1502
1514
  }
1503
1515
  function V(e, t, n) {
1504
- return [t.map((e) => H(e.label, n)).join(n), ...e.map((e) => t.map((t) => H(ye(e[t.key], t), n)).join(n))].join("\n");
1516
+ return [t.map((e) => H(e.label, n)).join(n), ...e.map((e) => t.map((t) => H(xe(e[t.key], t), n)).join(n))].join("\n");
1505
1517
  }
1506
1518
  function H(e, t) {
1507
1519
  return e.includes(t) || e.includes("\"") || e.includes("\n") || e.includes("\r") ? "\"" + e.replace(/"/g, "\"\"") + "\"" : e;
1508
1520
  }
1509
- function be(e, t) {
1521
+ function Se(e, t) {
1510
1522
  let n = e.map((e) => {
1511
1523
  let n = {};
1512
1524
  for (let r of t) {
@@ -1517,35 +1529,35 @@ function be(e, t) {
1517
1529
  });
1518
1530
  return JSON.stringify(n, null, 2);
1519
1531
  }
1520
- function xe(e, t, n) {
1532
+ function Ce(e, t, n) {
1521
1533
  let r = new Blob([e], { type: n }), i = URL.createObjectURL(r), a = document.createElement("a");
1522
1534
  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);
1523
1535
  }
1524
- var Se = {
1536
+ var U = {
1525
1537
  csv: "text/csv;charset=utf-8",
1526
1538
  tsv: "text/tab-separated-values;charset=utf-8",
1527
1539
  json: "application/json;charset=utf-8",
1528
1540
  xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1529
- }, Ce = {
1541
+ }, we = {
1530
1542
  csv: ".csv",
1531
1543
  tsv: ".tsv",
1532
1544
  json: ".json",
1533
1545
  xlsx: ".xlsx"
1534
1546
  };
1535
- function we(e) {
1536
- return Se[e];
1537
- }
1538
1547
  function Te(e) {
1539
- return Ce[e];
1548
+ return U[e];
1549
+ }
1550
+ function Ee(e) {
1551
+ return we[e];
1540
1552
  }
1541
1553
  //#endregion
1542
1554
  //#region src/export/xlsx-reader.ts
1543
- function Ee(e) {
1555
+ function De(e) {
1544
1556
  for (let t = e.byteLength - 22; t >= 0; t--) if (e.getUint32(t, !0) === 101010256) return t;
1545
1557
  throw Error("XLSX: End of central directory not found — not a valid ZIP file");
1546
1558
  }
1547
- function De(e) {
1548
- let t = Ee(e), n = e.getUint32(t + 16, !0), r = e.getUint32(t + 12, !0), i = new TextDecoder("utf-8"), a = [], o = n, s = n + r;
1559
+ function Oe(e) {
1560
+ 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;
1549
1561
  for (; o < s && e.getUint32(o, !0) === 33639248;) {
1550
1562
  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));
1551
1563
  a.push({
@@ -1558,7 +1570,7 @@ function De(e) {
1558
1570
  }
1559
1571
  return a;
1560
1572
  }
1561
- async function Oe(e) {
1573
+ async function ke(e) {
1562
1574
  let t = new DecompressionStream("deflate-raw"), n = t.writable.getWriter(), r = t.readable.getReader();
1563
1575
  n.write(e), n.close();
1564
1576
  let i = [];
@@ -1571,28 +1583,28 @@ async function Oe(e) {
1571
1583
  for (let e of i) o.set(e, s), s += e.length;
1572
1584
  return o;
1573
1585
  }
1574
- async function ke(e, t) {
1586
+ async function Ae(e, t) {
1575
1587
  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);
1576
1588
  if (t.compressionMethod === 0) return o.slice();
1577
- if (t.compressionMethod === 8) return Oe(o);
1589
+ if (t.compressionMethod === 8) return ke(o);
1578
1590
  throw Error(`XLSX: Unsupported compression method ${t.compressionMethod}`);
1579
1591
  }
1580
- async function Ae(e) {
1581
- let t = new DataView(e), n = De(t), r = /* @__PURE__ */ new Map();
1582
- for (let e of n) e.compressedSize === 0 && e.name.endsWith("/") || r.set(e.name, await ke(t, e));
1592
+ async function je(e) {
1593
+ let t = new DataView(e), n = Oe(t), r = /* @__PURE__ */ new Map();
1594
+ for (let e of n) e.compressedSize === 0 && e.name.endsWith("/") || r.set(e.name, await Ae(t, e));
1583
1595
  return r;
1584
1596
  }
1585
- var je = new TextDecoder("utf-8");
1586
- function U(e) {
1587
- let t = je.decode(e);
1597
+ var Me = new TextDecoder("utf-8");
1598
+ function W(e) {
1599
+ let t = Me.decode(e);
1588
1600
  return new DOMParser().parseFromString(t, "application/xml");
1589
1601
  }
1590
- function Me(e) {
1602
+ function Ne(e) {
1591
1603
  if (!e) return [];
1592
- let t = U(e);
1604
+ let t = W(e);
1593
1605
  return Array.from(t.querySelectorAll("si")).map((e) => Array.from(e.querySelectorAll("t")).map((e) => e.textContent ?? "").join(""));
1594
1606
  }
1595
- var Ne = /* @__PURE__ */ new Set([
1607
+ var Pe = /* @__PURE__ */ new Set([
1596
1608
  14,
1597
1609
  15,
1598
1610
  16,
@@ -1612,37 +1624,37 @@ var Ne = /* @__PURE__ */ new Set([
1612
1624
  57,
1613
1625
  58
1614
1626
  ]);
1615
- function Pe(e) {
1627
+ function Fe(e) {
1616
1628
  let t = e.replace(/"[^"]*"/g, "").replace(/\\./g, "").replace(/\[[^\]]*\]/g, "").split(";")[0];
1617
1629
  return /[dy]/i.test(t);
1618
1630
  }
1619
- function Fe(e) {
1631
+ function Ie(e) {
1620
1632
  let t = /* @__PURE__ */ new Set();
1621
1633
  if (!e) return t;
1622
- let n = U(e), r = /* @__PURE__ */ new Map();
1634
+ let n = W(e), r = /* @__PURE__ */ new Map();
1623
1635
  for (let e of Array.from(n.querySelectorAll("numFmts > numFmt"))) r.set(parseInt(e.getAttribute("numFmtId") ?? "", 10), e.getAttribute("formatCode") ?? "");
1624
1636
  return Array.from(n.querySelectorAll("cellXfs > xf")).forEach((e, n) => {
1625
1637
  let i = parseInt(e.getAttribute("numFmtId") ?? "0", 10), a = r.get(i);
1626
- (a === void 0 ? Ne.has(i) : Pe(a)) && t.add(n);
1638
+ (a === void 0 ? Pe.has(i) : Fe(a)) && t.add(n);
1627
1639
  }), t;
1628
1640
  }
1629
- function Ie(e) {
1641
+ function Le(e) {
1630
1642
  if (!e) return !1;
1631
- let t = U(e).querySelector("workbookPr")?.getAttribute("date1904");
1643
+ let t = W(e).querySelector("workbookPr")?.getAttribute("date1904");
1632
1644
  return t === "1" || t === "true";
1633
1645
  }
1634
- function W(e, t) {
1646
+ function Re(e, t) {
1635
1647
  return new Date((t ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30)) + Math.floor(e) * 864e5).toISOString().slice(0, 10);
1636
1648
  }
1637
- function Le(e, t, n, r) {
1638
- let i = U(e).querySelectorAll("row");
1649
+ function ze(e, t, n, r) {
1650
+ let i = W(e).querySelectorAll("row");
1639
1651
  if (i.length === 0) return [];
1640
1652
  let a = 0, o = /* @__PURE__ */ new Map();
1641
1653
  for (let e of i) {
1642
1654
  let i = parseInt(e.getAttribute("r") ?? "1", 10) - 1, s = /* @__PURE__ */ new Map();
1643
1655
  o.set(i, s);
1644
1656
  for (let i of e.querySelectorAll("c")) {
1645
- let e = Re(i.getAttribute("r") ?? "");
1657
+ let e = Be(i.getAttribute("r") ?? "");
1646
1658
  e > a && (a = e);
1647
1659
  let o = i.getAttribute("t") ?? "", c = i.getAttribute("s") ?? "", l = i.querySelector("v")?.textContent ?? "", u = i.querySelector("is > t")?.textContent ?? null, d;
1648
1660
  if (o === "s") d = t[parseInt(l, 10)] ?? "";
@@ -1651,7 +1663,7 @@ function Le(e, t, n, r) {
1651
1663
  else if (l === "") d = "";
1652
1664
  else {
1653
1665
  let e = parseFloat(l);
1654
- d = c !== "" && n.has(parseInt(c, 10)) && !isNaN(e) && e >= 0 ? W(e, r) : l;
1666
+ d = c !== "" && n.has(parseInt(c, 10)) && !isNaN(e) && e >= 0 ? Re(e, r) : l;
1655
1667
  }
1656
1668
  s.set(e, d);
1657
1669
  }
@@ -1665,13 +1677,13 @@ function Le(e, t, n, r) {
1665
1677
  }
1666
1678
  return c;
1667
1679
  }
1668
- function Re(e) {
1680
+ function Be(e) {
1669
1681
  let t = 0, n = 0;
1670
1682
  for (; n < e.length && e[n] >= "A" && e[n] <= "Z";) t = t * 26 + (e.charCodeAt(n) - 64), n++;
1671
1683
  return t - 1;
1672
1684
  }
1673
- async function ze(e) {
1674
- let t = await Ae(e), n = Me(t.get("xl/sharedStrings.xml")), r = t.get("xl/worksheets/sheet1.xml");
1685
+ async function Ve(e) {
1686
+ let t = await je(e), n = Ne(t.get("xl/sharedStrings.xml")), r = t.get("xl/worksheets/sheet1.xml");
1675
1687
  if (!r) {
1676
1688
  for (let [e, n] of t) if (e.toLowerCase().includes("worksheets/sheet")) {
1677
1689
  r = n;
@@ -1679,7 +1691,7 @@ async function ze(e) {
1679
1691
  }
1680
1692
  }
1681
1693
  if (!r) throw Error("XLSX: No worksheet found");
1682
- let i = Fe(t.get("xl/styles.xml")), a = Ie(t.get("xl/workbook.xml")), o = Le(r, n, i, a);
1694
+ let i = Ie(t.get("xl/styles.xml")), a = Le(t.get("xl/workbook.xml")), o = ze(r, n, i, a);
1683
1695
  return o.length === 0 ? {
1684
1696
  headers: [],
1685
1697
  rows: []
@@ -1710,14 +1722,14 @@ var q = {
1710
1722
  lt: "<",
1711
1723
  gte: "≥",
1712
1724
  lte: "≤"
1713
- }, J = 120, Y = 40, X = 20, Z = 32, Q = 5, Be = 200, $ = class extends n {
1725
+ }, J = 120, Y = 40, X = 20, Z = 32, Q = 5, He = 200, $ = class extends n {
1714
1726
  constructor(...e) {
1715
- 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 ne(), this._editing = new re(), 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 = () => {
1727
+ 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 re(), this._editing = new ie(), 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 = () => {
1716
1728
  this._commitCommentPopup();
1717
1729
  }, 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();
1718
1730
  }
1719
1731
  static {
1720
- this.styles = v;
1732
+ this.styles = y;
1721
1733
  }
1722
1734
  get data() {
1723
1735
  return this._data;
@@ -2082,7 +2094,7 @@ var q = {
2082
2094
  return B(this._sortedIndices.map((e) => this.data[e]), this.visibleColumns, e);
2083
2095
  }
2084
2096
  exportToFile(e, t) {
2085
- xe(this.exportToString(e), t ?? `export${Te(e)}`, we(e));
2097
+ Ce(this.exportToString(e), t ?? `export${Ee(e)}`, Te(e));
2086
2098
  }
2087
2099
  setComment(e, t, n) {
2088
2100
  let r = this.getComment(e, t);
@@ -2139,10 +2151,10 @@ var q = {
2139
2151
  async importFromFile(e) {
2140
2152
  let t = e.name.toLowerCase();
2141
2153
  if (t.endsWith(".xlsx")) {
2142
- let t = await ze(await e.arrayBuffer());
2154
+ let t = await Ve(await e.arrayBuffer());
2143
2155
  this._applyImportedSheet(t);
2144
2156
  } else if (t.endsWith(".csv") || t.endsWith(".tsv")) {
2145
- let t = await e.text(), n = h(t);
2157
+ let t = await e.text(), n = g(t);
2146
2158
  this._applyImportedRows(n);
2147
2159
  } else console.warn(`flex-table importFromFile: unsupported file type "${e.name}"`);
2148
2160
  }
@@ -2332,7 +2344,7 @@ var q = {
2332
2344
  this._filteredIndices = Array.from({ length: this.data.length }, (e, t) => t), this._sortedIndices = this._filteredIndices;
2333
2345
  return;
2334
2346
  }
2335
- if (this._filteredIndices = ie(this.data, this._filters, (e, t, n) => {
2347
+ if (this._filteredIndices = ae(this.data, this._filters, (e, t, n) => {
2336
2348
  this.dispatchEvent(new CustomEvent("filter-error", {
2337
2349
  detail: {
2338
2350
  error: e,
@@ -2362,7 +2374,7 @@ var q = {
2362
2374
  e !== this._viewportHeight && (this._viewportHeight = e), t !== this._viewportWidth && (this._viewportWidth = t), this._warnIfUnconstrained();
2363
2375
  }
2364
2376
  _warnIfUnconstrained() {
2365
- this._warnedUnconstrained || process.env.NODE_ENV === "production" || this._visibleRowCount < Be || 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.`));
2377
+ 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.`));
2366
2378
  }
2367
2379
  _onScroll() {
2368
2380
  this._scrollTop = this.scrollTop, this._scrollLeft = this.scrollLeft;
@@ -2516,8 +2528,8 @@ var q = {
2516
2528
  }));
2517
2529
  return;
2518
2530
  }
2519
- if (a.type === "number" && typeof e == "string" || a.type === "date" && typeof e == "string" && p(e) === null) {
2520
- let t = A(a.type === "number" ? "notANumber" : "notADate");
2531
+ if (a.type === "number" && typeof e == "string" || a.type === "date" && typeof e == "string" && p(e) === null || a.type === "datetime" && typeof e == "string" && m(e) === null) {
2532
+ let t = A(a.type === "number" ? "notANumber" : a.type === "date" ? "notADate" : "notADateTime");
2521
2533
  this._markCellInvalid(n, r, t), this.dispatchEvent(new CustomEvent("validation-error", {
2522
2534
  detail: {
2523
2535
  row: i,
@@ -2581,7 +2593,7 @@ var q = {
2581
2593
  }));
2582
2594
  }
2583
2595
  _onEditorKeyDown(e) {
2584
- if (!_(e)) {
2596
+ if (!v(e)) {
2585
2597
  if (this._autocompleteState && this._autocompleteState.candidates.length > 0) {
2586
2598
  if (e.key === "ArrowDown") {
2587
2599
  e.preventDefault(), e.stopPropagation();
@@ -2649,7 +2661,7 @@ var q = {
2649
2661
  ].includes(t) && this._handleCtrlKey(e)) return;
2650
2662
  }
2651
2663
  if (t.length !== 0 && this._visibleRowCount !== 0) {
2652
- if ((e.key === "Enter" || e.key === "F2") && this._activeCell && !_(e)) {
2664
+ if ((e.key === "Enter" || e.key === "F2") && this._activeCell && !v(e)) {
2653
2665
  e.preventDefault();
2654
2666
  let n = t[this._activeCell.col];
2655
2667
  n && this._isCellEditable(n) ? this._startEdit() : e.key === "Enter" && this._fireRowActivate(n);
@@ -2737,7 +2749,7 @@ var q = {
2737
2749
  async _handleCopy(e) {
2738
2750
  let t = this._selection.getEffectiveRange();
2739
2751
  if (!t) return;
2740
- let n = this.visibleColumns, r = oe(this._sortedIndices.map((e) => this.data[e]), n, t);
2752
+ let n = this.visibleColumns, r = se(this._sortedIndices.map((e) => this.data[e]), n, t);
2741
2753
  try {
2742
2754
  await navigator.clipboard.writeText(r);
2743
2755
  } catch (e) {
@@ -2763,7 +2775,7 @@ var q = {
2763
2775
  if (!this._activeCell) return;
2764
2776
  let e = await this._readClipboardText();
2765
2777
  if (e == null) return;
2766
- let t = h(e);
2778
+ let t = g(e);
2767
2779
  if (t.length === 0) return;
2768
2780
  let n = this._expandRowsForPaste(this._activeCell.row, t.length), r = this._applyPasteData(this._activeCell, t);
2769
2781
  if (r.length > 0 || n.length > 0) {
@@ -3492,7 +3504,7 @@ var q = {
3492
3504
  i[t] = {
3493
3505
  ...i[t],
3494
3506
  text: r,
3495
- value: r.trim() === "" ? null : m(r)
3507
+ value: r.trim() === "" ? null : h(r)
3496
3508
  }, this._numberFilterState.set(e, i), this._emptyFilterState.delete(e), this._applyFilterForKey(e);
3497
3509
  }}
3498
3510
  @keydown=${(e) => {
@@ -3998,7 +4010,7 @@ var q = {
3998
4010
  this._closeFindPanel();
3999
4011
  return;
4000
4012
  }
4001
- e.key === "Enter" && !_(e) && e.target instanceof HTMLInputElement && e.target.classList.contains("ft-find-input") && (e.shiftKey ? this._findPrev() : this._findNext());
4013
+ e.key === "Enter" && !v(e) && e.target instanceof HTMLInputElement && e.target.classList.contains("ft-find-input") && (e.shiftKey ? this._findPrev() : this._findNext());
4002
4014
  }}>
4003
4015
  <div class="ft-find-row">
4004
4016
  <input class="ft-find-input" type="text" placeholder=${A("findPlaceholder")}
@@ -4209,7 +4221,7 @@ var q = {
4209
4221
  ${this._renderEditor(e, t)}
4210
4222
  </div>
4211
4223
  `;
4212
- let v = s || l, y = this._isCellInvalid(n, r), b = (this._findState?.results ?? []).findIndex((e) => e.row === n && e.col === r), x = b >= 0, S = x && b === this._findState.currentIndex, w = [
4224
+ let v = s || l, y = this._isCellInvalid(n, r), b = (this._findState?.results ?? []).findIndex((e) => e.row === n && e.col === r), x = b >= 0, S = x && b === this._findState.currentIndex, C = [
4213
4225
  "ft-cell",
4214
4226
  `ft-type-${t.type ?? "text"}`,
4215
4227
  `ft-align-${G(t)}`,
@@ -4223,7 +4235,7 @@ var q = {
4223
4235
  o?.opensDown ? "ft-merge-open" : ""
4224
4236
  ].filter(Boolean).join(" "), T = this._toDataIndex(n), E = this._comments.get(T)?.get(t.key) ?? null, D = E !== null, O = D ? i`<div class="ft-comment-indicator" title=${E}></div>` : a;
4225
4237
  return i`
4226
- <div class=${D ? w + " ft-has-comment" : w}
4238
+ <div class=${D ? C + " ft-has-comment" : C}
4227
4239
  role="gridcell"
4228
4240
  aria-colindex=${r + 1}
4229
4241
  data-col-index=${r}
@@ -4237,7 +4249,7 @@ var q = {
4237
4249
  @click=${(e) => this._onCellClickEvent(e, n, r)}
4238
4250
  @dblclick=${() => this._onCellDblClick(n, r)}>
4239
4251
  ${O}
4240
- ${C(e[t.key], e, t)}
4252
+ ${w(e[t.key], e, t)}
4241
4253
  </div>
4242
4254
  `;
4243
4255
  }
@@ -4252,19 +4264,16 @@ var q = {
4252
4264
  `;
4253
4265
  if (t.type === "date") return i`
4254
4266
  <input class="ft-editor ft-editor-date" type="text" inputmode="numeric" placeholder=${u()}
4255
- .value=${se(n)}
4267
+ .value=${ce(n)}
4256
4268
  @keydown=${this._onEditorKeyDown}
4257
4269
  @blur=${() => this._commitEdit()}>
4258
4270
  `;
4259
- if (t.type === "datetime") {
4260
- let e = this._toDateTimeInputValue(n);
4261
- return i`
4262
- <input class="ft-editor" type="datetime-local"
4263
- .value=${e}
4271
+ if (t.type === "datetime") return i`
4272
+ <input class="ft-editor ft-editor-datetime" type="text" placeholder=${`${u()} HH:mm`}
4273
+ .value=${le(n)}
4264
4274
  @keydown=${this._onEditorKeyDown}
4265
4275
  @blur=${() => this._commitEdit()}>
4266
4276
  `;
4267
- }
4268
4277
  if (t.type === "select" && t.options && t.options.length > 0) {
4269
4278
  let e = t.options, r = typeof e[0] == "string";
4270
4279
  return i`
@@ -4305,11 +4314,6 @@ var q = {
4305
4314
  @blur=${() => this._commitEdit()}>
4306
4315
  `;
4307
4316
  }
4308
- _toDateTimeInputValue(e) {
4309
- if (!e) return "";
4310
- let t = e instanceof Date ? e : new Date(String(e));
4311
- return isNaN(t.getTime()) ? "" : `${t.getFullYear()}-${String(t.getMonth() + 1).padStart(2, "0")}-${String(t.getDate()).padStart(2, "0")}T${String(t.getHours()).padStart(2, "0")}:${String(t.getMinutes()).padStart(2, "0")}`;
4312
- }
4313
4317
  };
4314
4318
  K([s({ type: Array })], $.prototype, "columns", void 0), K([s({
4315
4319
  type: Array,
@@ -4367,4 +4371,4 @@ K([s({ type: Array })], $.prototype, "columns", void 0), K([s({
4367
4371
  attribute: "max-undo-size"
4368
4372
  })], $.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")], $);
4369
4373
  //#endregion
4370
- export { j as a, M as i, G as n, k as o, B as r, C as s, $ as t };
4374
+ export { j as a, M as i, G as n, k as o, B as r, w as s, $ as t };
@@ -525,9 +525,6 @@ export declare class FlexTable extends LitElement {
525
525
  private _mergeState;
526
526
  private _renderCell;
527
527
  private _renderEditor;
528
- /** Convert value to YYYY-MM-DD for date input (local timezone) */
529
- /** Convert value to YYYY-MM-DDTHH:mm for datetime-local input (local timezone) */
530
- private _toDateTimeInputValue;
531
528
  }
532
529
  declare global {
533
530
  interface HTMLElementTagNameMap {
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./flex-table-C6PFutM_.js";
1
+ import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./flex-table-CZPubYVD.js";
2
2
  export { o as FlexTable, e as RowSelectionState, t as UndoStack, n as effectiveAlign, i as exportData, r as flexTableLocale, a as renderCell };
package/dist/locale.d.ts CHANGED
@@ -25,7 +25,7 @@
25
25
  * (아이콘 자리의 글리프)는 어느 로케일에서도 같은 것을 뜻하며, 번역하면 오히려 읽히지 않는다.
26
26
  * 그 판단은 «번역하지 않기로 한 것»이지 «빠뜨린 것»이 아니다.
27
27
  */
28
- export type FlexTableMessageKey = 'showHiddenColumns' | 'columnMenu' | 'cellActions' | 'noColumnsDefined' | 'addCommentPlaceholder' | 'cancel' | 'save' | 'clear' | 'blankCells' | 'emptyOnly' | 'nonEmptyOnly' | 'blankAll' | 'all' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'searchPlaceholder' | 'valuePlaceholder' | 'fromPlaceholder' | 'toPlaceholder' | 'findPlaceholder' | 'findPrevious' | 'findNext' | 'matchCase' | 'wholeCell' | 'closeFind' | 'replaceWithPlaceholder' | 'replace' | 'replaceAll' | 'sortAscending' | 'sortDescending' | 'filter' | 'clearFilter' | 'hideColumn' | 'showColumn' | 'autoFitWidth' | 'wider' | 'narrower' | 'columnMenuFor' | 'columnMenuRegion' | 'copy' | 'insertRowAbove' | 'insertRowBelow' | 'deleteRow' | 'filterByThisValue' | 'addComment' | 'editComment' | 'deleteComment' | 'booleanTrue' | 'booleanFalse' | 'dropFileToImport' | 'notANumber' | 'notADate' | 'notInList';
28
+ export type FlexTableMessageKey = 'showHiddenColumns' | 'columnMenu' | 'cellActions' | 'noColumnsDefined' | 'addCommentPlaceholder' | 'cancel' | 'save' | 'clear' | 'blankCells' | 'emptyOnly' | 'nonEmptyOnly' | 'blankAll' | 'all' | 'contains' | 'startsWith' | 'endsWith' | 'wildcard' | 'searchPlaceholder' | 'valuePlaceholder' | 'fromPlaceholder' | 'toPlaceholder' | 'findPlaceholder' | 'findPrevious' | 'findNext' | 'matchCase' | 'wholeCell' | 'closeFind' | 'replaceWithPlaceholder' | 'replace' | 'replaceAll' | 'sortAscending' | 'sortDescending' | 'filter' | 'clearFilter' | 'hideColumn' | 'showColumn' | 'autoFitWidth' | 'wider' | 'narrower' | 'columnMenuFor' | 'columnMenuRegion' | 'copy' | 'insertRowAbove' | 'insertRowBelow' | 'deleteRow' | 'filterByThisValue' | 'addComment' | 'editComment' | 'deleteComment' | 'booleanTrue' | 'booleanFalse' | 'dropFileToImport' | 'notANumber' | 'notADate' | 'notADateTime' | 'notInList';
29
29
  /** 이 패키지의 chrome 문자열 묶음. 소비자가 `register()` 로 언어를 더하거나 문구를 덮을 수 있다. */
30
30
  export declare const flexTableLocale: import("@iyulab/components/dist/utilities/Locale.js").LocaleNamespace<FlexTableMessageKey>;
31
31
  /** 짧은 조회 별칭 — 렌더 코드가 읽히게 유지한다. */
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./flex-table-C6PFutM_.js";
1
+ import { t as e } from "./flex-table-CZPubYVD.js";
2
2
  import { i as t, t as n } from "./query-Dw4iO0ir.js";
3
3
  import { t as r } from "./view-DiLr-TdY.js";
4
4
  import i, { useCallback as a, useEffect as o, useMemo as s, useRef as c, useState as l } from "react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.41.1",
3
+ "version": "0.41.2",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",
@@ -72,7 +72,7 @@
72
72
  "odata-query": "^8.1.0"
73
73
  },
74
74
  "peerDependencies": {
75
- "@iyulab/components": ">=1.55.0",
75
+ "@iyulab/components": ">=1.56.0",
76
76
  "@lit/react": "^1.0.8",
77
77
  "react": "^18.0.0 || ^19.0.0"
78
78
  },
@@ -67,7 +67,7 @@ as `text`). See `references/api.md` for every field.
67
67
  - `editor` returns a Lit template containing an element with class `ft-editor`; its `.value` is committed.
68
68
  - `validator` returns `null` when valid, or an error message (the edit is rejected and `validation-error` fires).
69
69
  - `number` cells, the number filter and paste read numbers in the active `Locale` (`1,5` is 1.5 on a comma-decimal page); an edit that is not a number is rejected with `validation-error`.
70
- - `date` cells edit as a `YYYY-MM-DD` text box in every browser language (also `20261002`, `2026/10/2`, `10-02`); pasted dates are normalized to ISO.
70
+ - `date` cells edit as a `YYYY-MM-DD` text box in every browser language (also `20261002`, `2026/10/2`, `10-02`); pasted dates are normalized to ISO. `datetime` cells edit as `YYYY-MM-DD HH:mm` (local) and store `YYYY-MM-DDTHH:mm`.
71
71
  - `conditionalRules` applies `{ when, style }` rules in order; later matches override earlier ones.
72
72
  - `pinned: 'left' | 'right'` freezes a column during horizontal scroll.
73
73