@iyulab/flex-table 0.34.3 → 0.36.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,55 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.36.0] - 2026-09-17
4
+
5
+ ### Added
6
+
7
+ - **The table's own chrome text now goes through a locale namespace.** The filter menus, the
8
+ find-and-replace panel, the column menu and the empty-state message were written in English in the
9
+ source, so an application translated into another language showed thirty-one English strings in
10
+ the middle of its own UI — "Contains", "Starts with", "Match case", "Replace all" and the rest.
11
+ `flexTableLocale` is exported for consumers to register further languages or reword the built-in
12
+ ones:
13
+
14
+ ```ts
15
+ import { flexTableLocale } from '@iyulab/flex-table';
16
+ flexTableLocale.register('ja', { contains: '含む', startsWith: '前方一致' });
17
+ ```
18
+
19
+ English and Korean ship with the package; other languages are added the same way. The filter
20
+ operators `AND` and `OR`, and the glyphs standing in for icons, are deliberately left alone —
21
+ they read the same in every language and translating them makes them harder to recognise.
22
+
23
+ ### Changed
24
+
25
+ - The package compiles against `ESNext` rather than `ES2021`, matching every sibling package in the
26
+ same family.
27
+ ## [0.35.0] - 2026-09-15
28
+
29
+ ### Changed
30
+
31
+ - **Every header now has a 24×24 column menu button (`⋮`), which replaces the 14px filter button.**
32
+ The menu — the same one a header right-click opens — gathers the per-column actions: **Sort
33
+ ascending** / **Sort descending** (for sortable columns — the keyboard path to sorting), **Filter…**
34
+ and **Clear filter** (with `show-filters`), **Hide column** / **Show: …**, **Auto-fit width**,
35
+ **Wider** and **Narrower** (±20px, the menu stays open for repeated steps). Opening a filter is now
36
+ two clicks. The button is highlighted while its column is filtered, as the filter button was.
37
+ The old filter button was below the WCAG 2.2 SC 2.5.8 minimum and sat right next to the resize handle;
38
+ the handle keeps its 6px width and the column menu is its equivalent, which also means resizing
39
+ no longer requires a drag (SC 2.5.7).
40
+
41
+ ### Fixed
42
+
43
+ - **Sorting from the cell context menu broke the `sort-change` contract.** It reported
44
+ `{ sortCriteria }` instead of `{ criteria }`, re-sorted the data locally even with
45
+ `data-mode="server"`, and ignored `sortable: false`. It now behaves exactly like a header click.
46
+ - **The header and cell context menus could not be used from the keyboard, and could open
47
+ off-screen.** Their items are now buttons in a `role="menu"`: arrow keys, Home and End move between
48
+ them, Escape closes and returns focus (to the column menu button, or to the grid). The cell menu
49
+ focuses its first item when it opens. Both menus are moved back inside the visible area once their
50
+ real size is known — the cell menu previously flipped on a guessed 200×280 size, and a menu fitted
51
+ to the window width could still sit under the vertical scrollbar.
52
+
3
53
  ## [0.34.3] - 2026-09-13
4
54
 
5
55
  ### Fixed
package/README.md CHANGED
@@ -52,7 +52,8 @@ npm install @iyulab/flex-table
52
52
  - **Row Selection** — Checkbox-based row selection (`selectable`, single/multi mode)
53
53
  - **Clipboard** — Ctrl+C/X/V with TSV format (Excel/Google Sheets compatible, RFC 4180)
54
54
  - **Sorting** — Click header to sort (asc/desc/none), Shift+click for multi-sort
55
- - **Column Resize** — Drag header border, double-click to auto-fit, Alt+Arrow keyboard resize
55
+ - **Column Menu** — A 24×24 button in every header opens the column's menu: sort, filter, hide/show, auto-fit, wider/narrower (also opens on header right-click)
56
+ - **Column Resize** — Drag header border, double-click to auto-fit, Alt+Arrow keyboard resize, or the column menu
56
57
  - **Column Operations** — `addColumn()`, `deleteColumn()`, `moveColumn()` with undo
57
58
  - **Pinned Columns** — Freeze columns to left or right (`pinned: 'left' | 'right'`)
58
59
  - **Filtering** — Programmatic API + built-in header filter UI (`show-filters`)
@@ -103,7 +104,7 @@ guarantee about a *constrained* host. `height-model.browser.test.ts` pins both s
103
104
  | `showRowNumbers` | `show-row-numbers` | `boolean` | `false` | Show row number column |
104
105
  | `theme` | `theme` | `'light' \| 'dark'` | auto | Force theme; auto-detects `prefers-color-scheme` |
105
106
  | `editable` | `editable` | `boolean` | `true` | Global read-only mode when `false`. Defaults to `true` — a purely read-only grid should set this explicitly rather than relying on per-column `editable: false` alone, since it's also what makes Enter fire `row-activate` (see [Events](#events)) instead of entering edit mode |
106
- | `showFilters` | `show-filters` | `boolean` | `false` | Show built-in header filter dropdowns |
107
+ | `showFilters` | `show-filters` | `boolean` | `false` | Offer the built-in filter dropdowns through each column menu («Filter…») |
107
108
  | `maxRows` | `max-rows` | `number` | `0` | Max row count (0 = unlimited); blocks `addRow()` and paste expansion |
108
109
  | `maxUndoSize` | `max-undo-size` | `number` | `100` | Max undo history stack size |
109
110
  | `selectable` | `selectable` | `boolean` | `false` | Enable row-level checkbox selection |
@@ -404,6 +405,63 @@ package dependency; CSS custom properties are resolved at render time, not impor
404
405
  | Ctrl+Shift+Z / Ctrl+Y | Redo |
405
406
  | Alt+ArrowLeft / Alt+ArrowRight | Resize current column (±20px) |
406
407
  | Ctrl+Click header | Select entire column |
408
+ | Enter / Space on a column menu button | Open the column menu |
409
+ | ArrowUp / ArrowDown / Home / End (column menu) | Move between menu items |
410
+ | Escape (column menu) | Close the menu and return focus to its button |
411
+
412
+ ## Localization
413
+
414
+ The text the table draws itself — filter menus, the find-and-replace panel, the column menu, the
415
+ empty-state message — resolves through a locale namespace. English and Korean ship with the package
416
+ and follow whatever locale `@iyulab/components` has active:
417
+
418
+ ```ts
419
+ import { Locale } from '@iyulab/components';
420
+
421
+ Locale.set('ko'); // the table's own chrome follows
422
+ ```
423
+
424
+ Register another language, or reword the built-in strings, through the exported namespace. Partial
425
+ tables are merged, so you only pass the keys you want to change:
426
+
427
+ ```ts
428
+ import { flexTableLocale, type FlexTableMessageKey } from '@iyulab/flex-table';
429
+
430
+ flexTableLocale.register('ja', {
431
+ contains: '含む',
432
+ startsWith: '前方一致',
433
+ matchCase: '大文字と小文字を区別',
434
+ });
435
+
436
+ flexTableLocale.register('en', { replaceAll: 'Replace everything' }); // reword one string
437
+ ```
438
+
439
+ Keys cover the column header and menu (`showHiddenColumns`, `columnMenu`, `cellActions`,
440
+ `noColumnsDefined`), cell comments (`addCommentPlaceholder`, `cancel`, `save`), the filter panel
441
+ (`clear`, `blankCells`, `emptyOnly`, `nonEmptyOnly`, `blankAll`, `all`, `contains`, `startsWith`,
442
+ `endsWith`, `wildcard`, `searchPlaceholder`, `valuePlaceholder`, `fromPlaceholder`,
443
+ `toPlaceholder`) and find-and-replace (`findPlaceholder`, `findPrevious`, `findNext`, `matchCase`,
444
+ `wholeCell`, `closeFind`, `replaceWithPlaceholder`, `replace`, `replaceAll`). `FlexTableMessageKey`
445
+ is exported, so a missing or misspelled key is a type error rather than a string that silently falls
446
+ back to its own name.
447
+
448
+ The filter operators `AND` and `OR` are not in the table, and neither are the glyphs that stand in
449
+ for icons. They read the same in every language, and translating them makes them harder to
450
+ recognise rather than easier.
451
+
452
+ ## Accessibility
453
+
454
+ The baseline is **WCAG 2.2**. The table lists what this package **measures in tests** — it is not a
455
+ conformance claim for the success criteria it does not list.
456
+
457
+ | Success criterion | Guarantee | Measured by |
458
+ |---|---|---|
459
+ | SC 2.5.8 Target Size (Minimum) | Sortable headers, column menu buttons, the open column menu, the open filter dropdown (text and number), the find/replace bar, the cell context menu and row selection checkboxes are at least 24×24 CSS px or meet the spacing exception (24px between centers, counting the neighbouring resize handles), and are actually hit at that position. Two small targets use the equivalent-control exception: the 6px column resize handle (every resize is also in the column menu) and the hidden-column marker (its column menu offers **Show: …**) | `tests/browser/target-size.browser.test.ts` (real Chromium) |
460
+ | SC 2.1.1 Keyboard (pointer-cursor check) | Nothing the grid renders shows a pointer cursor without being an interactive element. Sorting by header click also has a keyboard path — the column menu's **Sort ascending** / **Sort descending** (the check alone cannot see that, because the header cell wraps the menu button) | `tests/browser/target-size.browser.test.ts` · `src/flex-table.test.ts` |
461
+ | SC 2.5.7 Dragging Movements | Resizing never requires a drag — the column menu's **Auto-fit width**, **Wider** and **Narrower** are single clicks | `tests/browser/column-menu.browser.test.ts` |
462
+
463
+ Not yet measured: the boolean and date filter dropdowns and the comment popup. Color contrast comes
464
+ from the `@iyulab/components` tokens this package reads.
407
465
 
408
466
  ## Usage Guide
409
467
 
@@ -569,7 +627,9 @@ Use `updateRows()` for programmatic edits — it provides undo/redo and dispatch
569
627
 
570
628
  ### Built-in Filter UI
571
629
 
572
- Enable with `show-filters` attribute. Filter dropdowns appear in column headers:
630
+ Enable with `show-filters` attribute. Each column menu (the `⋮` button in the header) then offers **Filter…**,
631
+ which opens that column's filter dropdown, and **Clear filter** while the column is filtered. The menu
632
+ button is highlighted while its column has an active filter.
573
633
 
574
634
  - **text**: case-insensitive substring search
575
635
  - **number**: min/max range inputs