@threestarsoftware/tssgrid 0.1.13 → 0.1.15

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.1.15] - 2026-09-30
7
+
8
+ ### 追加
9
+ - **Excel 入力ショートカットを組込**(コア・既定 ON・opt-out 可・すべて未バインドキー=追加的)— 業務入力でよく使うキーを最初から用意。**`Ctrl+;`=今日の日付** / **`Ctrl+:`=現在時刻** / **`Ctrl+D`=上のセルをコピー(fill down)** / **`Ctrl+R`=左のセルをコピー(fill right)**。`Ctrl+;`/`Ctrl+:` は**打鍵結果の文字で判定**するので **JIS の `:` 専用キーも US の `Ctrl+Shift+;` も両対応**。fill は範囲選択で一括(単一セルは上/左をコピー)、`setValue`/検証を通り **Undo 1回**・`readOnly` スキップ・**列の型に合わない値は貼付同様に弾く**。無効化は `dateShortcuts:false` / `fillShortcuts:false`(`addShortcut` で同キー登録すればそちらが優先)。
10
+ - **`todayFormat` / `nowFormat`**(コア)— `Ctrl+;` / `Ctrl+:` が**テキスト等(date/time 型でない)列**に入れる日付/時刻の形式を選べる(既定 `'YYYY-MM-DD'` / `'HH:MM'`)。文字列トークン(`YYYY`/`MM`/`DD`・`HH`/`mm`)か `(d: Date) => string`。例 `todayFormat:'YYYY/MM/DD'`。**`date`/`time` 型の列は従来どおり列の仕組み(ISO 保存+列 `format` 表示)に従う**(この設定に非依存)。
11
+
12
+ ### 変更
13
+ - README のカスタムショートカット例を `Ctrl+D`→`Alt+D` に変更(組込 `Ctrl+D`=fill down と紛れないように・機能変更なし)。
14
+
15
+ ## [0.1.14] - 2026-09-29
16
+
17
+ ### 修正
18
+ - **カスタムエディタの ▾ アイコンをネイティブ `type:'dropdown'` と同じ SVG キャレットに統一**(コア・CSS のみ・挙動不変)— `editor.icon:'▾'`(`tss-combo` / `tss-autocomplete` 等)は従来 `tg-haspicker` の**文字グリフ**で描かれ、`tg-dropdown` の**SVG シェブロン**と字形・余白(20px vs 18px)が食い違っていた。`data-ico="▾"` のときだけネイティブ dropdown と同一の SVG(11×8・`#7d8a99`・`padding-right:18px`)に差し替えて統一。絵文字系アイコン(`📅`/`🕐` 等)は対象外。※開いたリスト自体は、ネイティブ dropdown が OS 描画の `<select>`(CSS 装飾不可)・combo 等は自前ポップアップ(角丸/影/アクセント色)で、**見た目差はあえて残す**(「その他」入力を持つ合図・combo 側は `.tg-combo*`/`--tg-accent` で調整可)。
19
+
6
20
  ## [0.1.13] - 2026-09-24
7
21
 
8
22
  ### 追加
package/README.md CHANGED
@@ -392,7 +392,7 @@ shared.getMaster(); // マスタ全行(getRows 形式
392
392
  ```js
393
393
  new TssGrid(el, {
394
394
  shortcuts: [
395
- { keys: 'Ctrl+D', name: 'dup', context: 'grid', handler: (e, { grid }) => grid.insertRow(grid.active.r, 'below') },
395
+ { keys: 'Alt+D', name: 'dup', context: 'grid', handler: (e, { grid }) => grid.insertRow(grid.active.r, 'below') },
396
396
  { keys: ['Ctrl+S', 'Ctrl+Shift+S'], handler: () => save() }, // 複数キー可
397
397
  ],
398
398
  });
@@ -402,6 +402,19 @@ grid.removeShortcut('dup');
402
402
  - マッチすると既定動作を抑止します(`handler` が `true` を返すと既定も続行)。`cmd`/`meta` は `Ctrl` 扱い。
403
403
  - 全キーをまとめて捌きたいなら **`onBeforeKeyDown(e)`**(`false` / `preventDefault()` でグリッド既定を止める)。
404
404
 
405
+ **組込ショートカット(Excel 互換・既定 ON)**: 業務入力でよく使うキーを最初から用意(すべて未バインドキー=追加的)。
406
+
407
+ | キー | 動作 | 備考 |
408
+ |---|---|---|
409
+ | `Ctrl+;` | **今日の日付**(`YYYY-MM-DD`)をセルへ | `date` 列にそのまま入る |
410
+ | `Ctrl+:` | **現在時刻**(`HH:MM`)をセルへ | **JIS の `:` 専用キーも US の `Ctrl+Shift+;` も両対応**(打鍵結果の文字で判定) |
411
+ | `Ctrl+D` | **上のセルをコピー**(fill down)| 範囲選択なら先頭行を下へ一括 |
412
+ | `Ctrl+R` | **左のセルをコピー**(fill right)| 範囲選択なら左端列を右へ一括 |
413
+
414
+ - いずれも `setValue`/検証を通り **Undo 1回**で戻せます(fill は**列の型に合わない値は貼り付けと同様に弾かれます**)。`readOnly` セルはスキップ。
415
+ - 無効化: `dateShortcuts: false`(`Ctrl+;`/`Ctrl+:`)・`fillShortcuts: false`(`Ctrl+D`/`Ctrl+R`)。独自に `addShortcut` で同じキーを登録すれば**そちらが優先**されます。
416
+ - **入れる形式**: `date`/`time` 型の列は**列の仕組みに従う**(ISO 保存=`YYYY-MM-DD`/`HH:MM`、見た目は列の `format` で `/` でも自由)。**それ以外(テキスト等)の列は** `todayFormat` / `nowFormat` で形式を選べます(既定 `'YYYY-MM-DD'` / `'HH:MM'`。トークン `YYYY`/`MM`/`DD`・`HH`/`mm`、または `(d: Date) => string`)。例: `todayFormat: 'YYYY/MM/DD'`(スラッシュ区切り)。
417
+
405
418
  **プラグイン**(軽量 base-plugin 相当。`init(grid)→{destroy?}` の薄い契約):
406
419
 
407
420
  ```js
@@ -681,6 +694,7 @@ columns: [
681
694
  - 値列にエディタを付け、`codeField` で**別のコード列へ code を書き戻す**(`setValueRaw`=派生値・`readOnly` 列にも書ける)。`options` は `{code,label}` か文字列配列(code=label)。既存の「その他」値(選択肢に無い値)は開くと**入力欄に復元**。
682
695
  - undo/redo・貼付で code を値に追従させたい時は `TssCombo.codeOf({options, other})` を `onAfterChange` に噛ませる(任意)。
683
696
  - 見た目は `tg-combo*` クラス、色は `--tg-accent` を流用。`openOnClick` / `otherPlaceholder` / `icon` / `className`。
697
+ - **開いたリストの見た目はネイティブ `type:'dropdown'`(OS 描画の `<select>`)とはあえて別**(自前ポップアップ=角丸・影・アクセント色=「ここは『その他』入力もできる」合図)。**セル右の ▾ キャレットはネイティブ dropdown と統一済み**。リストを素の dropdown に寄せたい場合は `.tg-combo*` / `--tg-accent` を上書きすれば調整できます(※逆にネイティブ `<select>` のリストは OS 製で CSS 装飾不可)。
684
698
 
685
699
  ### 同梱プラグイン: セル内スパークライン(sparkline・ミニグラフ)
686
700
 
@@ -934,6 +948,10 @@ new TssGrid(el, { hiddenColumns: [1] }); // 初期で隠す
934
948
  | `onHeaderRender` | `(th, c)=>void` | — | 各列ヘッダ `th` の生成後に呼ぶ(**再描画毎に自動で再実行**)。ソートアイコン等の要素差し込み用 → 動く例: [`examples/multisort.html`](https://tssgrid.threestarsoftware.co.jp/examples/multisort.html) |
935
949
  | `disjointSelect` | `boolean` | `true` | Ctrl+ヘッダで**行/列を飛び飛びに複数選択**(`false` で Ctrl+クリックは単一選択に戻る)。`getSelectedColumns()`/`getSelectedRows()`・飛び飛びコピー/カットと連動 |
936
950
  | `shortcuts` | `Array` | `[]` | カスタムショートカット(→ [ショートカット / プラグイン](#ショートカット--プラグイン--破棄)) |
951
+ | `dateShortcuts` | `boolean` | `true` | 組込 `Ctrl+;`=今日 / `Ctrl+:`=現在時刻(`false` で無効) |
952
+ | `fillShortcuts` | `boolean` | `true` | 組込 `Ctrl+D`=上をコピー / `Ctrl+R`=左をコピー(`false` で無効) |
953
+ | `todayFormat` | `string \| (d:Date)=>string` | `'YYYY-MM-DD'` | `Ctrl+;` が**テキスト等の列**に入れる日付形式(トークン `YYYY`/`MM`/`DD`)。`date` 列は列準拠 |
954
+ | `nowFormat` | `string \| (d:Date)=>string` | `'HH:MM'` | `Ctrl+:` が**テキスト等の列**に入れる時刻形式(トークン `HH`/`mm`)。`time` 列は列準拠 |
937
955
  | `plugins` | `Array` | `[]` | プラグイン(関数 or 登録名)。`init(grid)` で初期化 |
938
956
  | `onPasteOverflow` | `(info)=>void` | — | `pasteOverflow:'error'` で超過時。`info = { anchor:{r,c}, height, width, rows, cols, overRows, overCols }` |
939
957
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threestarsoftware/tssgrid",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "軽量・ノービルド・日本語IME堅牢な編集グリッド(vanilla JS / 依存なし / MIT)。Excel ライクな入力画面を <script> タグ1本で。",
5
5
  "license": "MIT",
6
6
  "author": "ThreeStarSoftware (https://www.threestarsoftware.co.jp/)",
package/src/tssgrid.css CHANGED
@@ -203,6 +203,14 @@
203
203
  }
204
204
  .tssgrid .tg-table td.tg-readonly.tg-haspicker { padding-right: 6px; } /* 読取専用は出さない */
205
205
  .tssgrid .tg-table td.tg-readonly.tg-haspicker::after { display: none; }
206
+ /* editor.icon:'▾'(=プルダウン相当のキャレット)はネイティブ dropdown と同じ SVG シェブロンで統一
207
+ (combo / autocomplete 等・文字グリフの三角ではなく tg-dropdown と揃った見た目に)。絵文字系(📅/🕐)は対象外。 */
208
+ .tssgrid .tg-table td.tg-haspicker[data-ico="▾"] { padding-right: 18px; }
209
+ .tssgrid .tg-table td.tg-haspicker[data-ico="▾"]::after {
210
+ content: ''; right: 5px; top: 50%; bottom: auto; transform: translateY(-50%);
211
+ display: block; width: 11px; height: 8px; font-size: 0;
212
+ background: url("data:image/svg+xml;charset=utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='8'><path d='M1.5 2.2l4 4 4-4' fill='none' stroke='%237d8a99' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>") no-repeat center / 11px 8px;
213
+ }
206
214
 
207
215
  /* 固定列(frozen)は dropdown/haspicker/multiline でも sticky を維持する。
208
216
  これら型の position:relative は .tg-frozen と同じ詳細度(0,3,1)で後勝ち=固定列の
package/src/tssgrid.d.ts CHANGED
@@ -206,6 +206,14 @@ export interface TssGridOptions {
206
206
  allowInsertCols?: boolean;
207
207
  allowDeleteCols?: boolean;
208
208
  shortcuts?: any[];
209
+ /** 組込ショートカット Ctrl+;(今日)/ Ctrl+:(現在時刻)を有効化(既定 true)。 */
210
+ dateShortcuts?: boolean;
211
+ /** 組込ショートカット Ctrl+D(上をコピー=fill down)/ Ctrl+R(左をコピー=fill right)を有効化(既定 true)。 */
212
+ fillShortcuts?: boolean;
213
+ /** Ctrl+; が「date 型でない列」に入れる日付形式(既定 'YYYY-MM-DD')。トークン YYYY/MM/DD、または (d:Date)=>string。date 列は列の仕組み(ISO 保存+列 format 表示)に従う。 */
214
+ todayFormat?: string | ((d: Date) => string);
215
+ /** Ctrl+: が「time 型でない列」に入れる時刻形式(既定 'HH:MM')。トークン HH/mm、または (d:Date)=>string。time 列は 'HH:MM' 保存。 */
216
+ nowFormat?: string | ((d: Date) => string);
209
217
  /** プラグイン(関数 or 登録名)。init(grid) で初期化。 */
210
218
  plugins?: any[];
211
219
 
package/src/tssgrid.js CHANGED
@@ -281,6 +281,13 @@
281
281
  this._merges = null; // セル結合(横): [{r,c,colspan}] or null。null=結合なし=全経路ゼロコスト
282
282
  this._listeners = []; // destroy() 用に登録した document/window リスナを記録
283
283
  this._destroyed = false;
284
+ // Excel 入力ショートカット(組込・既定 ON・opt-out 可・未バインドキーなので追加的)。
285
+ this.dateShortcuts = opts.dateShortcuts !== false; // Ctrl+;=今日の日付 / Ctrl+:=現在時刻(文字で判定=JIS の Ctrl+: も US の Ctrl+Shift+; も拾う)
286
+ this.fillShortcuts = opts.fillShortcuts !== false; // Ctrl+D=上のセルをコピー(fill down) / Ctrl+R=左のセルをコピー(fill right)
287
+ // Ctrl+; / Ctrl+: が「テキスト等(date/time 型でない)」列に入れる形式(文字列トークン YYYY/MM/DD・HH/mm、または関数)。
288
+ // date/time 型の列はこの設定に関係なく列の仕組み(ISO 保存+列 format 表示)に従う。
289
+ this.todayFormat = opts.todayFormat || 'YYYY-MM-DD';
290
+ this.nowFormat = opts.nowFormat || 'HH:MM';
284
291
  (opts.shortcuts || []).forEach(s => this.addShortcut(s));
285
292
 
286
293
  this._padToMin(); // minRows/minCols まで空行・空列を補う
@@ -2290,6 +2297,45 @@
2290
2297
  else { const { r0, r1, c0, c1 } = this.rectRange(); for (let r = r0; r <= r1; r++) for (let c = c0; c <= c1; c++) this.setCell(r, c, '', changes); }
2291
2298
  this.pushCmd(changes, before, this.snapSel(), 'delete');
2292
2299
  }
2300
+ // フォーマット文字列 or 関数で日時を成形。トークン: YYYY/MM/DD(日付)・HH/mm(時刻)。
2301
+ _fmtDateTime(d, spec, isTime) {
2302
+ if (typeof spec === 'function') { try { return String(spec(d)); } catch (_) { return ''; } }
2303
+ const p2 = n => String(n).padStart(2, '0');
2304
+ const map = isTime ? { HH: p2(d.getHours()), mm: p2(d.getMinutes()) }
2305
+ : { YYYY: String(d.getFullYear()), MM: p2(d.getMonth() + 1), DD: p2(d.getDate()) };
2306
+ return String(spec).replace(/YYYY|MM|DD|HH|mm/g, t => (map[t] != null ? map[t] : t));
2307
+ }
2308
+ // Excel の Ctrl+; / Ctrl+: 相当。date/time 列は ISO ストレージ(表示は列 format)に従い、
2309
+ // テキスト等の列は todayFormat / nowFormat(既定 'YYYY-MM-DD' / 'HH:MM')で成形。検証/Undo を通る setValue。
2310
+ _insertDateTime(isTime) {
2311
+ const r = this.active.r, c = this.active.c;
2312
+ if (this._isReadOnly(r, c)) return;
2313
+ const d = new Date(), p2 = n => String(n).padStart(2, '0');
2314
+ let val;
2315
+ if (isTime) {
2316
+ val = this.colType(c) === 'time' ? (p2(d.getHours()) + ':' + p2(d.getMinutes())) // time 列は保存形式 HH:MM
2317
+ : this._fmtDateTime(d, this.nowFormat, true);
2318
+ } else {
2319
+ val = this.colType(c) === 'date' ? (d.getFullYear() + '-' + p2(d.getMonth() + 1) + '-' + p2(d.getDate())) // date 列は ISO 保存(表示は列 format)
2320
+ : this._fmtDateTime(d, this.todayFormat, false);
2321
+ }
2322
+ this.setValue(r, c, val);
2323
+ }
2324
+ // Excel の Ctrl+D / Ctrl+R 相当。選択範囲を先頭行/左端列の値で埋める(単一セルなら上/左のセルをコピー)。readOnly はスキップ・1 undo。
2325
+ _fillFrom(dir) {
2326
+ const { r0, r1, c0, c1 } = this.rectRange();
2327
+ const single = (r0 === r1 && c0 === c1);
2328
+ const before = this.snapSel(), changes = [];
2329
+ const put = (r, c, v) => { if (!this._isReadOnly(r, c)) this.setCell(r, c, v, changes); };
2330
+ if (dir === 'down') {
2331
+ if (single) { if (r0 > 0) put(r0, c0, this.data[r0 - 1][c0]); }
2332
+ else { for (let c = c0; c <= c1; c++) { const v = this.data[r0][c]; for (let r = r0 + 1; r <= r1; r++) put(r, c, v); } }
2333
+ } else {
2334
+ if (single) { if (c0 > 0) put(r0, c0, this.data[r0][c0 - 1]); }
2335
+ else { for (let r = r0; r <= r1; r++) { const v = this.data[r][c0]; for (let c = c0 + 1; c <= c1; c++) put(r, c, v); } }
2336
+ }
2337
+ if (changes.length) this.pushCmd(changes, before, this.snapSel(), 'edit');
2338
+ }
2293
2339
 
2294
2340
  // ---- 行/列の挿入・削除(構造変更。Undo に1コマンドで積む) ----
2295
2341
  // 並列配列(columns/colW は疎なことがある)を現在の COLS/ROWS 長に揃えてから splice する。
@@ -3289,6 +3335,9 @@
3289
3335
  if (ctrl && (e.key.toLowerCase() === 'y' || (e.shiftKey && e.key.toLowerCase() === 'z'))) { e.preventDefault(); this.history.redo(); return; }
3290
3336
  if (ctrl && e.key.toLowerCase() === 'c') { e.preventDefault(); this.copy(false); return; }
3291
3337
  if (ctrl && e.key.toLowerCase() === 'x') { e.preventDefault(); this.copy(true); return; }
3338
+ // Excel 入力ショートカット(未バインドキー=追加的)。文字で判定=JIS(Ctrl+:) も US(Ctrl+Shift+;) も拾う。
3339
+ if (this.dateShortcuts && ctrl && (e.key === ';' || e.key === ':')) { e.preventDefault(); this._insertDateTime(e.key === ':'); return; }
3340
+ if (this.fillShortcuts && ctrl && !e.shiftKey && (e.key.toLowerCase() === 'd' || e.key.toLowerCase() === 'r')) { e.preventDefault(); this._fillFrom(e.key.toLowerCase() === 'd' ? 'down' : 'right'); return; }
3292
3341
  // Ctrl+V は keydown で拾わず native paste イベントへ委譲(editor の paste リスナが処理)。
3293
3342
  // ここで preventDefault すると paste イベント自体を止めかねないため分岐を置かない。
3294
3343
  if (e.shiftKey && e.key.startsWith('Arrow')) {