@iyulab/flex-table 0.41.2 → 0.42.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,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.42.0] - 2026-10-04
4
+
5
+ ### Added
6
+
7
+ - **`reveal: 'hover'` column option** — the column's content shows only while its row is hovered,
8
+ holds focus or is selected; for a row-actions column, so a list does not repeat the same buttons
9
+ on every row. The content stays focusable (Tab reveals it), touch screens always show it, and it
10
+ is not printed.
11
+
12
+ ### Changed
13
+
14
+ - **The virtual scroll renders only the rows it needs above the view.** The first row in view was
15
+ computed as if the header and the frozen rows scrolled away with the body, so up to
16
+ (header + frozen rows) ÷ row height extra rows were rendered above the view — ten with eight frozen
17
+ rows. What is visible does not change.
18
+
3
19
  ## [0.41.2] - 2026-10-03
4
20
 
5
21
  ### Fixed
package/README.md CHANGED
@@ -151,6 +151,7 @@ interface ColumnDefinition {
151
151
  validator?: CellValidator; // Validate before commit: (value, row, col) => string | null
152
152
  conditionalRules?: ConditionalRule[]; // Per-cell style rules, see below
153
153
  mergeRepeated?: boolean | ((row, previousRow, col) => boolean); // Merge runs of repeated values, see below
154
+ reveal?: 'always' | 'hover'; // 'hover': show only while the row is hovered, focused or selected (row actions)
154
155
  }
155
156
  ```
156
157
 
@@ -198,6 +199,18 @@ const columns: ColumnDefinition<Order>[] = [
198
199
 
199
200
  Rules are evaluated in order and combined; later matching rules override earlier ones for overlapping style properties.
200
201
 
202
+ ### Row actions that appear on hover
203
+
204
+ A column of row actions (edit, a "more" menu) repeated on every row turns a list into a wall of
205
+ buttons. `reveal: 'hover'` shows that column's content only while its row is hovered, holds focus or
206
+ is selected. The controls stay in the DOM and focusable — Tab reveals them — touch screens (no
207
+ hover) always show them, and they are not printed.
208
+
209
+ ```ts
210
+ { key: 'actions', label: '', width: 72, editable: false, reveal: 'hover',
211
+ render: (_, row) => html`<u-button size="sm" variant="ghost" aria-label="Edit">…</u-button>` }
212
+ ```
213
+
201
214
  ### Merging Repeated Values
202
215
 
203
216
  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.
@@ -918,6 +918,28 @@ var y = r`
918
918
  outline: 2px solid var(--ft-find-color);
919
919
  outline-offset: -2px;
920
920
  }
921
+
922
+ /* reveal: 'hover' — a row-actions column shows while the row is hovered, focused or selected.
923
+ opacity (not display/visibility) keeps the controls focusable, so Tab reveals them. */
924
+ .ft-cell.ft-reveal-hover > * {
925
+ opacity: 0;
926
+ transition: opacity var(--u-duration-fast, 140ms) ease-out;
927
+ }
928
+ .ft-row:hover .ft-cell.ft-reveal-hover > *,
929
+ .ft-row:focus-within .ft-cell.ft-reveal-hover > *,
930
+ .ft-row-selected .ft-cell.ft-reveal-hover > *,
931
+ .ft-cell.ft-reveal-hover.ft-active > * {
932
+ opacity: 1;
933
+ }
934
+ @media (hover: none) {
935
+ .ft-cell.ft-reveal-hover > * { opacity: 1; }
936
+ }
937
+ @media (prefers-reduced-motion: reduce) {
938
+ .ft-cell.ft-reveal-hover > * { transition: none; }
939
+ }
940
+ @media print {
941
+ .ft-cell.ft-reveal-hover > * { visibility: hidden; }
942
+ }
921
943
  `;
922
944
  //#endregion
923
945
  //#region src/renderers/format.ts
@@ -2270,10 +2292,10 @@ var q = {
2270
2292
  return Math.max(0, this._visibleRowCount - this._frozenRowCount) * this.rowHeight;
2271
2293
  }
2272
2294
  get visibleRange() {
2273
- let e = this._frozenRowCount, t = Math.max(0, this._scrollTop - this.headerHeight - this.frozenRowsHeight), n = e + Math.floor(t / this.rowHeight), r = Math.max(e, n - Q), i = Math.ceil(this._viewportHeight / this.rowHeight);
2295
+ let e = this._frozenRowCount, t = e + Math.floor(Math.max(0, this._scrollTop) / this.rowHeight), n = Math.max(e, t - Q), r = Math.max(0, this._viewportHeight - this.headerHeight - this.frozenRowsHeight), i = Math.ceil(r / this.rowHeight) + 1;
2274
2296
  return {
2275
- start: r,
2276
- end: Math.min(this._visibleRowCount, n + i + Q)
2297
+ start: n,
2298
+ end: Math.min(this._visibleRowCount, t + i + Q)
2277
2299
  };
2278
2300
  }
2279
2301
  connectedCallback() {
@@ -4232,7 +4254,8 @@ var q = {
4232
4254
  S ? "ft-find-current" : x ? "ft-find-match" : "",
4233
4255
  o ? `ft-merge-${o.headParity}` : "",
4234
4256
  o?.continues ? "ft-merge-continued" : "",
4235
- o?.opensDown ? "ft-merge-open" : ""
4257
+ o?.opensDown ? "ft-merge-open" : "",
4258
+ t.reveal === "hover" ? "ft-reveal-hover" : ""
4236
4259
  ].filter(Boolean).join(" "), T = this._toDataIndex(n), E = this._comments.get(T)?.get(t.key) ?? null, D = E !== null, O = D ? i`<div class="ft-comment-indicator" title=${E}></div>` : a;
4237
4260
  return i`
4238
4261
  <div class=${D ? C + " ft-has-comment" : C}
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./flex-table-CZPubYVD.js";
1
+ import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./flex-table-BdnkC234.js";
2
2
  export { o as FlexTable, e as RowSelectionState, t as UndoStack, n as effectiveAlign, i as exportData, r as flexTableLocale, a as renderCell };
@@ -115,6 +115,15 @@ export interface ColumnDefinition<T = DataRow> {
115
115
  * the top of the scrolled view and below frozen rows, so it never scrolls out of sight.
116
116
  */
117
117
  mergeRepeated?: boolean | ((row: T, previousRow: T, col: ColumnDefinition<T>) => boolean);
118
+ /**
119
+ * When the column's content shows.
120
+ * - `'always'` (default)
121
+ * - `'hover'`: only while the row is hovered, holds focus, or is selected — for a row-actions
122
+ * column (edit, a "more" menu), so a list does not repeat the same buttons on every row. The
123
+ * content stays in the DOM and keyboard focus reveals it; on touch screens (no hover) it is
124
+ * always shown, and it is not printed.
125
+ */
126
+ reveal?: 'always' | 'hover';
118
127
  }
119
128
  /** Style applied to a cell by a conditional formatting rule */
120
129
  export interface CellStyle {
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./flex-table-CZPubYVD.js";
1
+ import { t as e } from "./flex-table-BdnkC234.js";
2
2
  import { i as t, t as n } from "./query-Dw4iO0ir.js";
3
3
  import { t as r } from "./view-DiLr-TdY.js";
4
4
  import i, { useCallback as a, useEffect as o, useMemo as s, useRef as c, useState as l } from "react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.41.2",
3
+ "version": "0.42.0",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",
@@ -4,7 +4,6 @@ description: Spreadsheet-grade data grid web component (`<flex-table>`, built wi
4
4
  license: MIT
5
5
  metadata:
6
6
  author: iyulab
7
- version: "0.40.1"
8
7
  ---
9
8
 
10
9
  # @iyulab/flex-table
@@ -66,6 +66,7 @@ Replacing `data` with the same array reference does not trigger the clear-on-cha
66
66
  | `validator` | `CellValidator<T>` | `(value, row, col) => string \| null \| undefined` |
67
67
  | `conditionalRules` | `ConditionalRule<T>[]` | `{ when(value, row, col): boolean, style: CellStyle }` |
68
68
  | `mergeRepeated` | `boolean \| (row, previousRow, col) => boolean` | Draw a run of repeated values as one merged cell; values, sort, filter and export are unchanged |
69
+ | `reveal` | `'always' \| 'hover'` | `'hover'`: content shows only while the row is hovered, focused or selected — for a row-actions column; stays focusable, always shown without hover, not printed |
69
70
 
70
71
  `CellStyle` = `{ background?, color?, fontWeight?: 'bold' | 'normal', fontStyle?: 'italic' | 'normal' }`.
71
72