@iyulab/flex-table 0.18.1 → 0.19.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/README.md +115 -0
- package/dist/{flex-table-BS_ADOUI.js → flex-table-BQc2PU5u.js} +5 -2
- package/dist/flex-table.d.ts +12 -0
- package/dist/flex-table.js +1 -1
- package/dist/models/types.d.ts +17 -11
- package/dist/odata/index.js +34 -32
- package/dist/odata/types.d.ts +6 -0
- package/dist/react.d.ts +32 -2
- package/dist/react.js +1 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,9 +105,11 @@ interface ColumnDefinition {
|
|
|
105
105
|
sortable?: boolean; // Enable sorting (default: true)
|
|
106
106
|
editable?: boolean; // Per-column edit control (follows global editable)
|
|
107
107
|
pinned?: 'left' | 'right'; // Freeze column during horizontal scroll
|
|
108
|
+
format?: string | ((value, row, col) => string); // Display format, see "format vs renderer" below
|
|
108
109
|
renderer?: CellRenderer; // Custom cell render: (value, row, col) => TemplateResult | string
|
|
109
110
|
editor?: CellEditor; // Custom cell editor: (value, row, col) => TemplateResult
|
|
110
111
|
validator?: CellValidator; // Validate before commit: (value, row, col) => string | null
|
|
112
|
+
conditionalRules?: ConditionalRule[]; // Per-cell style rules, see below
|
|
111
113
|
}
|
|
112
114
|
```
|
|
113
115
|
|
|
@@ -115,6 +117,42 @@ The `editor` callback must return a Lit `TemplateResult` containing an input ele
|
|
|
115
117
|
|
|
116
118
|
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.
|
|
117
119
|
|
|
120
|
+
### `format` vs `renderer`
|
|
121
|
+
|
|
122
|
+
Both control how a cell's raw value is displayed, but they differ in what they replace:
|
|
123
|
+
|
|
124
|
+
- **`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.
|
|
125
|
+
- **`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.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const columns: ColumnDefinition<Order>[] = [
|
|
129
|
+
{ key: 'total', header: 'Total', format: '#,##0.00' }, // "1,234.50"
|
|
130
|
+
{ key: 'placedAt', header: 'Placed', format: 'yyyy-MM-dd' }, // date pattern
|
|
131
|
+
{ key: 'status', header: 'Status', renderer: (v) => html`<span class="badge badge-${v}">${v}</span>` },
|
|
132
|
+
];
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
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.
|
|
136
|
+
|
|
137
|
+
### Conditional Formatting
|
|
138
|
+
|
|
139
|
+
`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:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const columns: ColumnDefinition<Order>[] = [
|
|
143
|
+
{
|
|
144
|
+
key: 'status',
|
|
145
|
+
header: 'Status',
|
|
146
|
+
conditionalRules: [
|
|
147
|
+
{ when: (v) => v === 'overdue', style: { color: '#dc2626', fontWeight: 'bold' } },
|
|
148
|
+
{ when: (v) => v === 'paid', style: { color: '#16a34a' } },
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Rules are evaluated in order and combined; later matching rules override earlier ones for overlapping style properties.
|
|
155
|
+
|
|
118
156
|
## Methods
|
|
119
157
|
|
|
120
158
|
### Row Operations
|
|
@@ -144,6 +182,14 @@ The `validator` callback returns `null` if valid, or an error message string. On
|
|
|
144
182
|
| `deselectAll()` | `void` | Deselect all rows |
|
|
145
183
|
| `getSelectedRows()` | `{ selectedIndices, selectedRows }` | Get selected row data |
|
|
146
184
|
|
|
185
|
+
Row selection is index-based (there is no row-key concept), so replacing `data` with a same-length but different set of rows leaves the selection pointing at the new rows occupying the old indices. If selection drives a bulk action (status changes, bulk delete, etc.), set `clear-selection-on-data-change` so a `data` swap always resets selection and re-fires `selection-change` with an empty selection:
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<flex-table selectable clear-selection-on-data-change></flex-table>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Default is `false`, matching `clear-undo-on-data-change`.
|
|
192
|
+
|
|
147
193
|
### Filtering
|
|
148
194
|
|
|
149
195
|
| Method | Returns | Description |
|
|
@@ -304,6 +350,50 @@ function App() {
|
|
|
304
350
|
|
|
305
351
|
All `<flex-table>` properties are available as React props, and all custom events are mapped to `on*` callbacks (e.g., `cell-edit-commit` → `onCellEditCommit`).
|
|
306
352
|
|
|
353
|
+
#### Imperative API via `ref`
|
|
354
|
+
|
|
355
|
+
`FlexTableReact` forwards `ref` to the underlying `FlexTable` custom element instance, so all [Methods](#methods) (`addRow`, `deleteRows`, `selectAll`, `setFilter`, etc.) are reachable without re-rendering the whole table:
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
import { useRef } from 'react';
|
|
359
|
+
import { FlexTableReact, type FlexTable } from '@iyulab/flex-table/react';
|
|
360
|
+
|
|
361
|
+
function App() {
|
|
362
|
+
const tableRef = useRef<FlexTable>(null);
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<>
|
|
366
|
+
<button onClick={() => tableRef.current?.addRow({ name: '', age: 0 })}>Add row</button>
|
|
367
|
+
<button onClick={() => tableRef.current?.deleteRows()}>Delete selected</button>
|
|
368
|
+
<FlexTableReact ref={tableRef} columns={columns} data={data} selectable />
|
|
369
|
+
</>
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### Typed rows (generics)
|
|
375
|
+
|
|
376
|
+
`FlexTableReact` and `ColumnDefinition` are generic over your row type — no `as unknown as` casts needed in `data`, `columns`, or callbacks:
|
|
377
|
+
|
|
378
|
+
```tsx
|
|
379
|
+
import { FlexTableReact, type ColumnDefinition } from '@iyulab/flex-table/react';
|
|
380
|
+
|
|
381
|
+
interface Order {
|
|
382
|
+
id: string;
|
|
383
|
+
total: number;
|
|
384
|
+
currency: string;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const columns: ColumnDefinition<Order>[] = [
|
|
388
|
+
{ key: 'id', header: 'ID' },
|
|
389
|
+
{ key: 'total', header: 'Total', renderer: (_value, row) => `${row.total} ${row.currency}` },
|
|
390
|
+
];
|
|
391
|
+
|
|
392
|
+
<FlexTableReact<Order> data={orders} columns={columns} />
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Omitting the type argument defaults to the previous `DataRow` (`Record<string, unknown>`) behavior — fully backward compatible.
|
|
396
|
+
|
|
307
397
|
### Custom Editor
|
|
308
398
|
|
|
309
399
|
The `editor` callback lets you provide a fully custom editing UI. The component reads `.value` from the element with class `ft-editor` when committing.
|
|
@@ -409,6 +499,31 @@ table.addEventListener('sort-change', (e) => {
|
|
|
409
499
|
});
|
|
410
500
|
```
|
|
411
501
|
|
|
502
|
+
### OData Source Hook (React)
|
|
503
|
+
|
|
504
|
+
`useODataSource(url, options)` fetches paginated/sorted/filtered data from an OData v4 endpoint and returns props ready to bind to `<FlexTableReact dataMode="server" ...>`.
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
import { useODataSource } from '@iyulab/flex-table/odata';
|
|
508
|
+
|
|
509
|
+
const source = useODataSource('/api/orders', {
|
|
510
|
+
pageSize: 20,
|
|
511
|
+
fetcher: httpClient.fetch, // custom transport, e.g. an HttpClient instance
|
|
512
|
+
onUnauthorized: () => navigate('/login'),
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
| Option | Default | Description |
|
|
517
|
+
|---|---|---|
|
|
518
|
+
| `pageSize` | `20` | Rows per page |
|
|
519
|
+
| `defaultOrderBy` | — | Initial `$orderby` (e.g. `'name asc'`) |
|
|
520
|
+
| `fixedFilter` | — | Filter always applied in addition to search |
|
|
521
|
+
| `baseUrl` | `window.location.origin` | Override the request origin (proxy/BFF setups) |
|
|
522
|
+
| `fetcher` | global `fetch` | Custom transport — pass a wrapper that injects auth headers |
|
|
523
|
+
| `onUnauthorized` | — | Called on `401`/`403` responses, before the generic error is set |
|
|
524
|
+
|
|
525
|
+
`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.
|
|
526
|
+
|
|
412
527
|
## Development
|
|
413
528
|
|
|
414
529
|
```bash
|
|
@@ -1480,7 +1480,7 @@ var Y = {
|
|
|
1480
1480
|
lte: "≤"
|
|
1481
1481
|
}, X = 120, Z = 40, xe = 32, Q = 5, $ = class extends e {
|
|
1482
1482
|
constructor(...e) {
|
|
1483
|
-
super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.rowHeight = xe, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new y(), this._editing = new b(), this._rowSelection = new x(), this._undo = new D(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, 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._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._onCommentPopupOutsideClick = () => {
|
|
1483
|
+
super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this.rowHeight = xe, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._activeCell = null, this._editingCell = null, this._sortCriteria = [], this._selection = new y(), this._editing = new b(), this._rowSelection = new x(), this._undo = new D(), this._filters = [], this._filteredIndices = [], this._sortedIndices = [], this._openFilterKey = null, this._rowSelectionVersion = 0, 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._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._onCommentPopupOutsideClick = () => {
|
|
1484
1484
|
this._commitCommentPopup();
|
|
1485
1485
|
}, 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();
|
|
1486
1486
|
}
|
|
@@ -1492,7 +1492,7 @@ var Y = {
|
|
|
1492
1492
|
}
|
|
1493
1493
|
set data(e) {
|
|
1494
1494
|
let t = this._data;
|
|
1495
|
-
this._data = e, this.clearUndoOnDataChange && !this._inUndoRedo && this._undo.clear(), this.requestUpdate("data", t);
|
|
1495
|
+
this._data = e, this.clearUndoOnDataChange && !this._inUndoRedo && this._undo.clear(), this.clearSelectionOnDataChange && !this._inUndoRedo && this._rowSelection.selectedCount > 0 && (this._rowSelection.deselectAll(), this._rowSelectionVersion++, this._dispatchRowSelectionEvent()), this.requestUpdate("data", t);
|
|
1496
1496
|
}
|
|
1497
1497
|
set selectionMode(e) {
|
|
1498
1498
|
this._rowSelection.mode = e, this.requestUpdate();
|
|
@@ -3922,6 +3922,9 @@ J([a({ type: Array })], $.prototype, "columns", void 0), J([a({
|
|
|
3922
3922
|
type: Boolean,
|
|
3923
3923
|
attribute: "clear-undo-on-data-change"
|
|
3924
3924
|
})], $.prototype, "clearUndoOnDataChange", void 0), J([a({
|
|
3925
|
+
type: Boolean,
|
|
3926
|
+
attribute: "clear-selection-on-data-change"
|
|
3927
|
+
})], $.prototype, "clearSelectionOnDataChange", void 0), J([a({
|
|
3925
3928
|
type: Number,
|
|
3926
3929
|
attribute: "row-height"
|
|
3927
3930
|
})], $.prototype, "rowHeight", void 0), J([a({
|
package/dist/flex-table.d.ts
CHANGED
|
@@ -23,6 +23,18 @@ export declare class FlexTable extends LitElement {
|
|
|
23
23
|
* Default: false. Internal undo/redo operations are never affected.
|
|
24
24
|
*/
|
|
25
25
|
clearUndoOnDataChange: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* When true, replacing `data` externally automatically clears row selection
|
|
28
|
+
* (checkbox selection) and re-dispatches `selection-change` with an empty selection.
|
|
29
|
+
* Default: false, for consistency with `clearUndoOnDataChange`. Internal undo/redo
|
|
30
|
+
* operations are never affected.
|
|
31
|
+
*
|
|
32
|
+
* Row selection is index-based (no row-key concept), so a full `data` replacement can
|
|
33
|
+
* leave selection pointing at different underlying rows at the same indices —
|
|
34
|
+
* recommended for any `selectable` grid whose selection drives bulk actions
|
|
35
|
+
* (e.g. server-mode grids refreshed via `useODataSource`).
|
|
36
|
+
*/
|
|
37
|
+
clearSelectionOnDataChange: boolean;
|
|
26
38
|
rowHeight: number;
|
|
27
39
|
showRowNumbers: boolean;
|
|
28
40
|
theme: 'light' | 'dark' | undefined;
|
package/dist/flex-table.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as e, i as t, n, r, t as i } from "./flex-table-
|
|
1
|
+
import { a as e, i as t, n, r, t as i } from "./flex-table-BQc2PU5u.js";
|
|
2
2
|
export { i as FlexTable, t as RowSelectionState, r as UndoStack, n as exportData, e as renderCell };
|
package/dist/models/types.d.ts
CHANGED
|
@@ -14,17 +14,17 @@ export interface SelectOption {
|
|
|
14
14
|
* Receives the cell value, the full row data, and the column definition.
|
|
15
15
|
* Returns either a Lit TemplateResult or a plain string.
|
|
16
16
|
*/
|
|
17
|
-
export type CellRenderer = (value: unknown, row:
|
|
17
|
+
export type CellRenderer<T = DataRow> = (value: unknown, row: T, col: ColumnDefinition<T>) => TemplateResult | string;
|
|
18
18
|
/**
|
|
19
19
|
* Custom cell editor function.
|
|
20
20
|
* Receives the cell value, the full row data, and the column definition.
|
|
21
21
|
* Should return a Lit TemplateResult containing an input element with class "ft-editor".
|
|
22
22
|
*/
|
|
23
|
-
export type CellEditor = (value: unknown, row:
|
|
23
|
+
export type CellEditor<T = DataRow> = (value: unknown, row: T, col: ColumnDefinition<T>) => TemplateResult;
|
|
24
24
|
/**
|
|
25
25
|
* Cell validator function. Returns null/undefined if valid, or an error message string.
|
|
26
26
|
*/
|
|
27
|
-
export type CellValidator = (value: unknown, row:
|
|
27
|
+
export type CellValidator<T = DataRow> = (value: unknown, row: T, col: ColumnDefinition<T>) => string | null | undefined;
|
|
28
28
|
/**
|
|
29
29
|
* Row selection mode.
|
|
30
30
|
*/
|
|
@@ -37,8 +37,14 @@ export type SelectionMode = 'single' | 'multi';
|
|
|
37
37
|
export type DataMode = 'client' | 'server';
|
|
38
38
|
/**
|
|
39
39
|
* Definition of a single column in the table.
|
|
40
|
+
*
|
|
41
|
+
* `T` is the consumer's row type (defaults to the schema-agnostic `DataRow`).
|
|
42
|
+
* Internally, `FlexTable` (the registered custom element) always operates on
|
|
43
|
+
* `ColumnDefinition<DataRow>` — a custom element cannot itself be generic across
|
|
44
|
+
* instances, so `FlexTableReact<T>` performs a single internal cast at the
|
|
45
|
+
* React boundary instead of requiring consumers to cast at every callback.
|
|
40
46
|
*/
|
|
41
|
-
export interface ColumnDefinition {
|
|
47
|
+
export interface ColumnDefinition<T = DataRow> {
|
|
42
48
|
/** Unique key matching data property names */
|
|
43
49
|
key: string;
|
|
44
50
|
/** Display header text */
|
|
@@ -54,15 +60,15 @@ export interface ColumnDefinition {
|
|
|
54
60
|
/** Whether the column is sortable (default: true) */
|
|
55
61
|
sortable?: boolean;
|
|
56
62
|
/** Custom cell renderer — overrides built-in type rendering */
|
|
57
|
-
renderer?: CellRenderer
|
|
63
|
+
renderer?: CellRenderer<T>;
|
|
58
64
|
/** Whether the column is editable (default: true — follows global editable setting) */
|
|
59
65
|
editable?: boolean;
|
|
60
66
|
/** Custom cell editor — overrides built-in type editing */
|
|
61
|
-
editor?: CellEditor
|
|
67
|
+
editor?: CellEditor<T>;
|
|
62
68
|
/** Pin the column to one side during horizontal scroll */
|
|
63
69
|
pinned?: 'left' | 'right';
|
|
64
70
|
/** Cell validator — called before committing edits */
|
|
65
|
-
validator?: CellValidator
|
|
71
|
+
validator?: CellValidator<T>;
|
|
66
72
|
/** Allowed values for select columns (strings or label/value pairs) */
|
|
67
73
|
options?: string[] | SelectOption[];
|
|
68
74
|
/**
|
|
@@ -76,9 +82,9 @@ export interface ColumnDefinition {
|
|
|
76
82
|
* - String: number format pattern (e.g. '#,##0.00', '0.00%', '$#,##0') or date pattern (e.g. 'yyyy-MM-dd')
|
|
77
83
|
* - Function: custom formatter receiving (value, row, col)
|
|
78
84
|
*/
|
|
79
|
-
format?: string | ((value: unknown, row:
|
|
85
|
+
format?: string | ((value: unknown, row: T, col: ColumnDefinition<T>) => string);
|
|
80
86
|
/** Per-column conditional formatting rules applied during cell rendering */
|
|
81
|
-
conditionalRules?: ConditionalRule[];
|
|
87
|
+
conditionalRules?: ConditionalRule<T>[];
|
|
82
88
|
}
|
|
83
89
|
/** Style applied to a cell by a conditional formatting rule */
|
|
84
90
|
export interface CellStyle {
|
|
@@ -88,9 +94,9 @@ export interface CellStyle {
|
|
|
88
94
|
fontStyle?: 'italic' | 'normal';
|
|
89
95
|
}
|
|
90
96
|
/** A single conditional formatting rule */
|
|
91
|
-
export interface ConditionalRule {
|
|
97
|
+
export interface ConditionalRule<T = DataRow> {
|
|
92
98
|
/** Returns true when this rule's style should be applied */
|
|
93
|
-
when: (value: unknown, row:
|
|
99
|
+
when: (value: unknown, row: T, col: ColumnDefinition<T>) => boolean;
|
|
94
100
|
style: CellStyle;
|
|
95
101
|
}
|
|
96
102
|
/**
|
package/dist/odata/index.js
CHANGED
|
@@ -2,27 +2,28 @@ import { useCallback as e, useEffect as t, useRef as n, useState as r } from "re
|
|
|
2
2
|
import i from "odata-query";
|
|
3
3
|
//#region src/odata/use-odata-source.ts
|
|
4
4
|
function a(a, s = {}) {
|
|
5
|
-
let { pageSize: c = 20, defaultOrderBy: l, fixedFilter: u } = s,
|
|
6
|
-
|
|
7
|
-
}, []),
|
|
8
|
-
|
|
9
|
-
}, []),
|
|
5
|
+
let { pageSize: c = 20, defaultOrderBy: l, fixedFilter: u, baseUrl: d, fetcher: f = fetch, onUnauthorized: p } = s, m = u ? JSON.stringify(u) : "", [h, g] = r([]), [_, v] = r(0), [y, b] = r(!1), [x, S] = r(null), [C, w] = r(0), [T, E] = r(() => l ? o(l) : []), [D, O] = r(""), [k, A] = r(0), j = n(null), M = e(() => {
|
|
6
|
+
A((e) => e + 1);
|
|
7
|
+
}, []), N = e((e) => {
|
|
8
|
+
O(e), w(0);
|
|
9
|
+
}, []), P = e((e) => {
|
|
10
10
|
let t = e.detail?.criteria;
|
|
11
|
-
t && (
|
|
11
|
+
t && (E(t), w(0));
|
|
12
12
|
}, []);
|
|
13
13
|
return t(() => {
|
|
14
|
-
|
|
14
|
+
j.current?.abort();
|
|
15
15
|
let e = new AbortController();
|
|
16
|
-
|
|
17
|
-
let t =
|
|
16
|
+
j.current = e, b(!0), S(null);
|
|
17
|
+
let t = T.length > 0 ? T.map((e) => `${e.key} ${e.direction}`).join(", ") : l, n = {
|
|
18
18
|
top: c,
|
|
19
|
-
skip:
|
|
19
|
+
skip: C * c,
|
|
20
20
|
count: !0
|
|
21
21
|
};
|
|
22
|
-
t && (n.orderBy = t), u && (n.filter = u),
|
|
23
|
-
let r = i(n)
|
|
24
|
-
return
|
|
22
|
+
t && (n.orderBy = t), u && (n.filter = u), D && (n.search = D);
|
|
23
|
+
let r = i(n);
|
|
24
|
+
return f(`${d ?? window.location.origin}${a}${r}`, { signal: e.signal }).then(async (e) => {
|
|
25
25
|
if (!e.ok) {
|
|
26
|
+
(e.status === 401 || e.status === 403) && p && p(e);
|
|
26
27
|
let t = await e.text().catch(() => ""), n = `요청 실패 (${e.status})`;
|
|
27
28
|
try {
|
|
28
29
|
let e = JSON.parse(t);
|
|
@@ -32,33 +33,34 @@ function a(a, s = {}) {
|
|
|
32
33
|
}
|
|
33
34
|
return e.json();
|
|
34
35
|
}).then((t) => {
|
|
35
|
-
e.signal.aborted || (
|
|
36
|
+
e.signal.aborted || (g(t.value ?? t), v(t["@odata.count"] ?? 0), S(null));
|
|
36
37
|
}).catch((t) => {
|
|
37
|
-
e.signal.aborted || t.name !== "AbortError" && (
|
|
38
|
+
e.signal.aborted || t.name !== "AbortError" && (S(t.message), g([]), v(0));
|
|
38
39
|
}).finally(() => {
|
|
39
|
-
e.signal.aborted ||
|
|
40
|
+
e.signal.aborted || b(!1);
|
|
40
41
|
}), () => e.abort();
|
|
41
42
|
}, [
|
|
42
43
|
a,
|
|
43
|
-
|
|
44
|
+
C,
|
|
44
45
|
c,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
T,
|
|
47
|
+
D,
|
|
48
|
+
m,
|
|
48
49
|
l,
|
|
49
|
-
|
|
50
|
+
k,
|
|
51
|
+
d
|
|
50
52
|
]), {
|
|
51
|
-
data:
|
|
52
|
-
totalCount:
|
|
53
|
-
loading:
|
|
54
|
-
error:
|
|
55
|
-
page:
|
|
56
|
-
setPage:
|
|
57
|
-
sortCriteria:
|
|
58
|
-
onSortChange:
|
|
59
|
-
search:
|
|
60
|
-
setSearch:
|
|
61
|
-
refresh:
|
|
53
|
+
data: h,
|
|
54
|
+
totalCount: _,
|
|
55
|
+
loading: y,
|
|
56
|
+
error: x,
|
|
57
|
+
page: C,
|
|
58
|
+
setPage: w,
|
|
59
|
+
sortCriteria: T,
|
|
60
|
+
onSortChange: P,
|
|
61
|
+
search: D,
|
|
62
|
+
setSearch: N,
|
|
63
|
+
refresh: M
|
|
62
64
|
};
|
|
63
65
|
}
|
|
64
66
|
function o(e) {
|
package/dist/odata/types.d.ts
CHANGED
|
@@ -3,6 +3,12 @@ export interface UseODataSourceOptions {
|
|
|
3
3
|
pageSize?: number;
|
|
4
4
|
defaultOrderBy?: string;
|
|
5
5
|
fixedFilter?: Record<string, unknown>;
|
|
6
|
+
/** 기본값: `window.location.origin`. 프록시/BFF 등 다른 origin으로 요청해야 할 때 지정. */
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
/** 커스텀 fetch transport(예: 인증 헤더를 주입하는 `HttpClient` 래퍼). 기본값: 전역 `fetch`. */
|
|
9
|
+
fetcher?: (input: string, init: RequestInit) => Promise<Response>;
|
|
10
|
+
/** 응답이 401/403일 때 호출(세션 만료 리다이렉트 등). 호출 후에도 기존 에러 처리는 계속 진행된다. */
|
|
11
|
+
onUnauthorized?: (response: Response) => void;
|
|
6
12
|
}
|
|
7
13
|
export interface UseODataSourceResult<T> {
|
|
8
14
|
data: T[];
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import { type EventName } from '@lit/react';
|
|
2
3
|
import { FlexTable } from './flex-table.js';
|
|
3
|
-
|
|
4
|
+
import type { ColumnDefinition, DataRow } from './models/types.js';
|
|
5
|
+
declare const FlexTableReactBase: import("@lit/react").ReactWebComponent<FlexTable, {
|
|
4
6
|
onCellSelect: EventName<CustomEvent>;
|
|
5
7
|
onCellEditCommit: EventName<CustomEvent>;
|
|
6
8
|
onCellEditCancel: EventName<CustomEvent>;
|
|
@@ -25,5 +27,33 @@ export declare const FlexTableReact: import("@lit/react").ReactWebComponent<Flex
|
|
|
25
27
|
onContextMenu: EventName<CustomEvent>;
|
|
26
28
|
onFilterError: EventName<CustomEvent>;
|
|
27
29
|
}>;
|
|
30
|
+
type BaseProps = React.ComponentProps<typeof FlexTableReactBase>;
|
|
31
|
+
/**
|
|
32
|
+
* Props for {@link FlexTableReact}, parameterized on the consumer's row type `T`
|
|
33
|
+
* (defaults to `DataRow` — identical to the previous non-generic behavior).
|
|
34
|
+
*/
|
|
35
|
+
export type FlexTableReactProps<T = DataRow> = Omit<BaseProps, 'data' | 'columns'> & {
|
|
36
|
+
data?: T[];
|
|
37
|
+
columns?: ColumnDefinition<T>[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* React wrapper for the `<flex-table>` custom element, generic over the row type `T`.
|
|
41
|
+
*
|
|
42
|
+
* The underlying custom element (`FlexTable`) is a single registered class and cannot
|
|
43
|
+
* itself be generic across instances — the DOM has no notion of `FlexTable<Order>` vs
|
|
44
|
+
* `FlexTable<Consumer>`. `FlexTableReact<T>` performs one internal cast at this boundary
|
|
45
|
+
* so consumers get end-to-end type safety (`data`, `columns`, `renderer`/`editor`/`validator`
|
|
46
|
+
* callbacks) without casting at every call site.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* const columns: ColumnDefinition<Order>[] = [
|
|
51
|
+
* { key: 'id', header: 'ID' },
|
|
52
|
+
* { key: 'total', header: 'Total', renderer: (v, row) => `${row.total} ${row.currency}` },
|
|
53
|
+
* ];
|
|
54
|
+
* <FlexTableReact<Order> data={orders} columns={columns} />
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare const FlexTableReact: <T = DataRow>(props: FlexTableReactProps<T> & React.RefAttributes<FlexTable>) => React.ReactElement | null;
|
|
28
58
|
export type { FlexTable };
|
|
29
|
-
export type { ColumnDefinition, DataRow, ColumnType, CellRenderer, CellEditor, CellValidator, SelectionMode, DataMode } from './models/types.js';
|
|
59
|
+
export type { ColumnDefinition, DataRow, ColumnType, CellRenderer, CellEditor, CellValidator, ConditionalRule, SelectionMode, DataMode } from './models/types.js';
|
package/dist/react.js
CHANGED