@iyulab/flex-table 0.50.4 → 0.52.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,33 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.52.0] - 2026-10-07
4
+
5
+ ### Changed
6
+
7
+ - **Requires `@iyulab/components` 2.8.0** (peer `>=2.8.0`) — for its locale change notification.
8
+
9
+ ### Fixed
10
+
11
+ - **`flex-table` follows a runtime locale switch.** `Locale.set()` or registering strings (`flexTableLocale.register`)
12
+ re-renders the table at once — menus, filters, empty states and a cell's error marker (now looked up when drawn). It
13
+ kept the old language until a scroll or data change redrew it. A table detached during the switch catches up when
14
+ attached again.
15
+
16
+ ## [0.51.0] - 2026-10-06
17
+
18
+ ### Fixed
19
+
20
+ - **A data-source failure the server said nothing about is described in the table's language.** With no message in
21
+ the response, `SourceError.message` was a fixed English `Request failed (<status>)`; with no response at all it was
22
+ the transport's exception text, which differs by browser (`Failed to fetch`, `NetworkError when attempting to fetch
23
+ resource.`). Both rendered in English in any locale, and telling them from a server sentence meant matching the
24
+ string's shape. They now come from `flexTableLocale` — `requestFailed` (`{status}` parameter) and `networkFailed`
25
+ (en and ko built in, others via `register`). A server sentence still wins.
26
+
27
+ ### Added
28
+
29
+ - `SourceError.cause` — on a failure with no response, the exception the transport threw (for diagnostics).
30
+
3
31
  ## [0.50.4] - 2026-10-06
4
32
 
5
33
  ### Fixed
@@ -13,7 +13,10 @@ export interface SourceErrorDetail {
13
13
  * 엿보는 것 말고는 길이 없다.
14
14
  */
15
15
  export interface SourceError {
16
- /** 보여 줄 문장 — 서버가 준 메시지가 있으면 그것, 없으면 `Request failed (<status>)`. */
16
+ /**
17
+ * 보여 줄 문장 — 서버가 준 메시지가 있으면 그것. 없으면 이 패키지가 채우는 문장이고 로케일(`flexTableLocale`)을
18
+ * 따른다: 응답은 있었으면 `requestFailed`(`Request failed ({status})`), 응답이 없었으면 `networkFailed`.
19
+ */
17
20
  message: string;
18
21
  /** HTTP 상태. 응답이 없던 실패(네트워크 오류 · `@odata.nextLink` 검사)에는 없다. */
19
22
  status?: number;
@@ -23,6 +26,8 @@ export interface SourceError {
23
26
  details?: SourceErrorDetail[];
24
27
  /** 응답 본문 — JSON 이면 파싱한 값, 아니면 텍스트. 비어 있으면 없다. */
25
28
  body?: unknown;
29
+ /** 응답이 없던 실패에서 전송(`fetcher`)이 던진 예외 — 진단용. 화면에는 `message` 를 그린다. */
30
+ cause?: unknown;
26
31
  }
27
32
  /** 실패 응답을 `SourceError` 로 읽는다. 본문을 읽을 수 없어도 상태와 기본 문장은 남긴다. */
28
33
  export declare function readFailedResponse(res: Response): Promise<SourceError>;
@@ -31,5 +36,7 @@ export declare class SourceRequestError extends Error {
31
36
  readonly failure: SourceError;
32
37
  constructor(failure: SourceError);
33
38
  }
39
+ /** 전송이 응답 없이 던진 실패(네트워크 · 오프라인)를 `SourceError` 로 — 브라우저마다 다른 예외 문구 대신 로케일 문장. */
40
+ export declare function networkFailure(cause: unknown): SourceRequestError;
34
41
  /** 잡힌 예외를 `SourceError` 로 — 응답이 있던 실패는 그 구조 그대로, 나머지는 메시지만. */
35
42
  export declare function toSourceError(err: unknown): SourceError;
@@ -1159,7 +1159,9 @@ O.register("en", {
1159
1159
  notANumber: "Enter a number",
1160
1160
  notADate: "Enter a date as YYYY-MM-DD",
1161
1161
  notADateTime: "Enter a date and time as YYYY-MM-DD HH:mm",
1162
- notInList: "Value must be from the existing list"
1162
+ notInList: "Value must be from the existing list",
1163
+ requestFailed: "Request failed ({status})",
1164
+ networkFailed: "Could not reach the server."
1163
1165
  }), O.register("ko", {
1164
1166
  showHiddenColumns: "숨긴 열 보기",
1165
1167
  columnMenu: "열 메뉴",
@@ -1227,7 +1229,9 @@ O.register("en", {
1227
1229
  notANumber: "숫자를 입력하세요",
1228
1230
  notADate: "날짜를 YYYY-MM-DD 로 입력하세요",
1229
1231
  notADateTime: "날짜와 시간을 YYYY-MM-DD HH:mm 으로 입력하세요",
1230
- notInList: "목록에 있는 값이어야 합니다"
1232
+ notInList: "목록에 있는 값이어야 합니다",
1233
+ requestFailed: "요청이 실패했습니다 ({status})",
1234
+ networkFailed: "서버에 연결하지 못했습니다."
1231
1235
  });
1232
1236
  var k = (e, t) => O.text(e, t);
1233
1237
  //#endregion
@@ -2439,10 +2443,10 @@ var K = {
2439
2443
  };
2440
2444
  }
2441
2445
  connectedCallback() {
2442
- super.connectedCallback(), this._onScroll = this._onScroll.bind(this), this._onKeyDown = this._onKeyDown.bind(this), this._onDocumentClick = this._onDocumentClick.bind(this), this._onContextMenu = this._onContextMenu.bind(this), this._onDragover = this._onDragover.bind(this), this._onDragleave = this._onDragleave.bind(this), this._onDrop = this._onDrop.bind(this), this.addEventListener("scroll", this._onScroll, { passive: !0 }), this.addEventListener("keydown", this._onKeyDown), this.addEventListener("focus", this._onHostFocus), this.renderRoot.addEventListener("focusin", this._onFocusIn), this.renderRoot.addEventListener("focusout", this._onFocusOut), this.addEventListener("contextmenu", this._onContextMenu), this.addEventListener("dragover", this._onDragover), this.addEventListener("dragleave", this._onDragleave), this.addEventListener("drop", this._onDrop), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "grid"), typeof ResizeObserver < "u" && (this._hostResizeObserver = new ResizeObserver(() => this._measureViewport()), this._hostResizeObserver.observe(this));
2446
+ super.connectedCallback(), this._unsubscribeLocale = l.subscribe(() => this.requestUpdate()), this._detachedLocaleRevision !== void 0 && this._detachedLocaleRevision !== l.revision && this.requestUpdate(), this._detachedLocaleRevision = void 0, this._onScroll = this._onScroll.bind(this), this._onKeyDown = this._onKeyDown.bind(this), this._onDocumentClick = this._onDocumentClick.bind(this), this._onContextMenu = this._onContextMenu.bind(this), this._onDragover = this._onDragover.bind(this), this._onDragleave = this._onDragleave.bind(this), this._onDrop = this._onDrop.bind(this), this.addEventListener("scroll", this._onScroll, { passive: !0 }), this.addEventListener("keydown", this._onKeyDown), this.addEventListener("focus", this._onHostFocus), this.renderRoot.addEventListener("focusin", this._onFocusIn), this.renderRoot.addEventListener("focusout", this._onFocusOut), this.addEventListener("contextmenu", this._onContextMenu), this.addEventListener("dragover", this._onDragover), this.addEventListener("dragleave", this._onDragleave), this.addEventListener("drop", this._onDrop), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.setAttribute("role", "grid"), typeof ResizeObserver < "u" && (this._hostResizeObserver = new ResizeObserver(() => this._measureViewport()), this._hostResizeObserver.observe(this));
2443
2447
  }
2444
2448
  disconnectedCallback() {
2445
- super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("focus", this._onHostFocus), this.renderRoot.removeEventListener("focusin", this._onFocusIn), this.renderRoot.removeEventListener("focusout", this._onFocusOut), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("dragover", this._onDragover), this.removeEventListener("dragleave", this._onDragleave), this.removeEventListener("drop", this._onDrop), document.removeEventListener("click", this._onDocumentClick), document.removeEventListener("mousedown", this._onCommentPopupOutsideClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
2449
+ super.disconnectedCallback(), this._unsubscribeLocale?.(), this._unsubscribeLocale = void 0, this._detachedLocaleRevision = l.revision, this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("focus", this._onHostFocus), this.renderRoot.removeEventListener("focusin", this._onFocusIn), this.renderRoot.removeEventListener("focusout", this._onFocusOut), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("dragover", this._onDragover), this.removeEventListener("dragleave", this._onDragleave), this.removeEventListener("drop", this._onDrop), document.removeEventListener("click", this._onDocumentClick), document.removeEventListener("mousedown", this._onCommentPopupOutsideClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
2446
2450
  }
2447
2451
  firstUpdated() {
2448
2452
  this._readDensityTokens(), this._measureViewport(), this.shadowRoot && Array.isArray(this.shadowRoot.adoptedStyleSheets) && (this._baseStyleSheets = [...this.shadowRoot.adoptedStyleSheets]), this._syncStylesheets();
@@ -2689,7 +2693,7 @@ var K = {
2689
2693
  let { row: n, col: r } = t.position, i = this._toDataIndex(n), a = this.visibleColumns[r], o = t.originalValue;
2690
2694
  if (a.autocomplete === "strict" && e != null && e !== "" && !this._getAutocompleteCandidates(a, "").includes(String(e))) {
2691
2695
  let t = k("notInList");
2692
- this._markCellInvalid(n, r, t), this._emit("validation-error", {
2696
+ this._markCellInvalid(n, r, () => k("notInList")), this._emit("validation-error", {
2693
2697
  row: i,
2694
2698
  col: r,
2695
2699
  key: a.key,
@@ -2699,13 +2703,13 @@ var K = {
2699
2703
  return;
2700
2704
  }
2701
2705
  if (a.type === "number" && typeof e == "string" || a.type === "date" && typeof e == "string" && f(e) === null || a.type === "datetime" && typeof e == "string" && p(e) === null) {
2702
- let t = k(a.type === "number" ? "notANumber" : a.type === "date" ? "notADate" : "notADateTime");
2703
- this._markCellInvalid(n, r, t), this._emit("validation-error", {
2706
+ let t = a.type === "number" ? "notANumber" : a.type === "date" ? "notADate" : "notADateTime", o = k(t);
2707
+ this._markCellInvalid(n, r, () => k(t)), this._emit("validation-error", {
2704
2708
  row: i,
2705
2709
  col: r,
2706
2710
  key: a.key,
2707
2711
  value: e,
2708
- error: t
2712
+ error: o
2709
2713
  });
2710
2714
  return;
2711
2715
  }
@@ -3805,7 +3809,7 @@ var K = {
3805
3809
  }
3806
3810
  _isCellInvalid(e, t) {
3807
3811
  let n = this._invalidCells.get(this._cellKey(e, t));
3808
- return n ? n.error : null;
3812
+ return n ? typeof n.error == "function" ? n.error() : n.error : null;
3809
3813
  }
3810
3814
  _renderDateFilter(e) {
3811
3815
  let t = e.type === "datetime", n = this._dateFilterState.get(e.key) ?? {}, r = (e) => e?.slice(0, 10), o = (e) => {
@@ -4624,4 +4628,4 @@ function $(e) {
4624
4628
  }
4625
4629
  }
4626
4630
  //#endregion
4627
- export { A as a, j as i, W as n, O as o, B as r, T as s, Q as t };
4631
+ export { A as a, T as c, j as i, W as n, O as o, B as r, k as s, Q as t };
@@ -345,6 +345,9 @@ export declare class FlexTable extends LitElement {
345
345
  private _rowBoundaryViewportY;
346
346
  private get totalBodyHeight();
347
347
  private get visibleRange();
348
+ /** 런타임 로캘 전환 구독 — 이 요소는 `LitElement` 를 직접 잇기에 `@iyulab/components` 의 `UElement` 구독을 받지 못한다. */
349
+ private _unsubscribeLocale?;
350
+ private _detachedLocaleRevision?;
348
351
  connectedCallback(): void;
349
352
  disconnectedCallback(): void;
350
353
  protected firstUpdated(): void;
@@ -556,6 +559,7 @@ export declare class FlexTable extends LitElement {
556
559
  private _defaultNumState;
557
560
  private _renderNumCondRow;
558
561
  private _renderNumberFilter;
562
+ /** 셀 오류 표시 — 우리 문장은 «그릴 때 찾는» 함수로(로캘 전환에 따라오게), 소비자 `validator` 문장은 그대로. */
559
563
  private _invalidCells;
560
564
  private _cellKey;
561
565
  private _markCellInvalid;
@@ -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-Hx-xTm0e.js";
2
- export { o as FlexTable, e as RowSelectionState, t as UndoStack, n as effectiveAlign, i as exportData, r as flexTableLocale, a as renderCell };
1
+ import { a as e, c as t, i as n, n as r, o as i, r as a, t as o } from "./flex-table-CtlqiwD8.js";
2
+ export { o as FlexTable, e as RowSelectionState, n as UndoStack, r as effectiveAlign, a as exportData, i as flexTableLocale, t 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' | 'findNoResults' | 'replaceWithPlaceholder' | 'replace' | 'replaceAll' | 'findInput' | 'replaceInput' | 'filterFor' | 'filterMatchMode' | 'filterText' | 'conditionOperator' | 'conditionValue' | 'conditionJoin' | 'sortAscending' | 'sortDescending' | 'filter' | 'clearFilter' | 'hideColumn' | 'showColumn' | 'autoFitWidth' | 'wider' | 'narrower' | 'columnMenuFor' | 'columnMenuRegion' | 'copy' | 'insertRowAbove' | 'insertRowBelow' | 'deleteRow' | 'selectRow' | 'selectAllRows' | 'filterByThisValue' | 'addComment' | 'editComment' | 'deleteComment' | 'booleanTrue' | 'booleanFalse' | 'dropFileToImport' | 'notANumber' | 'notADate' | 'notADateTime' | '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' | 'findNoResults' | 'replaceWithPlaceholder' | 'replace' | 'replaceAll' | 'findInput' | 'replaceInput' | 'filterFor' | 'filterMatchMode' | 'filterText' | 'conditionOperator' | 'conditionValue' | 'conditionJoin' | 'sortAscending' | 'sortDescending' | 'filter' | 'clearFilter' | 'hideColumn' | 'showColumn' | 'autoFitWidth' | 'wider' | 'narrower' | 'columnMenuFor' | 'columnMenuRegion' | 'copy' | 'insertRowAbove' | 'insertRowBelow' | 'deleteRow' | 'selectRow' | 'selectAllRows' | 'filterByThisValue' | 'addComment' | 'editComment' | 'deleteComment' | 'booleanTrue' | 'booleanFalse' | 'dropFileToImport' | 'notANumber' | 'notADate' | 'notADateTime' | 'notInList' | 'requestFailed' | 'networkFailed';
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,26 +1,26 @@
1
- import { t as e } from "./flex-table-Hx-xTm0e.js";
2
- import { i as t, t as n } from "./query-Dw4iO0ir.js";
3
- import { t as r } from "./view-DiLr-TdY.js";
4
- import i, { useCallback as a, useEffect as o, useMemo as s, useRef as c, useState as l } from "react";
5
- import { createComponent as u } from "@lit/react";
1
+ import { s as e, t } from "./flex-table-CtlqiwD8.js";
2
+ import { i as n, t as r } from "./query-Dw4iO0ir.js";
3
+ import { t as i } from "./view-DiLr-TdY.js";
4
+ import a, { useCallback as o, useEffect as s, useMemo as c, useRef as l, useState as u } from "react";
5
+ import { createComponent as d } from "@lit/react";
6
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
7
+ async function f(t) {
8
+ let n = await t.text().catch(() => ""), r = {
9
+ message: e("requestFailed", { status: t.status }),
10
+ status: t.status
11
11
  };
12
- if (!t) return n;
13
- let r = t;
12
+ if (!n) return r;
13
+ let i = n;
14
14
  try {
15
- r = JSON.parse(t);
15
+ i = JSON.parse(n);
16
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;
17
+ if (r.body = i, !i || typeof i != "object") return r;
18
+ let a = i, o = a.error && typeof a.error == "object" ? a.error : a;
19
+ typeof o.message == "string" && o.message ? r.message = o.message : typeof a.message == "string" && a.message && (r.message = a.message), typeof o.code == "string" && o.code && (r.code = o.code);
20
+ let s = p(o.details);
21
+ return s && (r.details = s), r;
22
22
  }
23
- function f(e) {
23
+ function p(e) {
24
24
  if (!Array.isArray(e)) return;
25
25
  let t = e.filter((e) => {
26
26
  if (!e || typeof e != "object") return !1;
@@ -29,56 +29,67 @@ function f(e) {
29
29
  });
30
30
  return t.length > 0 ? t : void 0;
31
31
  }
32
- var p = class extends Error {
32
+ var m = class extends Error {
33
33
  constructor(e) {
34
34
  super(e.message), this.name = "SourceRequestError", this.failure = e;
35
35
  }
36
36
  };
37
- function m(e) {
38
- return e instanceof p ? e.failure : e instanceof Error ? { message: e.message } : { message: String(e) };
37
+ function h(t) {
38
+ return new m({
39
+ message: e("networkFailed"),
40
+ cause: t
41
+ });
42
+ }
43
+ function g(e) {
44
+ return e instanceof m ? e.failure : e instanceof Error ? { message: e.message } : { message: String(e) };
39
45
  }
40
46
  //#endregion
41
47
  //#region src/odata/use-odata-source.ts
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(!0), [O, k] = l(null), A = t({
44
- defaultOrderBy: s,
45
- initialPage: u,
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) => {
48
+ function _(e, t = {}) {
49
+ let { pageSize: i = 20, defaultOrderBy: a, initialPage: c = 0, initialSearch: d = "", initialSort: p, fixedFilter: _, baseUrl: v, fetcher: y = fetch, onUnauthorized: b, enabled: x = !0 } = t, S = _ ? JSON.stringify(_) : "", [C, w] = u([]), [T, E] = u(0), [D, O] = u(!0), [k, A] = u(null), j = n({
50
+ defaultOrderBy: a,
51
+ initialPage: c,
52
+ initialSearch: d,
53
+ initialSort: p
54
+ }), [M, N] = u(j.page), [P, F] = u(j.sortCriteria), [I, L] = u(j.search), [R, z] = u(0), [B, V] = u(S);
55
+ S !== B && (V(S), N(0));
56
+ let H = l(null), U = o(() => {
57
+ z((e) => e + 1);
58
+ }, []), W = o((e) => {
59
+ L(e), N(0);
60
+ }, []), G = o((e) => {
55
61
  let t = e.detail?.criteria;
56
- t && (P(t), M(0));
62
+ t && (F(t), N(0));
57
63
  }, []);
58
- return o(() => {
59
- if (V.current?.abort(), !b) return;
64
+ return s(() => {
65
+ if (H.current?.abort(), !x) return;
60
66
  let t = new AbortController();
61
- V.current = t, D(!0), k(null);
62
- let r = n({
63
- page: j,
67
+ H.current = t, O(!0), A(null);
68
+ let n = r({
69
+ page: M,
64
70
  pageSize: i,
65
- sortCriteria: N,
66
- defaultOrderBy: s,
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));
71
+ sortCriteria: P,
72
+ defaultOrderBy: a,
73
+ search: I,
74
+ fixedFilter: _
75
+ }), o = `${v ?? window.location.origin}${e}${n}`, s = async (e) => {
76
+ let n;
77
+ try {
78
+ n = await y(e, { signal: t.signal });
79
+ } catch (e) {
80
+ throw e?.name === "AbortError" ? e : h(e);
81
+ }
82
+ if (!n.ok) throw n.status === 401 && b && b(n), new m(await f(n));
72
83
  return n.json();
73
84
  };
74
85
  return (async () => {
75
- let e = await o(a), t = [...e.value ?? e], n = new URL(a).origin, r = /* @__PURE__ */ new Set([a]), s = a, c = e["@odata.nextLink"];
86
+ let e = await s(o), t = [...e.value ?? e], n = new URL(o).origin, r = /* @__PURE__ */ new Set([o]), a = o, c = e["@odata.nextLink"];
76
87
  for (; typeof c == "string" && c && t.length < i;) {
77
- let e = new URL(c, s);
88
+ let e = new URL(c, a);
78
89
  if (e.origin !== n) throw Error(`OData nextLink points outside the source origin (${e.origin})`);
79
- if (s = e.toString(), r.has(s)) throw Error(`OData nextLink repeats an already-read page (${s})`);
80
- r.add(s);
81
- let i = await o(s);
90
+ if (a = e.toString(), r.has(a)) throw Error(`OData nextLink repeats an already-read page (${a})`);
91
+ r.add(a);
92
+ let i = await s(a);
82
93
  t.push(...i.value ?? []), c = i["@odata.nextLink"];
83
94
  }
84
95
  return {
@@ -88,57 +99,57 @@ function h(e, r = {}) {
88
99
  })().then(({ count: e, rows: n }) => {
89
100
  if (t.signal.aborted) return;
90
101
  let r = e ?? 0;
91
- C(n), T(r), k(null);
102
+ w(n), E(r), A(null);
92
103
  let a = r === 0 ? 0 : Math.ceil(r / i) - 1;
93
- j > a && M(a);
104
+ M > a && N(a);
94
105
  }).catch((e) => {
95
- t.signal.aborted || e.name !== "AbortError" && (k(m(e)), C([]), T(0));
106
+ t.signal.aborted || e.name !== "AbortError" && (A(g(e)), w([]), E(0));
96
107
  }).finally(() => {
97
- t.signal.aborted || D(!1);
108
+ t.signal.aborted || O(!1);
98
109
  }), () => t.abort();
99
110
  }, [
100
- b,
111
+ x,
101
112
  e,
102
- j,
113
+ M,
103
114
  i,
104
- N,
105
- F,
106
- x,
107
- s,
108
- L,
109
- _
115
+ P,
116
+ I,
117
+ S,
118
+ a,
119
+ R,
120
+ v
110
121
  ]), {
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
122
+ data: C,
123
+ totalCount: T,
124
+ loading: D || !x,
125
+ error: k,
126
+ page: M,
127
+ setPage: N,
128
+ sortCriteria: P,
129
+ onSortChange: G,
130
+ search: I,
131
+ setSearch: W,
132
+ refresh: U
122
133
  };
123
134
  }
124
135
  //#endregion
125
136
  //#region src/array/use-array-source.ts
126
- function g(e, n = {}) {
127
- let { pageSize: i = 20, defaultOrderBy: o, initialPage: c = 0, initialSearch: u = "", initialSort: d, columns: f, searchFields: p } = n, m = t({
128
- defaultOrderBy: o,
129
- initialPage: c,
130
- initialSearch: u,
137
+ function v(e, t = {}) {
138
+ let { pageSize: r = 20, defaultOrderBy: a, initialPage: s = 0, initialSearch: l = "", initialSort: d, columns: f, searchFields: p } = t, m = n({
139
+ defaultOrderBy: a,
140
+ initialPage: s,
141
+ initialSearch: l,
131
142
  initialSort: d
132
- }), [h, g] = l(m.page), [_, v] = l(m.sortCriteria), [y, b] = l(m.search), x = a((e) => {
143
+ }), [h, g] = u(m.page), [_, v] = u(m.sortCriteria), [y, b] = u(m.search), x = o((e) => {
133
144
  b(e), g(0);
134
- }, []), S = a((e) => {
145
+ }, []), S = o((e) => {
135
146
  let t = e.detail?.criteria;
136
147
  t && (v(t), g(0));
137
- }, []), C = a(() => {}, []), { data: w, totalCount: T } = s(() => r(e, {
148
+ }, []), C = o(() => {}, []), { data: w, totalCount: T } = c(() => i(e, {
138
149
  search: y,
139
150
  sortCriteria: _,
140
151
  page: h,
141
- pageSize: i,
152
+ pageSize: r,
142
153
  columns: f,
143
154
  searchFields: p
144
155
  }), [
@@ -146,10 +157,10 @@ function g(e, n = {}) {
146
157
  y,
147
158
  _,
148
159
  h,
149
- i,
160
+ r,
150
161
  f,
151
162
  p
152
- ]), E = T === 0 ? 0 : Math.ceil(T / i) - 1;
163
+ ]), E = T === 0 ? 0 : Math.ceil(T / r) - 1;
153
164
  return h > E && g(E), {
154
165
  data: w,
155
166
  totalCount: T,
@@ -164,10 +175,10 @@ function g(e, n = {}) {
164
175
  refresh: C
165
176
  };
166
177
  }
167
- var _ = u({
178
+ var y = d({
168
179
  tagName: "flex-table",
169
- elementClass: e,
170
- react: i,
180
+ elementClass: t,
181
+ react: a,
171
182
  events: {
172
183
  onCellSelect: "cell-select",
173
184
  onCellEditCommit: "cell-edit-commit",
@@ -203,4 +214,4 @@ var _ = u({
203
214
  }
204
215
  });
205
216
  //#endregion
206
- export { _ as FlexTableReact, g as useArraySource, h as useODataSource };
217
+ export { y as FlexTableReact, v as useArraySource, _ as useODataSource };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.50.4",
3
+ "version": "0.52.0",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",
@@ -74,7 +74,7 @@
74
74
  "odata-query": "^8.1.0"
75
75
  },
76
76
  "peerDependencies": {
77
- "@iyulab/components": ">=2.2.0",
77
+ "@iyulab/components": ">=2.8.0",
78
78
  "@lit/react": "^1.0.8",
79
79
  "react": "^18.0.0 || ^19.0.0"
80
80
  },
@@ -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, or no answer yet (true from the first render until the first response settles, and while `enabled: false`) — so `!loading && totalCount === 0` means "no results" |
114
- | `error` | `SourceError \| null` — `{ message, status?, code?, details?, body? }`; render `error.message`, branch on `status` / `code` (OData `error.code`) |
114
+ | `error` | `SourceError \| null` — `{ message, status?, code?, details?, body?, cause? }`; render `error.message`, branch on `status` / `code` (OData `error.code`). `message` is the server's sentence when it sent one; otherwise this package's, in the `flexTableLocale` language — `requestFailed` (`Request failed ({status})`) when a response came back, `networkFailed` when none did (the transport's exception is in `cause`) |
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) |