@threestarsoftware/tssgrid 0.0.8 → 0.0.9

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
@@ -3,6 +3,20 @@
3
3
  TssGrid の各リリースの変更点。日付は JST。形式は [Keep a Changelog](https://keepachangelog.com/ja/1.1.0/) 準拠(ゆるめ)。
4
4
  数値は特記なき限り**自社調べ**(headless Chrome / Windows 11・環境差あり)。
5
5
 
6
+ ## [0.0.9] - 2026-07-13
7
+
8
+ ### セキュリティ
9
+ - **CSV数式インジェクション対策を `toCSV`/`downloadCSV` に既定ONで追加**(コア)— セル値が `=`/`@`/`+`/`-`(およびタブ/CR)で始まる**非数値**のとき先頭に `'` を付けて無害化し、Excel/Google Sheets で開いた際に**数式として実行されない**ようにした(`=HYPERLINK(...)`・`=cmd|...`=DDE 等の CSV インジェクション/情報漏えい経路を塞ぐ)。`-100`/`-3.14` 等の**正当な数値は保全**(数値のまま)。破壊的変更を避けたい生値用途は `toCSV({ sanitizeFormula:false })` でオプトアウト可。`downloadCSV` は `toCSV` 経由で自動的に保護。外部入力(例: kintone テキスト項目)を CSV 化する全利用者に影響するため本体で対処。
10
+
11
+ ### 追加
12
+ - **行・列の飛び飛び(離散)複数選択 + 飛び飛びコピー**(コア)— 列/行ヘッダの **Ctrl+クリックで複数をトグル選択**(飛び飛びOK)、**Ctrl+Shift+クリックで範囲を追加**。素クリック=単一・Shift+クリック=連続範囲は従来どおり(=OS流の 単一/範囲/トグル が列・行とも揃う)。選択は **`grid.getSelectedColumns()` / `grid.getSelectedRows()`**(昇順・飛び飛び対応、そのモードでなければ `[]`)。ヘッダ+セルをハイライト。**飛び飛びの列/行は Ctrl+C コピー/Ctrl+X カットOK**=「選んだ列×全行」「選んだ行×全列」はきれいな長方形になり Excel にそのまま貼れる(カットは貼付先で元の列/行がクリア)。**`disjointSelect: false` で無効化**(Ctrl+クリックは単一選択に戻る)。**飛び飛び選択に対する Delete(内容クリア)・右クリック「N 列/行を削除」(構造削除、`deleteColsSet`/`deleteRowsSet`)も対応**(右クリックしても飛び飛び選択は解除されない)。**複数削除は1回のUndo/Redoでまとめて戻る/やり直す**(`_batchHistory` で N 個の構造変更を1段に合成)。既存の矩形選択エンジンには触れず、`_headerSel` が 'col'/'row' の時だけ効く軽いレイヤ(`_selCols`/`_selRows` 集合)として追加(**セル単位の離散選択・離散コピペは対象外**=Excel自身も拒否する領域)。
13
+ - **ヘッダ装飾フック `onHeaderRender(th, c)`**(コア)— 各列ヘッダ `th` の生成後に呼ばれ、**再描画のたびに自動で再実行**される。ヘッダにソートアイコン等の**要素を差し込む**用(コアはヘッダをテキストで描くため、クリックできるUIはこのフックで足す)。これを使い `examples/multisort.html` を**ソートアイコン方式に刷新**=ヘッダ右端の ▲▼ でソート(▲昇順/▼降順・点灯中を再クリックで解除・Ctrl+クリックで多段)+**ヘッダ本体クリックは列選択**(Shiftで範囲選択)=ソートと選択が別の場所で両立。優先度番号・固定スロットで列幅も不動。
14
+ - **右クリックメニューのカスタム項目に「右クリック対象」`ctx` を渡す**(コア)— `contextMenu` のカスタム項目の `name`/`disabled`/`hidden` が第2引数 `ctx` を、`callback` が `{ ctx }` を受け取れるようにした。`ctx = { on:'col'|'row'|'cell'|'corner', r, c }`=どこを右クリックしたか。例: **列ヘッダを右クリックした時だけ項目を出す**なら `hidden: (range, ctx) => ctx.on !== 'col'`。既存の1引数(`range` のみ)の書き方は後方互換でそのまま動作。`.d.ts` に `MenuContext`/`MenuItem` 型を追加。
15
+ - **多段(複数列)ソート `grid.sortByCols([{col, dir}, …])`**(コア)— 先頭を第1キーに、同値のときだけ次段で決める複数列ソート。各段は既存 `sortBy` と**同じ比較規則**(数値/文字列自動判定)を共有し、単一列ソートと並び挙動が一致。安定ソートなので全段同値の行は元の並びを保つ。空行の最下部固定・`clearSort()` での復元も従来どおり。※ヘッダクリック等の**操作UIは未添付**(コアはソートUIを持たない方針。Shift+クリック/専用ダイアログ等の体験は別途 example で示す予定)。
16
+
17
+ ### 修正・強化
18
+ - **`maxRows` の天井をすべての行増加経路に適用**(コア)— 従来はメニューの行挿入だけを止めていたが、`minSpareRows` の末尾自動空行と、フィルハンドルを下端外へドロップした際の行自動追加(`fillHandle.autoInsertRow`)も `maxRows` を超えないよう頭打ちにした。`maxRows` を「これ以上増やせない上限」として素直に使える。`minCols`/`maxCols`(列の下限/上限)も含め、上限・下限の挙動を確認済み。
19
+
6
20
  ## [0.0.8] - 2026-07-12
7
21
 
8
22
  ### 追加
package/README.md CHANGED
@@ -152,7 +152,7 @@ grid.downloadCSV('在庫.csv'); // → UTF-8 BOM付きで即ダウンロード
152
152
  // JSON出力は専用APIなし= JSON.stringify(grid.getRows()) で足ります(JSONは標準、CSVは非標準なので内蔵)
153
153
  ```
154
154
 
155
- - **CSV出力**: `toCSV(opts)` / `downloadCSV(filename, opts)`。`opts`: `headers`(既定true) / `formatted`(既定false=素の値で数値はそのまま, trueで表示形 `¥1,234`) / `skipEmpty`(既定true=空行除外) / `eol`(既定 `'\r\n'`)。`"`/カンマ/改行を含むセルは自動でクォート。**CSV入力(読込)は非内蔵**=Excelからの貼り付けで取り込めるため(パースが必要なら PapaParse 等を)。
155
+ - **CSV出力**: `toCSV(opts)` / `downloadCSV(filename, opts)`。`opts`: `headers`(既定true) / `formatted`(既定false=素の値で数値はそのまま, trueで表示形 `¥1,234`) / `skipEmpty`(既定true=空行除外) / `eol`(既定 `'\r\n'`) / `sanitizeFormula`(既定true)。`"`/カンマ/改行を含むセルは自動でクォート。**CSV数式インジェクション対策も既定ON**=`=`/`@`/`+`/`-` 始まりの非数値セルを `'` で無害化(Excel/Sheetsで式として実行されない。`-100` 等の数値は保全)。生値が要るなら `toCSV({sanitizeFormula:false})`。**CSV入力(読込)は非内蔵**=Excelからの貼り付けで取り込めるため(パースが必要なら PapaParse 等を)。
156
156
  - **Excel(xlsx)出力**: コア非搭載(zipバイナリで重いため)。`getRows()` + **ExcelJS**(MIT, CDN+SRI)でサンプル提供。数値を数値のまま・太字ヘッダ・`¥#,##0`書式・ヘッダ行固定まで付けられます → 動く例: [`examples/excel-export.html`](https://tssgrid.threestarsoftware.co.jp/examples/excel-export.html)。
157
157
  - **Excel(xlsx)読込**: 同じく ExcelJS でサンプル提供。**データ(セルの値)のみ**取り込み(書式・数式は無視=**数式は結果値**、日付は ISO)。1行目を見出し、2行目以降を `setData` に → 動く例: [`examples/excel-import.html`](https://tssgrid.threestarsoftware.co.jp/examples/excel-import.html)(外部ファイル不要の「生成→読込」round-trip 付き)。CSV と違い ExcelJS がパースを担うので自前実装は不要。
158
158
  - **CSV読込**: コア非搭載(簡単な取り込みは Excel からの貼り付けで足りるため)。**PapaParse**(MIT, CDN+SRI)でサンプル提供。素朴な `split(',')` では壊れる**クォート内カンマ・改行・`""` エスケープ**(RFC4180)を正しく解き、**文字コード指定**(Excel の **Shift_JIS** な `.csv` も読める)・**大容量のストリーミング/Worker**まで対応。1行目を見出し、2行目以降を `setData` に → 動く例: [`examples/csv-import.html`](https://tssgrid.threestarsoftware.co.jp/examples/csv-import.html)(クォート/改行入りの「生成→読込」round-trip + ファイル D&D・文字コード切替付き)。
@@ -199,9 +199,14 @@ grid.setCellReadOnly(false, { r0: 1, c0: 1, r1: 1, c1: 1 }); // 解除
199
199
  ```js
200
200
  grid.sortBy('数量', 'asc'); // 列キー or index で並べ替え(数値っぽければ数値比較)
201
201
  grid.sortBy(2, 'desc');
202
+ grid.sortByCols([ // ★ 多段(複数列): 先頭=第1キー。同値のときだけ次段で決める
203
+ { col: '部署', dir: 'asc' },
204
+ { col: '売上', dir: 'desc' },
205
+ ]);
202
206
  grid.sortRows((a, b) => a.qty - b.qty); // 任意比較(行はオブジェクト/配列)
203
207
  ```
204
- - `sortBy`/`sortRows` は**データ実体を並べ替え**ます。整列・セル readOnly・checkbox・隠しフィールド(`_src`)は**行ごと追従**します。**Undo には積みません**(書式系と同じ割り切り)。
208
+ - `sortBy`/`sortByCols`/`sortRows` は**データ実体を並べ替え**ます。整列・セル readOnly・checkbox・隠しフィールド(`_src`)は**行ごと追従**します。**Undo には積みません**(書式系と同じ割り切り)。
209
+ - `sortByCols` の各段は `sortBy` と**同じ比較規則**(数値/文字列自動判定)。安定ソートなので、全段が同値の行は**元の並びを保ちます**。**多段ソートのヘッダUI(▲▼アイコン+優先度番号・本体クリックで列選択と両立)**は `onHeaderRender` を使った → 動く例: [`examples/multisort.html`](https://tssgrid.threestarsoftware.co.jp/examples/multisort.html)。
205
210
  - **未入力(空)行はソート対象外**=元の順序のまま**最下部に固定**(`minSpareRows` の追加用行が上に来ない)。
206
211
  - `clearSort()` で**初期状態(入力順)に戻せます**(`isSorted()` で判定)。行参照ベースなので**編集してもズレず**、ソート後に追加した行は末尾へ、削除済みは無視。
207
212
 
@@ -768,8 +773,8 @@ new TssGrid(el, { hiddenColumns: [1] }); // 初期で隠す
768
773
  | `copyPaste` | `boolean` | `true` | `false` でコピー/カット/ペーストを無効化 |
769
774
  | `minSpareRows` | `number` | `0` | 末尾に常に確保する空行数(Excel風に下へ打ち足せる) |
770
775
  | `autoWrapRow` / `autoWrapCol` | `boolean` | `false` | Tab で行末→次行頭 / Enter で列末→次列頭に折り返し |
771
- | `minRows` / `maxRows` | `number` | — | 行数の下限/上限(min は初期パディング、削除の床。max は挿入の天井) |
772
- | `minCols` / `maxCols` | `number` | — | 列数の下限/上限 |
776
+ | `minRows` / `maxRows` | `number` | — | 行数の下限/上限(min は初期パディング、削除の床。max は天井=挿入・`minSpareRows` の空行・フィルハンドルの自動追加すべてを打ち止める) |
777
+ | `minCols` / `maxCols` | `number` | — | 列数の下限/上限(max は挿入の天井) |
773
778
  | `readOnly` | `boolean` | `false` | **グリッド全体**を読み取り専用に(ビューア用途) |
774
779
  | `columns[c].readOnly` | `boolean \| (value,{r,c})=>boolean` | — | **列単位**の読み取り専用。関数を渡すとセル単位で判定(→ [読み取り専用](#読み取り専用readonly)) |
775
780
  | `onChange` | `(grid)=>void` | — | データ変更時に呼ばれる(後方互換) |
@@ -786,6 +791,8 @@ new TssGrid(el, { hiddenColumns: [1] }); // 初期で隠す
786
791
  | `onBeforeSelectionChange` | `({range,active,extent})=>false\|void` | — | 選択変更の前。`false` で中止 |
787
792
  | `onBeforeKeyDown` | `(e)=>false\|void` | — | キーをグリッドより先に。`false` / `preventDefault()` で既定を止める |
788
793
  | `onHeaderClick` | `(c, e)=>false\|void` | — | 列ヘッダのクリック。`false` で既定(列選択)を抑止(ソートUI等を外部で組む用) |
794
+ | `onHeaderRender` | `(th, c)=>void` | — | 各列ヘッダ `th` の生成後に呼ぶ(**再描画毎に自動で再実行**)。ソートアイコン等の要素差し込み用 → 動く例: [`examples/multisort.html`](https://tssgrid.threestarsoftware.co.jp/examples/multisort.html) |
795
+ | `disjointSelect` | `boolean` | `true` | Ctrl+ヘッダで**行/列を飛び飛びに複数選択**(`false` で Ctrl+クリックは単一選択に戻る)。`getSelectedColumns()`/`getSelectedRows()`・飛び飛びコピー/カットと連動 |
789
796
  | `shortcuts` | `Array` | `[]` | カスタムショートカット(→ [ショートカット / プラグイン](#ショートカット--プラグイン--破棄)) |
790
797
  | `plugins` | `Array` | `[]` | プラグイン(関数 or 登録名)。`init(grid)` で初期化 |
791
798
  | `onPasteOverflow` | `(info)=>void` | — | `pasteOverflow:'error'` で超過時。`info = { anchor:{r,c}, height, width, rows, cols, overRows, overCols }` |
@@ -1030,6 +1037,30 @@ new TssGrid(el, {
1030
1037
  - 読み取り専用セルは淡色表示(`td.tg-readonly`)。checkbox は `disabled`、dropdown は ▾ を出しません。
1031
1038
  - 検証(`validator`)とは独立。`invalidMode` に関係なく常に元の値へ戻します。
1032
1039
 
1040
+ ### セル内改行(複数行入力・multiline)
1041
+
1042
+ 列に `multiline: true` を付けると、その列だけ**セル内で改行**できます(メモ・議事録・備考など)。TssGrid の本命である**日本語 IME の直打ち(セルに来ていきなり変換入力・1文字目が落ちない)はそのまま**——編集は隠しテキストエリアで行いますが、開いてから打つのではなく**そのまま打ち始められます**(→ 動く例: [`examples/multiline.html`](https://tssgrid.threestarsoftware.co.jp/examples/multiline.html))。
1043
+
1044
+ ```js
1045
+ new TssGrid(el, {
1046
+ defaultRowHeight: 64, // 見せる行数ぶんの高さを確保(固定・自動では伸びない)
1047
+ multilineEnter: 'commit', // 既定=Excel風(Enter=確定 / Alt+Enter=改行)。'newline' でメモ帳風
1048
+ columns: [
1049
+ { data: 'task', title: '項目' },
1050
+ { data: 'memo', title: 'メモ', width: 340, multiline: true }, // ← これだけ
1051
+ ],
1052
+ data: rows,
1053
+ });
1054
+ ```
1055
+
1056
+ - **行の高さは固定**(内容で伸びない=行高一定なので**大量行・仮想スクロールでも崩れない**)。`defaultRowHeight` / `rowHeights` で見せる行数ぶんを確保し、はみ出しはクリップ。複数行セルの**右上に薄いヒント**が出て「ここは複数行」と分かります。
1057
+ - **編集を始めると箱が内容ぶん下へ伸びて全行が見えます**(浮いたオーバーレイなので**行の高さ・スクロールには不干渉**・確定で元のクランプ表示に戻る)。`multilineEditMaxLines`(既定 `10`)で頭打ち+箱内スクロール、画面端では上へフリップしてビューポートからはみ出しません。
1058
+ - **`multilineEnter`**: `'commit'`(既定・Excel風=Enter で確定 / **Alt+Enter で改行**)/ `'newline'`(メモ帳風=Enter で改行 / **Ctrl+Enter で確定**)。同一画面での混在は非対応(起動時に選ぶ)。
1059
+ - **`multilineMark`**: 右上ヒントの表示(既定 `true`)。`false` で消す。色は CSS 変数 **`--tg-ml-mark`** で列/業務ごとに変えられます。
1060
+ - **`multilineEditMaxLines`**: 編集で伸びる箱の最大行数(既定 `10`)。
1061
+ - **コピー / 貼り付け**は Excel / Sheets と往復しても崩れません(改行を含むセルは引用符付き TSV で入出力)。改行コードは内部 **LF** に統一されます(貼り付け・入力とも CRLF→LF 正規化。`setData` で渡した値のみ無改変)。
1062
+ - ネイティブの日付/時刻ピッカー(素の `type:'date'`/`'time'`)は従来どおり(別要素なので multiline と競合しません)。
1063
+
1033
1064
  ### 右クリックメニュー(行/列の挿入・削除)
1034
1065
 
1035
1066
  セルやヘッダを**右クリック**すると、行/列の挿入・削除メニューが出ます。複数行/列を選択しておけば**まとめて削除**できます。挿入・削除は **Undo/Redo に1操作で積まれ**(`Ctrl+Z` / `Ctrl+Y`)、列の挿入・削除では `frozenCols` も自動で追従します。
@@ -1073,7 +1104,8 @@ new TssGrid(el, {
1073
1104
  ```
1074
1105
 
1075
1106
  - **組込キー**: `row_above` / `row_below` / `remove_row` / `col_left` / `col_right` / `remove_col` / `copy` / `cut` / `paste` / `clear` / `undo` / `redo`、区切りは `'---------'`(ダッシュのみ)。
1076
- - **カスタム項目**: `{ name, callback, disabled?, hidden?, key?, submenu? }`。`name`/`disabled`/`hidden` は**関数**も可(引数は選択範囲 `{r0,c0,r1,c1}`)。`callback` の `this` はグリッド、引数は `{ range, key }`。
1107
+ - **カスタム項目**: `{ name, callback, disabled?, hidden?, key?, submenu? }`。`name`/`disabled`/`hidden` は**関数**も可=引数は `(range, ctx)`(`range`=選択範囲 `{r0,c0,r1,c1}`)。`callback` の `this` はグリッド、引数は `{ range, key, ctx }`。
1108
+ - **`ctx`=右クリックの対象** `{ on, r, c }`。`on` は `'col'`(列ヘッダ)/`'row'`(行ヘッダ)/`'cell'`(データセル)/`'corner'`(隅)。例: **列ヘッダを右クリックした時だけ項目を出す**なら `hidden: (range, ctx) => ctx.on !== 'col'`。
1077
1109
  - `submenu` に配列を渡すとフライアウトの**サブメニュー**になります(同じ組込キー/カスタム項目が使えます)。
1078
1110
 
1079
1111
  #### 時刻の 12時間制(AM/PM)
@@ -1103,6 +1135,7 @@ command は `{ apply(), revert(), label }`。
1103
1135
  | 矢印 | セル移動 |
1104
1136
  | Shift+矢印 / ドラッグ / Shift+クリック | 範囲選択 |
1105
1137
  | 行/列ヘッダをクリック(ドラッグ・Shift+クリックで複数) | 行・列の選択。左上の角で全選択 |
1138
+ | **列/行ヘッダを Ctrl+クリック** | 列・行を**飛び飛びに複数選択**(トグル。Ctrl+Shift で範囲を追加。`disjointSelect:false` で無効化)。選択は `grid.getSelectedColumns()` / `grid.getSelectedRows()` で取得(昇順・飛び飛び対応)。**飛び飛びの列/行は Ctrl+C コピー / Ctrl+X カットOK**(選んだ列×全行/選んだ行×全列=Excelに貼れる長方形。カットは貼付先で元の列/行がクリア)。**Delete で内容クリア・右クリック「N 列/行を削除」で構造削除**もまとめて効く |
1106
1139
  | 列ヘッダ右端 / 行ヘッダ下端をドラッグ | 列幅 / 行高のリサイズ(既定はドラッグ中に線でプレビュー→離して確定) |
1107
1140
  | `frozenCols` で左 N 列を固定 | 横スクロールしても残る(`width` で枠幅を制約してスクロール可能に) |
1108
1141
  | 文字入力 / F2 / ダブルクリック | 編集 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threestarsoftware/tssgrid",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "軽量・ノービルド・日本語IME堅牢な編集グリッド(vanilla JS / 依存なし / MIT)。Excel ライクな入力画面を <script> タグ1本で。",
5
5
  "license": "MIT",
6
6
  "author": "ThreeStarSoftware (https://www.threestarsoftware.co.jp/)",