@iyulab/flex-table 0.54.0 → 0.55.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 +9 -0
- package/README.md +13 -0
- package/dist/array/index.d.ts +2 -0
- package/dist/array/index.js +71 -2
- package/dist/array/source.d.ts +43 -0
- package/dist/odata/index.js +3 -2
- package/dist/query-Dw4iO0ir.js +37 -0
- package/dist/react.js +2 -1
- package/dist/{source-CwbD-6ea.js → source-r2Pv6Pvo.js} +43 -78
- package/package.json +1 -1
- package/skills/iyulab-flex-table/SKILL.md +1 -1
- package/skills/iyulab-flex-table/references/react.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.55.0] - 2026-10-07
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`createArraySource(rows, options)`** and **`ArraySourceController`** (`@iyulab/flex-table/array`) — the in-memory
|
|
8
|
+
source without React, with the members of `createODataSource` (`getState`, `subscribe`, `setPage`, `setSort`,
|
|
9
|
+
`setSearch`, `refresh`) plus `update(rows, options)`. A custom-element screen can now switch between a server and
|
|
10
|
+
an in-memory source the way a React screen switches between `useODataSource` and `useArraySource`.
|
|
11
|
+
|
|
3
12
|
## [0.54.0] - 2026-10-07
|
|
4
13
|
|
|
5
14
|
### Added
|
package/README.md
CHANGED
|
@@ -939,6 +939,19 @@ count after search (not a server-reported total), and `loading`/`error` are alwa
|
|
|
939
939
|
`false`/`null` — there's no request to fail. `refresh` is a no-op kept only so a
|
|
940
940
|
"refresh" button wired unconditionally against either hook doesn't need a branch.
|
|
941
941
|
|
|
942
|
+
Without React, `createArraySource(rows, options)` (`@iyulab/flex-table/array`) is the same source with the same
|
|
943
|
+
members as `createODataSource` — `getState()`, `subscribe()`, `setPage`, `setSort`, `setSearch`, `refresh` (no-op) —
|
|
944
|
+
plus `update(rows, options)` when the rows change. `ArraySourceController` binds it to a Lit element:
|
|
945
|
+
|
|
946
|
+
```ts
|
|
947
|
+
import { ArraySourceController } from '@iyulab/flex-table/array';
|
|
948
|
+
|
|
949
|
+
class PricesPanel extends LitElement {
|
|
950
|
+
private prices = new ArraySourceController(this, [], { pageSize: 20 });
|
|
951
|
+
set rows(rows: DataRow[]) { this.prices.source.update(rows, { pageSize: 20 }); }
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
942
955
|
## Development
|
|
943
956
|
|
|
944
957
|
```bash
|
package/dist/array/index.d.ts
CHANGED
package/dist/array/index.js
CHANGED
|
@@ -1,2 +1,71 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { i as e } from "../query-Dw4iO0ir.js";
|
|
2
|
+
import { t } from "../view-DiLr-TdY.js";
|
|
3
|
+
//#region src/array/source.ts
|
|
4
|
+
function n(n, r = {}) {
|
|
5
|
+
let i = n, a = r, o = e({
|
|
6
|
+
defaultOrderBy: r.defaultOrderBy,
|
|
7
|
+
initialPage: r.initialPage ?? 0,
|
|
8
|
+
initialSearch: r.initialSearch ?? "",
|
|
9
|
+
initialSort: r.initialSort
|
|
10
|
+
}), s = o.page, c = o.sortCriteria, l = o.search, u = f(), d = /* @__PURE__ */ new Set();
|
|
11
|
+
function f() {
|
|
12
|
+
let e = a.pageSize ?? 20, n = t(i, {
|
|
13
|
+
search: l,
|
|
14
|
+
sortCriteria: c,
|
|
15
|
+
page: s,
|
|
16
|
+
pageSize: e,
|
|
17
|
+
columns: a.columns,
|
|
18
|
+
searchFields: a.searchFields
|
|
19
|
+
}), r = n.totalCount === 0 ? 0 : Math.ceil(n.totalCount / e) - 1;
|
|
20
|
+
return s > r && (s = r), {
|
|
21
|
+
data: n.data,
|
|
22
|
+
totalCount: n.totalCount,
|
|
23
|
+
loading: !1,
|
|
24
|
+
error: null,
|
|
25
|
+
page: s,
|
|
26
|
+
sortCriteria: c,
|
|
27
|
+
search: l
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function p() {
|
|
31
|
+
u = f();
|
|
32
|
+
for (let e of [...d]) e();
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
getState: () => u,
|
|
36
|
+
subscribe(e) {
|
|
37
|
+
return d.add(e), () => {
|
|
38
|
+
d.delete(e);
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
setPage(e) {
|
|
42
|
+
s = e, p();
|
|
43
|
+
},
|
|
44
|
+
setSort(e) {
|
|
45
|
+
c = e, s = 0, p();
|
|
46
|
+
},
|
|
47
|
+
setSearch(e) {
|
|
48
|
+
l = e, s = 0, p();
|
|
49
|
+
},
|
|
50
|
+
refresh() {},
|
|
51
|
+
update(e, t = {}) {
|
|
52
|
+
i = e, a = t, p();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
var r = class {
|
|
57
|
+
constructor(e, t, r = {}) {
|
|
58
|
+
this.host = e, this.source = n(t, r), e.addController(this);
|
|
59
|
+
}
|
|
60
|
+
get state() {
|
|
61
|
+
return this.source.getState();
|
|
62
|
+
}
|
|
63
|
+
hostConnected() {
|
|
64
|
+
this.unsubscribe ??= this.source.subscribe(() => this.host.requestUpdate());
|
|
65
|
+
}
|
|
66
|
+
hostDisconnected() {
|
|
67
|
+
this.unsubscribe?.(), this.unsubscribe = void 0;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
export { r as ArraySourceController, t as computeArrayView, n as createArraySource };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
2
|
+
import type { SortCriteria } from '../core/sorting.js';
|
|
3
|
+
import type { DataRow } from '../models/types.js';
|
|
4
|
+
import type { ODataSourceState } from '../odata/source.js';
|
|
5
|
+
import type { UseArraySourceOptions } from './types.js';
|
|
6
|
+
/** 메모리 소스의 설정 — `useArraySource` 의 옵션과 같다(`initial*` 은 만들 때만 읽는다). */
|
|
7
|
+
export type ArraySourceOptions<T> = UseArraySourceOptions<T>;
|
|
8
|
+
/** 메모리 소스 — `createODataSource` 와 같은 상태·조작 모양이라 같은 표 배선이 두 소스에서 돈다. */
|
|
9
|
+
export interface ArraySource<T> {
|
|
10
|
+
/** 현재 상태(`loading` 은 늘 `false`, `error` 는 늘 `null`). 바뀌지 않았으면 같은 객체다. */
|
|
11
|
+
getState(): ODataSourceState<T>;
|
|
12
|
+
/** 상태가 바뀔 때마다 부른다. 해지 함수를 돌려준다. */
|
|
13
|
+
subscribe(listener: () => void): () => void;
|
|
14
|
+
/** 0-based 페이지로 옮긴다(범위를 넘으면 마지막 페이지). */
|
|
15
|
+
setPage(page: number): void;
|
|
16
|
+
/** 정렬을 바꾸고 첫 장으로 간다. */
|
|
17
|
+
setSort(criteria: SortCriteria[]): void;
|
|
18
|
+
/** 검색어를 바꾸고 첫 장으로 간다. */
|
|
19
|
+
setSearch(term: string): void;
|
|
20
|
+
/** 아무 일도 하지 않는다 — 다시 불러올 원격 상태가 없다(OData 소스와 같은 자리에 이어도 안전하다). */
|
|
21
|
+
refresh(): void;
|
|
22
|
+
/** 행이나 설정이 바뀌었다 — 다시 계산한다. 결과가 줄어 지금 페이지가 없어지면 마지막 페이지로 내려온다. */
|
|
23
|
+
update(data: T[], options?: ArraySourceOptions<T>): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 이미 메모리에 있는 행의 데이터 소스 — 검색·정렬·페이지 나누기를 로컬에서 한다(`computeArrayView`). React 없이 쓴다;
|
|
27
|
+
* React 는 `useArraySource`, Lit 은 `ArraySourceController`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createArraySource<T extends DataRow = DataRow>(data: T[], options?: ArraySourceOptions<T>): ArraySource<T>;
|
|
30
|
+
/**
|
|
31
|
+
* Lit 어댑터 — 메모리 소스를 호스트에 묶는다. 상태가 바뀌면 호스트를 다시 그린다. 행이 바뀌면 `source.update(rows)`.
|
|
32
|
+
*/
|
|
33
|
+
export declare class ArraySourceController<T extends DataRow = DataRow> implements ReactiveController {
|
|
34
|
+
private readonly host;
|
|
35
|
+
/** 소스 — 조작(`setPage`·`setSort`·`setSearch`·`update`)은 이것으로 한다. */
|
|
36
|
+
readonly source: ArraySource<T>;
|
|
37
|
+
private unsubscribe?;
|
|
38
|
+
constructor(host: ReactiveControllerHost, data: T[], options?: ArraySourceOptions<T>);
|
|
39
|
+
/** 현재 상태. */
|
|
40
|
+
get state(): ODataSourceState<T>;
|
|
41
|
+
hostConnected(): void;
|
|
42
|
+
hostDisconnected(): void;
|
|
43
|
+
}
|
package/dist/odata/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as e, r as t, t as n } from "../query-Dw4iO0ir.js";
|
|
2
|
+
import { t as r } from "../source-r2Pv6Pvo.js";
|
|
2
3
|
//#region src/odata/controller.ts
|
|
3
4
|
var i = class {
|
|
4
5
|
constructor(e, t, n = {}) {
|
|
@@ -15,4 +16,4 @@ var i = class {
|
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
18
|
//#endregion
|
|
18
|
-
export { i as ODataSourceController,
|
|
19
|
+
export { i as ODataSourceController, n as buildODataQuery, e as buildSearchExpression, r as createODataSource, t as parseOrderBy };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import e from "odata-query";
|
|
2
|
+
//#region src/odata/query.ts
|
|
3
|
+
function t(e) {
|
|
4
|
+
let t = e.split(/\s+/).map((e) => e.replace(/"/g, "")).filter((e) => e.length > 0);
|
|
5
|
+
if (t.length !== 0) return t.map((e) => `"${e}"`).join(" AND ");
|
|
6
|
+
}
|
|
7
|
+
function n(e) {
|
|
8
|
+
let { defaultOrderBy: t, initialPage: n = 0, initialSearch: i = "", initialSort: a } = e;
|
|
9
|
+
return {
|
|
10
|
+
page: n,
|
|
11
|
+
search: i,
|
|
12
|
+
sortCriteria: a ?? (t ? r(t) : [])
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function r(e) {
|
|
16
|
+
return e.split(",").map((e) => {
|
|
17
|
+
let t = e.trim().split(/\s+/);
|
|
18
|
+
return {
|
|
19
|
+
key: t[0],
|
|
20
|
+
direction: t[1]?.toLowerCase() === "desc" ? "desc" : "asc"
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function i(n) {
|
|
25
|
+
let { page: r, pageSize: i, sortCriteria: a = [], defaultOrderBy: o, search: s, fixedFilter: c } = n, l = a.length > 0 ? a.map((e) => `${e.key} ${e.direction}`).join(", ") : o, u = {
|
|
26
|
+
top: i,
|
|
27
|
+
skip: r * i,
|
|
28
|
+
count: !0
|
|
29
|
+
};
|
|
30
|
+
if (l && (u.orderBy = l), c && (u.filter = c), s) {
|
|
31
|
+
let e = t(s);
|
|
32
|
+
e && (u.search = e);
|
|
33
|
+
}
|
|
34
|
+
return e(u);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { n as i, t as n, r, i as t };
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as e } from "./flex-table-DlvIBu4z.js";
|
|
2
|
-
import {
|
|
2
|
+
import { i as t } from "./query-Dw4iO0ir.js";
|
|
3
|
+
import { t as n } from "./source-r2Pv6Pvo.js";
|
|
3
4
|
import { t as r } from "./view-DiLr-TdY.js";
|
|
4
5
|
import i, { useCallback as a, useEffect as o, useMemo as s, useState as c, useSyncExternalStore as l } from "react";
|
|
5
6
|
import { createComponent as u } from "@lit/react";
|
|
@@ -1,58 +1,23 @@
|
|
|
1
1
|
import { n as e } from "./locale-B1SiVDS1.js";
|
|
2
|
-
import t from "
|
|
3
|
-
//#region src/odata/query.ts
|
|
4
|
-
function n(e) {
|
|
5
|
-
let t = e.split(/\s+/).map((e) => e.replace(/"/g, "")).filter((e) => e.length > 0);
|
|
6
|
-
if (t.length !== 0) return t.map((e) => `"${e}"`).join(" AND ");
|
|
7
|
-
}
|
|
8
|
-
function r(e) {
|
|
9
|
-
let { defaultOrderBy: t, initialPage: n = 0, initialSearch: r = "", initialSort: a } = e;
|
|
10
|
-
return {
|
|
11
|
-
page: n,
|
|
12
|
-
search: r,
|
|
13
|
-
sortCriteria: a ?? (t ? i(t) : [])
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function i(e) {
|
|
17
|
-
return e.split(",").map((e) => {
|
|
18
|
-
let t = e.trim().split(/\s+/);
|
|
19
|
-
return {
|
|
20
|
-
key: t[0],
|
|
21
|
-
direction: t[1]?.toLowerCase() === "desc" ? "desc" : "asc"
|
|
22
|
-
};
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
function a(e) {
|
|
26
|
-
let { page: r, pageSize: i, sortCriteria: a = [], defaultOrderBy: o, search: s, fixedFilter: c } = e, l = a.length > 0 ? a.map((e) => `${e.key} ${e.direction}`).join(", ") : o, u = {
|
|
27
|
-
top: i,
|
|
28
|
-
skip: r * i,
|
|
29
|
-
count: !0
|
|
30
|
-
};
|
|
31
|
-
if (l && (u.orderBy = l), c && (u.filter = c), s) {
|
|
32
|
-
let e = n(s);
|
|
33
|
-
e && (u.search = e);
|
|
34
|
-
}
|
|
35
|
-
return t(u);
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
2
|
+
import { i as t, t as n } from "./query-Dw4iO0ir.js";
|
|
38
3
|
//#region src/core/source-error.ts
|
|
39
|
-
async function
|
|
4
|
+
async function r(t) {
|
|
40
5
|
let n = await t.text().catch(() => ""), r = {
|
|
41
6
|
message: e("requestFailed", { status: t.status }),
|
|
42
7
|
status: t.status
|
|
43
8
|
};
|
|
44
9
|
if (!n) return r;
|
|
45
|
-
let
|
|
10
|
+
let a = n;
|
|
46
11
|
try {
|
|
47
|
-
|
|
12
|
+
a = JSON.parse(n);
|
|
48
13
|
} catch {}
|
|
49
|
-
if (r.body =
|
|
50
|
-
let
|
|
51
|
-
typeof
|
|
52
|
-
let c = s
|
|
14
|
+
if (r.body = a, !a || typeof a != "object") return r;
|
|
15
|
+
let o = a, s = o.error && typeof o.error == "object" ? o.error : o;
|
|
16
|
+
typeof s.message == "string" && s.message ? r.message = s.message : typeof o.message == "string" && o.message && (r.message = o.message), typeof s.code == "string" && s.code && (r.code = s.code);
|
|
17
|
+
let c = i(s.details);
|
|
53
18
|
return c && (r.details = c), r;
|
|
54
19
|
}
|
|
55
|
-
function
|
|
20
|
+
function i(e) {
|
|
56
21
|
if (!Array.isArray(e)) return;
|
|
57
22
|
let t = e.filter((e) => {
|
|
58
23
|
if (!e || typeof e != "object") return !1;
|
|
@@ -61,42 +26,42 @@ function s(e) {
|
|
|
61
26
|
});
|
|
62
27
|
return t.length > 0 ? t : void 0;
|
|
63
28
|
}
|
|
64
|
-
var
|
|
29
|
+
var a = class extends Error {
|
|
65
30
|
constructor(e) {
|
|
66
31
|
super(e.message), this.name = "SourceRequestError", this.failure = e;
|
|
67
32
|
}
|
|
68
33
|
};
|
|
69
|
-
function
|
|
70
|
-
return new
|
|
34
|
+
function o(t) {
|
|
35
|
+
return new a({
|
|
71
36
|
message: e("networkFailed"),
|
|
72
37
|
cause: t
|
|
73
38
|
});
|
|
74
39
|
}
|
|
75
|
-
function
|
|
76
|
-
return e instanceof
|
|
40
|
+
function s(e) {
|
|
41
|
+
return e instanceof a ? e.failure : e instanceof Error ? { message: e.message } : { message: String(e) };
|
|
77
42
|
}
|
|
78
43
|
//#endregion
|
|
79
44
|
//#region src/odata/source.ts
|
|
80
|
-
function
|
|
81
|
-
let
|
|
82
|
-
defaultOrderBy:
|
|
83
|
-
initialPage:
|
|
84
|
-
initialSearch:
|
|
85
|
-
initialSort:
|
|
45
|
+
function c(e, i = {}) {
|
|
46
|
+
let c = e, u = i, d = l(i.fixedFilter), f = t({
|
|
47
|
+
defaultOrderBy: i.defaultOrderBy,
|
|
48
|
+
initialPage: i.initialPage ?? 0,
|
|
49
|
+
initialSearch: i.initialSearch ?? "",
|
|
50
|
+
initialSort: i.initialSort
|
|
86
51
|
}), p = {
|
|
87
52
|
data: [],
|
|
88
53
|
totalCount: 0,
|
|
89
54
|
loading: !0,
|
|
90
55
|
error: null,
|
|
91
|
-
page:
|
|
92
|
-
sortCriteria:
|
|
93
|
-
search:
|
|
56
|
+
page: f.page,
|
|
57
|
+
sortCriteria: f.sortCriteria,
|
|
58
|
+
search: f.search
|
|
94
59
|
}, m = x(), h = /* @__PURE__ */ new Set(), g = null, _ = !1, v = null;
|
|
95
60
|
function y() {
|
|
96
|
-
return
|
|
61
|
+
return u.enabled ?? !0;
|
|
97
62
|
}
|
|
98
63
|
function b() {
|
|
99
|
-
return
|
|
64
|
+
return u.pageSize ?? 20;
|
|
100
65
|
}
|
|
101
66
|
function x() {
|
|
102
67
|
return {
|
|
@@ -119,11 +84,11 @@ function d(e, t = {}) {
|
|
|
119
84
|
}
|
|
120
85
|
function w() {
|
|
121
86
|
return JSON.stringify([
|
|
122
|
-
|
|
123
|
-
|
|
87
|
+
c,
|
|
88
|
+
u.baseUrl,
|
|
124
89
|
b(),
|
|
125
|
-
|
|
126
|
-
|
|
90
|
+
u.defaultOrderBy,
|
|
91
|
+
d,
|
|
127
92
|
p.page,
|
|
128
93
|
p.sortCriteria,
|
|
129
94
|
p.search
|
|
@@ -147,26 +112,26 @@ function d(e, t = {}) {
|
|
|
147
112
|
g?.abort();
|
|
148
113
|
let e = new AbortController();
|
|
149
114
|
g = e;
|
|
150
|
-
let { page: t, sortCriteria:
|
|
115
|
+
let { page: t, sortCriteria: i, search: l } = p, d = b(), f = u.fetcher ?? fetch, m = u.onUnauthorized;
|
|
151
116
|
S({
|
|
152
117
|
loading: !0,
|
|
153
118
|
error: null
|
|
154
119
|
});
|
|
155
|
-
let h =
|
|
120
|
+
let h = n({
|
|
156
121
|
page: t,
|
|
157
122
|
pageSize: d,
|
|
158
|
-
sortCriteria:
|
|
159
|
-
defaultOrderBy:
|
|
160
|
-
search:
|
|
161
|
-
fixedFilter:
|
|
162
|
-
}), _ = `${
|
|
123
|
+
sortCriteria: i,
|
|
124
|
+
defaultOrderBy: u.defaultOrderBy,
|
|
125
|
+
search: l,
|
|
126
|
+
fixedFilter: u.fixedFilter
|
|
127
|
+
}), _ = `${u.baseUrl ?? window.location.origin}${c}${h}`, v = async (t) => {
|
|
163
128
|
let n;
|
|
164
129
|
try {
|
|
165
130
|
n = await f(t, { signal: e.signal });
|
|
166
131
|
} catch (e) {
|
|
167
|
-
throw e?.name === "AbortError" ? e :
|
|
132
|
+
throw e?.name === "AbortError" ? e : o(e);
|
|
168
133
|
}
|
|
169
|
-
if (!n.ok) throw n.status === 401 && m && m(n), new
|
|
134
|
+
if (!n.ok) throw n.status === 401 && m && m(n), new a(await r(n));
|
|
170
135
|
return n.json();
|
|
171
136
|
};
|
|
172
137
|
(async () => {
|
|
@@ -198,7 +163,7 @@ function d(e, t = {}) {
|
|
|
198
163
|
});
|
|
199
164
|
}).catch((t) => {
|
|
200
165
|
e.signal.aborted || t?.name !== "AbortError" && S({
|
|
201
|
-
error:
|
|
166
|
+
error: s(t),
|
|
202
167
|
data: [],
|
|
203
168
|
totalCount: 0
|
|
204
169
|
});
|
|
@@ -232,16 +197,16 @@ function d(e, t = {}) {
|
|
|
232
197
|
y() && (v = null, T());
|
|
233
198
|
},
|
|
234
199
|
update(e, t = {}) {
|
|
235
|
-
let
|
|
236
|
-
|
|
200
|
+
let n = l(t.fixedFilter), r = n !== d;
|
|
201
|
+
c = e, u = t, d = n, r && (p = {
|
|
237
202
|
...p,
|
|
238
203
|
page: 0
|
|
239
204
|
}), C(), T();
|
|
240
205
|
}
|
|
241
206
|
};
|
|
242
207
|
}
|
|
243
|
-
function
|
|
208
|
+
function l(e) {
|
|
244
209
|
return e ? JSON.stringify(e) : "";
|
|
245
210
|
}
|
|
246
211
|
//#endregion
|
|
247
|
-
export {
|
|
212
|
+
export { c as t };
|
package/package.json
CHANGED
|
@@ -28,7 +28,7 @@ npm install @lit/react react
|
|
|
28
28
|
| `@iyulab/flex-table` | Registers `<flex-table>`; exports `FlexTable`, types, `exportData`, `renderCell`, `flexTableLocale`, `RowSelectionState`, `UndoStack`, `effectiveAlign` |
|
|
29
29
|
| `@iyulab/flex-table/react` | `FlexTableReact`, `useODataSource`, `useArraySource` |
|
|
30
30
|
| `@iyulab/flex-table/odata` | No React: `createODataSource` (the source `useODataSource` adapts), `ODataSourceController` (Lit), `buildODataQuery`, `buildSearchExpression`, `parseOrderBy` |
|
|
31
|
-
| `@iyulab/flex-table/array` |
|
|
31
|
+
| `@iyulab/flex-table/array` | No React: `createArraySource` (same members as `createODataSource`, plus `update(rows)`), `ArraySourceController` (Lit), `computeArrayView` |
|
|
32
32
|
|
|
33
33
|
## Quick start
|
|
34
34
|
|
|
@@ -181,6 +181,7 @@ Pure helpers:
|
|
|
181
181
|
```ts
|
|
182
182
|
import { buildODataQuery, buildSearchExpression, parseOrderBy } from '@iyulab/flex-table/odata';
|
|
183
183
|
import { computeArrayView } from '@iyulab/flex-table/array';
|
|
184
|
+
// createArraySource / ArraySourceController: the in-memory source with createODataSource's members + update(rows)
|
|
184
185
|
|
|
185
186
|
buildSearchExpression('red shirt'); // '"red" AND "shirt"' ('' → undefined)
|
|
186
187
|
parseOrderBy('name desc'); // [{ key: 'name', direction: 'desc' }]
|