@iyulab/flex-table 0.61.0 → 0.63.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 +58 -0
- package/README.md +60 -4
- package/dist/array/index.js +2 -2
- package/dist/clipboard/clipboard.d.ts +11 -0
- package/dist/core/cell-value.d.ts +13 -0
- package/dist/events.d.ts +3 -4
- package/dist/export/delimited-reader.d.ts +11 -0
- package/dist/export/export.d.ts +11 -2
- package/dist/export/import.d.ts +30 -0
- package/dist/export/values.d.ts +17 -0
- package/dist/{fetch-all-J37bOtgc.js → fetch-all-DkdNzWrF.js} +22 -19
- package/dist/{flex-table-BD_T3SqO.js → flex-table-BufHlQ2v.js} +781 -764
- package/dist/flex-table.d.ts +14 -7
- package/dist/flex-table.js +4 -3
- package/dist/index.d.ts +3 -1
- package/dist/{locale-D9g0ksXq.js → locale-Covm8PfH.js} +4 -0
- package/dist/locale.d.ts +1 -1
- package/dist/models/types.d.ts +11 -0
- package/dist/odata/index.js +2 -2
- package/dist/odata/query.d.ts +6 -0
- package/dist/odata/source.d.ts +7 -0
- package/dist/react.js +4 -4
- package/dist/sorting-BJszwEHw.js +75 -0
- package/dist/{source-DNPtWmC3.js → source-dm6qXFh1.js} +9 -3
- package/dist/{view-BtoXdUGF.js → view-DuDIMoXV.js} +2 -2
- package/package.json +2 -2
- package/skills/iyulab-flex-table/references/api.md +8 -5
- package/skills/iyulab-flex-table/references/react.md +2 -0
- package/dist/sorting-CjfjRxwL.js +0 -51
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.63.0] - 2026-10-08
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Dot-path column keys** — `{ key: 'Customer.Name' }` reads `row.Customer.Name`, so a referenced record's name is a
|
|
8
|
+
column. Display, `format`, sorting, filtering, copying, editing, import and export read and write the cell through the
|
|
9
|
+
same path (`getCellValue` / `setCellValue`, now exported); a property named by the whole key (`'@odata.etag'`) still
|
|
10
|
+
wins. The server sort of such a column is the OData path (`$orderby=Customer/Name`), and `parseOrderBy` reads it back
|
|
11
|
+
as the column key.
|
|
12
|
+
- **`createODataSource` / `useODataSource` `expand` and `select`** — `$expand` (a string or an array) and `$select`,
|
|
13
|
+
sent by the page reads and by `fetchAll` alike; changing either re-reads. `buildODataQuery` takes them too.
|
|
14
|
+
|
|
15
|
+
- **`importFromFile` reports what did not come in.** It returns an `ImportReport` — and `data-import` now carries the
|
|
16
|
+
same object — `{ count, unmatchedHeaders, missingColumns, coercionFailures }`: file headers no column matched (their
|
|
17
|
+
values were dropped without a trace before), columns the file lacks, and cells that are not their column's type
|
|
18
|
+
(`{ row, key, raw }` — the cell keeps its text). `null` for a file type it does not read.
|
|
19
|
+
- **`ColumnDefinition.importAliases`** — other headers a file may give the column (a template a person made says
|
|
20
|
+
«관리 번호» where the label is «관리번호»). Headers now also match ignoring surrounding spaces.
|
|
21
|
+
- `flexTableLocale` keys `booleanTrueWords` / `booleanFalseWords` — the words a boolean column reads as true and false
|
|
22
|
+
(`yes,y` / `no,n`; Korean `예,네` / `아니오,아니요`), besides `true`/`false`/`1`/`0` and the locale's labels.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **A boolean column keeps text it cannot read** — on import and on paste — instead of turning it into `false`.
|
|
27
|
+
«예», «Y» or «yes» became «no»; now the words above are read and anything else stays as written (and is reported on
|
|
28
|
+
import), as `number` and `date` columns already did.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **A comma-separated `.csv` imports.** It was read as tab-separated, so each line became one cell under an unmatched
|
|
33
|
+
header and the whole file came in as empty rows. A CSV may now be separated by commas or semicolons (Excel on
|
|
34
|
+
comma-decimal locales), detected from the header line.
|
|
35
|
+
- A CSV that starts with a byte-order mark — as `exportToFile` writes it — reads back: the mark was part of the first
|
|
36
|
+
header, so that column did not match.
|
|
37
|
+
- Two file headers that match the same column no longer both write into it; the second is reported as unmatched.
|
|
38
|
+
|
|
39
|
+
- **A hidden `flex-table` is hidden.** Its host's `display: block` outranked the browser's `[hidden]` rule, so
|
|
40
|
+
`hidden` did nothing — a list that switches between a table and a card view (which hides the view it is not
|
|
41
|
+
showing) drew both.
|
|
42
|
+
|
|
43
|
+
## [0.62.0] - 2026-10-08
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **`ColumnDefinition.exportValue(value, row)`** — what export writes for the column (CSV, TSV, JSON, XLSX). Without
|
|
48
|
+
it export writes the raw value as before; a column that shows a label for a code can now say so once instead of the
|
|
49
|
+
consumer rewriting the rows before `{ rows }`. A returned `Date` is a date cell in XLSX.
|
|
50
|
+
- **CSV/TSV byte order mark** — `{ bom: true }` on `exportToString`/`exportToBlob`/`exportData`/`exportDataBlob`, and
|
|
51
|
+
`exportToFile` adds it by default (a downloaded file is opened in a spreadsheet; Excel on a non-UTF-8 system code page
|
|
52
|
+
garbled Korean without it). `{ bom: false }` turns it off.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- XLSX: an ISO string in a `date`/`datetime` column is a date cell — JSON sources (OData) send dates as strings, so the
|
|
57
|
+
file had text where the list showed dates. Strings that do not read as a date stay text.
|
|
58
|
+
- XLSX: date serials are the wall-clock time the table shows. They were counted from UTC, so a local-midnight date in
|
|
59
|
+
a timezone ahead of UTC (Korea, +09) went in as the afternoon of the day before and a date format showed that day.
|
|
60
|
+
|
|
3
61
|
## [0.61.0] - 2026-10-07
|
|
4
62
|
|
|
5
63
|
### Added
|
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ guarantee about a *constrained* host. `height-model.browser.test.ts` pins both s
|
|
|
134
134
|
|
|
135
135
|
```typescript
|
|
136
136
|
interface ColumnDefinition {
|
|
137
|
-
key: string; //
|
|
137
|
+
key: string; // The row property, or a dot path into a nested record ('Customer.Name' — see below)
|
|
138
138
|
label: string; // Column header text
|
|
139
139
|
type?: ColumnType; // 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' (any other string falls back to 'text')
|
|
140
140
|
width?: number; // Column width in pixels (default: auto)
|
|
@@ -148,6 +148,7 @@ interface ColumnDefinition {
|
|
|
148
148
|
options?: string[] | SelectOption[]; // Allowed values for type: 'select' (SelectOption = { label, value })
|
|
149
149
|
autocomplete?: boolean | 'strict'; // Suggest existing column values while editing; 'strict' rejects values not in the list
|
|
150
150
|
format?: string | ((value, row, col) => string); // Display format, see "format vs render" below
|
|
151
|
+
exportValue?: (value, row) => string | number | boolean | Date | null; // What export writes for this column (default: the raw value)
|
|
151
152
|
render?: CellRenderer; // Custom cell render: (value, row, col) => TemplateResult | string
|
|
152
153
|
editor?: CellEditor; // Custom cell editor: (value, row, col) => TemplateResult
|
|
153
154
|
validator?: CellValidator; // Validate before commit: (value, row, col) => string | null
|
|
@@ -165,11 +166,28 @@ A `number` column's built-in editor reads numbers the way people type them in th
|
|
|
165
166
|
|
|
166
167
|
A `date` column's built-in editor is `u-date-picker` from `@iyulab/components`: a text box that shows and takes `YYYY-MM-DD` in every browser language (the native date input would show the browser's UI language, e.g. `10/02/2026`), with a calendar beside it — click the box or press ArrowDown, and a picked day is the new value. It also reads `2026/10/2`, `20261002` and `10-02` (this year), stores the ISO date string, and rejects text that is not a date (`error` is the localized "Enter a date as YYYY-MM-DD"). Pasted dates are read the same way. A `datetime` column's editor works the same with a time: it shows `YYYY-MM-DD HH:mm` in local time, reads `2026-10-02 14:05` (a date alone is midnight), and stores the local `YYYY-MM-DDTHH:mm` string; in its calendar a day and a time are applied together with Apply. While the calendar is open, Escape closes the calendar; the next Escape cancels the edit.
|
|
167
168
|
|
|
169
|
+
### Nested values — dot-path keys
|
|
170
|
+
|
|
171
|
+
A `key` may be a path into a nested record: `{ key: 'Customer.Name', label: 'Customer' }` reads `row.Customer.Name` —
|
|
172
|
+
what a server list gets from OData `$expand` (the source's `expand` option). Display, `format`, sorting, filtering,
|
|
173
|
+
copying, editing, import and export all read and write the cell through the same path, and the server sort of that
|
|
174
|
+
column is `$orderby=Customer/Name`. A row that has a property named by the whole key (`'@odata.etag'`) gives that
|
|
175
|
+
property; the path is read only when the name is not there. `getCellValue(row, key)` / `setCellValue(row, key, value)`
|
|
176
|
+
(root entry) are the functions the table uses.
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
const source = createODataSource('/api/orders', { expand: 'Customer($select=Name)' });
|
|
180
|
+
const columns: ColumnDefinition[] = [
|
|
181
|
+
{ key: 'Number', label: 'Order' },
|
|
182
|
+
{ key: 'Customer.Name', label: 'Customer' }, // sortable on the server, exported as shown
|
|
183
|
+
];
|
|
184
|
+
```
|
|
185
|
+
|
|
168
186
|
### `format` vs `render`
|
|
169
187
|
|
|
170
188
|
Both control how a cell's raw value is displayed, but they differ in what they replace:
|
|
171
189
|
|
|
172
|
-
- **`format`**: a plain string pattern (Excel-style, e.g. `'#,##0.00'`, `'0.00%'`, `'$#,##0'`, `'yyyy-MM-dd'`) or a `(value, row, col) => 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.
|
|
190
|
+
- **`format`**: a plain string pattern (Excel-style, e.g. `'#,##0.00'`, `'0.00%'`, `'$#,##0'`, `'yyyy-MM-dd'`) or a `(value, row, col) => string` function. Only the *displayed text* changes — editing, sorting, filtering, and export all keep operating on the raw underlying value (give the column an `exportValue` when the file should carry what the list shows, see Export). Use this for number/date/currency display formatting.
|
|
173
191
|
- **`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.
|
|
174
192
|
|
|
175
193
|
```typescript
|
|
@@ -290,7 +308,17 @@ Default is `false`, matching `clear-undo-on-data-change`.
|
|
|
290
308
|
|--------|---------|-------------|
|
|
291
309
|
| `exportToString(format, options?)` | `string \| Uint8Array` | Export to `'csv'` / `'tsv'` / `'json'` (a string) or `'xlsx'` (bytes, uncompressed). Pass `{ selectionOnly: true }` for selection range, or `{ rows }` to export rows the table does not hold (see below) |
|
|
292
310
|
| `exportToBlob(format, options?)` | `Promise<Blob>` | The same export as a `Blob` of the format's MIME type — `'xlsx'` is DEFLATE-compressed |
|
|
293
|
-
| `exportToFile(format, filename?, options?)` | `Promise<void>` | Export and trigger browser file download (`'xlsx'` compressed) |
|
|
311
|
+
| `exportToFile(format, filename?, options?)` | `Promise<void>` | Export and trigger browser file download (`'xlsx'` compressed). CSV/TSV start with a UTF-8 BOM by default — pass `{ bom: false }` for a file another program loads |
|
|
312
|
+
|
|
313
|
+
What goes into the file:
|
|
314
|
+
|
|
315
|
+
- **Values**: the raw value of each visible column, or the column's `exportValue(value, row)` when it has one — e.g. a
|
|
316
|
+
status code shown as a label: `{ key: 'status', render: …, exportValue: (v) => statusLabel(v) }`.
|
|
317
|
+
- **Dates**: in XLSX a `date`/`datetime` column is a date cell — a `Date`, or an ISO string as JSON sources (OData) send
|
|
318
|
+
it (`YYYY-MM-DD` is that day; a full ISO string is read with its offset), the same rule the cells display with. The
|
|
319
|
+
cell holds the wall-clock time the table shows. A string that does not read as a date stays text.
|
|
320
|
+
- **BOM**: `{ bom: true }` starts CSV/TSV with a UTF-8 byte order mark so Excel on a non-UTF-8 system code page reads
|
|
321
|
+
non-ASCII text correctly — the default for `exportToFile`, off for `exportToString`/`exportToBlob`.
|
|
294
322
|
|
|
295
323
|
The table exports the rows it holds — the filtered rows in sort order, or the selection. **A server-paged table
|
|
296
324
|
(`data-mode="server"`) holds one page**, so its export is one page. To export what the list shows — the whole result
|
|
@@ -312,6 +340,32 @@ try {
|
|
|
312
340
|
Without a table, `exportDataBlob(rows, columns, format)` and `downloadBlob(blob, filename)` (root entry) do the same
|
|
313
341
|
— `exportData` stays synchronous and writes XLSX uncompressed.
|
|
314
342
|
|
|
343
|
+
### Import
|
|
344
|
+
|
|
345
|
+
`importFromFile(file)` reads an `.xlsx`, `.csv` or `.tsv` file into `data` (undoable) — also what dropping a file on a
|
|
346
|
+
table with `import-enabled` does. The first row is the header: each header goes to the column whose `label` — or one
|
|
347
|
+
of its `importAliases` — it matches, exactly first, then ignoring case and surrounding spaces. Each cell is read as its
|
|
348
|
+
column's type, the same way pasting reads it. A CSV may be separated by commas or semicolons; the byte-order mark an
|
|
349
|
+
export starts with is not part of the first header, so an exported file reads back as it was.
|
|
350
|
+
|
|
351
|
+
Nothing is dropped silently. The returned report — the same object `data-import` carries — says what did not come in:
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
const report = await table.importFromFile(file); // null for a file type it does not read
|
|
355
|
+
// { count: 120,
|
|
356
|
+
// unmatchedHeaders: ['비고2'], // their values were not imported
|
|
357
|
+
// missingColumns: ['since'], // empty in every imported row
|
|
358
|
+
// coercionFailures: [{ row: 4, key: 'qty', raw: 'many' }] } // the cell keeps its text
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
A boolean column reads `true`/`false`/`1`/`0`, the locale's true/false labels and its words (`flexTableLocale` keys
|
|
362
|
+
`booleanTrueWords`/`booleanFalseWords` — `yes,y`/`no,n` in English, `예,네`/`아니오,아니요` in Korean); any other text
|
|
363
|
+
stays text and is reported, rather than becoming `false`.
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
{ key: 'code', label: '관리번호', importAliases: ['관리 번호', 'Asset no.'] } // a template a person made
|
|
367
|
+
```
|
|
368
|
+
|
|
315
369
|
## Events
|
|
316
370
|
|
|
317
371
|
All events use `CustomEvent` with `bubbles: true, composed: true`. They are typed: `FlexTableEventMap` maps
|
|
@@ -338,7 +392,7 @@ type-checks without a cast. The React wrapper's `on*` props carry the same types
|
|
|
338
392
|
| `row-activate` | `{ row, id, via, index, col, key }` | "Open this row" (e.g. navigate to a detail view): a plain click on a body cell (`via: 'click'`), or Enter on a non-editable cell (`via: 'keyboard'`). Not a Shift / Ctrl / Cmd click (those extend the selection), the click that ends a drag, or a click on a control the cell renders (a link, a button). The grid's own contract — its Enter handler keeps the keystroke from reliably reaching a listener the host attaches to the same element |
|
|
339
393
|
| `batch-update` | `{ changes: [{ row, key, oldValue, newValue }] }` | Batch update applied |
|
|
340
394
|
| `row-reorder` | `{ from, to }` | Row dragged to a new place (data indices) |
|
|
341
|
-
| `data-import` | `{ count }` | Rows imported from a file |
|
|
395
|
+
| `data-import` | `ImportReport` — `{ count, unmatchedHeaders, missingColumns, coercionFailures }` | Rows imported from a file (see Import) |
|
|
342
396
|
| `fill-handle-apply` | `{ sourceRange, targetRange, cells }` | Fill handle wrote `cells` (`{ dataRow, key, oldValue, newValue }`) |
|
|
343
397
|
| `find-replace` | `{ type, cells }` | Replace (`type: 'replace'`) or replace-all from the find panel; `cells` are `{ row, col, oldValue, newValue }` with `col` the column key |
|
|
344
398
|
| `comment-change` | `{ dataIndex, id, colKey, text }` | Cell comment set, changed or removed (`text: null`). Comments stay on their rows (`id`) when rows move |
|
|
@@ -785,6 +839,8 @@ const source = useODataSource('/api/orders', {
|
|
|
785
839
|
| `initialSearch` | `''` | Initial search term |
|
|
786
840
|
| `initialSort` | — | Initial sort as `SortCriteria[]`. Takes precedence over `defaultOrderBy` — it is the shape `onSortChange` hands you, so a stored sort round-trips without re-serializing it |
|
|
787
841
|
| `fixedFilter` | — | Filter always applied in addition to search. Changing it resets the page to 0 — see below |
|
|
842
|
+
| `expand` | — | `$expand` — referenced records to fetch with each row: `'Customer($select=Name),Owner'` or `['Customer', 'Owner']`. A column reads one with a dot-path key (`key: 'Customer.Name'`), and its server sort is `$orderby=Customer/Name`. The page reads and `fetchAll` send the same value |
|
|
843
|
+
| `select` | — | `$select` — the properties to fetch; all when omitted |
|
|
788
844
|
| `baseUrl` | `window.location.origin` | Override the request origin (proxy/BFF setups) |
|
|
789
845
|
| `fetcher` | global `fetch` | Custom transport — pass a wrapper that injects auth headers |
|
|
790
846
|
| `onUnauthorized` | — | Called on `401` responses, before the generic error is set. A `403` (signed in, not permitted) does not call it — it surfaces as `error` |
|
package/dist/array/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as e, t, u as n } from "../fetch-all-
|
|
2
|
-
import { n as r, t as i } from "../view-
|
|
1
|
+
import { n as e, t, u as n } from "../fetch-all-DkdNzWrF.js";
|
|
2
|
+
import { n as r, t as i } from "../view-DuDIMoXV.js";
|
|
3
3
|
//#region src/array/source.ts
|
|
4
4
|
function a(e, t = {}) {
|
|
5
5
|
let a = e, o = t, s = n({
|
|
@@ -6,6 +6,17 @@ import type { ColumnDefinition, DataRow } from '../models/types.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function copyToClipboard(data: DataRow[], columns: ColumnDefinition[], range: CellRange): string;
|
|
8
8
|
export declare function parseValueForColumn(raw: string, col: ColumnDefinition): unknown;
|
|
9
|
+
/**
|
|
10
|
+
* {@link parseValueForColumn} with the outcome: `failed` is true when the column has a type (`number`, `boolean`,
|
|
11
|
+
* `date`, `datetime`) and the text is not one — the value is then the text itself, unchanged. An importer reports
|
|
12
|
+
* those cells instead of losing them.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseCellForColumn(raw: string, col: ColumnDefinition): {
|
|
15
|
+
value: unknown;
|
|
16
|
+
failed: boolean;
|
|
17
|
+
};
|
|
18
|
+
/** A boolean as a spreadsheet writes it, or `null` when the text is not one. */
|
|
19
|
+
export declare function parseBoolean(raw: string): boolean | null;
|
|
9
20
|
/**
|
|
10
21
|
* A number as a person edits it: the active locale's decimal separator, no grouping, every digit
|
|
11
22
|
* kept (`1234.5` → `1234,5` on a German page). The inverse is {@link parseValueForColumn}.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataRow } from '../models/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A column's value in a row. `key` is a property name, or a dot path into nested objects — `'Customer.Name'` reads
|
|
4
|
+
* `row.Customer.Name` (an OData `$expand`, a joined record). A row that has a property by the whole name (`'a.b'`,
|
|
5
|
+
* `'@odata.etag'`) gives that property: the path is only read when the name is not there. Every place the table reads
|
|
6
|
+
* a cell — display, format, sort, filter, copy, export — goes through this, so they agree.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCellValue(row: DataRow | null | undefined, key: string): unknown;
|
|
9
|
+
/**
|
|
10
|
+
* Writes a column's value — the inverse of {@link getCellValue}: the property by the whole name when the row has it
|
|
11
|
+
* (or the key has no dot), otherwise the path, creating the objects along it that are missing.
|
|
12
|
+
*/
|
|
13
|
+
export declare function setCellValue(row: DataRow, key: string, value: unknown): void;
|
package/dist/events.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ImportReport } from './export/import.js';
|
|
1
2
|
import type { CellPosition, CellRange } from './core/selection.js';
|
|
2
3
|
import type { SortCriteria } from './core/sorting.js';
|
|
3
4
|
import type { ColumnDefinition, DataRow } from './models/types.js';
|
|
@@ -143,10 +144,8 @@ export interface FlexTableEventMap {
|
|
|
143
144
|
colKey: string;
|
|
144
145
|
text: string | null;
|
|
145
146
|
}>;
|
|
146
|
-
/** Rows were imported from a file
|
|
147
|
-
'data-import': CustomEvent<
|
|
148
|
-
count: number;
|
|
149
|
-
}>;
|
|
147
|
+
/** Rows were imported from a file — the same report `importFromFile` returns: `count`, and what did not come in. */
|
|
148
|
+
'data-import': CustomEvent<ImportReport>;
|
|
150
149
|
'sort-change': CustomEvent<{
|
|
151
150
|
criteria: SortCriteria[];
|
|
152
151
|
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ImportedSheet } from './xlsx-reader.js';
|
|
2
|
+
/**
|
|
3
|
+
* The separator a CSV file uses — `,` or, as Excel writes it on locales whose decimal mark is a comma, `;` (a tab
|
|
4
|
+
* also counts). Counted on the first line outside quotes; the most frequent wins, and `,` when none appears.
|
|
5
|
+
*/
|
|
6
|
+
export declare function detectDelimiter(text: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* A CSV or TSV file as a header row and data rows. The byte-order mark a spreadsheet-bound export starts with
|
|
9
|
+
* (`exportToFile` writes one) is not part of the first header.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readDelimited(text: string, kind: 'csv' | 'tsv'): ImportedSheet;
|
package/dist/export/export.d.ts
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import type { ColumnDefinition, DataRow } from '../models/types.js';
|
|
2
2
|
export type ExportFormat = 'csv' | 'tsv' | 'json' | 'xlsx';
|
|
3
|
+
/** Options for `exportData` / `exportDataBlob`. */
|
|
4
|
+
export interface ExportOptions {
|
|
5
|
+
/**
|
|
6
|
+
* CSV/TSV only — start the text with a UTF-8 byte order mark. Spreadsheet apps (Excel on a non-UTF-8 system
|
|
7
|
+
* code page, e.g. Korean Windows) read a CSV without one in the system code page and garble non-ASCII text.
|
|
8
|
+
* Leave it off for files another program loads. Default: `false`.
|
|
9
|
+
*/
|
|
10
|
+
bom?: boolean;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* Export data to the specified format.
|
|
5
14
|
* Returns string for text formats (csv/tsv/json) or Uint8Array for xlsx.
|
|
6
15
|
*/
|
|
7
|
-
export declare function exportData(data: DataRow[], columns: ColumnDefinition[], format: ExportFormat): string | Uint8Array<ArrayBuffer>;
|
|
16
|
+
export declare function exportData(data: DataRow[], columns: ColumnDefinition[], format: ExportFormat, options?: ExportOptions): string | Uint8Array<ArrayBuffer>;
|
|
8
17
|
/**
|
|
9
18
|
* Export data as a `Blob` of the format's MIME type. XLSX is DEFLATE-compressed (unlike `exportData`,
|
|
10
19
|
* which stays synchronous and therefore stores the workbook uncompressed).
|
|
11
20
|
*/
|
|
12
|
-
export declare function exportDataBlob(data: DataRow[], columns: ColumnDefinition[], format: ExportFormat): Promise<Blob>;
|
|
21
|
+
export declare function exportDataBlob(data: DataRow[], columns: ColumnDefinition[], format: ExportFormat, options?: ExportOptions): Promise<Blob>;
|
|
13
22
|
/**
|
|
14
23
|
* Trigger a file download in the browser.
|
|
15
24
|
*/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ColumnDefinition, DataRow } from '../models/types.js';
|
|
2
|
+
import type { ImportedSheet } from './xlsx-reader.js';
|
|
3
|
+
/**
|
|
4
|
+
* What an import took in and what it could not — `importFromFile` returns it and `data-import` carries it, so a
|
|
5
|
+
* preview can show «what will not come in» before anything is saved.
|
|
6
|
+
*/
|
|
7
|
+
export interface ImportReport {
|
|
8
|
+
/** Rows imported. */
|
|
9
|
+
count: number;
|
|
10
|
+
/** File headers no column matched (by `label` or `importAliases`) — their values were not imported. */
|
|
11
|
+
unmatchedHeaders: string[];
|
|
12
|
+
/** Keys of the columns no file header matched — those cells are empty in every imported row. */
|
|
13
|
+
missingColumns: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Cells whose text is not a value of the column's type (`number`, `boolean`, `date`, `datetime`). The cell keeps the
|
|
16
|
+
* text as it was. `row` is the 0-based index among the imported rows.
|
|
17
|
+
*/
|
|
18
|
+
coercionFailures: {
|
|
19
|
+
row: number;
|
|
20
|
+
key: string;
|
|
21
|
+
raw: string;
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
/** File header → column key: the label or an alias, exactly first, then ignoring case and surrounding spaces. */
|
|
25
|
+
export declare function matchHeaders(headers: string[], columns: ColumnDefinition[]): Map<number, string>;
|
|
26
|
+
/** A parsed sheet as table rows, with the report of what did not come in. */
|
|
27
|
+
export declare function buildImport(sheet: ImportedSheet, columns: ColumnDefinition[]): {
|
|
28
|
+
rows: DataRow[];
|
|
29
|
+
report: ImportReport;
|
|
30
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ColumnDefinition, DataRow } from '../models/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 내보낼 셀 값 — 열이 `exportValue` 를 주면 그 결과, 아니면 원시값. 표시 규칙(`format`·`render`)은 쓰지 않는다:
|
|
4
|
+
* 원시값이 맞는 내보내기(다시 적재)가 있고, 라벨이 맞는 열은 그것을 열 스스로 말한다.
|
|
5
|
+
*/
|
|
6
|
+
export declare function exportCellValue(row: DataRow, col: ColumnDefinition): unknown;
|
|
7
|
+
/**
|
|
8
|
+
* 날짜로 내보낼 값이면 `Date` — 표시 경로(`@iyulab/components` `formatDate`)와 같은 규칙이다: `Date` 는 그대로, 날짜 열의
|
|
9
|
+
* 문자열은 `YYYY-MM-DD` 면 그 날(로컬 달력), 아니면 ISO 로 읽는다. 읽지 못하면 `null`(글자로 남긴다 — 버리지 않는다).
|
|
10
|
+
* JSON 으로 오는 소스(OData 포함)는 날짜가 문자열이라, 종전에는 날짜 열이어도 XLSX 에 글자 셀로 들어갔다.
|
|
11
|
+
*/
|
|
12
|
+
export declare function exportDate(value: unknown, col: ColumnDefinition): Date | null;
|
|
13
|
+
/**
|
|
14
|
+
* Excel 직렬값 — **벽시계 시각**으로 센다(표가 보여 주는 로컬 날짜·시각과 같은 칸). 직렬값에는 시간대가 없어, UTC 시각으로
|
|
15
|
+
* 세면 로컬 자정의 날짜가 UTC 와 다른 시간대(한국 +09)에서 전날 오후로 들어가 날짜 서식에 전날이 보였다.
|
|
16
|
+
*/
|
|
17
|
+
export declare function excelSerial(d: Date): number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e } from "./locale-
|
|
1
|
+
import { n as e } from "./locale-Covm8PfH.js";
|
|
2
2
|
import t from "odata-query";
|
|
3
3
|
//#region src/odata/query.ts
|
|
4
4
|
function n(e) {
|
|
@@ -17,26 +17,29 @@ function i(e) {
|
|
|
17
17
|
return e.split(",").map((e) => {
|
|
18
18
|
let t = e.trim().split(/\s+/);
|
|
19
19
|
return {
|
|
20
|
-
key: t[0],
|
|
20
|
+
key: t[0].replace(/\//g, "."),
|
|
21
21
|
direction: t[1]?.toLowerCase() === "desc" ? "desc" : "asc"
|
|
22
22
|
};
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
function a(e) {
|
|
26
|
-
|
|
26
|
+
return e.replace(/\./g, "/");
|
|
27
|
+
}
|
|
28
|
+
function o(e) {
|
|
29
|
+
let { page: r = 0, pageSize: i, sortCriteria: o = [], defaultOrderBy: s, search: c, fixedFilter: l, expand: u, select: d } = e, f = o.length > 0 ? o.map((e) => `${a(e.key)} ${e.direction}`).join(", ") : s, p = i === void 0 ? { count: !0 } : {
|
|
27
30
|
top: i,
|
|
28
31
|
skip: r * i,
|
|
29
32
|
count: !0
|
|
30
33
|
};
|
|
31
|
-
if (
|
|
32
|
-
let e = n(
|
|
33
|
-
e && (
|
|
34
|
+
if (f && (p.orderBy = f), l && (p.filter = l), u && u.length > 0 && (p.expand = u), d && d.length > 0 && (p.select = d), c) {
|
|
35
|
+
let e = n(c);
|
|
36
|
+
e && (p.search = e);
|
|
34
37
|
}
|
|
35
|
-
return t(
|
|
38
|
+
return t(p);
|
|
36
39
|
}
|
|
37
40
|
//#endregion
|
|
38
41
|
//#region src/core/source-error.ts
|
|
39
|
-
async function
|
|
42
|
+
async function s(t) {
|
|
40
43
|
let n = await t.text().catch(() => ""), r = {
|
|
41
44
|
message: e("requestFailed", { status: t.status }),
|
|
42
45
|
status: t.status
|
|
@@ -49,10 +52,10 @@ async function o(t) {
|
|
|
49
52
|
if (r.body = i, !i || typeof i != "object") return r;
|
|
50
53
|
let a = i, o = a.error && typeof a.error == "object" ? a.error : a;
|
|
51
54
|
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);
|
|
52
|
-
let
|
|
53
|
-
return
|
|
55
|
+
let s = c(o.details);
|
|
56
|
+
return s && (r.details = s), r;
|
|
54
57
|
}
|
|
55
|
-
function
|
|
58
|
+
function c(e) {
|
|
56
59
|
if (!Array.isArray(e)) return;
|
|
57
60
|
let t = e.filter((e) => {
|
|
58
61
|
if (!e || typeof e != "object") return !1;
|
|
@@ -61,26 +64,26 @@ function s(e) {
|
|
|
61
64
|
});
|
|
62
65
|
return t.length > 0 ? t : void 0;
|
|
63
66
|
}
|
|
64
|
-
var
|
|
67
|
+
var l = class extends Error {
|
|
65
68
|
constructor(e) {
|
|
66
69
|
super(e.message), this.name = "SourceRequestError", this.failure = e;
|
|
67
70
|
}
|
|
68
|
-
},
|
|
71
|
+
}, u = class extends l {
|
|
69
72
|
constructor(t, n) {
|
|
70
73
|
super({ message: e("tooManyRows", { maxRows: t }) }), this.name = "RowLimitError", this.total = n, this.maxRows = t;
|
|
71
74
|
}
|
|
72
75
|
};
|
|
73
|
-
function
|
|
74
|
-
return new
|
|
76
|
+
function d(t) {
|
|
77
|
+
return new l({
|
|
75
78
|
message: e("networkFailed"),
|
|
76
79
|
cause: t
|
|
77
80
|
});
|
|
78
81
|
}
|
|
79
|
-
function
|
|
80
|
-
return e instanceof
|
|
82
|
+
function f(e) {
|
|
83
|
+
return e instanceof l ? e.failure : e instanceof Error ? { message: e.message } : { message: String(e) };
|
|
81
84
|
}
|
|
82
85
|
//#endregion
|
|
83
86
|
//#region src/core/fetch-all.ts
|
|
84
|
-
var
|
|
87
|
+
var p = 1e5;
|
|
85
88
|
//#endregion
|
|
86
|
-
export {
|
|
89
|
+
export { s as a, n as c, d as i, i as l, u as n, f as o, l as r, o as s, p as t, r as u };
|