@iyulab/flex-table 0.27.0 → 0.29.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 +28 -0
- package/README.md +6 -1
- package/dist/{flex-table-CeT8zkEi.js → flex-table-DuQWDNlT.js} +25 -6
- package/dist/flex-table.d.ts +18 -0
- package/dist/flex-table.js +1 -1
- package/dist/react.d.ts +1 -0
- package/dist/react.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.29.0] - 2026-08-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`row-activate` event, fired on Enter for a non-editable cell.** The internal
|
|
8
|
+
keydown handler always consumed Enter/F2 regardless of a column's editability,
|
|
9
|
+
so a host attaching its own `keydown` listener to the grid had no reliable way
|
|
10
|
+
to react to Enter in a read-only grid (registration order dependent). Enter on
|
|
11
|
+
a non-editable cell now dispatches `row-activate` (`{ row, index, col, key }`)
|
|
12
|
+
instead of attempting to start an edit — mirroring the existing `row-add`/
|
|
13
|
+
`row-delete` detail shape. F2 is unaffected (edit-only key). Mapped through to
|
|
14
|
+
the React wrapper as `onRowActivate`.
|
|
15
|
+
|
|
16
|
+
## [0.28.0] - 2026-08-23
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`stylesheets: CSSStyleSheet[]`** — constructable stylesheets adopted into the grid's shadow
|
|
21
|
+
root alongside its own styles. A `ColumnDefinition.renderer` returns content that's inserted
|
|
22
|
+
inside `<flex-table>`'s shadow root, so a class-based utility from the host document's CSS
|
|
23
|
+
(`.is-xs`, a design-system size variant, anything selector-based rather than a CSS custom
|
|
24
|
+
property) never reaches it — the class attaches but no rule matches, since document stylesheets
|
|
25
|
+
don't cross the shadow boundary. Passing the same `CSSStyleSheet` the host document already
|
|
26
|
+
uses (`document.adoptedStyleSheets`) into this new property closes that gap without copying
|
|
27
|
+
CSS or reaching into internals. Reassigning `stylesheets` swaps the previously-adopted sheets
|
|
28
|
+
for the new ones — it doesn't accumulate — and the grid's own styles are never affected either
|
|
29
|
+
way.
|
|
30
|
+
|
|
3
31
|
## [0.27.0] - 2026-08-23
|
|
4
32
|
|
|
5
33
|
### Added
|
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ npm install @iyulab/flex-table
|
|
|
76
76
|
| `rowHeight` | `row-height` | `number` | `32` | Row height in pixels. Falls back to the `--ft-row-height` token when not set — see [Density](#density-and-header-hierarchy) |
|
|
77
77
|
| `showRowNumbers` | `show-row-numbers` | `boolean` | `false` | Show row number column |
|
|
78
78
|
| `theme` | `theme` | `'light' \| 'dark'` | auto | Force theme; auto-detects `prefers-color-scheme` |
|
|
79
|
-
| `editable` | `editable` | `boolean` | `true` | Global read-only mode when `false` |
|
|
79
|
+
| `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 |
|
|
80
80
|
| `showFilters` | `show-filters` | `boolean` | `false` | Show built-in header filter dropdowns |
|
|
81
81
|
| `maxRows` | `max-rows` | `number` | `0` | Max row count (0 = unlimited); blocks `addRow()` and paste expansion |
|
|
82
82
|
| `maxUndoSize` | `max-undo-size` | `number` | `100` | Max undo history stack size |
|
|
@@ -84,6 +84,9 @@ npm install @iyulab/flex-table
|
|
|
84
84
|
| `selectionMode` | `selection-mode` | `'single' \| 'multi'` | `'multi'` | Row selection mode |
|
|
85
85
|
| `dataMode` | `data-mode` | `'client' \| 'server'` | `'client'` | Client-side or server-side data processing |
|
|
86
86
|
| `footerData` | `footer-data` | `Record<string, string>` | `null` | Footer/summary row data (keys match column keys) |
|
|
87
|
+
| `emptyMessage` | `empty-message` | `string` | `'No data'` | Shown when `data` is empty |
|
|
88
|
+
| `noMatchingMessage` | `no-matching-message` | `string` | `'No matching data'` | Shown when `data` has rows but every one is hidden by an active column filter |
|
|
89
|
+
| `stylesheets` | — | `CSSStyleSheet[]` | `[]` | Constructable stylesheets adopted into the shadow root alongside the grid's own styles — the escape hatch for styling content a `renderer` inserts, since document CSS doesn't cross the shadow boundary. Reassigning swaps the previous set, it doesn't accumulate |
|
|
87
90
|
|
|
88
91
|
### Read-only Properties
|
|
89
92
|
|
|
@@ -231,6 +234,7 @@ All events use `CustomEvent` with `bubbles: true, composed: true`.
|
|
|
231
234
|
|-------|--------|-------------|
|
|
232
235
|
| `row-add` | `{ row, index }` | Row added |
|
|
233
236
|
| `row-delete` | `{ indices, rows }` | Rows deleted |
|
|
237
|
+
| `row-activate` | `{ row, index, col, key }` | Enter pressed on a non-editable cell — the grid's own contract for "activate this row" (e.g. navigate to a detail view), guaranteed even though the internal Enter handler prevents the keystroke from reliably reaching a listener the host attaches to the same element |
|
|
234
238
|
| `batch-update` | `{ changes: [{ row, key, oldValue, newValue }] }` | Batch update applied |
|
|
235
239
|
|
|
236
240
|
### Column Events
|
|
@@ -303,6 +307,7 @@ flex-table {
|
|
|
303
307
|
--ft-row-even-bg: #fff; /* --u-bg-color */
|
|
304
308
|
--ft-row-odd-bg: #fafafa; /* --u-bg-color-raised */
|
|
305
309
|
--ft-row-hover-bg: #f0f4ff; /* --u-bg-color-hover */
|
|
310
|
+
--ft-row-odd-hover-bg: #f0f4ff; /* --u-bg-color-raised-hover — odd row's hover, independent of --ft-row-hover-bg */
|
|
306
311
|
--ft-editor-bg: #fff; /* --u-input-bg-color */
|
|
307
312
|
--ft-sort-indicator-color: #5f6368;/* --u-txt-color-weak */
|
|
308
313
|
--ft-empty-color: #5f6368; /* --u-txt-color-weak */
|
|
@@ -1546,7 +1546,7 @@ async function xe(e) {
|
|
|
1546
1546
|
};
|
|
1547
1547
|
}
|
|
1548
1548
|
//#endregion
|
|
1549
|
-
//#region \0@oxc-project+runtime@0.
|
|
1549
|
+
//#region \0@oxc-project+runtime@0.147.0/helpers/esm/decorate.js
|
|
1550
1550
|
function q(e, t, n, r) {
|
|
1551
1551
|
var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
|
|
1552
1552
|
if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
|
|
@@ -1564,7 +1564,7 @@ var J = {
|
|
|
1564
1564
|
lte: "≤"
|
|
1565
1565
|
}, Y = 120, X = 40, Z = 32, Q = 5, $ = class extends e {
|
|
1566
1566
|
constructor(...e) {
|
|
1567
|
-
super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = Z, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.emptyMessage = "No data", this.noMatchingMessage = "No matching data", this.loading = !1, 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._lastCheckboxRowIndex = null, this._checkboxShiftPending = !1, 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 = () => {
|
|
1567
|
+
super(...e), this.columns = [], this._data = [], this._inUndoRedo = !1, this.clearUndoOnDataChange = !1, this.clearSelectionOnDataChange = !1, this._rowHeightFromCss = Z, this.showRowNumbers = !1, this.theme = void 0, this.maxRows = 0, this.editable = !0, this.showFilters = !1, this.showContextMenu = !1, this.frozenRows = 0, this.emptyMessage = "No data", this.noMatchingMessage = "No matching data", this.loading = !1, this.importEnabled = !1, this.selectable = !1, this.dataMode = "client", this.footerData = null, this.stylesheets = [], this._scrollTop = 0, this._scrollLeft = 0, this._viewportHeight = 0, this._viewportWidth = 0, this._colLeftOffsets = [], this._totalRowWidth = 0, this._baseStyleSheets = [], 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._lastCheckboxRowIndex = null, this._checkboxShiftPending = !1, 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 = () => {
|
|
1568
1568
|
this._commitCommentPopup();
|
|
1569
1569
|
}, 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();
|
|
1570
1570
|
}
|
|
@@ -2115,7 +2115,10 @@ var J = {
|
|
|
2115
2115
|
super.disconnectedCallback(), this.removeEventListener("scroll", this._onScroll), this.removeEventListener("keydown", this._onKeyDown), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("dragover", this._onDragover), this.removeEventListener("dragleave", this._onDragleave), this.removeEventListener("drop", this._onDrop), document.removeEventListener("click", this._onDocumentClick), document.removeEventListener("mousedown", this._onCommentPopupOutsideClick), this._isDragging = !1, this._wasDrag = !1, this._resizeCleanup &&= (this._resizeCleanup(), null), this._hostResizeObserver &&= (this._hostResizeObserver.disconnect(), null);
|
|
2116
2116
|
}
|
|
2117
2117
|
firstUpdated() {
|
|
2118
|
-
this._readDensityTokens(), this._measureViewport();
|
|
2118
|
+
this._readDensityTokens(), this._measureViewport(), this.shadowRoot && Array.isArray(this.shadowRoot.adoptedStyleSheets) && (this._baseStyleSheets = [...this.shadowRoot.adoptedStyleSheets]), this._syncStylesheets();
|
|
2119
|
+
}
|
|
2120
|
+
_syncStylesheets() {
|
|
2121
|
+
!this.shadowRoot || !Array.isArray(this.shadowRoot.adoptedStyleSheets) || (this.shadowRoot.adoptedStyleSheets = [...this._baseStyleSheets, ...this.stylesheets]);
|
|
2119
2122
|
}
|
|
2120
2123
|
_readDensityTokens() {
|
|
2121
2124
|
let e = getComputedStyle(this).getPropertyValue("--ft-row-height").trim();
|
|
@@ -2161,7 +2164,7 @@ var J = {
|
|
|
2161
2164
|
(!(e.size <= 2 && !e.has("data") && !e.has("columns") && !e.has("_openFilterKey") && !e.has("_editingCell") && !e.has("_activeCell") && (e.has("_scrollTop") || e.has("_scrollLeft"))) || this._viewDirty) && (this._recomputeView(), this._viewDirty = !1), this._updateColOffsets(), this._selection.setDimensions(this._visibleRowCount, this.visibleColumns.length), this._rowSelection.setRowCount(this._visibleRowCount);
|
|
2162
2165
|
}
|
|
2163
2166
|
updated(e) {
|
|
2164
|
-
this._focusEditor(), this._adjustFilterDropdown();
|
|
2167
|
+
this._focusEditor(), this._adjustFilterDropdown(), e.has("stylesheets") && this._syncStylesheets();
|
|
2165
2168
|
let t = String(this._visibleRowCount), n = String(this.visibleColumns.length);
|
|
2166
2169
|
if (this.getAttribute("aria-rowcount") !== t && this.setAttribute("aria-rowcount", t), this.getAttribute("aria-colcount") !== n && this.setAttribute("aria-colcount", n), this.loading ? this.getAttribute("aria-busy") !== "true" && this.setAttribute("aria-busy", "true") : this.hasAttribute("aria-busy") && this.removeAttribute("aria-busy"), e.has("_commentPopup") && this._commentPopup) {
|
|
2167
2170
|
let e = this.shadowRoot?.querySelector(".ft-comment-popup textarea");
|
|
@@ -2278,6 +2281,20 @@ var J = {
|
|
|
2278
2281
|
_isCellEditable(e) {
|
|
2279
2282
|
return !(!this.editable || e.editable === !1);
|
|
2280
2283
|
}
|
|
2284
|
+
_fireRowActivate(e) {
|
|
2285
|
+
if (!this._activeCell) return;
|
|
2286
|
+
let t = this._toDataIndex(this._activeCell.row), n = this.data[t];
|
|
2287
|
+
n && this.dispatchEvent(new CustomEvent("row-activate", {
|
|
2288
|
+
detail: {
|
|
2289
|
+
row: n,
|
|
2290
|
+
index: t,
|
|
2291
|
+
col: this._activeCell.col,
|
|
2292
|
+
key: e?.key
|
|
2293
|
+
},
|
|
2294
|
+
bubbles: !0,
|
|
2295
|
+
composed: !0
|
|
2296
|
+
}));
|
|
2297
|
+
}
|
|
2281
2298
|
_startEdit() {
|
|
2282
2299
|
if (!this._activeCell) return;
|
|
2283
2300
|
let e = this.visibleColumns[this._activeCell.col];
|
|
@@ -2453,7 +2470,9 @@ var J = {
|
|
|
2453
2470
|
}
|
|
2454
2471
|
if (t.length !== 0 && this._visibleRowCount !== 0) {
|
|
2455
2472
|
if ((e.key === "Enter" || e.key === "F2") && this._activeCell) {
|
|
2456
|
-
e.preventDefault()
|
|
2473
|
+
e.preventDefault();
|
|
2474
|
+
let n = t[this._activeCell.col];
|
|
2475
|
+
n && this._isCellEditable(n) ? this._startEdit() : e.key === "Enter" && this._fireRowActivate(n);
|
|
2457
2476
|
return;
|
|
2458
2477
|
}
|
|
2459
2478
|
if (!this._selection.activeCell) {
|
|
@@ -4096,7 +4115,7 @@ q([a({ type: Array })], $.prototype, "columns", void 0), q([a({
|
|
|
4096
4115
|
})], $.prototype, "dataMode", void 0), q([a({
|
|
4097
4116
|
type: Object,
|
|
4098
4117
|
attribute: "footer-data"
|
|
4099
|
-
})], $.prototype, "footerData", void 0), q([a({
|
|
4118
|
+
})], $.prototype, "footerData", void 0), q([a({ attribute: !1 })], $.prototype, "stylesheets", void 0), q([a({
|
|
4100
4119
|
type: Number,
|
|
4101
4120
|
attribute: "max-undo-size"
|
|
4102
4121
|
})], $.prototype, "maxUndoSize", null), q([o()], $.prototype, "_scrollTop", void 0), q([o()], $.prototype, "_scrollLeft", void 0), q([o()], $.prototype, "_viewportHeight", void 0), q([o()], $.prototype, "_viewportWidth", void 0), q([o()], $.prototype, "_activeCell", void 0), q([o()], $.prototype, "_editingCell", void 0), q([o()], $.prototype, "_sortCriteria", void 0), q([o()], $.prototype, "_openFilterKey", void 0), q([o()], $.prototype, "_rowSelectionVersion", void 0), q([o()], $.prototype, "_autocompleteState", void 0), q([o()], $.prototype, "_headerMenu", void 0), q([o()], $.prototype, "_bodyContextMenu", void 0), q([o()], $.prototype, "_commentPopup", void 0), q([o()], $.prototype, "_isDragOver", void 0), $ = q([i("flex-table")], $);
|
package/dist/flex-table.d.ts
CHANGED
|
@@ -85,6 +85,14 @@ export declare class FlexTable extends LitElement {
|
|
|
85
85
|
dataMode: DataMode;
|
|
86
86
|
/** Footer/summary row data. Keys match column keys; values are display strings. */
|
|
87
87
|
footerData: Record<string, string | TemplateResult> | null;
|
|
88
|
+
/**
|
|
89
|
+
* Constructable stylesheets adopted into this element's shadow root, in addition to the
|
|
90
|
+
* grid's own styles. Cell renderers run inside the shadow root, so external document
|
|
91
|
+
* stylesheets (class-based utilities, design-system CSS) don't reach elements a `renderer`
|
|
92
|
+
* returns — this is the escape hatch for that. Not an attribute (a `CSSStyleSheet` can't be
|
|
93
|
+
* serialized to one) — set it as a property.
|
|
94
|
+
*/
|
|
95
|
+
stylesheets: CSSStyleSheet[];
|
|
88
96
|
set maxUndoSize(value: number);
|
|
89
97
|
get maxUndoSize(): number;
|
|
90
98
|
private _scrollTop;
|
|
@@ -93,6 +101,8 @@ export declare class FlexTable extends LitElement {
|
|
|
93
101
|
private _viewportWidth;
|
|
94
102
|
private _colLeftOffsets;
|
|
95
103
|
private _totalRowWidth;
|
|
104
|
+
/** The grid's own compiled styles, captured once so `stylesheets` merges without dropping them. */
|
|
105
|
+
private _baseStyleSheets;
|
|
96
106
|
private _activeCell;
|
|
97
107
|
private _editingCell;
|
|
98
108
|
private _sortCriteria;
|
|
@@ -294,6 +304,7 @@ export declare class FlexTable extends LitElement {
|
|
|
294
304
|
connectedCallback(): void;
|
|
295
305
|
disconnectedCallback(): void;
|
|
296
306
|
protected firstUpdated(): void;
|
|
307
|
+
private _syncStylesheets;
|
|
297
308
|
/**
|
|
298
309
|
* `--ft-row-height` 를 판독해 가상화 계산에 넣는다.
|
|
299
310
|
*
|
|
@@ -322,6 +333,13 @@ export declare class FlexTable extends LitElement {
|
|
|
322
333
|
private _onCellDblClick;
|
|
323
334
|
/** Check if a column is editable based on global + per-column settings */
|
|
324
335
|
private _isCellEditable;
|
|
336
|
+
/**
|
|
337
|
+
* Enter가 non-editable 셀에서 눌렸을 때 "이 행을 확정한다"는 신호를 호스트에
|
|
338
|
+
* 공식적으로 알린다. 그리드가 자체 `keydown` 핸들러에서 Enter를 먼저 처리하므로,
|
|
339
|
+
* 호스트가 같은 엘리먼트에 직접 붙인 리스너는 등록 순서에 의존하게 되어 안전한
|
|
340
|
+
* 공개 계약이 못 된다 — 이 이벤트가 유일한 보장된 훅이다.
|
|
341
|
+
*/
|
|
342
|
+
private _fireRowActivate;
|
|
325
343
|
private _startEdit;
|
|
326
344
|
private _commitEdit;
|
|
327
345
|
private _applyEdit;
|
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-DuQWDNlT.js";
|
|
2
2
|
export { i as FlexTable, t as RowSelectionState, r as UndoStack, n as exportData, e as renderCell };
|
package/dist/react.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ declare const FlexTableReactBase: import("@lit/react").ReactWebComponent<FlexTab
|
|
|
11
11
|
onFilterChange: EventName<CustomEvent>;
|
|
12
12
|
onRowAdd: EventName<CustomEvent>;
|
|
13
13
|
onRowDelete: EventName<CustomEvent>;
|
|
14
|
+
onRowActivate: EventName<CustomEvent>;
|
|
14
15
|
onColumnResize: EventName<CustomEvent>;
|
|
15
16
|
onColumnSelect: EventName<CustomEvent>;
|
|
16
17
|
onColumnAdd: EventName<CustomEvent>;
|
package/dist/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "./flex-table-
|
|
1
|
+
import { t as e } from "./flex-table-DuQWDNlT.js";
|
|
2
2
|
import t from "react";
|
|
3
3
|
import { createComponent as n } from "@lit/react";
|
|
4
4
|
var r = n({
|
|
@@ -14,6 +14,7 @@ var r = n({
|
|
|
14
14
|
onFilterChange: "filter-change",
|
|
15
15
|
onRowAdd: "row-add",
|
|
16
16
|
onRowDelete: "row-delete",
|
|
17
|
+
onRowActivate: "row-activate",
|
|
17
18
|
onColumnResize: "column-resize",
|
|
18
19
|
onColumnSelect: "column-select",
|
|
19
20
|
onColumnAdd: "column-add",
|