@iyulab/flex-table 0.46.0 → 0.47.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.47.0] - 2026-10-05
4
+
5
+ ### Changed
6
+
7
+ - **Breaking: `error` from `useODataSource` and `useArraySource` is a structured failure, not a
8
+ string** — `SourceError | null`, where `SourceError` is `{ message, status?, code?, details?, body? }`
9
+ (exported from `@iyulab/flex-table/react` with `SourceErrorDetail`). The message alone lost which
10
+ failure it was, so an app could not tell a 403 the server marked with its own code (for example
11
+ "password change required") from any other 403, or a 404 from a 409, without wrapping `fetcher`
12
+ to watch the status. Now `status` is the HTTP status, `code` the server's rejection code (OData
13
+ `error.code`), `details` the OData `error.details` entries, and `body` the parsed response (or its
14
+ text). A failure with no response — a network error, or a `@odata.nextLink` the hook refused — has
15
+ a `message` only. The message itself is unchanged.
16
+
17
+ Migration: render `error.message` where you rendered `error`
18
+ (`{source.error && <p role="alert">{source.error.message}</p>}`), and compare `error?.message`
19
+ where you compared the string.
20
+
21
+ - **Date and datetime column filters use `u-date-picker`** for their From and To bounds, like the
22
+ cell editor since 0.46. The native date inputs they replace showed the browser's UI language
23
+ (`10/02/2026` in an English browser) while the table shows ISO; the bounds now read and show
24
+ `YYYY-MM-DD` (`YYYY-MM-DD HH:mm`) everywhere, with a calendar beside each. The bounds are labelled
25
+ (**From**, **To**), each calendar stops at the other bound, and either bound may still stay empty.
26
+ A bound now applies when it is committed — Enter, leaving the box, or a day picked in the calendar —
27
+ rather than on every keystroke. While a calendar is open, Escape closes the calendar and the next
28
+ Escape closes the filter. Opening the filter from the column menu focuses the From bound.
29
+
3
30
  ## [0.46.0] - 2026-10-05
4
31
 
5
32
  ### Changed
package/README.md CHANGED
@@ -684,8 +684,13 @@ button is highlighted while its column has an active filter.
684
684
  - **text**: case-insensitive substring search
685
685
  - **number**: min/max range inputs
686
686
  - **boolean**: All / True / False select
687
- - **date**: from/to date range picker (`<input type="date">`)
688
- - **datetime**: from/to datetime range picker (`<input type="datetime-local">`)
687
+ - **date**: **From** and **To** `u-date-picker`s (`@iyulab/components`) — the cell editor's control, so the
688
+ bounds read and show `YYYY-MM-DD` in every browser language, with a calendar beside each. Either
689
+ bound may stay empty; the end day is inclusive, and each calendar stops at the other bound.
690
+ - **datetime**: the same pickers with a time (`YYYY-MM-DD HH:mm`)
691
+
692
+ A bound applies when it is committed — Enter, leaving the box, or a day picked in its calendar. While a
693
+ calendar is open, Escape closes the calendar; the next Escape closes the filter.
689
694
 
690
695
  Filters set via the UI and the programmatic API (`setFilter()`) share the same filter state. Filter dropdowns automatically flip upward when near the viewport bottom.
691
696
 
@@ -787,7 +792,7 @@ The hook returns:
787
792
  |---|---|
788
793
  | `data` / `totalCount` | Current page rows and the server's total (`@odata.count`). When the server pages its response (`@odata.nextLink`, e.g. a page size smaller than `pageSize`), the hook follows the link until the page is filled; a link outside the request's origin, or one that returns to a page already read, is reported through `error` instead of showing a short page |
789
794
  | `loading` | A request is in flight |
790
- | `error` | Message of the last failed request, or `null`. **Render this** — a failed request otherwise leaves the grid silently empty |
795
+ | `error` | The last failed request, or `null`: `{ message, status?, code?, details?, body? }`. **Render `error.message`** — a failed request otherwise leaves the grid silently empty. Branch on `status` (HTTP), `code` (the server's rejection code, OData `error.code`) and `details` (OData `error.details`); `body` is the parsed response (or its text). A failure with no response — a network error, or a `@odata.nextLink` the hook refused — has a `message` only |
791
796
  | `page` / `setPage` | Zero-based page index |
792
797
  | `sortCriteria` / `onSortChange` | Bind `onSortChange` to the table's `sort-change` event |
793
798
  | `search` / `setSearch` | Current search term and its setter (resets to page 0) |
@@ -1,4 +1,5 @@
1
1
  import type { SortCriteria } from '../core/sorting.js';
2
+ import type { SourceError } from '../core/source-error.js';
2
3
  export interface UseArraySourceOptions<T> {
3
4
  /** 페이지당 행 수. `useODataSource`와 동일 기본값. */
4
5
  pageSize?: number;
@@ -36,7 +37,7 @@ export interface UseArraySourceResult<T> {
36
37
  /** 항상 `false` — 로컬 배열은 동기 처리라 로딩 상태가 없다. `useODataSource`와의 반환 형태 동일성을 위해 유지. */
37
38
  loading: boolean;
38
39
  /** 항상 `null` — 로컬 배열 처리는 실패하지 않는다. 위와 같은 이유로 유지. */
39
- error: string | null;
40
+ error: SourceError | null;
40
41
  page: number;
41
42
  setPage: (page: number) => void;
42
43
  sortCriteria: SortCriteria[];
@@ -0,0 +1,35 @@
1
+ /** OData v4 오류 봉투의 `error.details` 항목 — 필드별 검증 실패 상세. */
2
+ export interface SourceErrorDetail {
3
+ code: string;
4
+ message: string;
5
+ target?: string;
6
+ }
7
+ /**
8
+ * 데이터 소스 훅(`useODataSource`/`useArraySource`)의 실패 값.
9
+ *
10
+ * 문자열 하나가 아니라 구조로 싣는 이유: 소비자는 «어떤 실패인가» 로 갈라야 한다 — 403 중에서도
11
+ * 서버가 코드로 구분한 거절(«비밀번호를 바꿔야 한다»), 404(지워진 행), 409(동시성), 429(제한).
12
+ * 메시지만 남기면 그 정보가 소스 경계에서 사라지고, 소비자는 전송(`fetcher`)을 감싸 상태를
13
+ * 엿보는 것 말고는 길이 없다.
14
+ */
15
+ export interface SourceError {
16
+ /** 보여 줄 문장 — 서버가 준 메시지가 있으면 그것, 없으면 `Request failed (<status>)`. */
17
+ message: string;
18
+ /** HTTP 상태. 응답이 없던 실패(네트워크 오류 · `@odata.nextLink` 검사)에는 없다. */
19
+ status?: number;
20
+ /** 서버가 정한 거절 코드 — OData 오류 봉투의 `error.code`(또는 최상위 `code`). */
21
+ code?: string;
22
+ /** 오류 봉투의 `error.details` 중 `code`·`message` 가 둘 다 문자열인 항목. */
23
+ details?: SourceErrorDetail[];
24
+ /** 응답 본문 — JSON 이면 파싱한 값, 아니면 텍스트. 비어 있으면 없다. */
25
+ body?: unknown;
26
+ }
27
+ /** 실패 응답을 `SourceError` 로 읽는다. 본문을 읽을 수 없어도 상태와 기본 문장은 남긴다. */
28
+ export declare function readFailedResponse(res: Response): Promise<SourceError>;
29
+ /** 실패 응답을 실어 나르는 내부 예외 — `catch` 가 상태를 잃지 않고 `SourceError` 를 꺼낸다. */
30
+ export declare class SourceRequestError extends Error {
31
+ readonly failure: SourceError;
32
+ constructor(failure: SourceError);
33
+ }
34
+ /** 잡힌 예외를 `SourceError` 로 — 응답이 있던 실패는 그 구조 그대로, 나머지는 메시지만. */
35
+ export declare function toSourceError(err: unknown): SourceError;
@@ -567,6 +567,19 @@ var v = r`
567
567
  width: 50%;
568
568
  }
569
569
 
570
+ /* Date bounds stack: side by side, half of the dropdown is narrower than a date (and far narrower
571
+ than a date and a time) plus the calendar button. */
572
+ .ft-filter-range-dates {
573
+ flex-direction: column;
574
+ gap: 6px;
575
+ }
576
+
577
+ .ft-filter-date {
578
+ display: block;
579
+ width: 100%;
580
+ min-width: 0;
581
+ }
582
+
570
583
  .ft-filter-actions {
571
584
  margin-top: 6px;
572
585
  text-align: right;
@@ -1464,19 +1477,19 @@ function N(e, t) {
1464
1477
  default: return e;
1465
1478
  }
1466
1479
  }
1467
- function P(e) {
1480
+ function se(e) {
1468
1481
  let t = String(e);
1469
1482
  if (!Number.isFinite(e) || t.includes("e")) return t;
1470
1483
  let n = new Intl.NumberFormat(l.get()).formatToParts(1.5).find((e) => e.type === "decimal")?.value;
1471
1484
  return n && n !== "." ? t.replace(".", n) : t;
1472
1485
  }
1473
- function se(e) {
1486
+ function ce(e) {
1474
1487
  if (e == null || e === "") return "";
1475
1488
  if (e instanceof Date) return Number.isNaN(e.getTime()) ? "" : `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
1476
1489
  let t = String(e), n = /^(\d{4}-\d{2}-\d{2})(?:$|T)/.exec(t);
1477
1490
  return n ? n[1] : t;
1478
1491
  }
1479
- function ce(e) {
1492
+ function le(e) {
1480
1493
  if (e == null || e === "") return "";
1481
1494
  let t = e instanceof Date ? "" : String(e), n = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})(?::\d{2}(?:\.\d+)?)?$/.exec(t);
1482
1495
  if (n) return `${n[1]} ${n[2]}`;
@@ -1487,7 +1500,7 @@ function ce(e) {
1487
1500
  }
1488
1501
  //#endregion
1489
1502
  //#region src/export/xlsx-writer.ts
1490
- var le = (() => {
1503
+ var ue = (() => {
1491
1504
  let e = /* @__PURE__ */ new Uint32Array(256);
1492
1505
  for (let t = 0; t < 256; t++) {
1493
1506
  let n = t;
@@ -1496,23 +1509,23 @@ var le = (() => {
1496
1509
  }
1497
1510
  return e;
1498
1511
  })();
1499
- function ue(e) {
1512
+ function de(e) {
1500
1513
  let t = 4294967295;
1501
- for (let n = 0; n < e.length; n++) t = le[(t ^ e[n]) & 255] ^ t >>> 8;
1514
+ for (let n = 0; n < e.length; n++) t = ue[(t ^ e[n]) & 255] ^ t >>> 8;
1502
1515
  return (t ^ 4294967295) >>> 0;
1503
1516
  }
1504
- var F = new TextEncoder();
1505
- function de(e) {
1506
- return I(e.map((e) => ({
1517
+ var P = new TextEncoder();
1518
+ function fe(e) {
1519
+ return F(e.map((e) => ({
1507
1520
  ...e,
1508
1521
  body: e.data,
1509
1522
  method: 0
1510
1523
  })));
1511
1524
  }
1512
- async function fe(e) {
1525
+ async function pe(e) {
1513
1526
  let t = [];
1514
1527
  for (let n of e) {
1515
- let e = await pe(n.data);
1528
+ let e = await me(n.data);
1516
1529
  t.push(e.length < n.data.length ? {
1517
1530
  ...n,
1518
1531
  body: e,
@@ -1523,9 +1536,9 @@ async function fe(e) {
1523
1536
  method: 0
1524
1537
  });
1525
1538
  }
1526
- return I(t);
1539
+ return F(t);
1527
1540
  }
1528
- async function pe(e) {
1541
+ async function me(e) {
1529
1542
  let t = new CompressionStream("deflate-raw"), n = t.writable.getWriter(), r = t.readable.getReader();
1530
1543
  n.write(e), n.close();
1531
1544
  let i = [];
@@ -1534,52 +1547,52 @@ async function pe(e) {
1534
1547
  if (e) break;
1535
1548
  i.push(t);
1536
1549
  }
1537
- return L(i);
1550
+ return I(i);
1538
1551
  }
1539
- function I(e) {
1552
+ function F(e) {
1540
1553
  let t = [], n = [], r = 0;
1541
1554
  for (let i of e) {
1542
- let e = F.encode(i.name), a = ue(i.data), o = i.data.length, s = i.body.length, c = i.method === 8 ? 20 : 10, l = new ArrayBuffer(30 + e.length), u = new DataView(l);
1555
+ let e = P.encode(i.name), a = de(i.data), o = i.data.length, s = i.body.length, c = i.method === 8 ? 20 : 10, l = new ArrayBuffer(30 + e.length), u = new DataView(l);
1543
1556
  u.setUint32(0, 67324752, !0), u.setUint16(4, c, !0), u.setUint16(6, 0, !0), u.setUint16(8, i.method, !0), u.setUint16(10, 0, !0), u.setUint16(12, 33, !0), u.setUint32(14, a, !0), u.setUint32(18, s, !0), u.setUint32(22, o, !0), u.setUint16(26, e.length, !0), u.setUint16(28, 0, !0), new Uint8Array(l, 30).set(e), t.push(new Uint8Array(l)), t.push(i.body);
1544
1557
  let d = new ArrayBuffer(46 + e.length), f = new DataView(d);
1545
1558
  f.setUint32(0, 33639248, !0), f.setUint16(4, 20, !0), f.setUint16(6, c, !0), f.setUint16(8, 0, !0), f.setUint16(10, i.method, !0), f.setUint16(12, 0, !0), f.setUint16(14, 33, !0), f.setUint32(16, a, !0), f.setUint32(20, s, !0), f.setUint32(24, o, !0), f.setUint16(28, e.length, !0), f.setUint16(30, 0, !0), f.setUint16(32, 0, !0), f.setUint16(34, 0, !0), f.setUint16(36, 0, !0), f.setUint32(38, 0, !0), f.setUint32(42, r, !0), new Uint8Array(d, 46).set(e), n.push(new Uint8Array(d)), r += 30 + e.length + s;
1546
1559
  }
1547
- let i = L(n), a = /* @__PURE__ */ new ArrayBuffer(22), o = new DataView(a);
1548
- return o.setUint32(0, 101010256, !0), o.setUint16(4, 0, !0), o.setUint16(6, 0, !0), o.setUint16(8, e.length, !0), o.setUint16(10, e.length, !0), o.setUint32(12, i.length, !0), o.setUint32(16, r, !0), o.setUint16(20, 0, !0), L([
1560
+ let i = I(n), a = /* @__PURE__ */ new ArrayBuffer(22), o = new DataView(a);
1561
+ return o.setUint32(0, 101010256, !0), o.setUint16(4, 0, !0), o.setUint16(6, 0, !0), o.setUint16(8, e.length, !0), o.setUint16(10, e.length, !0), o.setUint32(12, i.length, !0), o.setUint32(16, r, !0), o.setUint16(20, 0, !0), I([
1549
1562
  ...t,
1550
1563
  i,
1551
1564
  new Uint8Array(a)
1552
1565
  ]);
1553
1566
  }
1554
- function L(e) {
1567
+ function I(e) {
1555
1568
  let t = e.reduce((e, t) => e + t.length, 0), n = new Uint8Array(t), r = 0;
1556
1569
  for (let t of e) n.set(t, r), r += t.length;
1557
1570
  return n;
1558
1571
  }
1559
- function R(e) {
1572
+ function L(e) {
1560
1573
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1561
1574
  }
1562
- function me(e) {
1575
+ function he(e) {
1563
1576
  let t = "";
1564
1577
  for (e++; e > 0;) t = String.fromCharCode(64 + (e % 26 || 26)) + t, e = Math.floor((e - 1) / 26);
1565
1578
  return t;
1566
1579
  }
1567
- function z(e, t) {
1568
- return me(t) + (e + 1);
1580
+ function R(e, t) {
1581
+ return he(t) + (e + 1);
1569
1582
  }
1570
- function he(e) {
1583
+ function ge(e) {
1571
1584
  let t = Date.UTC(1899, 11, 30);
1572
1585
  return (e.getTime() - t) / 864e5;
1573
1586
  }
1574
- var ge = "<?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>", _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/officeDocument\" Target=\"xl/workbook.xml\"/>\n</Relationships>", ve = "<?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>", ye = "<?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>", be = "<?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>";
1575
- function xe(e, t) {
1576
- let n = [], r = t.map((e, t) => `<c r="${z(0, t)}" t="str" s="2"><v>${R(e.label)}</v></c>`);
1587
+ var _e = "<?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>", ve = "<?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>", ye = "<?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>", be = "<?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>", xe = "<?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>";
1588
+ function Se(e, t) {
1589
+ let n = [], r = t.map((e, t) => `<c r="${R(0, t)}" t="str" s="2"><v>${L(e.label)}</v></c>`);
1577
1590
  return n.push(`<row r="1">${r.join("")}</row>`), e.forEach((e, r) => {
1578
1591
  let i = t.map((t, n) => {
1579
- let i = z(r + 1, n), a = e[t.key];
1592
+ let i = R(r + 1, n), a = e[t.key];
1580
1593
  if (a == null) return `<c r="${i}" t="str"><v></v></c>`;
1581
1594
  let o = t.type ?? "text";
1582
- 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>${he(a).toFixed(6)}</v></c>` : o === "boolean" ? `<c r="${i}" t="b"><v>${+!!a}</v></c>` : `<c r="${i}" t="str"><v>${R(String(a))}</v></c>`;
1595
+ 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>${ge(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>`;
1583
1596
  });
1584
1597
  n.push(`<row r="${r + 2}">${i.join("")}</row>`);
1585
1598
  }), `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -1587,65 +1600,65 @@ function xe(e, t) {
1587
1600
  <sheetData>${n.join("")}</sheetData>
1588
1601
  </worksheet>`;
1589
1602
  }
1590
- function Se(e, t) {
1591
- return de(B(e, t));
1592
- }
1593
1603
  function Ce(e, t) {
1594
- return fe(B(e, t));
1604
+ return fe(z(e, t));
1605
+ }
1606
+ function we(e, t) {
1607
+ return pe(z(e, t));
1595
1608
  }
1596
- function B(e, t) {
1597
- let n = xe(e, t);
1609
+ function z(e, t) {
1610
+ let n = Se(e, t);
1598
1611
  return [
1599
1612
  {
1600
1613
  name: "[Content_Types].xml",
1601
- data: F.encode(ge)
1614
+ data: P.encode(_e)
1602
1615
  },
1603
1616
  {
1604
1617
  name: "_rels/.rels",
1605
- data: F.encode(_e)
1618
+ data: P.encode(ve)
1606
1619
  },
1607
1620
  {
1608
1621
  name: "xl/workbook.xml",
1609
- data: F.encode(ve)
1622
+ data: P.encode(ye)
1610
1623
  },
1611
1624
  {
1612
1625
  name: "xl/_rels/workbook.xml.rels",
1613
- data: F.encode(ye)
1626
+ data: P.encode(be)
1614
1627
  },
1615
1628
  {
1616
1629
  name: "xl/worksheets/sheet1.xml",
1617
- data: F.encode(n)
1630
+ data: P.encode(n)
1618
1631
  },
1619
1632
  {
1620
1633
  name: "xl/styles.xml",
1621
- data: F.encode(be)
1634
+ data: P.encode(xe)
1622
1635
  }
1623
1636
  ];
1624
1637
  }
1625
1638
  //#endregion
1626
1639
  //#region src/export/export.ts
1627
- function V(e, t, n) {
1640
+ function B(e, t, n) {
1628
1641
  switch (n) {
1629
- case "csv": return H(e, t, ",");
1630
- case "tsv": return H(e, t, " ");
1631
- case "json": return Ee(e, t);
1632
- case "xlsx": return Se(e, t);
1642
+ case "csv": return V(e, t, ",");
1643
+ case "tsv": return V(e, t, " ");
1644
+ case "json": return De(e, t);
1645
+ case "xlsx": return Ce(e, t);
1633
1646
  }
1634
1647
  }
1635
- async function we(e, t, n) {
1636
- let r = n === "xlsx" ? await Ce(e, t) : V(e, t, n);
1637
- return new Blob([r], { type: Ae(n) });
1648
+ async function Te(e, t, n) {
1649
+ let r = n === "xlsx" ? await we(e, t) : B(e, t, n);
1650
+ return new Blob([r], { type: je(n) });
1638
1651
  }
1639
- function Te(e, t) {
1652
+ function Ee(e, t) {
1640
1653
  return e == null ? "" : (t.type === "date" || t.type === "datetime") && e instanceof Date ? e.toISOString() : String(e);
1641
1654
  }
1642
- function H(e, t, n) {
1643
- return [t.map((e) => U(e.label, n)).join(n), ...e.map((e) => t.map((t) => U(Te(e[t.key], t), n)).join(n))].join("\n");
1655
+ function V(e, t, n) {
1656
+ return [t.map((e) => H(e.label, n)).join(n), ...e.map((e) => t.map((t) => H(Ee(e[t.key], t), n)).join(n))].join("\n");
1644
1657
  }
1645
- function U(e, t) {
1658
+ function H(e, t) {
1646
1659
  return e.includes(t) || e.includes("\"") || e.includes("\n") || e.includes("\r") ? "\"" + e.replace(/"/g, "\"\"") + "\"" : e;
1647
1660
  }
1648
- function Ee(e, t) {
1661
+ function De(e, t) {
1649
1662
  let n = e.map((e) => {
1650
1663
  let n = {};
1651
1664
  for (let r of t) {
@@ -1656,35 +1669,35 @@ function Ee(e, t) {
1656
1669
  });
1657
1670
  return JSON.stringify(n, null, 2);
1658
1671
  }
1659
- function De(e, t) {
1672
+ function Oe(e, t) {
1660
1673
  let n = URL.createObjectURL(e), r = document.createElement("a");
1661
1674
  r.href = n, r.download = t, r.style.display = "none", document.body.appendChild(r), r.click(), document.body.removeChild(r), setTimeout(() => URL.revokeObjectURL(n), 100);
1662
1675
  }
1663
- var Oe = {
1676
+ var ke = {
1664
1677
  csv: "text/csv;charset=utf-8",
1665
1678
  tsv: "text/tab-separated-values;charset=utf-8",
1666
1679
  json: "application/json;charset=utf-8",
1667
1680
  xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1668
- }, ke = {
1681
+ }, Ae = {
1669
1682
  csv: ".csv",
1670
1683
  tsv: ".tsv",
1671
1684
  json: ".json",
1672
1685
  xlsx: ".xlsx"
1673
1686
  };
1674
- function Ae(e) {
1675
- return Oe[e];
1676
- }
1677
1687
  function je(e) {
1678
1688
  return ke[e];
1679
1689
  }
1690
+ function Me(e) {
1691
+ return Ae[e];
1692
+ }
1680
1693
  //#endregion
1681
1694
  //#region src/export/xlsx-reader.ts
1682
- function Me(e) {
1695
+ function Ne(e) {
1683
1696
  for (let t = e.byteLength - 22; t >= 0; t--) if (e.getUint32(t, !0) === 101010256) return t;
1684
1697
  throw Error("XLSX: End of central directory not found — not a valid ZIP file");
1685
1698
  }
1686
- function Ne(e) {
1687
- let t = Me(e), n = e.getUint32(t + 16, !0), r = e.getUint32(t + 12, !0), i = new TextDecoder("utf-8"), a = [], o = n, s = n + r;
1699
+ function Pe(e) {
1700
+ let t = Ne(e), n = e.getUint32(t + 16, !0), r = e.getUint32(t + 12, !0), i = new TextDecoder("utf-8"), a = [], o = n, s = n + r;
1688
1701
  for (; o < s && e.getUint32(o, !0) === 33639248;) {
1689
1702
  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));
1690
1703
  a.push({
@@ -1697,7 +1710,7 @@ function Ne(e) {
1697
1710
  }
1698
1711
  return a;
1699
1712
  }
1700
- async function Pe(e) {
1713
+ async function Fe(e) {
1701
1714
  let t = new DecompressionStream("deflate-raw"), n = t.writable.getWriter(), r = t.readable.getReader();
1702
1715
  n.write(e), n.close();
1703
1716
  let i = [];
@@ -1710,28 +1723,28 @@ async function Pe(e) {
1710
1723
  for (let e of i) o.set(e, s), s += e.length;
1711
1724
  return o;
1712
1725
  }
1713
- async function Fe(e, t) {
1726
+ async function Ie(e, t) {
1714
1727
  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);
1715
1728
  if (t.compressionMethod === 0) return o.slice();
1716
- if (t.compressionMethod === 8) return Pe(o);
1729
+ if (t.compressionMethod === 8) return Fe(o);
1717
1730
  throw Error(`XLSX: Unsupported compression method ${t.compressionMethod}`);
1718
1731
  }
1719
- async function Ie(e) {
1720
- let t = new DataView(e), n = Ne(t), r = /* @__PURE__ */ new Map();
1721
- for (let e of n) e.compressedSize === 0 && e.name.endsWith("/") || r.set(e.name, await Fe(t, e));
1732
+ async function Le(e) {
1733
+ let t = new DataView(e), n = Pe(t), r = /* @__PURE__ */ new Map();
1734
+ for (let e of n) e.compressedSize === 0 && e.name.endsWith("/") || r.set(e.name, await Ie(t, e));
1722
1735
  return r;
1723
1736
  }
1724
- var Le = new TextDecoder("utf-8");
1725
- function W(e) {
1726
- let t = Le.decode(e);
1737
+ var Re = new TextDecoder("utf-8");
1738
+ function U(e) {
1739
+ let t = Re.decode(e);
1727
1740
  return new DOMParser().parseFromString(t, "application/xml");
1728
1741
  }
1729
- function Re(e) {
1742
+ function ze(e) {
1730
1743
  if (!e) return [];
1731
- let t = W(e);
1744
+ let t = U(e);
1732
1745
  return Array.from(t.querySelectorAll("si")).map((e) => Array.from(e.querySelectorAll("t")).map((e) => e.textContent ?? "").join(""));
1733
1746
  }
1734
- var ze = /* @__PURE__ */ new Set([
1747
+ var Be = /* @__PURE__ */ new Set([
1735
1748
  14,
1736
1749
  15,
1737
1750
  16,
@@ -1751,37 +1764,37 @@ var ze = /* @__PURE__ */ new Set([
1751
1764
  57,
1752
1765
  58
1753
1766
  ]);
1754
- function Be(e) {
1767
+ function Ve(e) {
1755
1768
  let t = e.replace(/"[^"]*"/g, "").replace(/\\./g, "").replace(/\[[^\]]*\]/g, "").split(";")[0];
1756
1769
  return /[dy]/i.test(t);
1757
1770
  }
1758
- function Ve(e) {
1771
+ function He(e) {
1759
1772
  let t = /* @__PURE__ */ new Set();
1760
1773
  if (!e) return t;
1761
- let n = W(e), r = /* @__PURE__ */ new Map();
1774
+ let n = U(e), r = /* @__PURE__ */ new Map();
1762
1775
  for (let e of Array.from(n.querySelectorAll("numFmts > numFmt"))) r.set(parseInt(e.getAttribute("numFmtId") ?? "", 10), e.getAttribute("formatCode") ?? "");
1763
1776
  return Array.from(n.querySelectorAll("cellXfs > xf")).forEach((e, n) => {
1764
1777
  let i = parseInt(e.getAttribute("numFmtId") ?? "0", 10), a = r.get(i);
1765
- (a === void 0 ? ze.has(i) : Be(a)) && t.add(n);
1778
+ (a === void 0 ? Be.has(i) : Ve(a)) && t.add(n);
1766
1779
  }), t;
1767
1780
  }
1768
- function He(e) {
1781
+ function Ue(e) {
1769
1782
  if (!e) return !1;
1770
- let t = W(e).querySelector("workbookPr")?.getAttribute("date1904");
1783
+ let t = U(e).querySelector("workbookPr")?.getAttribute("date1904");
1771
1784
  return t === "1" || t === "true";
1772
1785
  }
1773
- function Ue(e, t) {
1786
+ function We(e, t) {
1774
1787
  return new Date((t ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30)) + Math.floor(e) * 864e5).toISOString().slice(0, 10);
1775
1788
  }
1776
- function We(e, t, n, r) {
1777
- let i = W(e).querySelectorAll("row");
1789
+ function Ge(e, t, n, r) {
1790
+ let i = U(e).querySelectorAll("row");
1778
1791
  if (i.length === 0) return [];
1779
1792
  let a = 0, o = /* @__PURE__ */ new Map();
1780
1793
  for (let e of i) {
1781
1794
  let i = parseInt(e.getAttribute("r") ?? "1", 10) - 1, s = /* @__PURE__ */ new Map();
1782
1795
  o.set(i, s);
1783
1796
  for (let i of e.querySelectorAll("c")) {
1784
- let e = Ge(i.getAttribute("r") ?? "");
1797
+ let e = Ke(i.getAttribute("r") ?? "");
1785
1798
  e > a && (a = e);
1786
1799
  let o = i.getAttribute("t") ?? "", c = i.getAttribute("s") ?? "", l = i.querySelector("v")?.textContent ?? "", u = i.querySelector("is > t")?.textContent ?? null, d;
1787
1800
  if (o === "s") d = t[parseInt(l, 10)] ?? "";
@@ -1790,7 +1803,7 @@ function We(e, t, n, r) {
1790
1803
  else if (l === "") d = "";
1791
1804
  else {
1792
1805
  let e = parseFloat(l);
1793
- d = c !== "" && n.has(parseInt(c, 10)) && !isNaN(e) && e >= 0 ? Ue(e, r) : l;
1806
+ d = c !== "" && n.has(parseInt(c, 10)) && !isNaN(e) && e >= 0 ? We(e, r) : l;
1794
1807
  }
1795
1808
  s.set(e, d);
1796
1809
  }
@@ -1804,13 +1817,13 @@ function We(e, t, n, r) {
1804
1817
  }
1805
1818
  return c;
1806
1819
  }
1807
- function Ge(e) {
1820
+ function Ke(e) {
1808
1821
  let t = 0, n = 0;
1809
1822
  for (; n < e.length && e[n] >= "A" && e[n] <= "Z";) t = t * 26 + (e.charCodeAt(n) - 64), n++;
1810
1823
  return t - 1;
1811
1824
  }
1812
- async function Ke(e) {
1813
- let t = await Ie(e), n = Re(t.get("xl/sharedStrings.xml")), r = t.get("xl/worksheets/sheet1.xml");
1825
+ async function qe(e) {
1826
+ let t = await Le(e), n = ze(t.get("xl/sharedStrings.xml")), r = t.get("xl/worksheets/sheet1.xml");
1814
1827
  if (!r) {
1815
1828
  for (let [e, n] of t) if (e.toLowerCase().includes("worksheets/sheet")) {
1816
1829
  r = n;
@@ -1818,7 +1831,7 @@ async function Ke(e) {
1818
1831
  }
1819
1832
  }
1820
1833
  if (!r) throw Error("XLSX: No worksheet found");
1821
- let i = Ve(t.get("xl/styles.xml")), a = He(t.get("xl/workbook.xml")), o = We(r, n, i, a);
1834
+ let i = He(t.get("xl/styles.xml")), a = Ue(t.get("xl/workbook.xml")), o = Ge(r, n, i, a);
1822
1835
  return o.length === 0 ? {
1823
1836
  headers: [],
1824
1837
  rows: []
@@ -1829,12 +1842,12 @@ async function Ke(e) {
1829
1842
  }
1830
1843
  //#endregion
1831
1844
  //#region src/models/types.ts
1832
- function G(e) {
1845
+ function W(e) {
1833
1846
  return e.align ? e.align : e.type === "number" ? "end" : e.type === "boolean" ? "center" : "start";
1834
1847
  }
1835
1848
  //#endregion
1836
1849
  //#region \0@oxc-project+runtime@0.152.0/helpers/esm/decorate.js
1837
- function K(e, t, n, r) {
1850
+ function G(e, t, n, r) {
1838
1851
  var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
1839
1852
  if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
1840
1853
  else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
@@ -1842,16 +1855,16 @@ function K(e, t, n, r) {
1842
1855
  }
1843
1856
  //#endregion
1844
1857
  //#region src/flex-table.ts
1845
- var q = {
1858
+ var K = {
1846
1859
  eq: "=",
1847
1860
  neq: "≠",
1848
1861
  gt: ">",
1849
1862
  lt: "<",
1850
1863
  gte: "≥",
1851
1864
  lte: "≤"
1852
- }, J = 120, Y = 40, X = 20, Z = 32, Q = 5, qe = 200, $ = class extends n {
1865
+ }, q = 120, J = 40, Y = 20, X = 32, Z = 5, Je = 200, Q = class extends n {
1853
1866
  constructor(...e) {
1854
- super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = Z, this._targetFloor = 0, 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 = () => {
1867
+ super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = X, this._targetFloor = 0, 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 = () => {
1855
1868
  this._commitCommentPopup();
1856
1869
  }, 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();
1857
1870
  }
@@ -1866,7 +1879,7 @@ var q = {
1866
1879
  this._data = e, n && !this._inUndoRedo && (this.clearUndoOnDataChange && this._undo.clear(), this.clearSelectionOnDataChange && this._rowSelection.selectedCount > 0 && (this._rowSelection.deselectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent())), this.requestUpdate("data", t);
1867
1880
  }
1868
1881
  get rowHeight() {
1869
- let e = this._rowHeightExplicit ?? this._rowHeightFromCss ?? Z;
1882
+ let e = this._rowHeightExplicit ?? this._rowHeightFromCss ?? X;
1870
1883
  return Math.max(e, this._targetFloor);
1871
1884
  }
1872
1885
  set rowHeight(e) {
@@ -2216,17 +2229,17 @@ var q = {
2216
2229
  }
2217
2230
  exportToString(e, t) {
2218
2231
  let n = this._exportSlice(t);
2219
- return n ? V(n.rows, n.cols, e) : "";
2232
+ return n ? B(n.rows, n.cols, e) : "";
2220
2233
  }
2221
2234
  async exportToBlob(e, t) {
2222
2235
  let n = this._exportSlice(t) ?? {
2223
2236
  rows: [],
2224
2237
  cols: []
2225
2238
  };
2226
- return we(n.rows, n.cols, e);
2239
+ return Te(n.rows, n.cols, e);
2227
2240
  }
2228
2241
  async exportToFile(e, t) {
2229
- De(await this.exportToBlob(e), t ?? `export${je(e)}`);
2242
+ Oe(await this.exportToBlob(e), t ?? `export${Me(e)}`);
2230
2243
  }
2231
2244
  _exportSlice(e) {
2232
2245
  if (e?.selectionOnly) {
@@ -2299,7 +2312,7 @@ var q = {
2299
2312
  async importFromFile(e) {
2300
2313
  let t = e.name.toLowerCase();
2301
2314
  if (t.endsWith(".xlsx")) {
2302
- let t = await Ke(await e.arrayBuffer());
2315
+ let t = await qe(await e.arrayBuffer());
2303
2316
  this._applyImportedSheet(t);
2304
2317
  } else if (t.endsWith(".csv") || t.endsWith(".tsv")) {
2305
2318
  let t = await e.text(), n = h(t);
@@ -2391,8 +2404,8 @@ var q = {
2391
2404
  return this._columnWidths.get(e);
2392
2405
  }
2393
2406
  _getColWidth(e) {
2394
- let t = this._columnWidths.get(e.key) ?? e.width ?? J;
2395
- return Math.max(t, e.minWidth ?? Y);
2407
+ let t = this._columnWidths.get(e.key) ?? e.width ?? q;
2408
+ return Math.max(t, e.minWidth ?? J);
2396
2409
  }
2397
2410
  get headerHeight() {
2398
2411
  return this.rowHeight + 8;
@@ -2418,10 +2431,10 @@ var q = {
2418
2431
  return Math.max(0, this._visibleRowCount - this._frozenRowCount) * this.rowHeight;
2419
2432
  }
2420
2433
  get visibleRange() {
2421
- let e = this._frozenRowCount, t = e + Math.floor(Math.max(0, this._scrollTop) / this.rowHeight), n = Math.max(e, t - Q), r = Math.max(0, this._viewportHeight - this.headerHeight - this.frozenRowsHeight), i = Math.ceil(r / this.rowHeight) + 1;
2434
+ let e = this._frozenRowCount, t = e + Math.floor(Math.max(0, this._scrollTop) / this.rowHeight), n = Math.max(e, t - Z), r = Math.max(0, this._viewportHeight - this.headerHeight - this.frozenRowsHeight), i = Math.ceil(r / this.rowHeight) + 1;
2422
2435
  return {
2423
2436
  start: n,
2424
- end: Math.min(this._visibleRowCount, t + i + Q)
2437
+ end: Math.min(this._visibleRowCount, t + i + Z)
2425
2438
  };
2426
2439
  }
2427
2440
  connectedCallback() {
@@ -2464,13 +2477,13 @@ var q = {
2464
2477
  i = r;
2465
2478
  break;
2466
2479
  }
2467
- i = Math.max(0, i - Q);
2480
+ i = Math.max(0, i - Z);
2468
2481
  let a = e.length;
2469
2482
  for (let e = i; e < t.length; e++) if (t[e] > r) {
2470
2483
  a = e;
2471
2484
  break;
2472
2485
  }
2473
- return a = Math.min(e.length, a + Q), {
2486
+ return a = Math.min(e.length, a + Z), {
2474
2487
  start: i,
2475
2488
  end: a
2476
2489
  };
@@ -2530,7 +2543,7 @@ var q = {
2530
2543
  e !== this._viewportHeight && (this._viewportHeight = e), t !== this._viewportWidth && (this._viewportWidth = t), this._warnIfUnconstrained();
2531
2544
  }
2532
2545
  _warnIfUnconstrained() {
2533
- this._warnedUnconstrained || process.env.NODE_ENV === "production" || this._visibleRowCount < qe || 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.`));
2546
+ this._warnedUnconstrained || process.env.NODE_ENV === "production" || this._visibleRowCount < Je || 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.`));
2534
2547
  }
2535
2548
  _onScroll() {
2536
2549
  this._scrollTop = this.scrollTop, this._scrollLeft = this.scrollLeft;
@@ -2766,7 +2779,7 @@ var q = {
2766
2779
  _onEditorKeyDown(e) {
2767
2780
  if (_(e)) return;
2768
2781
  let t = e.currentTarget;
2769
- if (!(t?.localName === "u-date-picker" && (e.composedPath().some((e) => e instanceof Element && e.part?.contains("popover")) || e.key === "Escape" && Ye(t)))) {
2782
+ if (!(t?.localName === "u-date-picker" && (e.composedPath().some((e) => e instanceof Element && e.part?.contains("popover")) || e.key === "Escape" && $(t)))) {
2770
2783
  if (this._autocompleteState && this._autocompleteState.candidates.length > 0) {
2771
2784
  if (e.key === "ArrowDown") {
2772
2785
  e.preventDefault(), e.stopPropagation();
@@ -2822,7 +2835,7 @@ var q = {
2822
2835
  this._activeCell = this._selection.activeCell ? { ...this._selection.activeCell } : null, this._scrollToActiveCell(), this._dispatchSelectionEvent();
2823
2836
  }
2824
2837
  _onKeyDown(e) {
2825
- if (this._editing.current) return;
2838
+ if (this._editing.current || this._openFilterKey && e.composedPath().some((e) => e instanceof Element && e.classList.contains("ft-filter-dropdown"))) return;
2826
2839
  let t = this.visibleColumns;
2827
2840
  if ((e.ctrlKey || e.metaKey) && !e.altKey) {
2828
2841
  let t = e.key.toLowerCase();
@@ -2888,12 +2901,12 @@ var q = {
2888
2901
  if (!e.altKey || !this._activeCell || e.key !== "ArrowLeft" && e.key !== "ArrowRight") return !1;
2889
2902
  e.preventDefault();
2890
2903
  let n = t[this._activeCell.col];
2891
- return n && this._resizeColumnBy(n.key, e.key === "ArrowRight" ? X : -20), !0;
2904
+ return n && this._resizeColumnBy(n.key, e.key === "ArrowRight" ? Y : -20), !0;
2892
2905
  }
2893
2906
  _resizeColumnBy(e, t) {
2894
2907
  let n = this.visibleColumns.findIndex((t) => t.key === e), r = this.visibleColumns[n];
2895
2908
  if (!r) return;
2896
- let i = this._columnWidths.get(r.key) ?? r.width ?? J, a = r.minWidth ?? Y, o = Math.max(a, i + t);
2909
+ let i = this._columnWidths.get(r.key) ?? r.width ?? q, a = r.minWidth ?? J, o = Math.max(a, i + t);
2897
2910
  this._columnWidths.set(r.key, o), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-resize", {
2898
2911
  detail: {
2899
2912
  key: r.key,
@@ -3215,7 +3228,7 @@ var q = {
3215
3228
  return Math.min(n, i);
3216
3229
  }
3217
3230
  _renderHeaderCell(e, t) {
3218
- let n = e.sortable !== !1, r = this._sortCriteria.find((t) => t.key === e.key), o = this._sortCriteria.length > 1 ? this._sortCriteria.findIndex((t) => t.key === e.key) : -1, s = this._filters.some((t) => t.key === e.key), c = e.pinned === "left", l = e.pinned === "right", u = c || l, d = e.headerAlign ?? G(e), f = [
3231
+ let n = e.sortable !== !1, r = this._sortCriteria.find((t) => t.key === e.key), o = this._sortCriteria.length > 1 ? this._sortCriteria.findIndex((t) => t.key === e.key) : -1, s = this._filters.some((t) => t.key === e.key), c = e.pinned === "left", l = e.pinned === "right", u = c || l, d = e.headerAlign ?? W(e), f = [
3219
3232
  "ft-header-cell",
3220
3233
  n ? "ft-sortable" : "",
3221
3234
  u ? "ft-pinned" : "",
@@ -3349,8 +3362,9 @@ var q = {
3349
3362
  _openFilterFromMenu(e) {
3350
3363
  this._headerMenu = null, this._openFilterKey = e, requestAnimationFrame(() => {
3351
3364
  document.addEventListener("click", this._onDocumentClick, { once: !0 });
3352
- }), this.updateComplete.then(() => {
3353
- this.shadowRoot?.querySelector(".ft-filter-dropdown input, .ft-filter-dropdown select")?.focus();
3365
+ }), this.updateComplete.then(async () => {
3366
+ let e = this.shadowRoot?.querySelector(".ft-filter-dropdown input, .ft-filter-dropdown select, .ft-filter-dropdown u-date-picker");
3367
+ await e?.updateComplete, e?.focus();
3354
3368
  });
3355
3369
  }
3356
3370
  _showHiddenBefore(e) {
@@ -3386,7 +3400,7 @@ var q = {
3386
3400
  ${r.map((e) => c("show", A("showColumn", { header: e.label }), () => this._setColumnHidden(e.key, !1)))}
3387
3401
  <div class="ft-header-menu-separator" role="separator"></div>
3388
3402
  ${c("autofit", A("autoFitWidth"), () => this._autoFitColumn(e))}
3389
- ${c("wider", A("wider"), () => this._resizeColumnBy(e, X), !0)}
3403
+ ${c("wider", A("wider"), () => this._resizeColumnBy(e, Y), !0)}
3390
3404
  ${c("narrower", A("narrower"), () => this._resizeColumnBy(e, -20), !0)}
3391
3405
  </div>
3392
3406
  `;
@@ -3675,10 +3689,10 @@ var q = {
3675
3689
  @keydown=${(e) => {
3676
3690
  e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
3677
3691
  }}>
3678
- ${Object.keys(q).map((e) => i`<option value=${e}>${q[e]}</option>`)}
3692
+ ${Object.keys(K).map((e) => i`<option value=${e}>${K[e]}</option>`)}
3679
3693
  </select>
3680
3694
  <input class="ft-filter-input ft-num-cond-input" type="text" inputmode="decimal" placeholder=${A("valuePlaceholder")}
3681
- .value=${n.text ?? (n.value == null ? "" : P(n.value))}
3695
+ .value=${n.text ?? (n.value == null ? "" : se(n.value))}
3682
3696
  aria-invalid=${n.text && n.value == null ? "true" : "false"}
3683
3697
  @input=${(n) => {
3684
3698
  let r = n.target.value, i = this._numberFilterState.get(e) ?? this._defaultNumState();
@@ -3737,21 +3751,21 @@ var q = {
3737
3751
  return n ? n.error : null;
3738
3752
  }
3739
3753
  _renderDateFilter(e) {
3740
- let t = e.type === "datetime" ? "datetime-local" : "date", n = this._dateFilterState.get(e.key) ?? {};
3754
+ let t = e.type === "datetime", n = this._dateFilterState.get(e.key) ?? {}, r = (e) => e?.slice(0, 10), o = (e) => {
3755
+ e.key === "Escape" && $(e.currentTarget) || (e.stopPropagation(), e.key === "Escape" && (this._openFilterKey = null));
3756
+ };
3741
3757
  return i`
3742
- <div class="ft-filter-range">
3743
- <input class="ft-filter-input" type=${t} placeholder=${A("fromPlaceholder")}
3744
- .value=${n.from ?? ""}
3745
- @input=${(t) => this._applyDateFilter(e.key, t, "from")}
3746
- @keydown=${(e) => {
3747
- e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
3748
- }}>
3749
- <input class="ft-filter-input" type=${t} placeholder=${A("toPlaceholder")}
3750
- .value=${n.to ?? ""}
3751
- @input=${(t) => this._applyDateFilter(e.key, t, "to")}
3752
- @keydown=${(e) => {
3753
- e.key === "Escape" && (this._openFilterKey = null), e.stopPropagation();
3754
- }}>
3758
+ <div class="ft-filter-range ft-filter-range-dates">
3759
+ <u-date-picker class="ft-filter-date" size="sm" clearable
3760
+ mode=${t ? "datetime" : "date"} label=${A("fromPlaceholder")}
3761
+ .value=${n.from ?? ""} max=${r(n.to) ?? a}
3762
+ @change=${(t) => this._applyDateFilter(e.key, t, "from")}
3763
+ @keydown=${o}></u-date-picker>
3764
+ <u-date-picker class="ft-filter-date" size="sm" clearable
3765
+ mode=${t ? "datetime" : "date"} label=${A("toPlaceholder")}
3766
+ .value=${n.to ?? ""} min=${r(n.from) ?? a}
3767
+ @change=${(t) => this._applyDateFilter(e.key, t, "to")}
3768
+ @keydown=${o}></u-date-picker>
3755
3769
  </div>
3756
3770
  ${this._renderEmptyFilterRow(e.key, () => {
3757
3771
  this._dateFilterState.delete(e.key);
@@ -3759,7 +3773,7 @@ var q = {
3759
3773
  `;
3760
3774
  }
3761
3775
  _applyDateFilter(e, t, n) {
3762
- let r = t.target.value, i = this._dateFilterState.get(e) ?? {};
3776
+ let r = t.target.value ?? "", i = this._dateFilterState.get(e) ?? {};
3763
3777
  r === "" ? delete i[n] : i[n] = r, this._dateFilterState.set(e, i), this._emptyFilterState.delete(e), this._applyFilterForKey(e);
3764
3778
  }
3765
3779
  _renderBooleanFilter(e) {
@@ -3787,7 +3801,7 @@ var q = {
3787
3801
  if (!n) return;
3788
3802
  let r = this.shadowRoot?.querySelectorAll(`.ft-cell[data-col-index="${t}"]`), i = 0, a = this.shadowRoot?.querySelector(`.ft-header-cell[data-col-index="${t}"]`);
3789
3803
  if (a && (i = Math.max(i, a.scrollWidth)), r) for (let e of r) i = Math.max(i, e.scrollWidth);
3790
- let o = n.minWidth ?? Y, s = Math.max(o, i + 8);
3804
+ let o = n.minWidth ?? J, s = Math.max(o, i + 8);
3791
3805
  this._columnWidths.set(n.key, s), this.requestUpdate(), this.dispatchEvent(new CustomEvent("column-resize", {
3792
3806
  detail: {
3793
3807
  key: n.key,
@@ -3800,7 +3814,7 @@ var q = {
3800
3814
  }
3801
3815
  _onResizeStart(e, t) {
3802
3816
  e.preventDefault(), e.stopPropagation();
3803
- let n = this.visibleColumns[t], r = this._columnWidths.get(n.key) ?? n.width ?? J;
3817
+ let n = this.visibleColumns[t], r = this._columnWidths.get(n.key) ?? n.width ?? q;
3804
3818
  this._resizing = {
3805
3819
  colIndex: t,
3806
3820
  startX: e.clientX,
@@ -3808,13 +3822,13 @@ var q = {
3808
3822
  };
3809
3823
  let i = (e) => {
3810
3824
  if (!this._resizing) return;
3811
- let t = e.clientX - this._resizing.startX, r = n.minWidth ?? Y, i = Math.max(r, this._resizing.startWidth + t);
3825
+ let t = e.clientX - this._resizing.startX, r = n.minWidth ?? J, i = Math.max(r, this._resizing.startWidth + t);
3812
3826
  this._columnWidths.set(n.key, i), this.requestUpdate();
3813
3827
  }, a = () => {
3814
3828
  document.removeEventListener("mousemove", i), document.removeEventListener("mouseup", o), this._resizeCleanup = null;
3815
3829
  }, o = () => {
3816
3830
  if (a(), this._resizing) {
3817
- let e = this._columnWidths.get(n.key) ?? J;
3831
+ let e = this._columnWidths.get(n.key) ?? q;
3818
3832
  this.dispatchEvent(new CustomEvent("column-resize", {
3819
3833
  detail: {
3820
3834
  key: n.key,
@@ -4406,7 +4420,7 @@ var q = {
4406
4420
  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 = [
4407
4421
  "ft-cell",
4408
4422
  `ft-type-${t.type ?? "text"}`,
4409
- `ft-align-${G(t)}`,
4423
+ `ft-align-${W(t)}`,
4410
4424
  s ? "ft-active" : "",
4411
4425
  l ? "ft-selected" : "",
4412
4426
  f ? "ft-pinned" : "",
@@ -4441,7 +4455,7 @@ var q = {
4441
4455
  let n = e[t.key], r = n == null ? "" : String(n);
4442
4456
  if (t.type === "number") return i`
4443
4457
  <input class="ft-editor ft-editor-number" type="text" inputmode="decimal"
4444
- .value=${typeof n == "number" ? P(n) : r}
4458
+ .value=${typeof n == "number" ? se(n) : r}
4445
4459
  @keydown=${this._onEditorKeyDown}
4446
4460
  @blur=${() => this._commitEdit()}>
4447
4461
  `;
@@ -4450,7 +4464,7 @@ var q = {
4450
4464
  return i`
4451
4465
  <u-date-picker class="ft-editor ft-editor-${t.type}" size="sm"
4452
4466
  mode=${e ? "datetime" : "date"} ?confirm=${e}
4453
- .value=${Je(n, e)}
4467
+ .value=${Ye(n, e)}
4454
4468
  @keydown=${this._onEditorKeyDown}
4455
4469
  @change=${() => this._commitEdit()}
4456
4470
  @blur=${() => this._commitEdit()}></u-date-picker>
@@ -4497,70 +4511,70 @@ var q = {
4497
4511
  `;
4498
4512
  }
4499
4513
  };
4500
- K([s({ type: Array })], $.prototype, "columns", void 0), K([s({
4514
+ G([s({ type: Array })], Q.prototype, "columns", void 0), G([s({
4501
4515
  type: Array,
4502
4516
  hasChanged: () => !0
4503
- })], $.prototype, "data", null), K([s({
4517
+ })], Q.prototype, "data", null), G([s({
4504
4518
  type: Boolean,
4505
4519
  attribute: "clear-undo-on-data-change"
4506
- })], $.prototype, "clearUndoOnDataChange", void 0), K([s({
4520
+ })], Q.prototype, "clearUndoOnDataChange", void 0), G([s({
4507
4521
  type: Boolean,
4508
4522
  attribute: "clear-selection-on-data-change"
4509
- })], $.prototype, "clearSelectionOnDataChange", void 0), K([s({
4523
+ })], Q.prototype, "clearSelectionOnDataChange", void 0), G([s({
4510
4524
  type: Number,
4511
4525
  attribute: "row-height"
4512
- })], $.prototype, "rowHeight", null), K([s({
4526
+ })], Q.prototype, "rowHeight", null), G([s({
4513
4527
  type: Boolean,
4514
4528
  attribute: "show-row-numbers"
4515
- })], $.prototype, "showRowNumbers", void 0), K([s({
4529
+ })], Q.prototype, "showRowNumbers", void 0), G([s({
4516
4530
  type: String,
4517
4531
  reflect: !0
4518
- })], $.prototype, "theme", void 0), K([s({
4532
+ })], Q.prototype, "theme", void 0), G([s({
4519
4533
  type: Number,
4520
4534
  attribute: "max-rows"
4521
- })], $.prototype, "maxRows", void 0), K([s({ type: Boolean })], $.prototype, "editable", void 0), K([s({
4535
+ })], Q.prototype, "maxRows", void 0), G([s({ type: Boolean })], Q.prototype, "editable", void 0), G([s({
4522
4536
  type: Boolean,
4523
4537
  attribute: "show-filters"
4524
- })], $.prototype, "showFilters", void 0), K([s({
4538
+ })], Q.prototype, "showFilters", void 0), G([s({
4525
4539
  type: Boolean,
4526
4540
  attribute: "show-context-menu"
4527
- })], $.prototype, "showContextMenu", void 0), K([s({
4541
+ })], Q.prototype, "showContextMenu", void 0), G([s({
4528
4542
  type: Number,
4529
4543
  attribute: "frozen-rows"
4530
- })], $.prototype, "frozenRows", void 0), K([s({
4544
+ })], Q.prototype, "frozenRows", void 0), G([s({
4531
4545
  type: String,
4532
4546
  attribute: "empty-message"
4533
- })], $.prototype, "emptyMessage", void 0), K([s({
4547
+ })], Q.prototype, "emptyMessage", void 0), G([s({
4534
4548
  type: String,
4535
4549
  attribute: "no-matching-message"
4536
- })], $.prototype, "noMatchingMessage", void 0), K([s({
4550
+ })], Q.prototype, "noMatchingMessage", void 0), G([s({
4537
4551
  type: Boolean,
4538
4552
  reflect: !0
4539
- })], $.prototype, "loading", void 0), K([s({
4553
+ })], Q.prototype, "loading", void 0), G([s({
4540
4554
  type: Boolean,
4541
4555
  attribute: "import-enabled"
4542
- })], $.prototype, "importEnabled", void 0), K([s({ type: Boolean })], $.prototype, "selectable", void 0), K([s({
4556
+ })], Q.prototype, "importEnabled", void 0), G([s({ type: Boolean })], Q.prototype, "selectable", void 0), G([s({
4543
4557
  type: String,
4544
4558
  attribute: "selection-mode"
4545
- })], $.prototype, "selectionMode", null), K([s({
4559
+ })], Q.prototype, "selectionMode", null), G([s({
4546
4560
  type: String,
4547
4561
  attribute: "data-mode"
4548
- })], $.prototype, "dataMode", void 0), K([s({
4562
+ })], Q.prototype, "dataMode", void 0), G([s({
4549
4563
  type: Object,
4550
4564
  attribute: "footer-data"
4551
- })], $.prototype, "footerData", void 0), K([s({ attribute: !1 })], $.prototype, "stylesheets", void 0), K([s({
4565
+ })], Q.prototype, "footerData", void 0), G([s({ attribute: !1 })], Q.prototype, "stylesheets", void 0), G([s({
4552
4566
  type: Number,
4553
4567
  attribute: "max-undo-size"
4554
- })], $.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")], $);
4555
- function Je(e, t) {
4568
+ })], Q.prototype, "maxUndoSize", null), G([c()], Q.prototype, "_scrollTop", void 0), G([c()], Q.prototype, "_scrollLeft", void 0), G([c()], Q.prototype, "_viewportHeight", void 0), G([c()], Q.prototype, "_viewportWidth", void 0), G([c()], Q.prototype, "_activeCell", void 0), G([c()], Q.prototype, "_editingCell", void 0), G([c()], Q.prototype, "_sortCriteria", void 0), G([c()], Q.prototype, "_openFilterKey", void 0), G([c()], Q.prototype, "_rowSelectionVersion", void 0), G([c()], Q.prototype, "_autocompleteState", void 0), G([c()], Q.prototype, "_headerMenu", void 0), G([c()], Q.prototype, "_bodyContextMenu", void 0), G([c()], Q.prototype, "_commentPopup", void 0), G([c()], Q.prototype, "_isDragOver", void 0), Q = G([o("flex-table")], Q);
4569
+ function Ye(e, t) {
4556
4570
  if (t) {
4557
- let t = ce(e);
4571
+ let t = le(e);
4558
4572
  return /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(t) ? t.replace(" ", "T") : void 0;
4559
4573
  }
4560
- let n = se(e);
4574
+ let n = ce(e);
4561
4575
  return /^\d{4}-\d{2}-\d{2}$/.test(n) ? n : void 0;
4562
4576
  }
4563
- function Ye(e) {
4577
+ function $(e) {
4564
4578
  try {
4565
4579
  return e.matches(":state(open)");
4566
4580
  } catch {
@@ -4568,4 +4582,4 @@ function Ye(e) {
4568
4582
  }
4569
4583
  }
4570
4584
  //#endregion
4571
- export { j as a, M as i, G as n, k as o, V as r, C as s, $ as t };
4585
+ export { j as a, M as i, W as n, k as o, B as r, C as s, Q as t };
@@ -492,6 +492,12 @@ export declare class FlexTable extends LitElement {
492
492
  private _numberFilterState;
493
493
  private _dateFilterState;
494
494
  private _emptyFilterState;
495
+ /**
496
+ * From/to bounds as two `u-date-picker`s — the cell editor's control, for the same reason: the native
497
+ * date inputs show the browser's UI language (`10/02/2026` in an English browser) while the table
498
+ * shows ISO. Two pickers, not one `u-date-range-picker`: either bound may be left open ("from this
499
+ * day on"), which a range value cannot say. Each bound's calendar stops at the other bound.
500
+ */
495
501
  private _renderDateFilter;
496
502
  private _applyDateFilter;
497
503
  private _renderBooleanFilter;
@@ -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-DIQhqj12.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-h2noRChg.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 };
@@ -1,4 +1,5 @@
1
1
  import type { SortCriteria } from '../core/sorting.js';
2
+ import type { SourceError } from '../core/source-error.js';
2
3
  export interface UseODataSourceOptions {
3
4
  pageSize?: number;
4
5
  defaultOrderBy?: string;
@@ -43,7 +44,11 @@ export interface UseODataSourceResult<T> {
43
44
  data: T[];
44
45
  totalCount: number;
45
46
  loading: boolean;
46
- error: string | null;
47
+ /**
48
+ * 마지막 요청의 실패, 없으면 `null`. 화면에는 `error.message` 를 그린다. «어떤 실패인가» 는
49
+ * `status`(HTTP) · `code`(서버의 거절 코드) · `details` 로 가른다 — 401 은 `onUnauthorized` 도 부른다.
50
+ */
51
+ error: SourceError | null;
47
52
  page: number;
48
53
  setPage: (page: number) => void;
49
54
  sortCriteria: SortCriteria[];
package/dist/react.d.ts CHANGED
@@ -69,3 +69,4 @@ export { useODataSource } from './odata/use-odata-source.js';
69
69
  export type { UseODataSourceOptions, UseODataSourceResult } from './odata/types.js';
70
70
  export { useArraySource } from './array/use-array-source.js';
71
71
  export type { UseArraySourceOptions, UseArraySourceResult } from './array/types.js';
72
+ export type { SourceError, SourceErrorDetail } from './core/source-error.js';
package/dist/react.js CHANGED
@@ -1,47 +1,74 @@
1
- import { t as e } from "./flex-table-DIQhqj12.js";
1
+ import { t as e } from "./flex-table-h2noRChg.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";
5
5
  import { createComponent as u } from "@lit/react";
6
+ //#region src/core/source-error.ts
7
+ async function d(e) {
8
+ let t = await e.text().catch(() => ""), n = {
9
+ message: `Request failed (${e.status})`,
10
+ status: e.status
11
+ };
12
+ if (!t) return n;
13
+ let r = t;
14
+ try {
15
+ r = JSON.parse(t);
16
+ } catch {}
17
+ if (n.body = r, !r || typeof r != "object") return n;
18
+ let i = r, a = i.error && typeof i.error == "object" ? i.error : i;
19
+ typeof a.message == "string" && a.message ? n.message = a.message : typeof i.message == "string" && i.message && (n.message = i.message), typeof a.code == "string" && a.code && (n.code = a.code);
20
+ let o = f(a.details);
21
+ return o && (n.details = o), n;
22
+ }
23
+ function f(e) {
24
+ if (!Array.isArray(e)) return;
25
+ let t = e.filter((e) => {
26
+ if (!e || typeof e != "object") return !1;
27
+ let t = e;
28
+ return typeof t.code == "string" && typeof t.message == "string";
29
+ });
30
+ return t.length > 0 ? t : void 0;
31
+ }
32
+ var p = class extends Error {
33
+ constructor(e) {
34
+ super(e.message), this.name = "SourceRequestError", this.failure = e;
35
+ }
36
+ };
37
+ function m(e) {
38
+ return e instanceof p ? e.failure : e instanceof Error ? { message: e.message } : { message: String(e) };
39
+ }
40
+ //#endregion
6
41
  //#region src/odata/use-odata-source.ts
7
- function d(e, r = {}) {
8
- let { pageSize: i = 20, defaultOrderBy: s, initialPage: u = 0, initialSearch: d = "", initialSort: f, fixedFilter: p, baseUrl: m, fetcher: h = fetch, onUnauthorized: g, enabled: _ = !0 } = r, v = p ? JSON.stringify(p) : "", [y, b] = l([]), [x, S] = l(0), [C, w] = l(!1), [T, E] = l(null), D = t({
42
+ function h(e, r = {}) {
43
+ let { pageSize: i = 20, defaultOrderBy: s, initialPage: u = 0, initialSearch: f = "", initialSort: h, fixedFilter: g, baseUrl: _, fetcher: v = fetch, onUnauthorized: y, enabled: b = !0 } = r, x = g ? JSON.stringify(g) : "", [S, C] = l([]), [w, T] = l(0), [E, D] = l(!1), [O, k] = l(null), A = t({
9
44
  defaultOrderBy: s,
10
45
  initialPage: u,
11
- initialSearch: d,
12
- initialSort: f
13
- }), [O, k] = l(D.page), [A, j] = l(D.sortCriteria), [M, N] = l(D.search), [P, F] = l(0), [I, L] = l(v);
14
- v !== I && (L(v), k(0));
15
- let R = c(null), z = a(() => {
16
- F((e) => e + 1);
17
- }, []), B = a((e) => {
18
- N(e), k(0);
19
- }, []), V = a((e) => {
46
+ initialSearch: f,
47
+ initialSort: h
48
+ }), [j, M] = l(A.page), [N, P] = l(A.sortCriteria), [F, I] = l(A.search), [L, R] = l(0), [z, B] = l(x);
49
+ x !== z && (B(x), M(0));
50
+ let V = c(null), H = a(() => {
51
+ R((e) => e + 1);
52
+ }, []), U = a((e) => {
53
+ I(e), M(0);
54
+ }, []), W = a((e) => {
20
55
  let t = e.detail?.criteria;
21
- t && (j(t), k(0));
56
+ t && (P(t), M(0));
22
57
  }, []);
23
58
  return o(() => {
24
- if (R.current?.abort(), !_) return;
59
+ if (V.current?.abort(), !b) return;
25
60
  let t = new AbortController();
26
- R.current = t, w(!0), E(null);
61
+ V.current = t, D(!0), k(null);
27
62
  let r = n({
28
- page: O,
63
+ page: j,
29
64
  pageSize: i,
30
- sortCriteria: A,
65
+ sortCriteria: N,
31
66
  defaultOrderBy: s,
32
- search: M,
33
- fixedFilter: p
34
- }), a = `${m ?? window.location.origin}${e}${r}`, o = async (e) => {
35
- let n = await h(e, { signal: t.signal });
36
- if (!n.ok) {
37
- n.status === 401 && g && g(n);
38
- let e = await n.text().catch(() => ""), t = `Request failed (${n.status})`;
39
- try {
40
- let n = JSON.parse(e);
41
- t = n?.error?.message ?? n?.message ?? t;
42
- } catch {}
43
- throw Error(t);
44
- }
67
+ search: F,
68
+ fixedFilter: g
69
+ }), a = `${_ ?? window.location.origin}${e}${r}`, o = async (e) => {
70
+ let n = await v(e, { signal: t.signal });
71
+ if (!n.ok) throw n.status === 401 && y && y(n), new p(await d(n));
45
72
  return n.json();
46
73
  };
47
74
  return (async () => {
@@ -61,42 +88,42 @@ function d(e, r = {}) {
61
88
  })().then(({ count: e, rows: n }) => {
62
89
  if (t.signal.aborted) return;
63
90
  let r = e ?? 0;
64
- b(n), S(r), E(null);
91
+ C(n), T(r), k(null);
65
92
  let a = r === 0 ? 0 : Math.ceil(r / i) - 1;
66
- O > a && k(a);
93
+ j > a && M(a);
67
94
  }).catch((e) => {
68
- t.signal.aborted || e.name !== "AbortError" && (E(e.message), b([]), S(0));
95
+ t.signal.aborted || e.name !== "AbortError" && (k(m(e)), C([]), T(0));
69
96
  }).finally(() => {
70
- t.signal.aborted || w(!1);
97
+ t.signal.aborted || D(!1);
71
98
  }), () => t.abort();
72
99
  }, [
73
- _,
100
+ b,
74
101
  e,
75
- O,
102
+ j,
76
103
  i,
77
- A,
78
- M,
79
- v,
104
+ N,
105
+ F,
106
+ x,
80
107
  s,
81
- P,
82
- m
108
+ L,
109
+ _
83
110
  ]), {
84
- data: y,
85
- totalCount: x,
86
- loading: C || !_,
87
- error: T,
88
- page: O,
89
- setPage: k,
90
- sortCriteria: A,
91
- onSortChange: V,
92
- search: M,
93
- setSearch: B,
94
- refresh: z
111
+ data: S,
112
+ totalCount: w,
113
+ loading: E || !b,
114
+ error: O,
115
+ page: j,
116
+ setPage: M,
117
+ sortCriteria: N,
118
+ onSortChange: W,
119
+ search: F,
120
+ setSearch: U,
121
+ refresh: H
95
122
  };
96
123
  }
97
124
  //#endregion
98
125
  //#region src/array/use-array-source.ts
99
- function f(e, n = {}) {
126
+ function g(e, n = {}) {
100
127
  let { pageSize: i = 20, defaultOrderBy: o, initialPage: c = 0, initialSearch: u = "", initialSort: d, columns: f, searchFields: p } = n, m = t({
101
128
  defaultOrderBy: o,
102
129
  initialPage: c,
@@ -137,7 +164,7 @@ function f(e, n = {}) {
137
164
  refresh: C
138
165
  };
139
166
  }
140
- var p = u({
167
+ var _ = u({
141
168
  tagName: "flex-table",
142
169
  elementClass: e,
143
170
  react: i,
@@ -176,4 +203,4 @@ var p = u({
176
203
  }
177
204
  });
178
205
  //#endregion
179
- export { p as FlexTableReact, f as useArraySource, d as useODataSource };
206
+ export { _ as FlexTableReact, g as useArraySource, h as useODataSource };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.46.0",
3
+ "version": "0.47.0",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",
@@ -45,6 +45,7 @@
45
45
  "build": "npm run typecheck && vite build && tsc --emitDeclarationOnly",
46
46
  "build:demo": "vite build --config vite.config.demo.ts",
47
47
  "typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
48
+ "pretest": "node -e \"if(require('fs').existsSync('../../scripts/sibling-dist-check.js'))require('child_process').execFileSync('node',['../../scripts/sibling-dist-check.js'],{stdio:'inherit'})\"",
48
49
  "test": "vitest run",
49
50
  "test:watch": "vitest",
50
51
  "lint": "eslint src/",
@@ -127,7 +127,7 @@ Server paging from OData or an in-memory array uses the same binding — see `re
127
127
  - Styles for elements returned by `render` must be passed through the `stylesheets` property
128
128
  (constructable `CSSStyleSheet[]`); document CSS does not cross the shadow boundary.
129
129
  - `useODataSource` `fetcher` / `onUnauthorized` must be stable references (`useCallback`).
130
- - Always render `error` from `useODataSource`; a failed request otherwise leaves the grid empty.
130
+ - Always render `error.message` from `useODataSource`; a failed request otherwise leaves the grid empty. Branch on `error.status` / `error.code` rather than parsing the message.
131
131
 
132
132
  ## References
133
133
 
@@ -73,7 +73,7 @@ function Orders() {
73
73
  return (
74
74
  <>
75
75
  <input value={source.search} onChange={(e) => source.setSearch(e.target.value)} />
76
- {source.error && <p role="alert">{source.error}</p>}
76
+ {source.error && <p role="alert">{source.error.message}</p>}
77
77
  <FlexTableReact<Order>
78
78
  dataMode="server"
79
79
  columns={columns}
@@ -111,7 +111,7 @@ function Orders() {
111
111
  |---|---|
112
112
  | `data`, `totalCount` | Current page and `@odata.count`; `@odata.nextLink` is followed to fill a page |
113
113
  | `loading` | Request in flight |
114
- | `error` | `string \| null` — render it |
114
+ | `error` | `SourceError \| null` — `{ message, status?, code?, details?, body? }`; render `error.message`, branch on `status` / `code` (OData `error.code`) |
115
115
  | `page`, `setPage` | Zero-based |
116
116
  | `sortCriteria`, `onSortChange` | Pass `onSortChange` to the table's `sort-change` (resets to page 0) |
117
117
  | `search`, `setSearch` | Literal text (resets to page 0) |