@iyulab/flex-table 0.38.2 โ†’ 0.40.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,56 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.40.0] - 2026-09-28
4
+
5
+ ### Changed
6
+
7
+ - ๐Ÿ”ด **Breaking โ€” the React hooks moved to `./react`.** `useODataSource` and `useArraySource` (and
8
+ their option/result types) are now exported from `@iyulab/flex-table/react`, next to
9
+ `FlexTableReact`. `./odata` and `./array` keep only the pure functions โ€” `buildSearchExpression`,
10
+ `parseOrderBy`, `computeArrayView`, and the new `buildODataQuery` โ€” and no longer load React, so an
11
+ app without React (a typeahead that is not a table, a Lit app) can use them without installing it.
12
+ Before, importing `buildSearchExpression` from `./odata` required `react` statically.
13
+ Migration: `import { useODataSource } from '@iyulab/flex-table/odata'` โ†’
14
+ `import { useODataSource } from '@iyulab/flex-table/react'` (same for `useArraySource` from
15
+ `./array`).
16
+
17
+ - ๐Ÿ”ด **Breaking โ€” column definitions use the same words as `u-rich-table`.** `header` โ†’ `label` and
18
+ `renderer` โ†’ `render`, so one column list reads the same in either table (`header-context-menu`'s detail likewise carries
19
+ `label` instead of `header`). Migration: rename the two keys
20
+ in your `ColumnDefinition` objects; the types reject the old names.
21
+ - **Headers follow their values.** A header's default alignment is now the column's cell alignment,
22
+ so a `number` column's header is right-aligned over its right-aligned values instead of sitting
23
+ at the left edge (on a wide column it read as the neighbour's header). Set `headerAlign` to keep
24
+ a different header alignment. Cell alignment uses logical values (`text-align: end`), so
25
+ right-to-left locales mirror.
26
+
27
+ - **The column menu, the cell context menu and the drag ghost read the shared stacking tokens.**
28
+ The menus sit on `--u-layer-floating` (1000 โ€” they were at 200, below every other floating
29
+ surface) and the drag ghost on `--u-layer-overlay` (9999, as before), so they stack the same way
30
+ as popovers and dialogs from `@iyulab/components`.
31
+
32
+ ### Added
33
+
34
+ - **`align` on `ColumnDefinition`** (`'start' | 'center' | 'end'`) โ€” cell alignment. Default comes
35
+ from `type` as before (`number` โ†’ end, `boolean` โ†’ center, otherwise start); set it for a code or
36
+ Y/N column that is text but should center. `effectiveAlign(col)` returns what a column renders with.
37
+ - **`buildODataQuery(state)` on `./odata`** โ€” the step `useODataSource` runs on every request (page,
38
+ page size, sort, search, fixed filter โ†’ OData query string), now callable without React. A Lit
39
+ table or a non-table list doing server paging can send exactly the query the hook would, instead
40
+ of re-deriving `$top`/`$skip`/`$orderby`/`$search`. The hook now calls it.
41
+
42
+ ## [0.39.0] - 2026-09-27
43
+
44
+ ### Added
45
+
46
+ - **`enabled` option on `useODataSource`** (default `true`). While `false` the hook makes no
47
+ request and reports `loading: true`; the first request goes out when it turns `true`, with that
48
+ render's conditions. For lists whose query depends on a value that arrives asynchronously (a
49
+ server-decided default filter, the current user, a selected parent): without it the first render
50
+ sent a wasted request with the wrong conditions โ€” often the heaviest one, unfiltered โ€” before the
51
+ real one. Turning it `false` mid-request cancels the request; `refresh()` does nothing while
52
+ disabled.
53
+
3
54
  ## [0.38.2] - 2026-09-24
4
55
 
5
56
  ### Fixed
package/README.md CHANGED
@@ -28,9 +28,9 @@ npm install @iyulab/flex-table
28
28
  const table = document.getElementById('table');
29
29
 
30
30
  table.columns = [
31
- { key: 'name', header: 'Name', type: 'text', width: 200 },
32
- { key: 'age', header: 'Age', type: 'number', width: 100 },
33
- { key: 'active', header: 'Active', type: 'boolean', width: 80 },
31
+ { key: 'name', label: 'Name', type: 'text', width: 200 },
32
+ { key: 'age', label: 'Age', type: 'number', width: 100 },
33
+ { key: 'active', label: 'Active', type: 'boolean', width: 80 },
34
34
  ];
35
35
 
36
36
  table.data = [
@@ -113,7 +113,7 @@ guarantee about a *constrained* host. `height-model.browser.test.ts` pins both s
113
113
  | `footerData` | `footer-data` | `Record<string, string>` | `null` | Footer/summary row data (keys match column keys) |
114
114
  | `emptyMessage` | `empty-message` | `string` | `'No data'` | Shown when `data` is empty |
115
115
  | `noMatchingMessage` | `no-matching-message` | `string` | `'No matching data'` | Shown when `data` has rows but every one is hidden by an active column filter |
116
- | `stylesheets` | โ€” | `CSSStyleSheet[]` | `[]` | Constructable stylesheets adopted into the shadow root alongside the grid's own styles โ€” the escape hatch for styling content a `renderer` inserts, since document CSS doesn't cross the shadow boundary. Reassigning swaps the previous set, it doesn't accumulate |
116
+ | `stylesheets` | โ€” | `CSSStyleSheet[]` | `[]` | Constructable stylesheets adopted into the shadow root alongside the grid's own styles โ€” the escape hatch for styling content a `render` function inserts, since document CSS doesn't cross the shadow boundary. Reassigning swaps the previous set, it doesn't accumulate |
117
117
 
118
118
  ### Read-only Properties
119
119
 
@@ -133,19 +133,20 @@ guarantee about a *constrained* host. `height-model.browser.test.ts` pins both s
133
133
  ```typescript
134
134
  interface ColumnDefinition {
135
135
  key: string; // Unique key matching data property names
136
- header: string; // Display header text
136
+ label: string; // Column header text
137
137
  type?: ColumnType; // 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' (any other string falls back to 'text')
138
138
  width?: number; // Column width in pixels (default: auto)
139
139
  minWidth?: number; // Minimum width in pixels (default: 40, enforced in rendering)
140
140
  hidden?: boolean; // Hide column from view
141
141
  sortable?: boolean; // Enable sorting (default: true)
142
- headerAlign?: 'start' | 'center' | 'end'; // Header label alignment (default: 'start'), independent of cell content alignment
142
+ align?: 'start' | 'center' | 'end'; // Cell alignment (default from type: number โ†’ end, boolean โ†’ center, else start)
143
+ headerAlign?: 'start' | 'center' | 'end'; // Header alignment (default: the cell alignment above)
143
144
  editable?: boolean; // Per-column edit control (follows global editable)
144
145
  pinned?: 'left' | 'right'; // Freeze column during horizontal scroll
145
146
  options?: string[] | SelectOption[]; // Allowed values for type: 'select' (SelectOption = { label, value })
146
147
  autocomplete?: boolean | 'strict'; // Suggest existing column values while editing; 'strict' rejects values not in the list
147
- format?: string | ((value, row, col) => string); // Display format, see "format vs renderer" below
148
- renderer?: CellRenderer; // Custom cell render: (value, row, col) => TemplateResult | string
148
+ format?: string | ((value, row, col) => string); // Display format, see "format vs render" below
149
+ render?: CellRenderer; // Custom cell render: (value, row, col) => TemplateResult | string
149
150
  editor?: CellEditor; // Custom cell editor: (value, row, col) => TemplateResult
150
151
  validator?: CellValidator; // Validate before commit: (value, row, col) => string | null
151
152
  conditionalRules?: ConditionalRule[]; // Per-cell style rules, see below
@@ -156,32 +157,32 @@ The `editor` callback must return a Lit `TemplateResult` containing an input ele
156
157
 
157
158
  The `validator` callback returns `null` if valid, or an error message string. On failure, the cell shows a red border for 3 seconds and a `validation-error` event is dispatched.
158
159
 
159
- ### `format` vs `renderer`
160
+ ### `format` vs `render`
160
161
 
161
162
  Both control how a cell's raw value is displayed, but they differ in what they replace:
162
163
 
163
164
  - **`format`**: a plain string pattern (Excel-style, e.g. `'#,##0.00'`, `'0.00%'`, `'$#,##0'`, `'yyyy-MM-dd'`) or a `(value) => string` function. Only the *displayed text* changes โ€” editing, sorting, filtering, and export all keep operating on the raw underlying value. Use this for number/date/currency display formatting.
164
- - **`renderer`**: a `(value, row, col) => TemplateResult | string` function that replaces the cell's rendered content entirely โ€” badges, links, icons, multi-field composites. Sorting/filtering still use the raw value, but the visual output is fully custom.
165
+ - **`render`**: a `(value, row, col) => TemplateResult | string` function that replaces the cell's rendered content entirely โ€” badges, links, icons, multi-field composites. Sorting/filtering still use the raw value, but the visual output is fully custom.
165
166
 
166
167
  ```typescript
167
168
  const columns: ColumnDefinition<Order>[] = [
168
- { key: 'total', header: 'Total', format: '#,##0.00' }, // "1,234.50"
169
- { key: 'placedAt', header: 'Placed', format: 'yyyy-MM-dd' }, // date pattern
170
- { key: 'status', header: 'Status', renderer: (v) => html`<span class="badge badge-${v}">${v}</span>` },
169
+ { key: 'total', label: 'Total', format: '#,##0.00' }, // "1,234.50"
170
+ { key: 'placedAt', label: 'Placed', format: 'yyyy-MM-dd' }, // date pattern
171
+ { key: 'status', label: 'Status', render: (v) => html`<span class="badge badge-${v}">${v}</span>` },
171
172
  ];
172
173
  ```
173
174
 
174
- If both are set on the same column, `renderer` takes precedence โ€” `format` has no effect once a custom `renderer` fully controls the cell's output.
175
+ If both are set on the same column, `render` takes precedence โ€” `format` has no effect once a custom `render` fully controls the cell's output.
175
176
 
176
177
  ### Conditional Formatting
177
178
 
178
- `conditionalRules` applies a style to a cell when its `when` predicate matches โ€” a declarative alternative to writing a `renderer` just to color-code status/threshold values:
179
+ `conditionalRules` applies a style to a cell when its `when` predicate matches โ€” a declarative alternative to writing a `render` function just to color-code status/threshold values:
179
180
 
180
181
  ```typescript
181
182
  const columns: ColumnDefinition<Order>[] = [
182
183
  {
183
184
  key: 'status',
184
- header: 'Status',
185
+ label: 'Status',
185
186
  conditionalRules: [
186
187
  { when: (v) => v === 'overdue', style: { color: '#dc2626', fontWeight: 'bold' } },
187
188
  { when: (v) => v === 'paid', style: { color: '#16a34a' } },
@@ -489,8 +490,8 @@ import { FlexTableReact } from '@iyulab/flex-table/react';
489
490
 
490
491
  function App() {
491
492
  const columns = [
492
- { key: 'name', header: 'Name', type: 'text' },
493
- { key: 'age', header: 'Age', type: 'number' },
493
+ { key: 'name', label: 'Name', type: 'text' },
494
+ { key: 'age', label: 'Age', type: 'number' },
494
495
  ];
495
496
 
496
497
  const data = [
@@ -547,8 +548,8 @@ interface Order {
547
548
  }
548
549
 
549
550
  const columns: ColumnDefinition<Order>[] = [
550
- { key: 'id', header: 'ID' },
551
- { key: 'total', header: 'Total', renderer: (_value, row) => `${row.total} ${row.currency}` },
551
+ { key: 'id', label: 'ID' },
552
+ { key: 'total', label: 'Total', render: (_value, row) => `${row.total} ${row.currency}` },
552
553
  ];
553
554
 
554
555
  <FlexTableReact<Order> data={orders} columns={columns} />
@@ -566,7 +567,7 @@ import { html } from 'lit';
566
567
  table.columns = [
567
568
  {
568
569
  key: 'color',
569
- header: 'Color',
570
+ label: 'Color',
570
571
  type: 'text',
571
572
  editor: (value) => html`
572
573
  <input class="ft-editor" type="color" .value=${String(value ?? '#000000')}
@@ -593,7 +594,7 @@ Use the `validator` callback to validate input before committing. Returns `null`
593
594
  table.columns = [
594
595
  {
595
596
  key: 'age',
596
- header: 'Age',
597
+ label: 'Age',
597
598
  type: 'number',
598
599
  validator: (value) => {
599
600
  const n = Number(value);
@@ -612,10 +613,10 @@ Freeze columns on either side during horizontal scroll:
612
613
 
613
614
  ```typescript
614
615
  table.columns = [
615
- { key: 'id', header: 'ID', pinned: 'left' },
616
- { key: 'name', header: 'Name' },
616
+ { key: 'id', label: 'ID', pinned: 'left' },
617
+ { key: 'name', label: 'Name' },
617
618
  // ... many columns ...
618
- { key: 'actions', header: 'Actions', pinned: 'right' },
619
+ { key: 'actions', label: 'Actions', pinned: 'right' },
619
620
  ];
620
621
  ```
621
622
 
@@ -668,7 +669,7 @@ table.addEventListener('sort-change', (e) => {
668
669
  `useODataSource(url, options)` fetches paginated/sorted/filtered data from an OData v4 endpoint and returns props ready to bind to `<FlexTableReact dataMode="server" ...>`.
669
670
 
670
671
  ```tsx
671
- import { useODataSource } from '@iyulab/flex-table/odata';
672
+ import { useODataSource } from '@iyulab/flex-table/react';
672
673
 
673
674
  const source = useODataSource('/api/orders', {
674
675
  pageSize: 20,
@@ -688,6 +689,7 @@ const source = useODataSource('/api/orders', {
688
689
  | `baseUrl` | `window.location.origin` | Override the request origin (proxy/BFF setups) |
689
690
  | `fetcher` | global `fetch` | Custom transport โ€” pass a wrapper that injects auth headers |
690
691
  | `onUnauthorized` | โ€” | Called on `401`/`403` responses, before the generic error is set |
692
+ | `enabled` | `true` | While `false`, no request is made and `loading` stays `true` โ€” see below |
691
693
 
692
694
  `fetcher`/`onUnauthorized` should be stable references (e.g. wrap in `useCallback`) โ€” they are intentionally excluded from the hook's internal effect dependencies to avoid refetch loops on every render.
693
695
 
@@ -704,6 +706,22 @@ rows, a `refresh` landing after a change), and holding the old `$skip` would lea
704
706
  table next to a non-zero total. Reaching that state costs one extra request, only in that
705
707
  case; the page only ever moves down, so it cannot loop.
706
708
 
709
+ Set `enabled: false` while the query depends on a value that has not arrived yet โ€” a default
710
+ filter the server decides, the current user, a selected parent record. Without it, the first
711
+ render requests with the wrong conditions (often the heaviest query: no filter) and then again
712
+ once the value arrives. The first request goes out the moment `enabled` turns `true`, with the
713
+ conditions of that render; until then `loading` is `true`, so the table shows loading rather
714
+ than "no data". Turning it `false` mid-request cancels that request, and `refresh()` does nothing
715
+ while disabled.
716
+
717
+ ```tsx
718
+ const season = useDefaultSeason(); // resolves asynchronously
719
+ const source = useODataSource('/api/orders', {
720
+ fixedFilter: season ? { Season: season } : undefined,
721
+ enabled: season !== undefined,
722
+ });
723
+ ```
724
+
707
725
  The three `initial*` options are read **on the first render only** (the same contract
708
726
  `defaultOrderBy` has always had); use `setPage`/`setSearch` to move afterwards. Reach for
709
727
  them when a list has to come back the way the user left it โ€” going to a detail screen and
@@ -743,7 +761,7 @@ The hook returns:
743
761
 
744
762
  Terms are always quoted because OData 4.0 only allows letters in an unquoted `searchWord`, so `2026` or `ZT-E2E-A` would be rejected by servers that follow it (4.01 relaxed this, but [Microsoft.OData still lexes as 4.0](https://github.com/OData/odata.net/issues/2445)). Quoting keeps any term valid regardless of server version. Since a `$search` phrase cannot contain `"` and OData defines no escape for it, double quotes are stripped from the term.
745
763
 
746
- The quoting/escaping logic above is also available standalone as `buildSearchExpression(term)`, for consumers that need the same `$search` encoding without the pagination hook (e.g. a typeahead/combobox that isn't a table). `parseOrderBy(orderBy)` (`'a asc, b desc'` โ†’ `SortCriteria[]`) is exported the same way, for consumers driving a sort UI that isn't `useODataSource` either:
764
+ The quoting/escaping logic above is also available standalone as `buildSearchExpression(term)`, for consumers that need the same `$search` encoding without the pagination hook (e.g. a typeahead/combobox that isn't a table). `parseOrderBy(orderBy)` (`'a asc, b desc'` โ†’ `SortCriteria[]`) is exported the same way, for consumers driving a sort UI that isn't `useODataSource` either. The `./odata` entry holds only pure functions and does not load React, so an app without React can use it (the hooks live on `./react`):
747
765
 
748
766
  ```ts
749
767
  import { buildSearchExpression, parseOrderBy } from '@iyulab/flex-table/odata';
@@ -753,6 +771,20 @@ buildSearchExpression(''); // undefined
753
771
  parseOrderBy('name desc'); // [{ key: 'name', direction: 'desc' }]
754
772
  ```
755
773
 
774
+ `buildODataQuery(state)` is the step the hook runs on every request โ€” table state in, OData query string out. Use it to drive server paging without React (a Lit table, a list that is not a table) with exactly the query the hook would send:
775
+
776
+ ```ts
777
+ import { buildODataQuery } from '@iyulab/flex-table/odata';
778
+
779
+ buildODataQuery({
780
+ page: 2, pageSize: 20, // 0-based page โ†’ $skip=40
781
+ sortCriteria: [{ key: 'name', direction: 'desc' }], // else defaultOrderBy
782
+ search: 'red shirt', // encoded by buildSearchExpression
783
+ fixedFilter: { IsActive: true }, // odata-query filter object
784
+ });
785
+ // '?$filter=IsActive eq true&$orderby=name desc&$count=true&$top=20&$skip=40&$search=%22red%22%20AND%20%22shirt%22'
786
+ ```
787
+
756
788
  ### Array Source Hook (React)
757
789
 
758
790
  `useArraySource(data, options)` runs search/sort/pagination over an in-memory array and
@@ -771,7 +803,7 @@ e.g. a lookup table whose display name lives on a different endpoint than the ro
771
803
  so search/sort has to run after the join, in memory:
772
804
 
773
805
  ```tsx
774
- import { useArraySource } from '@iyulab/flex-table/array';
806
+ import { useArraySource } from '@iyulab/flex-table/react';
775
807
 
776
808
  const joined = useMemo(
777
809
  () => seasonPrices.map(p => ({ ...p, productName: productsById[p.productId]?.name ?? '' })),
@@ -1,3 +1,2 @@
1
- export { useArraySource, computeArrayView } from './use-array-source.js';
2
- export type { UseArraySourceOptions, UseArraySourceResult } from './types.js';
3
- export type { ComputeArrayViewOptions } from './use-array-source.js';
1
+ export { computeArrayView } from './view.js';
2
+ export type { ComputeArrayViewOptions } from './view.js';
@@ -1,56 +1,2 @@
1
- import { t as e } from "../sorting-CjfjRxwL.js";
2
- import { r as t } from "../use-odata-source-l9dVCi9l.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 = d === 0 ? 0 : Math.ceil(d / a) - 1, p = Math.min(Math.max(i, 0), f) * a;
9
- return {
10
- data: u.slice(p, p + a),
11
- totalCount: d
12
- };
13
- }
14
- function o(e, o = {}) {
15
- let { pageSize: s = 20, defaultOrderBy: c, initialPage: l = 0, initialSearch: u = "", initialSort: d, columns: f, searchFields: p } = o, m = t({
16
- defaultOrderBy: c,
17
- initialPage: l,
18
- initialSearch: u,
19
- initialSort: d
20
- }), [h, g] = i(m.page), [_, v] = i(m.sortCriteria), [y, b] = i(m.search), x = n((e) => {
21
- b(e), g(0);
22
- }, []), S = n((e) => {
23
- let t = e.detail?.criteria;
24
- t && (v(t), g(0));
25
- }, []), C = n(() => {}, []), { data: w, totalCount: T } = r(() => a(e, {
26
- search: y,
27
- sortCriteria: _,
28
- page: h,
29
- pageSize: s,
30
- columns: f,
31
- searchFields: p
32
- }), [
33
- e,
34
- y,
35
- _,
36
- h,
37
- s,
38
- f,
39
- p
40
- ]), E = T === 0 ? 0 : Math.ceil(T / s) - 1;
41
- return h > E && g(E), {
42
- data: w,
43
- totalCount: T,
44
- loading: !1,
45
- error: null,
46
- page: h,
47
- setPage: g,
48
- sortCriteria: _,
49
- onSortChange: S,
50
- search: y,
51
- setSearch: x,
52
- refresh: C
53
- };
54
- }
55
- //#endregion
56
- export { a as computeArrayView, o as useArraySource };
1
+ import { t as e } from "../view-DiLr-TdY.js";
2
+ export { e as computeArrayView };
@@ -1,28 +1,5 @@
1
- import type { SortCriteria } from '../core/sorting.js';
2
- import type { ColumnDefinition, DataRow } from '../models/types.js';
1
+ import type { DataRow } from '../models/types.js';
3
2
  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
3
  /**
27
4
  * ํด๋ผ์ด์–ธํŠธ ๋ฐฐ์—ด(์ด๋ฏธ ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ, ํ”ํžˆ ์—ฌ๋Ÿฌ ์ถœ์ฒ˜๋ฅผ ์กฐ์ธํ•ด ๋งŒ๋“  ํŒŒ์ƒ
28
5
  * ํ–‰ ๋ฐฐ์—ด) ์ „์šฉ React ํ›…. `useODataSource`์™€ **๊ฐ™์€ ๋ฐ˜ํ™˜ ํ˜•ํƒœ**(`data`/`totalCount`/
@@ -0,0 +1,24 @@
1
+ import type { SortCriteria } from '../core/sorting.js';
2
+ import type { ColumnDefinition, DataRow } from '../models/types.js';
3
+ export interface ComputeArrayViewOptions<T> {
4
+ search: string;
5
+ sortCriteria: SortCriteria[];
6
+ page: number;
7
+ pageSize: number;
8
+ columns?: ColumnDefinition<T>[];
9
+ searchFields?: (row: T) => Array<string | number | boolean | null | undefined>;
10
+ }
11
+ /**
12
+ * `useArraySource`์˜ ๊ฒ€์ƒ‰โ†’์ •๋ ฌโ†’ํŽ˜์ด์ง€ ํŒŒ์ดํ”„๋ผ์ธ์„ React ์—†์ด ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๊ณ„์‚ฐํ•œ๋‹ค
13
+ * (ํ›…์€ ์ด ํ•จ์ˆ˜๋ฅผ `useMemo`๋กœ ๊ฐ์‹ธ๊ธฐ๋งŒ ํ•œ๋‹ค) โ€” React ํ›… ๋ Œ๋” ์ธํ”„๋ผ ์—†์ด ์ด ํŒจํ‚ค์ง€์˜
14
+ * ๋‹ค๋ฅธ ์ˆœ์ˆ˜ ํ—ฌํผ(`buildSearchExpression`/`parseOrderBy`)์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋‹จ์œ„
15
+ * ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„๋ฆฌํ–ˆ๋‹ค.
16
+ *
17
+ * ์ •๋ ฌ์€ ๊ทธ๋ฆฌ๋“œ ์ž์‹ ์˜ ํด๋ผ์ด์–ธํŠธ ์ •๋ ฌ ํŒŒ์ดํ”„๋ผ์ธ์ด ์“ฐ๋Š” `computeSortedIndices`๋ฅผ
18
+ * ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉํ•œ๋‹ค โ€” `columns`๋ฅผ ๋„˜๊ธฐ๋ฉด ์ˆซ์ž/๋‚ ์งœ/๋ถˆ๋ฆฌ์–ธ๋„ ๊ฐ’ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ต๋˜๊ณ ,
19
+ * ์ƒ๋žตํ•˜๋ฉด ์ „๋ถ€ ํ…์ŠคํŠธ ๋น„๊ต๋กœ ๋‚ฎ์•„์ง„๋‹ค.
20
+ */
21
+ export declare function computeArrayView<T extends DataRow>(data: T[], { search, sortCriteria, page, pageSize, columns, searchFields }: ComputeArrayViewOptions<T>): {
22
+ data: T[];
23
+ totalCount: number;
24
+ };