@iyulab/flex-table 0.30.0 → 0.31.1
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 +25 -0
- package/README.md +37 -0
- package/dist/array/index.d.ts +3 -0
- package/dist/array/index.js +51 -0
- package/dist/array/types.d.ts +39 -0
- package/dist/array/use-array-source.d.ts +39 -0
- package/dist/array/use-array-source.test.d.ts +1 -0
- package/dist/{flex-table-DuQWDNlT.js → flex-table-BH1lOINr.js} +244 -293
- package/dist/flex-table.js +1 -1
- package/dist/odata/index.js +2 -83
- package/dist/react.js +1 -1
- package/dist/sorting-CjfjRxwL.js +51 -0
- package/dist/use-odata-source-5gOJiMFj.js +83 -0
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.31.1] - 2026-09-01
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **`0.31.0`'s release pipeline never actually published to npm** — the repo's
|
|
8
|
+
`preversion` guard script assumed a monorepo layout this repo doesn't have,
|
|
9
|
+
so the workflow's own version-sync step failed before publishing. No package
|
|
10
|
+
code changed; this release exists to get `0.31.0`'s content onto the
|
|
11
|
+
registry with a working pipeline.
|
|
12
|
+
|
|
13
|
+
## [0.31.0] - 2026-08-31
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`useArraySource`, a client-array sibling to `useODataSource`.** `useODataSource`
|
|
18
|
+
is server-mode only, so a lookup table needing a client-side join (a display
|
|
19
|
+
field living on a different endpoint than the row) had no library-level path
|
|
20
|
+
and required reimplementing filter/sort/pagination by hand. `useArraySource`
|
|
21
|
+
returns the exact same shape (`data`/`totalCount`/`loading`/`error`/`page`/
|
|
22
|
+
`setPage`/`sortCriteria`/`onSortChange`/`search`/`setSearch`/`refresh`) driven
|
|
23
|
+
off a local array instead of a fetch, so the same `<FlexTableReact
|
|
24
|
+
dataMode="server" ...>` binding code works with either source. Sorting reuses
|
|
25
|
+
the grid's own `computeSortedIndices` for value-aware (not string) comparison.
|
|
26
|
+
New `./array` subpath export, mirroring `./odata`'s shape.
|
|
27
|
+
|
|
3
28
|
## [0.30.0] - 2026-08-28
|
|
4
29
|
|
|
5
30
|
### Added
|
package/README.md
CHANGED
|
@@ -616,6 +616,43 @@ buildSearchExpression(''); // undefined
|
|
|
616
616
|
parseOrderBy('name desc'); // [{ key: 'name', direction: 'desc' }]
|
|
617
617
|
```
|
|
618
618
|
|
|
619
|
+
### Array Source Hook (React)
|
|
620
|
+
|
|
621
|
+
`useArraySource(data, options)` runs search/sort/pagination over an in-memory array and
|
|
622
|
+
returns the **same shape** as `useODataSource` — `data`/`totalCount`/`loading`/`error`/
|
|
623
|
+
`page`/`setPage`/`sortCriteria`/`onSortChange`/`search`/`setSearch`/`refresh` — so the
|
|
624
|
+
same `<FlexTableReact dataMode="server" ...>` binding code works with either source.
|
|
625
|
+
|
|
626
|
+
Reach for this when the rows come from a client-side join a server query can't express —
|
|
627
|
+
e.g. a lookup table whose display name lives on a different endpoint than the row itself,
|
|
628
|
+
so search/sort has to run after the join, in memory:
|
|
629
|
+
|
|
630
|
+
```tsx
|
|
631
|
+
import { useArraySource } from '@iyulab/flex-table/array';
|
|
632
|
+
|
|
633
|
+
const joined = useMemo(
|
|
634
|
+
() => seasonPrices.map(p => ({ ...p, productName: productsById[p.productId]?.name ?? '' })),
|
|
635
|
+
[seasonPrices, productsById]
|
|
636
|
+
);
|
|
637
|
+
|
|
638
|
+
const source = useArraySource(joined, {
|
|
639
|
+
pageSize: 20,
|
|
640
|
+
columns, // pass the same ColumnDefinition[] used by <FlexTableReact> for value-aware sort
|
|
641
|
+
});
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
| Option | Default | Description |
|
|
645
|
+
|---|---|---|
|
|
646
|
+
| `pageSize` | `20` | Rows per page |
|
|
647
|
+
| `defaultOrderBy` | — | Initial sort (e.g. `'name asc'`), same syntax as `useODataSource` |
|
|
648
|
+
| `columns` | — | `ColumnDefinition[]` — enables value-aware sort (numbers/dates/booleans compared by value, not as text). Omit and every column sorts as text. |
|
|
649
|
+
| `searchFields` | all values | `(row) => value[]` — narrows or widens what free-text search matches; the default searches every property on the row, including client-joined ones |
|
|
650
|
+
|
|
651
|
+
The returned fields mean the same thing as `useODataSource`'s, except `totalCount` is the
|
|
652
|
+
count after search (not a server-reported total), and `loading`/`error` are always
|
|
653
|
+
`false`/`null` — there's no request to fail. `refresh` is a no-op kept only so a
|
|
654
|
+
"refresh" button wired unconditionally against either hook doesn't need a branch.
|
|
655
|
+
|
|
619
656
|
## Development
|
|
620
657
|
|
|
621
658
|
```bash
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { t as e } from "../sorting-CjfjRxwL.js";
|
|
2
|
+
import { n as t } from "../use-odata-source-5gOJiMFj.js";
|
|
3
|
+
import { useCallback as n, useMemo as r, useState as i } from "react";
|
|
4
|
+
//#region src/array/use-array-source.ts
|
|
5
|
+
function a(t, { search: n, sortCriteria: r, page: i, pageSize: a, columns: o, searchFields: s }) {
|
|
6
|
+
let c = n.trim().toLowerCase(), l = c ? t.filter((e) => (s ? s(e) : Object.values(e)).some((e) => e != null && String(e).toLowerCase().includes(c))) : t, u = l;
|
|
7
|
+
r.length > 0 && (u = e(l, r, o ?? []).map((e) => l[e]));
|
|
8
|
+
let d = u.length, f = i * a;
|
|
9
|
+
return {
|
|
10
|
+
data: u.slice(f, f + a),
|
|
11
|
+
totalCount: d
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function o(e, o = {}) {
|
|
15
|
+
let { pageSize: s = 20, defaultOrderBy: c, columns: l, searchFields: u } = o, [d, f] = i(0), [p, m] = i(() => c ? t(c) : []), [h, g] = i(""), _ = n((e) => {
|
|
16
|
+
g(e), f(0);
|
|
17
|
+
}, []), v = n((e) => {
|
|
18
|
+
let t = e.detail?.criteria;
|
|
19
|
+
t && (m(t), f(0));
|
|
20
|
+
}, []), y = n(() => {}, []), { data: b, totalCount: x } = r(() => a(e, {
|
|
21
|
+
search: h,
|
|
22
|
+
sortCriteria: p,
|
|
23
|
+
page: d,
|
|
24
|
+
pageSize: s,
|
|
25
|
+
columns: l,
|
|
26
|
+
searchFields: u
|
|
27
|
+
}), [
|
|
28
|
+
e,
|
|
29
|
+
h,
|
|
30
|
+
p,
|
|
31
|
+
d,
|
|
32
|
+
s,
|
|
33
|
+
l,
|
|
34
|
+
u
|
|
35
|
+
]);
|
|
36
|
+
return {
|
|
37
|
+
data: b,
|
|
38
|
+
totalCount: x,
|
|
39
|
+
loading: !1,
|
|
40
|
+
error: null,
|
|
41
|
+
page: d,
|
|
42
|
+
setPage: f,
|
|
43
|
+
sortCriteria: p,
|
|
44
|
+
onSortChange: v,
|
|
45
|
+
search: h,
|
|
46
|
+
setSearch: _,
|
|
47
|
+
refresh: y
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { a as computeArrayView, o as useArraySource };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SortCriteria } from '../core/sorting.js';
|
|
2
|
+
export interface UseArraySourceOptions<T> {
|
|
3
|
+
/** 페이지당 행 수. `useODataSource`와 동일 기본값. */
|
|
4
|
+
pageSize?: number;
|
|
5
|
+
/** 초기 정렬(`'a asc, b desc'` 형식, `useODataSource`와 동일 문법). */
|
|
6
|
+
defaultOrderBy?: string;
|
|
7
|
+
/**
|
|
8
|
+
* 타입 인지 정렬 비교(숫자/불리언/날짜/텍스트)에 쓸 컬럼 정의. 생략하면 전부
|
|
9
|
+
* 텍스트로 비교한다(숫자 컬럼도 문자열 정렬 순서를 따름) — 그리드에 이미 넘기는
|
|
10
|
+
* `columns`를 그대로 전달하면 된다.
|
|
11
|
+
*/
|
|
12
|
+
columns?: import('../models/types.js').ColumnDefinition<T>[];
|
|
13
|
+
/**
|
|
14
|
+
* 자유 텍스트 검색이 대조할 값들을 행에서 뽑아낸다. 생략하면 행의 모든 값
|
|
15
|
+
* (`Object.values`)을 대상으로 한다 — 서버 read 모델에 없는 클라이언트 조인
|
|
16
|
+
* 파생 필드(예: 조인해 붙인 상품명)도 이 행 객체에 실제로 들어있는 한 기본
|
|
17
|
+
* 동작만으로 검색된다. 명시적으로 검색 범위를 좁히거나 넓히고 싶을 때만 지정.
|
|
18
|
+
*/
|
|
19
|
+
searchFields?: (row: T) => Array<string | number | boolean | null | undefined>;
|
|
20
|
+
}
|
|
21
|
+
export interface UseArraySourceResult<T> {
|
|
22
|
+
/** 현재 페이지의 행(검색+정렬 적용 후 slice). */
|
|
23
|
+
data: T[];
|
|
24
|
+
/** 검색+정렬 적용 후, 페이지 나누기 전의 총 건수(`useODataSource`의 `@odata.count`와 동일 의미). */
|
|
25
|
+
totalCount: number;
|
|
26
|
+
/** 항상 `false` — 로컬 배열은 동기 처리라 로딩 상태가 없다. `useODataSource`와의 반환 형태 동일성을 위해 유지. */
|
|
27
|
+
loading: boolean;
|
|
28
|
+
/** 항상 `null` — 로컬 배열 처리는 실패하지 않는다. 위와 같은 이유로 유지. */
|
|
29
|
+
error: string | null;
|
|
30
|
+
page: number;
|
|
31
|
+
setPage: (page: number) => void;
|
|
32
|
+
sortCriteria: SortCriteria[];
|
|
33
|
+
onSortChange: (e: CustomEvent) => void;
|
|
34
|
+
setSearch: (term: string) => void;
|
|
35
|
+
search: string;
|
|
36
|
+
/** no-op — 로컬 배열에는 다시 불러올 원격 상태가 없다. 소비자가 `useODataSource`와
|
|
37
|
+
* 같은 자리에 무조건 배선한 refresh 버튼이 있어도 안전하게 아무 일도 하지 않는다. */
|
|
38
|
+
refresh: () => void;
|
|
39
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SortCriteria } from '../core/sorting.js';
|
|
2
|
+
import type { ColumnDefinition, DataRow } from '../models/types.js';
|
|
3
|
+
import type { UseArraySourceOptions, UseArraySourceResult } from './types.js';
|
|
4
|
+
export interface ComputeArrayViewOptions<T> {
|
|
5
|
+
search: string;
|
|
6
|
+
sortCriteria: SortCriteria[];
|
|
7
|
+
page: number;
|
|
8
|
+
pageSize: number;
|
|
9
|
+
columns?: ColumnDefinition<T>[];
|
|
10
|
+
searchFields?: (row: T) => Array<string | number | boolean | null | undefined>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* `useArraySource`의 검색→정렬→페이지 파이프라인을 React 없이 순수하게 계산한다
|
|
14
|
+
* (훅은 이 함수를 `useMemo`로 감싸기만 한다) — React 훅 렌더 인프라 없이 이 패키지의
|
|
15
|
+
* 다른 순수 헬퍼(`buildSearchExpression`/`parseOrderBy`)와 같은 방식으로 단위
|
|
16
|
+
* 테스트하기 위해 분리했다.
|
|
17
|
+
*
|
|
18
|
+
* 정렬은 그리드 자신의 클라이언트 정렬 파이프라인이 쓰는 `computeSortedIndices`를
|
|
19
|
+
* 그대로 재사용한다 — `columns`를 넘기면 숫자/날짜/불리언도 값 기준으로 비교되고,
|
|
20
|
+
* 생략하면 전부 텍스트 비교로 낮아진다.
|
|
21
|
+
*/
|
|
22
|
+
export declare function computeArrayView<T extends DataRow>(data: T[], { search, sortCriteria, page, pageSize, columns, searchFields }: ComputeArrayViewOptions<T>): {
|
|
23
|
+
data: T[];
|
|
24
|
+
totalCount: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* 클라이언트 배열(이미 메모리에 있는 데이터, 흔히 여러 출처를 조인해 만든 파생
|
|
28
|
+
* 행 배열) 전용 React 훅. `useODataSource`와 **같은 반환 형태**(`data`/`totalCount`/
|
|
29
|
+
* `loading`/`error`/`page`/`setPage`/`sortCriteria`/`onSortChange`/`search`/
|
|
30
|
+
* `setSearch`/`refresh`)를 제공해, `dataMode="server"` + `<FlexTableReact>` 배선
|
|
31
|
+
* 코드를 서버·클라이언트 소스 사이에서 그대로 재사용할 수 있게 한다.
|
|
32
|
+
*
|
|
33
|
+
* `useODataSource`가 서버에 `$search`/`$orderby`/`$top`/`$skip`을 보내 처리를
|
|
34
|
+
* 위임하는 것과 달리, 이 훅은 검색·정렬·페이지 나누기를 전부 로컬에서 계산한다
|
|
35
|
+
* (`computeArrayView`) — 서버 read 모델에 없는 클라이언트 조인 파생 필드(예: 별도
|
|
36
|
+
* 엔드포인트에서 가져와 붙인 상품명)로 검색/정렬해야 해서 서버 쿼리로 표현할 수
|
|
37
|
+
* 없는 lookup 테이블에 쓴다.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useArraySource<T extends DataRow = DataRow>(data: T[], options?: UseArraySourceOptions<T>): UseArraySourceResult<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|