@iyulab/flex-table 0.40.3 → 0.41.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,46 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.41.0] - 2026-10-03
4
+
5
+ ### Added
6
+
7
+ - **`mergeRepeated` column option — a run of repeated values reads as one merged cell.** For lists of
8
+ child rows under a parent (order lines under an order, boxes under a shipment), the parent's columns
9
+ no longer repeat on every line: the value shows once, on the run's first row, the lines inside the run
10
+ are dropped, and the run keeps one background. `true` merges equal values (empty values never merge);
11
+ a function `(row, previousRow, col) => boolean` decides by any rule — e.g. merge a customer only within
12
+ one order. Every row keeps its own value, so sorting, filtering, copying, export and screen readers
13
+ see each row as before. Rows are compared in display order; the value is drawn again on the first row
14
+ in view and below frozen rows, so scrolling or paging through a run never hides it.
15
+
16
+ ### Fixed
17
+
18
+ - **Number entry reads a decimal comma.** The `number` cell editor and the number filter used the native
19
+ number input, which turns `1,5` into `15` or an empty value depending on the browser. Both are now text
20
+ fields with a decimal keyboard (`inputmode="decimal"`) that read numbers in the active `Locale` — `1,5`
21
+ is 1.5 and `1.234,5` is 1234.5 on a comma-decimal page — and the editor shows the current value with
22
+ that locale's decimal separator. The filter keeps what you typed while you type it and marks a condition
23
+ it cannot read (`aria-invalid`).
24
+ - **Pasting `1,5` into a number column stores 1.5.** Pasted text was read with `Number()`, so a value from a
25
+ comma-decimal spreadsheet stayed text (`"1,5"`) and sorted and summed wrongly. Plain notation (`1e3`) is
26
+ still read; text that is not a number still stays text.
27
+ - **The built-in editor rejects text that is not a number** in a `number` column. It fires
28
+ `validation-error` (`error`: "Enter a number") and keeps the old value, like a validator failure — the
29
+ native input never let such text through, so a text field must not store it.
30
+ - The strict-autocomplete error ("Value must be from the existing list") follows the `Locale` (new keys
31
+ `notANumber` and `notInList` in `flexTableLocale`; `ko` built in).
32
+
33
+ ### Changed
34
+
35
+ - **The `@iyulab/components` peer is `>=1.54.0`** — number parsing uses its `parseNumber`.
36
+
37
+ - The optional `@lit/react` peer is `^1.0.8` (was `^1.0.0`) — the version the React entry is tested
38
+ with.
39
+
40
+ ### Documentation
41
+
42
+ - README: the Accessibility section links the KWCAG 2.2 table in `@iyulab/components`.
43
+
3
44
  ## [0.40.3] - 2026-09-30
4
45
 
5
46
  ### Fixed
@@ -587,8 +628,6 @@ All notable changes to this project will be documented in this file.
587
628
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
588
629
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
589
630
 
590
- ## [Unreleased]
591
-
592
631
  ## [0.23.1] - 2026-08-03
593
632
 
594
633
  ### Fixed
package/README.md CHANGED
@@ -150,6 +150,7 @@ interface ColumnDefinition {
150
150
  editor?: CellEditor; // Custom cell editor: (value, row, col) => TemplateResult
151
151
  validator?: CellValidator; // Validate before commit: (value, row, col) => string | null
152
152
  conditionalRules?: ConditionalRule[]; // Per-cell style rules, see below
153
+ mergeRepeated?: boolean | ((row, previousRow, col) => boolean); // Merge runs of repeated values, see below
153
154
  }
154
155
  ```
155
156
 
@@ -157,6 +158,8 @@ The `editor` callback must return a Lit `TemplateResult` containing an input ele
157
158
 
158
159
  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.
159
160
 
161
+ A `number` column's built-in editor reads numbers the way people type them in the active `Locale` — `1,5` on a comma-decimal page is 1.5, `1.234,5` is 1234.5 — and shows the value with that locale's decimal separator. Text that is not a number is rejected the same way as a validator failure (`error` is the localized "Enter a number"). The number filter's conditions and pasted values are read the same way; pasted text that is not a number stays text.
162
+
160
163
  ### `format` vs `render`
161
164
 
162
165
  Both control how a cell's raw value is displayed, but they differ in what they replace:
@@ -193,6 +196,22 @@ const columns: ColumnDefinition<Order>[] = [
193
196
 
194
197
  Rules are evaluated in order and combined; later matching rules override earlier ones for overlapping style properties.
195
198
 
199
+ ### Merging Repeated Values
200
+
201
+ A list of child rows under a parent — order lines under an order, boxes under a shipment — repeats the parent's columns on every line. `mergeRepeated` draws each run of repeated values as one merged cell: the value shows once, on the run's first row, and the lines between the run's rows are dropped.
202
+
203
+ ```typescript
204
+ const columns: ColumnDefinition<OrderLine>[] = [
205
+ { key: 'orderNo', label: 'Order', mergeRepeated: true },
206
+ // Two adjacent orders can share a customer — merge only within one order.
207
+ { key: 'customer', label: 'Customer', mergeRepeated: (row, prev) => row.orderNo === prev.orderNo },
208
+ { key: 'product', label: 'Product' },
209
+ { key: 'qty', label: 'Qty', type: 'number' },
210
+ ];
211
+ ```
212
+
213
+ Every row keeps its own value. Sorting, filtering, copying, CSV/XLSX export and screen readers see each row exactly as without merging — a filter that drops a run's first row leaves the rest of the run labelled, and an export pivots. Rows are compared in display order, so sort by the merged column (or keep the server's order) for runs to form. The value is drawn again on the first row in view and on the first row below frozen rows, so scrolling or paging through a run never hides it. With `true`, empty values (`null`, `undefined`, `''`) never merge.
214
+
196
215
  ## Methods
197
216
 
198
217
  ### Row Operations
@@ -209,7 +228,7 @@ Rules are evaluated in order and combined; later matching rules override earlier
209
228
  | Method | Returns | Description |
210
229
  |--------|---------|-------------|
211
230
  | `addColumn(def, index?)` | `ColumnDefinition` | Add column at position (default: end) |
212
- | `deleteColumn(key)` | `void` | Remove column + cleanup filters/sort/widths |
231
+ | `deleteColumn(key)` | `void` | Remove column + cleanup filters/sort/widths. Row objects keep that key's values (undo restores the column with them); delete the key from `data` yourself if you need it gone |
213
232
  | `moveColumn(key, newIndex)` | `void` | Reorder column to target index (clamped) |
214
233
  | `getColumnWidth(key)` | `number \| undefined` | Get internal resize width for column |
215
234
  | `selectColumn(colIndex)` | `void` | Select entire column (range selection) |
@@ -257,7 +276,7 @@ All events use `CustomEvent` with `bubbles: true, composed: true`.
257
276
  | `cell-edit-start` | `{ row, col, key, value }` | Cell editing started |
258
277
  | `cell-edit-commit` | `{ row, col, key, oldValue, newValue }` | Cell value committed |
259
278
  | `cell-edit-cancel` | `{ row, col }` | Cell edit cancelled (Escape) |
260
- | `validation-error` | `{ row, col, key, value, error }` | Cell validator rejected value |
279
+ | `validation-error` | `{ row, col, key, value, error }` | Cell validator rejected value, or a `number` cell got text that is not a number |
261
280
 
262
281
  ### Data Events
263
282
 
@@ -476,6 +495,8 @@ conformance claim for the success criteria it does not list.
476
495
  Not yet measured: the boolean and date filter dropdowns and the comment popup. Color contrast comes
477
496
  from the `@iyulab/components` tokens this package reads.
478
497
 
498
+ For **KWCAG 2.2** (the Korean web accessibility standard), the `@iyulab/components` README has a table of all 33 check items — which are guaranteed by a test across the sibling packages, which are shared with the app, and which do not apply: [KWCAG 2.2 대응표](https://github.com/iyulab/node-components#kwcag-22-대응표).
499
+
479
500
  ## Usage Guide
480
501
 
481
502
  ### React
@@ -6,3 +6,8 @@ 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
+ * A number as a person edits it: the active locale's decimal separator, no grouping, every digit
11
+ * kept (`1234.5` → `1234,5` on a German page). The inverse is {@link parseValueForColumn}.
12
+ */
13
+ export declare function editableNumber(value: number): string;