@iyulab/flex-table 0.23.2 → 0.25.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 ADDED
@@ -0,0 +1,558 @@
1
+ # Changelog
2
+
3
+ ## [0.25.0] - 2026-08-07
4
+
5
+ ### Added
6
+
7
+ - **`--ft-font-size` now reads `var(--u-density, 14px)`.** When a consumer sets the design
8
+ system's `--u-density` switch on an ancestor, the table's base font size (and everything
9
+ derived from it) follows automatically. Unset, behavior is unchanged.
10
+
11
+ ### Fixed
12
+
13
+ - **Hovering an odd (striped) row produced no visible feedback in dark mode.** Odd rows sit on
14
+ the raised-surface background, and the hover style used the same global hover token that raised
15
+ happened to equal in dark — so the row simply didn't respond. Odd-row hover now reads a
16
+ dedicated raised-surface hover token when the design system sheet provides one, falling back to
17
+ the previous behavior otherwise. Even rows are unaffected.
18
+
19
+ ## [0.24.0] - 2026-08-05
20
+
21
+ ### Changed
22
+
23
+ - ⚠**`@iyulab/components` is now a required peer dependency (`>=1.24.0`).** The
24
+ stylesheet is not decoration here — 313 token references depend on it, and without
25
+ it the fallback literals silently stand in for the real theme. Declaring the peer as
26
+ optional would keep allowing exactly the situation the fallbacks were meant to reveal.
27
+
28
+ Consumers pinned to `@iyulab/components@1.23.x` will see an `ERESOLVE` on install.
29
+
30
+ ### Fixed
31
+
32
+ - **`sideEffects` no longer misses the shared chunk.** With more than one entry point,
33
+ the bundler splits common code — including the custom-element registrations — into a
34
+ hash-named chunk. The declaration listed only the named entries, so a consumer's
35
+ bundler could drop that chunk and the elements would never register, with no error at
36
+ build time. It now covers the emitted output as a whole (`./dist/*.js`), which is
37
+ hash-stable across builds.
38
+
39
+ - **The `./react` and `./odata` subpaths point back at the built output.** They had been
40
+ rewritten to source paths, which do not exist in the published package.
41
+
42
+ ## [0.23.2] - 2026-08-04
43
+
44
+ ### Changed
45
+
46
+ - **OData 요청 실패 기본 문구가 영어가 된다** — `요청 실패 (500)` → `Request failed (500)`.
47
+ 서버가 오류 메시지를 주면 **그쪽이 이긴다**(종전과 같다) — 이 문구는 서버가 아무것도 주지
48
+ 않을 때의 폴백이다.
49
+
50
+ ⚠**로케일 레지스트리를 도입하지 않았다.** 문자열 하나를 위해 런타임 의존을 들이는 것은
51
+ 비용이 이득을 넘는다(이 패키지의 의존은 `lit` · `odata-query` 둘뿐이다). 수요가 모이면 그때
52
+ 같은 형태로 연다.
53
+
54
+ All notable changes to this project will be documented in this file.
55
+
56
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
57
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
58
+
59
+ ## [Unreleased]
60
+
61
+ ## [0.23.1] - 2026-08-03
62
+
63
+ ### Fixed
64
+
65
+ - 🔴**토큰 폴백 리터럴 48곳이 디자인 시스템 값이 아니었다.** `var(--u-토큰, #리터럴)` 의
66
+ 리터럴은 **정의상 시트 값의 복제**이고, 시트를 로드하지 않은 소비자가 실제로 보는
67
+ 값이다. 그런데 이 표의 48곳은 낡은 것이 아니라 **처음부터 다른 팔레트**였다.
68
+
69
+ ```
70
+ --u-primary-color #1a73e8 → #1976D2 (7곳)
71
+ --u-txt-color #202124 → #212121 (6곳)
72
+ --u-bg-color-raised #f8f9fa → #FAFAFA (6곳)
73
+ --u-txt-color-weak #5f6368 → #757575 (6곳)
74
+ --u-bg-color-active #e8eaed → #EEEEEE (3곳) … 외 7종
75
+ ```
76
+
77
+ ⚠**시트를 로드하는 소비자에게는 변화가 없다** — 폴백은 그 경우 아예 평가되지 않는다.
78
+ **시트 없이 쓰던 소비자**는 표의 색이 디자인 시스템 기본값으로 바뀐 것을 본다. 그것이
79
+ 이 폴백이 원래 뜻하던 값이다.
80
+
81
+ ⚠**개발 환경에서는 드러날 수 없는 부류의 결함이다.** 시트가 있으면 폴백은 평가되지
82
+ 않으므로, 어긋난 값은 *우리가 보지 못하는 화면*에서만 나타난다.
83
+
84
+ ## [0.23.0] - 2026-08-03
85
+
86
+ ### Added
87
+
88
+ - ★**표의 밀도와 머리행 위계를 조절할 수 있다.** 색은 0.22.0 에서 열렸지만 **치수는 닫혀
89
+ 있었다** — 한 화면에 이 표와 다른 표가 함께 놓이는 경우, 소비자는 색만 맞추고 밀도·위계는
90
+ 맞추지 못했다. 그리고 *"고칠 수 있는 쪽만 고치면 더 갈라지므로"* 실제로는 **양쪽 다
91
+ 포기하는** 선택으로 밀린다.
92
+
93
+ ```
94
+ --ft-row-height 32px 행 높이
95
+ --ft-cell-padding-block 6px 그 높이 안에서 글자의 자리
96
+ --ft-cell-padding-inline 12px
97
+ --ft-header-font-size 기본값 = --ft-font-size
98
+ --ft-header-font-weight 600
99
+ ```
100
+
101
+ **기본값이 종전 렌더값과 같다** — 아무것도 선언하지 않은 소비자의 화면은 바뀌지 않는다.
102
+
103
+ ⚠**`--ft-row-height` 만 성질이 다르다.** 이 표는 가상 스크롤이라 행이 `index × rowHeight`
104
+ 로 절대 배치되고 셀 높이가 인라인으로 박힌다 — ***행 높이는 캐스케이드로 닿지 않는다.***
105
+ 그래서 이 토큰은 **첫 렌더에 한 번 판독**되어 가상화 계산에 들어간다. 이후에 바꾸려면
106
+ `rowHeight` 프로퍼티(또는 `row-height` 속성)를 쓴다. 명시 지정은 **항상 토큰을 이기고**,
107
+ `px` 이외 단위는 무시된다.
108
+
109
+ ⚠**행 높이는 고정이고 여백은 그 안에서 글자를 배치한다.** 셀은 설계상 한 줄이다
110
+ (`nowrap` + 말줄임). 행 높이를 줄이면 여백도 함께 줄일 것 —
111
+ `padding-block × 2 + 한 줄 높이 ≤ row-height` 를 넘으면 아래가 잘린다.
112
+
113
+ ## [0.22.0] - 2026-08-03
114
+
115
+ ### Changed
116
+
117
+ - ★**표 색이 `@iyulab/components` 디자인 토큰에서 파생한다.**
118
+
119
+ 종전에는 자체 팔레트를 리터럴로 갖고 있어, 소비자가 셸·버튼의 브랜드를 맞춰도
120
+ **표만 다른 색 체계**로 남았다. 업무앱에서 표는 화면 면적의 대부분이라 나머지를
121
+ 아무리 맞춰도 체감이 바뀌지 않는다. 이제 `--u-primary-color` 한 줄로 표의 강조색·
122
+ 선택 표시·불리언 표시가 함께 따라온다.
123
+
124
+ ```
125
+ --ft-active-color → --u-primary-color (강조 · 정렬 활성 · 포커스)
126
+ --ft-selection-bg → --u-primary-bg-color (선택된 셀/행)
127
+ --ft-bg / -row-even-bg → --u-bg-color
128
+ --ft-header-bg → --u-bg-color-raised (크롬 면)
129
+ --ft-row-hover-bg → --u-bg-color-hover
130
+ --ft-text-color → --u-txt-color
131
+ --ft-border-color → --u-border-color
132
+ --ft-sort-…/-empty-… → --u-txt-color-weak
133
+ --ft-editor-bg → --u-input-bg-color
134
+ ```
135
+
136
+ ⚠**의존성이 늘지 않는다.** CSS 커스텀 프로퍼티 참조는 `import` 를 만들지 않는다 —
137
+ `package.json` 은 그대로다.
138
+
139
+ ⚠**시트 없는 독립 사용은 종전과 같다.** 모든 참조가 리터럴 폴백을 갖고 다크 블록도
140
+ 남아 있어, 토큰 시트를 로드하지 않으면 예전 색·예전 자동 다크로 렌더된다.
141
+ 회귀 테스트가 이 둘을 함께 지킨다.
142
+
143
+ **소비자 영향**: 토큰 시트를 쓰는 앱에서는 **표 색이 바뀐다** — Google 계열
144
+ (`#1a73e8` 등)에서 디자인 시스템 팔레트로 이동한다. 종전 색을 유지하려면 `--ft-*` 를
145
+ 직접 지정하면 된다(그 경로는 그대로다).
146
+
147
+ ### Fixed
148
+
149
+ - **상태 색이 규칙 안에 박혀 있어 덮을 수 없고 테마를 몰랐다** — 무효 셀, 드롭 표시,
150
+ 찾기 강조가 리터럴이라 다크에서도 라이트 값 그대로였다. `--ft-invalid-*`·`--ft-drop-*`·
151
+ `--ft-find-*` 로 열고 상태 색에서 알파를 뽑는다.
152
+
153
+ ★**면 토큰이 아니라 알파 파생인 이유**: 이 배경들은 불투명 면이 아니라 **겹침**이다 —
154
+ 줄무늬(홀/짝 행)와 선택 표시가 아래에서 비쳐야 "어느 행의 어떤 셀"인지 읽힌다.
155
+ 부수 효과로 두 테마 모두에서 성립한다.
156
+
157
+ - **댓글 입력 포커스 링이 팔레트에 없는 색이었다**(`rgba(59,130,246,.2)` — Tailwind
158
+ blue-500). 바로 옆 줄의 테두리는 `--ft-active-color` 를 쓰고 있어 **두 색이 서로 달랐다.**
159
+
160
+ ## [0.21.1] - 2026-08-02
161
+
162
+ ### Fixed
163
+
164
+ - **빈 셀 문구가 라이트 테마에서 WCAG AA 에 미달하던 문제.** `--ft-empty-color` 가 `#999`
165
+ 로 흰 바탕 대비 **2.85** 였다(AA 기준 4.5). 정렬 표시와 같은 회색인 `#5f6368`(**6.05**)로
166
+ 맞췄다 — 팔레트를 한 계열로 유지한다.
167
+
168
+ 다크 값(`#9aa0a6` on `#1e1e2e` = 6.31)은 원래 정상이었으므로 손대지 않았다.
169
+ **라이트 한쪽만의 결함**이었다.
170
+
171
+ ### Known issues
172
+
173
+ - `--ft-border-color` 가 바탕 대비 **1.32**(라이트) · **1.59**(다크)로 WCAG 1.4.11(3.0)에
174
+ 미달한다. 표 격자선을 "UI 컴포넌트 경계"로 볼지가 판단을 요구하고, 값을 올리면 표의
175
+ 시각 무게가 크게 바뀌므로 이번에 손대지 않았다. 나머지 조합(본문·헤더·선택행·호버행·
176
+ 활성색·불리언 표시)은 두 테마 모두 통과한다.
177
+
178
+ ## [0.21.0] - 2026-07-17
179
+
180
+ ### Fixed
181
+ - `useODataSource`: 검색어를 인용 없이 `$search`로 전송해 **숫자·하이픈이 포함된 검색어가 전부 400**으로 거부되던 결함 수정. 이제 공백으로 나눈 토큰을 각각 인용된 phrase로 감싸 `AND`로 결합해 전송한다 (`red shirt` → `$search="red" AND "shirt"`). 실사용에서 관측(상품코드·주문번호·연도처럼 숫자·하이픈을 포함한 검색이 전부 무응답).
182
+ - **원인은 문법 제약이 아니라 버전 스큐**: OData 4.0의 `searchWord`는 문자(Unicode L/Nl)만 허용하나, 4.01은 `searchChar`(`unreserved` 포함 — 숫자·`-`·`.`·`_`·`~`)로 완화했다. Microsoft.OData 렉서가 아직 4.0 규칙이라 `2026`·`ZT-E2E-A`를 거부한다([odata.net#2445](https://github.com/OData/odata.net/issues/2445), OPEN). `searchPhrase`는 4.0·4.01 양쪽에서 적법해 서버 버전과 무관하게 안전하다.
183
+ - **통째가 아니라 토큰별로 감싸는 이유**: 인용 없는 다중 단어는 암묵 AND로 파싱된다(`searchAndExpr = RWS [ 'AND' RWS ] searchExpr`). 전체를 한 phrase로 감싸면 연속 문자열 매칭으로 의미가 바뀌므로, 토큰별 인용이 기존 의미론을 보존한다.
184
+ - `"`는 phrase에 담을 수 없고 OData가 이스케이프를 정의하지 않아 검색어에서 제거한다. 공백뿐인 검색어는 `$search`를 붙이지 않는다.
185
+ - **거동 변경 주의**: 단일 토큰도 word에서 phrase로 바뀐다. `$search`의 매칭 정의는 스펙상 implementation-specific이라 서버에 따라 결과가 달라질 수 있어 patch가 아닌 minor로 올린다.
186
+ - `eslint.config.js`에 `eslint-plugin-react-hooks`가 등록된 적이 없는데 `use-odata-source.ts`가 `react-hooks/exhaustive-deps` disable 지시자를 사용해 **`npm run lint`가 계속 exit 1**이던 결함 수정. 존재하지 않는 규칙을 가리키는 고아 지시자를 제거하고 deps가 부분집합인 이유는 산문 주석으로 보존했다.
187
+
188
+ ### Added
189
+ - `src/odata/` 단위 테스트 신설(11건) — 이 디렉터리는 테스트가 전무했고, 그것이 위 `$search` 결함이 배포된 원인이다. `$search` 쿼리 문자열을 `odata-query` 통합까지 포함해 검증한다.
190
+
191
+ ### Documentation
192
+ - README `OData Source Hook`: **반환값 표 신설**. 기존엔 옵션만 문서화되어 `setSearch`·`error` 등 반환 필드의 계약을 알 수 없었다. `error`는 렌더하지 않으면 실패한 요청이 그리드를 조용히 비운다는 점을 명시.
193
+ - README `Search semantics` 신설: `setSearch`가 OData 검색 표현식이 아닌 **리터럴 텍스트**를 받는다는 계약과 인용 근거를 문서화.
194
+
195
+ ## [0.20.1] - 2026-07-03
196
+
197
+ ### Fixed
198
+ - `FlexTable`: `clearSelectionOnDataChange` 활성화 시 React 래퍼(`FlexTableReact`, `@lit/react`) 경유하면 체크박스 행 선택 자체가 불가능하던 결함 수정. `@lit/react`가 dirty-check 없이 매 렌더마다 `.data`를 재대입하는데, `set data()`가 참조 동일성 비교 없이 무조건 `deselectAll()`을 호출해 "선택 → setState → 리렌더 → data 재대입 → 선택 해제" 루프가 발생했다. 이제 `set data()`는 참조가 실제로 바뀐(외부 교체) 경우에만 선택 해제/undo 클리어 side-effect를 실행한다(`clearUndoOnDataChange`도 동일 가드 적용). 동일 참조 재대입에도 `hasChanged: () => true`에 의한 in-place 리렌더는 유지된다. 실사용에서 관측(기존 우회: `gridKey` remount).
199
+
200
+ ## [0.20.0] - 2026-07-02
201
+
202
+ ### Added
203
+ - `FlexTable`/`FlexTableReact`: `loading?: boolean` prop 추가. `true`일 때 그리드 위에 내장 오버레이를 표시하고 host에 `aria-busy="true"`를 반영한다. `useODataSource()`가 반환하는 `loading`과 자연 연동(`<FlexTableReact loading={source.loading} .../>`). 이전에는 각 소비 페이지가 `style={{opacity: loading ? 0.6 : 1}}` 같은 인라인 opacity 해킹으로 우회하고 있었다.
204
+
205
+ ## [0.19.1] - 2026-07-02
206
+
207
+ ### Documentation
208
+ - README: `format` vs `renderer` 가이드 추가 — `ColumnDefinition.format`이 인터페이스 표에서 누락되어 있었고, 두 옵션의 차이(원본 값 유지 vs 렌더 전체 대체)와 우선순위(`renderer` > `format`)가 문서화되어 있지 않았음
209
+ - README: React `ref` 명령형 API 사용 예시 추가 — `FlexTableReact`가 `ref`를 내부 `FlexTable` 엘리먼트로 포워딩해 `addRow`/`deleteRows`/`selectAll` 등 [Methods](#methods)를 리렌더 없이 호출 가능함을 명시
210
+
211
+ ## [0.19.0] - 2026-07-02
212
+
213
+ ### Added
214
+ - `useODataSource`: `fetcher`(커스텀 transport), `baseUrl`(origin override), `onUnauthorized`(401/403 콜백) 옵션 추가
215
+ - 기본값은 기존 동작(전역 `fetch` + `window.location.origin`)과 동일 — 하위 호환
216
+ - 소비 앱이 인증 헤더 주입·세션 만료 처리를 `HttpClient` 등 자체 transport로 일원화 가능 (전역 `window.fetch` 몽키패치 우회 불필요)
217
+ - `ColumnDefinition<T>`/`CellRenderer<T>`/`CellEditor<T>`/`CellValidator<T>`/`ConditionalRule<T>` 제네릭화, `FlexTableReact<T>` React 래퍼 제네릭 지원
218
+ - 기본값 `T = DataRow`로 기존(비제네릭) 사용 100% 하위 호환. `<FlexTableReact<Order> data={orders} columns={columns} />`처럼 실제 행 타입을 지정하면 `renderer`/`editor`/`validator`/`format` 콜백까지 타입 추론됨 — 소비 측 `as unknown as` 캐스트 불필요
219
+ - 내부 커스텀 엘리먼트(`FlexTable`)는 DOM 특성상 인스턴스별 제네릭이 불가능하므로 계속 `DataRow` 기반으로 동작 — 캐스트는 `FlexTableReact` 경계에서 라이브러리가 1회 수행(소비자에게는 보이지 않음)
220
+ - `clearSelectionOnDataChange` 속성(`clear-selection-on-data-change`) 추가 — 활성화 시 `data`가 외부에서 교체될 때 행 선택(체크박스)을 자동 해제하고 빈 선택으로 `selection-change`를 재발화
221
+ - 기본값 `false`(기존 `clearUndoOnDataChange`와 동일 컨벤션) — 하위 호환
222
+ - **안전 목적**: 행 선택은 인덱스 기반이라, `data`가 동일 길이의 다른 행으로 교체돼도 선택 상태가 그대로 남아 잘못된 행에 일괄 작업(상태전이/입금 등)이 적용될 위험이 있음. 선택이 벌크 액션을 구동하는 `selectable` 그리드(특히 서버 모드 + `useODataSource` 조합)에는 이 옵션 활성화를 권장
223
+
224
+ ## [0.18.0] - 2026-05-19
225
+
226
+ ### Added
227
+ - **셀 코멘트 편집 팝업**: 우클릭 컨텍스트 메뉴에서 코멘트를 직접 편집
228
+ - 코멘트 없는 셀: "Add Comment" 메뉴 항목 표시
229
+ - 코멘트 있는 셀: "Edit Comment" + "Delete Comment" 메뉴 항목 표시
230
+ - 편집 팝업: textarea + Cancel/Save 버튼
231
+ - 단축키: Ctrl+Enter 저장, Escape 취소
232
+ - 팝업 외부 클릭 시 자동 저장
233
+ - 편집 결과는 `setComment()` API와 동일하게 undo/redo 연동
234
+
235
+ ## [0.17.0] - 2026-05-19
236
+
237
+ ### Added
238
+ - **Undo/Redo 갭 보완**: 주요 API에 undo/redo 지원 추가
239
+ - `importFromFile()` undo/redo 지원 — import 전 데이터 상태로 복원 가능
240
+ - `setComment()` undo/redo 지원 — 이전 코멘트 상태로 복원 가능
241
+ - `clearComments()` undo 지원 — 전체 코멘트 복원 가능
242
+ - `hideColumn()` / `showColumn()` undo/redo 지원 — 컬럼 가시성 복원 가능
243
+ - **Ctrl+Y** Redo 단축키 (Excel/브라우저 표준)
244
+ - **공개 API**: `undo()`, `redo()`, `clearUndoHistory()` 메서드 추가
245
+ - 외부 툴바/버튼에서 직접 호출 가능
246
+ - **`clear-undo-on-data-change`** 속성 (`clearUndoOnDataChange: boolean`, 기본값: `false`)
247
+ - `true`로 설정 시 외부에서 `table.data = ...`를 통해 데이터를 교체하면 undo/redo 히스토리 자동 clear
248
+ - 내부 undo/redo 동작은 영향받지 않음
249
+
250
+ ### Internal
251
+ - `_applyComment()` 내부 메서드 분리 (undo/redo 재귀 호출 방지)
252
+ - `_inUndoRedo: boolean` 플래그로 내부 undo/redo 경로 식별 (`clearUndoOnDataChange` 연동)
253
+ - `data` 속성을 getter/setter 패턴으로 전환 (backing field `_data`, Lit reactive property 유지)
254
+ - 키보드 핸들러(Ctrl+Z/Y)가 공개 `undo()`/`redo()` 메서드를 재사용 (DRY)
255
+
256
+ ## [0.16.1] - 2026-05-19
257
+
258
+ ### Fixed
259
+ - Fill handle position offset: `_colLeftOffsets` already includes `_prefixWidth`, but `_renderFillHandle` and `_renderFillPreview` were adding it again, causing the handle to appear displaced to the right (especially noticeable with row numbers or checkbox columns enabled)
260
+
261
+ ## [0.16.0] - 2026-05-19
262
+
263
+ ### Added
264
+ - **XLSX Import**: `.xlsx` 및 `.csv` 파일을 테이블에 가져오기
265
+ - `importFromFile(file: File): Promise<void>` API
266
+ - `import-enabled` 속성으로 드래그&드롭 활성화 (파일 드롭 오버레이 포함)
267
+ - 첫 행 헤더 → 기존 컬럼 key 자동 매칭 (exact 우선, 대소문자 무관 fallback)
268
+ - 컬럼 타입에 따라 자동 형 변환 (number, boolean, text)
269
+ - `data-import` CustomEvent (`detail.count`: 가져온 행 수)
270
+ - 외부 의존성 없는 순수 TypeScript 구현 (ZIP 중앙 디렉터리 파싱, OOXML DOMParser, DEFLATE/STORE 지원)
271
+ - **셀 코멘트**: 셀 단위 메모/코멘트 부착
272
+ - `setComment(dataIndex, colKey, text|null)` API — 빈 문자열/null 전달 시 제거
273
+ - `getComment(dataIndex, colKey)` API
274
+ - `getAllComments()` — 전체 코멘트 배열 반환
275
+ - `clearComments()` — 전체 코멘트 삭제
276
+ - `comment-change` CustomEvent (`detail: { dataIndex, colKey, text }`)
277
+ - 코멘트 있는 셀 우상단에 오렌지색 삼각형 인디케이터 표시, hover 시 title tooltip
278
+
279
+ ### Internal
280
+ - `src/export/xlsx-reader.ts`: ZIP 리더 + OOXML 파서 (shared strings, 셀 타입 처리, 날짜 시리얼 변환)
281
+ - `_comments: Map<number, Map<string, string>>` 내부 저장소 (dataIndex → colKey → text)
282
+ - `_applyImportedSheet`, `_applyImportedRows`, `_buildHeaderColumnMap` 내부 메서드
283
+ - `_onDragover`, `_onDragleave`, `_onDrop` 드래그&드롭 핸들러
284
+ - `.ft-import-overlay`, `.ft-has-comment`, `.ft-comment-indicator` 스타일 추가
285
+
286
+ ## [0.15.0] - 2026-05-19
287
+
288
+ ### Added
289
+ - **고급 필터 — 텍스트 모드**: 필터 드롭다운에 모드 셀렉터 추가 (`contains` / `starts with` / `ends with` / `wildcard`). 와일드카드는 `*`(임의 문자열), `?`(단일 문자) 지원
290
+ - **고급 필터 — 빈 셀 필터**: 모든 컬럼 타입 (text/number/date/boolean)에 "Empty only" / "Non-empty only" 옵션 추가. 텍스트 입력 시 자동 해제
291
+ - **고급 필터 — 숫자 2조건 AND/OR**: 숫자 필터가 `=`, `≠`, `>`, `<`, `≥`, `≤` 연산자 선택 + 2개 조건 AND/OR 결합으로 대체. 단일 조건만 설정해도 동작
292
+ - **행 고정 (`frozen-rows`)**: `frozenRows: number` 속성으로 상단 N행 고정. 세로 스크롤 중 항상 표시. 편집 가능, 핀 컬럼과 올바르게 교차 렌더링, `position: sticky` 기반
293
+
294
+ ### Changed
295
+ - 숫자 필터 UI: 기존 Min/Max 범위 입력 → 연산자 선택 + 2조건 AND/OR UI로 교체
296
+ - 필터 드롭다운 최소 너비 160px → 200px
297
+
298
+ ### Internal
299
+ - `TextFilterMode` 타입 추가 (`contains` | `starts` | `ends` | `wildcard`)
300
+ - `NumericOp`, `NumCondition`, `NumberAdvState` 타입 추가
301
+ - `_buildTextPredicate`, `_buildNumberPredicate`, `_buildDatePredicate`, `_buildEmptyPredicate` predicate 빌더 메서드 추가
302
+ - `_applyFilterForKey`: 필터 재적용 단일 진입점으로 리팩터링
303
+ - `_frozenRowCount`, `frozenRowsHeight` getter 추가
304
+ - `_renderFrozenRows`: sticky 컨테이너에 frozen rows 렌더링
305
+
306
+ ## [0.14.0] - 2026-05-19
307
+
308
+ ### Added
309
+ - **내장 컨텍스트 메뉴 (`show-context-menu`)**: 셀 우클릭 시 기본 메뉴 표시 (복사, 행 삽입·삭제, 컬럼 숨기기, 정렬, 필터)
310
+ - `context-menu` 이벤트에서 `preventDefault()` 호출 시 내장 메뉴 억제
311
+ - 화면 경계 자동 위치 보정
312
+ - **XLSX Export**: `exportToFile('xlsx', ...)` / `exportToString('xlsx')` 지원
313
+ - 외부 의존성 없는 순수 TypeScript 구현 (ZIP STORE + OOXML)
314
+ - 헤더 행 포함, 숫자/날짜/불리언 셀 타입 지원, 헤더 bold 스타일
315
+
316
+ ### Changed
317
+ - `ExportFormat`에 `'xlsx'` 추가
318
+ - `exportToString` 반환 타입: `string | Uint8Array` (xlsx는 Uint8Array)
319
+ - `context-menu` CustomEvent가 이제 `cancelable: true`
320
+
321
+ ---
322
+
323
+ ## [0.13.0] - 2026-05-19
324
+
325
+ ### Added
326
+ - **셀 표시 형식 (`format`)**: `ColumnDefinition.format`에 형식 문자열(`'#,##0.00'`, `'0.00%'`, `'$#,##0'`, `'yyyy-MM-dd'` 등) 또는 커스텀 함수 지정. 편집/클립보드에는 raw value 유지
327
+ - **조건부 서식 (`conditionalRules`)**: `ColumnDefinition.conditionalRules`에 `{ when, style }` 규칙 배열 지정. 조건 true 시 background/color/fontWeight/fontStyle 인라인 스타일 적용. 다중 규칙 병합
328
+ - **자동완성 편집기 (`autocomplete`)**: `ColumnDefinition.autocomplete: true | 'strict'`. 텍스트 편집 시 기존 컬럼 값 기반 드롭다운 제안. Arrow Down/Up으로 탐색, Enter로 선택. `'strict'` 모드는 목록 외 값 거부
329
+ - **컬럼 숨기기/표시 UI**: 헤더 우클릭 → 내장 컨텍스트 메뉴 (Hide column / Show 숨긴 열). 숨겨진 열 인접 인디케이터 버튼. `hideColumn(key)` / `showColumn(key)` / `getHiddenColumns()` API
330
+
331
+ ### Changed
332
+ - `ColumnDefinition`에 `format`, `conditionalRules`, `autocomplete` 필드 추가
333
+ - 새 공개 타입: `CellStyle`, `ConditionalRule`
334
+ - 새 이벤트: `header-context-menu`, `column-visibility-change`
335
+
336
+ ---
337
+
338
+ ## [0.12.0] - 2026-05-19
339
+
340
+ ### Added
341
+ - **비연속 다중 선택 (Ctrl+Click)**: Ctrl+Click으로 떨어진 셀들 추가/제거 토글. 선택된 비연속 셀 Delete 시 일괄 클리어 (단일 undo)
342
+ - **컬럼 드래그 이동 UI**: 헤더 셀 드래그로 열 순서 변경. ghost + 드롭 인디케이터 표시. 리사이즈 핸들과 드래그 영역 분리
343
+ - **드롭다운 편집기 (`type: 'select'`)**: `options: string[] | { label, value }[]` 로 셀 편집 시 `<select>` 편집기 표시. 미편집 시 label 표시
344
+ - **찾기/바꾸기 (Ctrl+F / Ctrl+H)**: 찾기 패널 + 바꾸기 패널 오버레이. 다음/이전 이동, 단건/모두 바꾸기 (모두 바꾸기는 단일 undo). `find-replace` 이벤트
345
+ - **행 드래그 정렬**: 행 번호 셀 드래그로 행 순서 변경. ghost + 수평 인디케이터. undo/redo + `row-reorder` 이벤트
346
+ - **Fill Handle**: 선택 범위 우하단 8px 핸들 드래그로 값 복제/시리즈 채우기. 숫자 등차수열 자동 감지. undo/redo + `fill-handle-apply` 이벤트
347
+ - Ctrl+Z/Y 키가 active cell 없이도 동작하도록 개선 (전역 처리)
348
+
349
+ ### Changed
350
+ - `ColumnDefinition`에 `options?: string[] | SelectOption[]` 필드 추가
351
+ - `ColumnType`에 `'select'` 추가
352
+
353
+ ---
354
+
355
+ ## [0.11.0] - 2026-05-18
356
+
357
+ ### Added
358
+ - Mouse drag range selection: mousedown + mouseenter로 셀 범위 드래그 확장
359
+ - Fill Down (Ctrl+D): 선택 범위 첫 행 값을 아래 행에 채우기. 단일 셀 시 위 셀 값 복사
360
+ - Fill Right (Ctrl+R): 선택 범위 첫 열 값을 오른쪽 열에 채우기. 단일 셀 시 왼쪽 셀 값 복사
361
+ - 모든 Fill 동작은 undo/redo 지원
362
+
363
+ ---
364
+
365
+ ## [0.10.0] - 2026-03-31
366
+
367
+ ### Added
368
+ - React wrapper via `@iyulab/flex-table/react` subpath export
369
+ - `FlexTableReact` component wraps `<flex-table>` for idiomatic React usage
370
+ - All 23 custom events mapped to React callback props (onCellSelect, onSortChange, etc.)
371
+ - `react` and `@lit/react` as optional peer dependencies
372
+
373
+ ### Changed
374
+ - Vite build now produces multi-entry output (flex-table + react)
375
+
376
+ ## [0.9.0] - 2026-03-31
377
+
378
+ ### Added
379
+ - `pinned: 'right'` support for right-side fixed columns during horizontal scroll
380
+ - Scroll-only update optimization: `_recomputeView()` skipped during pure scroll events (100K+ row performance)
381
+ - `_getPinnedRight()` method for calculating right-pinned column offsets
382
+
383
+ ### Changed
384
+ - `willUpdate()` uses `changedProperties` analysis to skip unnecessary filter/sort recomputation
385
+ - `ColumnDefinition.pinned` type extended: `'left' | 'right'`
386
+ - Pinned column rendering unified for header, body, and footer cells
387
+
388
+ ## [0.8.0] - 2026-03-31
389
+
390
+ ### Added
391
+ - ESLint configuration (`@typescript-eslint` + `eslint-plugin-lit`, flat config)
392
+ - `lint` and `lint:fix` npm scripts
393
+ - 5 API coverage tests (getColumnWidth, activeCell, editingCell, sortCriteria, filterKeys)
394
+ - `minWidth` enforcement in cell rendering (not just resize)
395
+
396
+ ### Changed
397
+ - `_onKeyDown` refactored: split into `_handleCtrlKey`, `_handleAltKey`, `_handleNavigation`
398
+ - `_handlePaste` refactored: split into `_readClipboardText`, `_expandRowsForPaste`, `_applyPasteData`
399
+ - `_getColWidth` now enforces `minWidth` floor on all rendered cells
400
+
401
+ ## [0.7.0] - 2026-03-31
402
+
403
+ ### Added
404
+ - Date/datetime filter UI with native date range picker (from/to inputs)
405
+ - Column selection via `selectColumn(colIndex)` API and Ctrl+Click on header
406
+ - `column-select` event with column index, key, and row count detail
407
+ - Keyboard column resize with Alt+ArrowLeft/Right (±20px per keystroke)
408
+ - Validation visual feedback: red border + `aria-invalid` on cells that fail validator (auto-clears after 3s)
409
+ - Filter UI state persistence: text, number, and date filter inputs retain values when dropdown reopens
410
+
411
+ ### Fixed
412
+ - Filter dropdown clipped at viewport bottom now flips upward (boundary detection)
413
+ - Number filter inputs now reflect `_numberFilterState` via `.value` binding (API↔UI sync)
414
+ - Text filter inputs now track state across open/close cycles
415
+
416
+ ## [0.6.3] - 2026-03-31
417
+
418
+ ### Fixed
419
+ - Pinned column rendered one row below due to block-level stacking of `position: sticky` elements
420
+ - Header pinned/prefix cells not visible on vertical scroll (nested `position: sticky` paint issue in Chrome)
421
+ - Whitespace gap between row-number and pinned columns caused by inline-flex layout hack
422
+ - Unified all prefix/pinned cell positioning to `position: absolute` with `scrollLeft` compensation across header, body, and footer
423
+
424
+ ### Added
425
+ - GitHub Actions CI/CD: npm publish on release, GitHub Pages demo deployment
426
+ - `build:demo` script and `vite.config.demo.ts` for standalone demo build
427
+ - npm version existence check in publish workflow (idempotent deploys)
428
+
429
+ ### Changed
430
+ - `.ft-header` z-index raised from 2 to 3 to ensure header paints above body sticky cells
431
+
432
+ ## [0.6.0] - 2026-02-20
433
+
434
+ ### Added
435
+ - Horizontal virtual scrolling: only columns visible in the viewport (+ 5 overscan) are rendered to DOM
436
+ - Constant DOM footprint regardless of column count (50, 100, or more columns)
437
+ - `data-col-index` attribute on cells for reliable column identification
438
+ - Demo: 100-column horizontal virtual scroll test section
439
+
440
+ ### Changed
441
+ - Row/cell layout changed from CSS Grid to absolute positioning for selective column rendering
442
+ - Auto-fit resize and context menu now use `data-col-index` instead of DOM position
443
+ - `_scrollToActiveCell` uses cached column offsets instead of manual recomputation
444
+
445
+ ### Fixed
446
+ - Filter predicate error handling wraps predicates in try-catch (fail-open)
447
+ - Data mutation reactivity: `hasChanged: () => true` on data property, public `refreshData()` method
448
+
449
+ ## [0.5.0] - 2026-02-19
450
+
451
+ ### Added
452
+ - Row selection via checkbox (`selectable` property, `selection-mode` attribute)
453
+ - `selectAll()`, `deselectAll()`, `getSelectedRows()` public API
454
+ - `selection-change` event with `{ selectedIndices, selectedRows }` detail
455
+ - Footer/summary row support (`footer-data` property)
456
+ - Data mode: `dataMode` property (`'client'` / `'server'`)
457
+ - Context menu event: `context-menu` with position, row data, and column info
458
+
459
+ ## [0.4.0] - 2026-02-19
460
+
461
+ ### Added
462
+ - `aria-selected` on all cells (`"true"` / `"false"`) per WAI-ARIA grid pattern
463
+ - `aria-readonly="true"` on non-editable cells (global `editable` or per-column `editable`)
464
+ - `aria-label` and `aria-expanded` on filter buttons for screen reader support
465
+ - Editor focus outline (`outline: 2px solid`) for keyboard navigation visibility
466
+ - README: full API documentation rewrite (Properties, Methods, Events, Usage Guide)
467
+
468
+ ### Changed
469
+ - Filter button opacity `0.5` → `0.7` for improved visibility (WCAG)
470
+
471
+ ## [0.3.0] - 2026-02-19
472
+
473
+ ### Added
474
+ - `addColumn(def, index?)` method — dynamically add columns
475
+ - `deleteColumn(key)` method — remove columns with automatic filter/sort cleanup
476
+ - `moveColumn(key, newIndex)` method — reorder columns programmatically
477
+ - `updateRows(changes)` method — batch update multiple cells as single undo action
478
+ - `exportToString(format, { selectionOnly: true })` — export only selected range
479
+ - `maxUndoSize` property (`max-undo-size` attribute) — configurable undo stack size
480
+ - `showFilters` property (`show-filters` attribute) — built-in header filter dropdown UI
481
+ - `ColumnDefinition.pinned` field — freeze columns during horizontal scroll (`'left'`)
482
+ - Built-in filter UI: text search, number range (min/max), boolean toggle
483
+ - Filter active indicator — highlighted filter icon when filter is applied
484
+ - Events: `column-add`, `column-delete`, `column-reorder`, `batch-update`
485
+ - Row number column sticky positioning on horizontal scroll
486
+ - Demo: add/delete column buttons, pinned columns, built-in filter UI
487
+
488
+ ## [0.2.0] - 2026-02-19
489
+
490
+ ### Added
491
+ - `theme` property with `reflect: true` — programmatic theme switching (`table.theme = 'dark'`)
492
+ - `editable` property — global read-only mode (`table.editable = false`)
493
+ - `ColumnDefinition.editable` field — per-column editing control
494
+ - `maxRows` property — cap row additions and paste auto-expansion
495
+ - `canUndo` / `canRedo` public getters
496
+ - `undo-state-change` event with `{ canUndo, canRedo }` detail
497
+ - `cell-edit-start` event with `{ row, col, key, value }` detail
498
+ - `clipboard-error` event on clipboard API failure
499
+ - `getColumnWidth(key)` method — query internal resize widths
500
+ - RFC 4180 compliant clipboard parser (quoted fields, embedded tabs/newlines)
501
+ - Horizontal scroll tracking in keyboard navigation
502
+ - Column auto-fit on resize handle double-click
503
+ - Demo: filter UI, add row, export CSV, undo/redo status display
504
+ - `typecheck` and `test:coverage` npm scripts
505
+
506
+ ### Fixed
507
+ - `aria-sort` no longer rendered on non-sortable columns (ARIA spec compliance)
508
+ - Column resize no longer mutates original `ColumnDefinition` objects
509
+ - Date/datetime export uses ISO 8601 for `Date` objects
510
+ - Clipboard errors now dispatch events instead of being silently swallowed
511
+
512
+ ### Changed
513
+ - `addRow()` returns `DataRow | null` (returns `null` when `maxRows` reached)
514
+
515
+ ## [0.1.0] - 2026-02-19
516
+
517
+ ### Added
518
+ - Initial release
519
+ - `<flex-table>` Lit 3 web component with CSS Grid layout
520
+ - Column types: text, number, boolean, date, datetime
521
+ - Custom cell renderer via `ColumnDefinition.renderer` callback
522
+ - Virtual scroll (10K+ rows, overscan=5)
523
+ - Cell selection and keyboard navigation (Arrow, Tab, Home, End, Ctrl+Home/End)
524
+ - Range selection (Shift+Arrow, Shift+Click)
525
+ - Row selection via row number click
526
+ - Inline editing (Enter/F2, Escape, Tab/Enter commit)
527
+ - Type-specific editors (text, number, date, datetime-local, boolean toggle)
528
+ - Type-to-start editing (printable character starts edit with that character)
529
+ - Clipboard: copy (Ctrl+C), cut (Ctrl+X), paste (Ctrl+V) in TSV format
530
+ - Paste auto-expand rows beyond data bounds
531
+ - Delete/Backspace clears selected range
532
+ - Column sorting (header click asc/desc/none)
533
+ - Multi-column sorting (Shift+click)
534
+ - Sort indicators (arrow + order number)
535
+ - Filter API: `setFilter()`, `removeFilter()`, `clearFilters()`
536
+ - Row operations: `addRow()`, `deleteRows()`
537
+ - Undo/Redo (Ctrl+Z/Y, max 100 actions)
538
+ - Column resize (drag header border)
539
+ - Optional row numbers (`show-row-numbers` attribute)
540
+ - Dark/Light theme (CSS custom properties, `prefers-color-scheme` auto)
541
+ - Export: `exportToString('csv'|'tsv'|'json')`, `exportToFile()`
542
+ - ARIA: `role="grid"`, `aria-sort`, `aria-rowcount`, `aria-colcount`
543
+ - Events: cell-select, cell-edit-commit, cell-edit-cancel, sort-change, filter-change, row-add, row-delete, column-resize, clipboard-copy, clipboard-cut, clipboard-paste
544
+ - 16 CSS custom properties for theming
545
+ - README with full API documentation
546
+
547
+ [unreleased]: https://github.com/iyulab/flex-table/compare/v0.10.0...HEAD
548
+ [0.10.0]: https://github.com/iyulab/flex-table/compare/v0.9.0...v0.10.0
549
+ [0.9.0]: https://github.com/iyulab/flex-table/compare/v0.8.0...v0.9.0
550
+ [0.8.0]: https://github.com/iyulab/flex-table/compare/v0.7.0...v0.8.0
551
+ [0.7.0]: https://github.com/iyulab/flex-table/compare/v0.6.3...v0.7.0
552
+ [0.6.3]: https://github.com/iyulab/flex-table/compare/v0.6.0...v0.6.3
553
+ [0.6.0]: https://github.com/iyulab/flex-table/compare/v0.5.0...v0.6.0
554
+ [0.5.0]: https://github.com/iyulab/flex-table/compare/v0.4.0...v0.5.0
555
+ [0.4.0]: https://github.com/iyulab/flex-table/compare/v0.3.0...v0.4.0
556
+ [0.3.0]: https://github.com/iyulab/flex-table/compare/v0.2.0...v0.3.0
557
+ [0.2.0]: https://github.com/iyulab/flex-table/compare/v0.1.0...v0.2.0
558
+ [0.1.0]: https://github.com/iyulab/flex-table/releases/tag/v0.1.0
@@ -5,7 +5,8 @@ var s = t`
5
5
  /* --- Theme Variables (Light defaults) --- */
6
6
  :host {
7
7
  --ft-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
8
- --ft-font-size: 14px;
8
+ /* 밀도 스위치 진입점 — components 의 --u-density 를 그대로 읽는다(묶음 결정 DL-253-1). */
9
+ --ft-font-size: var(--u-density, 14px);
9
10
 
10
11
  /* --- 치수·위계 축 (기본값 = 종전 렌더값) ---
11
12
  이 표는 가상 스크롤이라 행 높이가 **JS 로 계산된다**(index * rowHeight).
@@ -29,6 +30,13 @@ var s = t`
29
30
  --ft-row-even-bg: var(--u-bg-color, #FFFFFF);
30
31
  --ft-row-odd-bg: var(--u-bg-color-raised, #FAFAFA);
31
32
  --ft-row-hover-bg: var(--u-bg-color-hover, #F5F5F5);
33
+ /* ★홀수 행은 --ft-row-odd-bg(=raised) 위에 앉는다 — 짝수 행과 같은
34
+ --ft-row-hover-bg(=전역 hover) 를 쓰면 다크에서 raised==hover 라 «올려도 아무
35
+ 일도 안 일어난다»(§D-14, L2-11-1). --u-bg-color-raised-hover 는 다크에서
36
+ color-mix 로 새로 계산되고, 라이트에서는 기존 hover 에 별칭된다(components
37
+ light.css) — 두 테마 다 늘 선언돼 있으므로 폴백 리터럴은 시트 미로드 시에만
38
+ 쓰인다(다른 토큰들과 같은 관례). */
39
+ --ft-row-odd-hover-bg: var(--u-bg-color-raised-hover, #F5F5F5);
32
40
  --ft-active-color: var(--u-primary-color, #1976D2);
33
41
  --ft-selection-bg: var(--u-primary-bg-color, #E3F2FD);
34
42
  --ft-bool-color: var(--u-primary-color, #1976D2);
@@ -72,6 +80,7 @@ var s = t`
72
80
  --ft-row-even-bg: var(--u-bg-color, #FFFFFF);
73
81
  --ft-row-odd-bg: var(--u-bg-color-raised, #FAFAFA);
74
82
  --ft-row-hover-bg: var(--u-bg-color-hover, #F5F5F5);
83
+ --ft-row-odd-hover-bg: var(--u-bg-color-raised-hover, #F5F5F5);
75
84
  --ft-active-color: var(--u-primary-color, #1976D2);
76
85
  --ft-selection-bg: var(--u-primary-bg-color, #E3F2FD);
77
86
  --ft-bool-color: var(--u-primary-color, #1976D2);
@@ -92,6 +101,7 @@ var s = t`
92
101
  --ft-row-even-bg: var(--u-bg-color, #FFFFFF);
93
102
  --ft-row-odd-bg: var(--u-bg-color-raised, #FAFAFA);
94
103
  --ft-row-hover-bg: var(--u-bg-color-hover, #F5F5F5);
104
+ --ft-row-odd-hover-bg: var(--u-bg-color-raised-hover, #F5F5F5);
95
105
  --ft-active-color: var(--u-primary-color, #1976D2);
96
106
  --ft-selection-bg: var(--u-primary-bg-color, #E3F2FD);
97
107
  --ft-bool-color: var(--u-primary-color, #1976D2);
@@ -241,7 +251,8 @@ var s = t`
241
251
 
242
252
  .ft-row-even .ft-cell { background: var(--ft-row-even-bg); }
243
253
  .ft-row-odd .ft-cell { background: var(--ft-row-odd-bg); }
244
- .ft-row:hover .ft-cell { background: var(--ft-row-hover-bg); }
254
+ .ft-row-even:hover .ft-cell { background: var(--ft-row-hover-bg); }
255
+ .ft-row-odd:hover .ft-cell { background: var(--ft-row-odd-hover-bg); }
245
256
 
246
257
  .ft-cell.ft-active {
247
258
  outline: 2px solid var(--ft-active-color);
@@ -407,7 +418,8 @@ var s = t`
407
418
  }
408
419
 
409
420
  .ft-row-odd .ft-row-num { background: var(--ft-row-odd-bg); }
410
- .ft-row:hover .ft-row-num { background: var(--ft-row-hover-bg); }
421
+ .ft-row-even:hover .ft-row-num { background: var(--ft-row-hover-bg); }
422
+ .ft-row-odd:hover .ft-row-num { background: var(--ft-row-odd-hover-bg); }
411
423
 
412
424
  .ft-row-num:hover {
413
425
  background: var(--ft-header-hover-bg);
@@ -425,7 +437,8 @@ var s = t`
425
437
 
426
438
  .ft-row-even .ft-cell.ft-pinned { background: var(--ft-row-even-bg); }
427
439
  .ft-row-odd .ft-cell.ft-pinned { background: var(--ft-row-odd-bg); }
428
- .ft-row:hover .ft-cell.ft-pinned { background: var(--ft-row-hover-bg); }
440
+ .ft-row-even:hover .ft-cell.ft-pinned { background: var(--ft-row-hover-bg); }
441
+ .ft-row-odd:hover .ft-cell.ft-pinned { background: var(--ft-row-odd-hover-bg); }
429
442
  .ft-cell.ft-pinned.ft-selected { background: var(--ft-selection-bg) !important; }
430
443
 
431
444
  /* --- Filter UI --- */
@@ -576,7 +589,8 @@ var s = t`
576
589
  }
577
590
 
578
591
  .ft-row-odd .ft-checkbox-cell { background: var(--ft-row-odd-bg); }
579
- .ft-row:hover .ft-checkbox-cell { background: var(--ft-row-hover-bg); }
592
+ .ft-row-even:hover .ft-checkbox-cell { background: var(--ft-row-hover-bg); }
593
+ .ft-row-odd:hover .ft-checkbox-cell { background: var(--ft-row-odd-hover-bg); }
580
594
  .ft-row-selected .ft-checkbox-cell { background: var(--ft-selection-bg); }
581
595
  .ft-row-selected .ft-cell { background: var(--ft-selection-bg) !important; }
582
596
  .ft-row-selected .ft-row-num { background: var(--ft-selection-bg); }
@@ -1228,12 +1242,13 @@ function O(e) {
1228
1242
  }
1229
1243
  if (t[i] === "\"") {
1230
1244
  let e = "";
1231
- for (i++; i < a;) if (t[i] === "\"") if (i + 1 < a && t[i + 1] === "\"") e += "\"", i += 2;
1232
- else {
1233
- i++;
1234
- break;
1235
- }
1236
- else e += t[i], i++;
1245
+ for (i++; i < a;) if (t[i] === "\"") {
1246
+ if (i + 1 < a && t[i + 1] === "\"") e += "\"", i += 2;
1247
+ else {
1248
+ i++;
1249
+ break;
1250
+ }
1251
+ } else e += t[i], i++;
1237
1252
  r.push(e), i < a && t[i] === " " ? i++ : i < a && t[i] === "\n" && (n.push(r), r = [], i++);
1238
1253
  } else {
1239
1254
  let e = "";
@@ -1520,7 +1535,7 @@ async function xe(e) {
1520
1535
  };
1521
1536
  }
1522
1537
  //#endregion
1523
- //#region \0@oxc-project+runtime@0.142.0/helpers/esm/decorate.js
1538
+ //#region \0@oxc-project+runtime@0.143.0/helpers/esm/decorate.js
1524
1539
  function q(e, t, n, r) {
1525
1540
  var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
1526
1541
  if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
@@ -1,2 +1,2 @@
1
- import { a as e, i as t, n, r, t as i } from "./flex-table-D-OLUYir.js";
1
+ import { a as e, i as t, n, r, t as i } from "./flex-table-DZFtW02v.js";
2
2
  export { i as FlexTable, t as RowSelectionState, r as UndoStack, n as exportData, e as renderCell };
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./flex-table-D-OLUYir.js";
1
+ import { t as e } from "./flex-table-DZFtW02v.js";
2
2
  import t from "react";
3
3
  import { createComponent as n } from "@lit/react";
4
4
  var r = n({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/flex-table",
3
- "version": "0.23.2",
3
+ "version": "0.25.0",
4
4
  "description": "A minimalist, input-centric data grid web component",
5
5
  "type": "module",
6
6
  "main": "./dist/flex-table.js",
@@ -20,12 +20,23 @@
20
20
  "import": "./dist/odata/index.js"
21
21
  }
22
22
  },
23
+ "sideEffects": [
24
+ "./src/flex-table.ts",
25
+ "./dist/*.js"
26
+ ],
27
+ "engines": {
28
+ "node": ">=20"
29
+ },
23
30
  "files": [
24
- "dist"
31
+ "dist",
32
+ "package.json",
33
+ "README.md",
34
+ "CHANGELOG.md",
35
+ "LICENSE"
25
36
  ],
26
37
  "scripts": {
27
38
  "dev": "vite serve demo",
28
- "build": "vite build && tsc --emitDeclarationOnly",
39
+ "build": "npm run typecheck && vite build && tsc --emitDeclarationOnly",
29
40
  "build:demo": "vite build --config vite.config.demo.ts",
30
41
  "typecheck": "tsc --noEmit",
31
42
  "test": "vitest run",
@@ -56,6 +67,7 @@
56
67
  "odata-query": "^8.1.0"
57
68
  },
58
69
  "peerDependencies": {
70
+ "@iyulab/components": ">=1.24.0",
59
71
  "@lit/react": "^1.0.0",
60
72
  "react": "^18.0.0 || ^19.0.0"
61
73
  },