@threestarsoftware/tssgrid 0.1.36 → 0.1.38

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,21 @@
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.38] - 2026-11-06
7
+
8
+ ### 追加
9
+ - **`selectOnEdit`(編集開始で中身を全選択=打てば丸ごと置き換わる)**。クリック/F2 で編集を始めた時に共有 input を `select()`。**時刻/日付ピッカー(tss-time / tss-calendar / tss-datetime)は既定 ON**(値が入ったセルをクリックしてそのまま打てば置換)。列単位 `columns[c].selectOnEdit: true|false` でも指定でき、任意の列や個別の上書きに使える。
10
+ - **`flashInvalid`(不正値を弾いて巻き戻した時にセルを短く点滅して知らせる・コア/既定 ON)**。確定時の検証で弾かれた(=元の値へ巻き戻した)セルに短い赤パルス(`.tg-reject` 0.5s、`prefers-reduced-motion` 配慮)。従来 "revert" は無言で戻っていた穴を埋める(他グリッド同様「弾いたら知らせる」)。既存の `onInvalid(rejections, source)` コールバックはそのまま発火。`flashInvalid: false` で無効化。
11
+
12
+ ## [0.1.37] - 2026-11-06
13
+
14
+ ### 追加(公式フレームワークアダプタ)
15
+ - **React / Vue 3 の薄い公式アダプタを追加**(`@threestarsoftware/tssgrid/react`・`@threestarsoftware/tssgrid/vue`)。競合(`ag-grid-react` / `@handsontable/react`)と同じ「コアはフレームワーク非依存のまま・薄いコンポーネントがライフサイクルと props を橋渡し」の形。**コアは無依存を維持**=`react` / `vue` は **peerDependency(任意・`peerDependenciesMeta.optional`)**、アダプタは `React.createElement` / `Vue.h` で手書き=**ビルド不要(UMD)**。
16
+ - グリッドは**アンコントロールド**:マウントで生成・アンマウントで `destroy()`、**cell を React/Vue で描かない**(高速)。値は **ref で公開した grid 本体(命令API)** + `onAfterChange` 等のコールバック。`data` プロップは参照が変わった時だけ `setData`(毎レンダー新配列を渡すとリセット=頻繁な更新は命令APIで)。
17
+ - React: `<TssGridReact columns={..} data={..} onAfterChange={..} ref={ref} />`、`ref.current` が grid 本体。StrictMode 二重マウント安全(`destroy` 冪等)、SSR/Next 安全(構築は `useEffect`=クライアント専用)。
18
+ - Vue: `<TssGridVue :columns :data :options="{ onAfterChange }" ref="g" />`、`g.grid()` が grid 本体。
19
+ - `columns/data/plugins/options` と全 `on*` コールバックをそのまま透過。型(`.d.ts`)付き。例 `examples/react.html` / `examples/vue.html`(CDN UMD のノービルドデモ)。
20
+
6
21
  ## [0.1.36] - 2026-11-06
7
22
 
8
23
  inline ピッカー3兄弟(**tss-time / tss-calendar / tss-datetime**)に共通して潜んでいた「ポップアップの `<select>` が使えない/確定がピッカー内部の値を書き戻す/編集中の表示が食い違う」を一掃。土台としてコアに2つの affordance を追加。
package/README.md CHANGED
@@ -78,9 +78,39 @@ const { TssGrid, HistoryManager } = require('@threestarsoftware/tssgrid');
78
78
 
79
79
  ## フレームワークで使う(React / Vue / Angular)
80
80
 
81
- 専用ラッパーは**作りません**。vanilla on DOM なので CRA/Vite/Next/Webpack/Angular/Nuxt でそのまま動きます。コツは **マウント時に生成し、アンマウント時に `grid.destroy()`** するだけ(リスナ・ResizeObserver・DOM を後始末。idempotent)。
81
+ **React / Vue には薄い公式アダプタ**(`@threestarsoftware/tssgrid/react`・`/vue`)があります。コアは無依存のまま=`react`・`vue` は **peerDependency(任意)**、アダプタは `React.createElement` / `Vue.h` で手書き=**ノービルド**。グリッドは「アンコントロールド」(マウントで生成・アンマウントで `destroy()`・**cell は React/Vue で描かない**=高速)、値は **ref で公開した grid 本体(命令API)** + `onAfterChange` 等のコールバック、`data` プロップは「差し替え」用(参照が変わった時だけ `setData`)。動く例: [`examples/react.html`](https://tssgrid.threestarsoftware.co.jp/examples/react.html) / [`examples/vue.html`](https://tssgrid.threestarsoftware.co.jp/examples/vue.html)。
82
82
 
83
- **React**:
83
+ **React(公式アダプタ)**:
84
+ ```jsx
85
+ import { useRef } from 'react';
86
+ import { TssGridReact } from '@threestarsoftware/tssgrid/react';
87
+ import '@threestarsoftware/tssgrid/tssgrid.css';
88
+
89
+ function Grid({ columns, data }) {
90
+ const ref = useRef(null); // ref.current = grid 本体(命令API)
91
+ return <TssGridReact columns={columns} data={data}
92
+ onAfterChange={(ch, src) => console.log(ch, src)} ref={ref} />;
93
+ // 例: ref.current.sortBy('age','desc') / ref.current.getRows()
94
+ }
95
+ ```
96
+
97
+ **Vue 3(公式アダプタ)**:
98
+ ```vue
99
+ <script setup>
100
+ import { ref } from 'vue';
101
+ import { TssGridVue } from '@threestarsoftware/tssgrid/vue';
102
+ import '@threestarsoftware/tssgrid/tssgrid.css';
103
+ const g = ref(null); // g.value.grid() = grid 本体
104
+ </script>
105
+ <template>
106
+ <TssGridVue :columns="columns" :data="data"
107
+ :options="{ onAfterChange: (ch, src) => console.log(ch, src) }" ref="g" />
108
+ </template>
109
+ ```
110
+
111
+ アダプタを使わず**依存ゼロで直接**使うこともできます(vanilla on DOM。CRA/Vite/Next/Webpack/Angular/Nuxt でそのまま。コツは **マウント時に生成し、アンマウント時に `grid.destroy()`**)。
112
+
113
+ **React(直接)**:
84
114
  ```jsx
85
115
  import { useEffect, useRef } from 'react';
86
116
  import { TssGrid } from '@threestarsoftware/tssgrid';
@@ -999,6 +1029,7 @@ new TssGrid(el, { hiddenColumns: [1] }); // 初期で隠す
999
1029
  | `hiddenColumns` | `number[]` | `[]` | 初期で隠す列インデックス。実行時は `hideColumn`/`showColumn`/`toggleColumn`(→ [列の表示/非表示](#列の表示非表示)) |
1000
1030
  | `wordWrap` | `boolean` | `false` | セル内で折り返し(行高は内容に合わせ伸びる)。`columns[c].wordWrap` で列単位も可 |
1001
1031
  | `ellipsis` | `boolean` | `false` | 溢れた文字を **… で省略**し、溢れたセルは**ホバーで全文(`title`)**。`columns[c].ellipsis` で列単位も可。見え方だけ=値・コピー・編集は全文のまま。`wordWrap` と同時なら折り返しが優先 |
1032
+ | `columns[c].selectOnEdit` | `boolean` | — | クリック/F2 の**編集開始で中身を全選択**(打てば丸ごと置換)。**時刻/日付ピッカーは既定 ON**。列に明示すれば任意の列で有効/無効にできる(列指定がエディタ既定より優先) |
1002
1033
  | `placeholder` | `string` | — | 空セルに薄いヒント文字(`getData` には入らない)。`columns[c].placeholder` で列単位も可 |
1003
1034
  | `className` | `string` | — | コンテナ(`.tssgrid`)に付ける任意クラス(テーマ付け) |
1004
1035
  | `fillHandle` | `boolean \| {direction,autoInsertRow}` | `true` | **`false`でフィル完全OFF**(ハンドルを出さない=ドラッグでの消去/上書きなし。フィルの起点はハンドルのみなので fill 自体が無効に)。`{direction:'vertical'\|'horizontal'\|'both', autoInsertRow:true}`で詳細指定(下へドラッグで行追加)。設定/表示専用グリッドで誤フィルを防ぐのに有効 |
@@ -1015,6 +1046,7 @@ new TssGrid(el, { hiddenColumns: [1] }); // 初期で隠す
1015
1046
  | `columns[c].readOnly` | `boolean \| (value,{r,c})=>boolean` | — | **列単位**の読み取り専用。関数を渡すとセル単位で判定(→ [読み取り専用](#読み取り専用readonly)) |
1016
1047
  | `onChange` | `(grid)=>void` | — | データ変更時に呼ばれる(後方互換) |
1017
1048
  | `onInvalid` | `(rejections, source)=>void` | — | 列ルールで弾かれた時。`rejections = [{ r, c, value, message }]` |
1049
+ | `flashInvalid` | `boolean` | `true` | 不正値を弾いて**巻き戻した時にセルを短く赤く点滅**して知らせる(`.tg-reject`・`prefers-reduced-motion` 配慮)。`onInvalid` は別途そのまま発火。`false` で無効 |
1018
1050
  | `onReadOnly` | `(blocked, source)=>void` | — | 読み取り専用セルへの変更を弾いた時。`blocked = [{ r, c, value }]` |
1019
1051
  | `contextMenu` | `boolean \| Array \| {items}` | `true` | 右クリックメニュー。`true`=既定項目 / `false`=無効 / **配列**=項目を構成(組込キー+カスタム項目)(→ [右クリックメニュー](#右クリックメニュー行列の挿入削除)) |
1020
1052
  | `allowInsertRows` / `allowDeleteRows` | `boolean` | `true` | 行の挿入 / 削除の可否(メニュー項目の表示も連動) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threestarsoftware/tssgrid",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "軽量・ノービルド・日本語IME堅牢な編集グリッド(vanilla JS / 依存なし / MIT)。Excel ライクな入力画面を <script> タグ1本で。",
5
5
  "license": "MIT",
6
6
  "author": "ThreeStarSoftware (https://www.threestarsoftware.co.jp/)",
@@ -67,9 +67,29 @@
67
67
  "types": "./plugins/tss-comment.d.ts",
68
68
  "default": "./plugins/tss-comment.js"
69
69
  },
70
+ "./react": {
71
+ "types": "./react/index.d.ts",
72
+ "default": "./react/index.js"
73
+ },
74
+ "./vue": {
75
+ "types": "./vue/index.d.ts",
76
+ "default": "./vue/index.js"
77
+ },
70
78
  "./plugins/*": "./plugins/*",
71
79
  "./package.json": "./package.json"
72
80
  },
81
+ "peerDependencies": {
82
+ "react": ">=16.8.0",
83
+ "vue": ">=3.0.0"
84
+ },
85
+ "peerDependenciesMeta": {
86
+ "react": {
87
+ "optional": true
88
+ },
89
+ "vue": {
90
+ "optional": true
91
+ }
92
+ },
73
93
  "unpkg": "src/tssgrid.js",
74
94
  "jsdelivr": "src/tssgrid.js",
75
95
  "sideEffects": [
@@ -83,6 +103,8 @@
83
103
  "src/tssgrid.css",
84
104
  "src/tssgrid.d.ts",
85
105
  "plugins/",
106
+ "react/",
107
+ "vue/",
86
108
  "README.md",
87
109
  "CHANGELOG.md",
88
110
  "LICENSE"
@@ -214,6 +214,7 @@
214
214
  close: function () { teardown(); },
215
215
  icon: opts.icon != null ? opts.icon : '📅', // セル右端に表示する合図(opts.icon:'' で消せる)
216
216
  openOnClick: opts.openOnClick !== false, // シングルクリックで開く(既定 ON)
217
+ selectOnEdit: true, // クリック/F2 の編集開始で中身を全選択=打てば丸ごと置き換わる
217
218
  inline: inline, // true=共有 input に乗る(_usesTextEditor が見る)
218
219
  // inline のみ: 打った内容にカレンダーが追従(列の parse があれば表示形→保存値に変換して解釈)。
219
220
  // 矢印/Enter/Esc は本体に返す=onKeyDown は持たない(キー派は打つ・マウス派はクリック)。
@@ -184,6 +184,7 @@
184
184
  close: function () { teardown(); },
185
185
  icon: opts.icon != null ? opts.icon : '📅',
186
186
  openOnClick: opts.openOnClick !== false,
187
+ selectOnEdit: true, // クリック/F2 の編集開始で中身を全選択=打てば丸ごと置き換わる
187
188
  inline: inline, // true=共有 input に乗る=日時をそのまま直打ちできる(矢印/Enter/Esc は本体の既定)
188
189
  // inline のみ: 打った内容にピッカーが追従(ctx.parseCell=セルの確定と同じ読み方。上で付けた parse を使う)。
189
190
  onInput: inline ? function (v, ctx) {
@@ -104,6 +104,7 @@
104
104
  close: function () { teardown(); },
105
105
  icon: opts.icon != null ? opts.icon : '🕐',
106
106
  openOnClick: opts.openOnClick !== false,
107
+ selectOnEdit: true, // クリック/F2 の編集開始で中身を全選択=打てば丸ごと置き換わる
107
108
  inline: inline, // true=共有 input に乗る=時刻をそのまま直打ちできる(矢印/Enter/Esc は本体の既定)
108
109
  openAt: function (anchorEl, value, onPick) { show(anchorEl, value, function (v) { onPick(v); }, null); },
109
110
  };
@@ -0,0 +1,19 @@
1
+ // TssGridReact — TssGrid の薄い React アダプタの型。
2
+ import * as React from 'react';
3
+ import { TssGrid, TssGridOptions } from '../src/tssgrid';
4
+
5
+ // トップレベルに書ける定番オプション+全 on* コールバックは Partial<TssGridOptions> として受ける。
6
+ // それ以外は options={{…}} でまとめて渡す。className / style は host の <div> に付く。
7
+ export interface TssGridReactProps extends Partial<TssGridOptions> {
8
+ className?: string;
9
+ style?: React.CSSProperties;
10
+ options?: TssGridOptions;
11
+ }
12
+
13
+ // ref には grid 本体(命令API)が入る。
14
+ declare const TssGridReact: React.ForwardRefExoticComponent<
15
+ TssGridReactProps & React.RefAttributes<TssGrid>
16
+ >;
17
+
18
+ export default TssGridReact;
19
+ export { TssGridReact };
package/react/index.js ADDED
@@ -0,0 +1,74 @@
1
+ /*! TssGridReact — TssGrid の薄い React アダプタ(UMD・ノービルド・react は peerDependency)
2
+ *
3
+ * 方針(競合 ag-grid-react / @handsontable/react と同じ):
4
+ * - グリッドは「アンコントロールド」= マウント時に1回生成し、アンマウントで destroy()。cell を React で描かない(高速)。
5
+ * - 値の読み書きは ref 経由の命令API(grid 本体)+ onAfterChange 等のコールバック。data プロップは「差し替え」用。
6
+ * - 全ての on* コールバック(onAfterChange / onEditEnd …)と columns/data/plugins/options をそのまま TssGrid へ渡す。
7
+ *
8
+ * 使い方:
9
+ * import { TssGridReact } from '@threestarsoftware/tssgrid/react';
10
+ * import '@threestarsoftware/tssgrid/tssgrid.css';
11
+ * const ref = useRef(null);
12
+ * <TssGridReact columns={cols} data={rows} plugins={[...]}
13
+ * onAfterChange={(ch, src) => ...} ref={ref} />
14
+ * // 命令API: ref.current.sortBy('col','desc') / ref.current.getRows() など(grid 本体)
15
+ *
16
+ * 注意:
17
+ * - data は「参照が変わった時だけ」setData されます(毎レンダー新配列を渡すと毎回リセット=カーソルも飛ぶ)。
18
+ * 頻繁な更新は ref の命令API(setValue/ appendRows 等)を使うのが定石。
19
+ * - 構築は useEffect(クライアント専用)なので SSR/Next でもそのまま(サーバでは空 div)。columns を変えたい時は key で remount。
20
+ */
21
+ (function (root, factory) {
22
+ if (typeof module !== 'undefined' && module.exports) {
23
+ module.exports = factory(require('react'), require('../src/tssgrid.js'));
24
+ } else {
25
+ root.TssGridReact = factory(root.React, { TssGrid: root.TssGrid });
26
+ }
27
+ })(typeof self !== 'undefined' ? self : this, function (React, core) {
28
+ 'use strict';
29
+ var TssGrid = core && (core.TssGrid || core);
30
+ var h = React.createElement;
31
+ // トップレベルに書ける定番オプション(それ以外は options={{…}} で)。
32
+ var PASS = { columns: 1, headers: 1, data: 1, plugins: 1, name: 1, width: 1, height: 1, rowHeight: 1, rowHeaders: 1, colHeaders: 1, minSpareRows: 1, maxRows: 1, history: 1, virtual: 1, hiddenColumns: 1 };
33
+
34
+ function buildOptions(props) {
35
+ var o = {};
36
+ if (props.options) for (var k in props.options) o[k] = props.options[k];
37
+ for (var key in props) {
38
+ if (PASS[key]) o[key] = props[key];
39
+ else if (/^on[A-Z]/.test(key) && typeof props[key] === 'function') o[key] = props[key]; // on* コールバック総通し
40
+ }
41
+ return o;
42
+ }
43
+
44
+ var TssGridReact = React.forwardRef(function (props, ref) {
45
+ var hostRef = React.useRef(null);
46
+ var gridRef = React.useRef(null);
47
+ var propsRef = React.useRef(props);
48
+ propsRef.current = props;
49
+ var firstData = React.useRef(true);
50
+ var readyState = React.useState(0); // grid 生成後に ref(命令API)を更新させるためのバンプ
51
+
52
+ React.useEffect(function () { // 生成は1回(アンコントロールド)。StrictMode 二重でも destroy が冪等。
53
+ var grid = new TssGrid(hostRef.current, buildOptions(propsRef.current));
54
+ gridRef.current = grid;
55
+ firstData.current = true;
56
+ readyState[1](function (n) { return n + 1; }); // ref.current = grid 本体 に更新(useImperativeHandle を再評価)
57
+ return function () { try { grid.destroy(); } catch (e) {} if (gridRef.current === grid) gridRef.current = null; };
58
+ }, []);
59
+
60
+ React.useEffect(function () { // data の参照が変わったら差し替え(初回=生成時の data を使うのでスキップ)
61
+ if (firstData.current) { firstData.current = false; return; }
62
+ var g = gridRef.current;
63
+ if (g && propsRef.current.data != null) g.setData(propsRef.current.data);
64
+ }, [props.data]);
65
+
66
+ React.useImperativeHandle(ref, function () { return gridRef.current; }, [readyState[0]]); // grid 本体を命令API として公開(生成後に更新)
67
+
68
+ return h('div', { ref: hostRef, className: props.className, style: props.style });
69
+ });
70
+ TssGridReact.displayName = 'TssGridReact';
71
+ TssGridReact.TssGridReact = TssGridReact; // import { TssGridReact } / import TssGridReact どちらも通す
72
+ TssGridReact.default = TssGridReact;
73
+ return TssGridReact;
74
+ });
package/src/tssgrid.css CHANGED
@@ -109,6 +109,14 @@
109
109
  /* invalidMode:'keep' で検証 NG のセル: 値は残して赤く警告(色は変数で調整可) */
110
110
  .tssgrid .tg-table td.tg-invalid { color: var(--tg-invalid-fg); background: var(--tg-invalid-bg); }
111
111
  .tssgrid .tg-table td.tg-invalid.sel { background: #ffd0d6; }
112
+ /* 不正入力を弾いて巻き戻した時の合図(短い赤パルス)。flashInvalid:false で無効。 */
113
+ .tssgrid .tg-table td.tg-reject { animation: tg-reject-flash .5s ease; }
114
+ @keyframes tg-reject-flash {
115
+ 0% { background: var(--tg-invalid-bg); box-shadow: inset 0 0 0 2px var(--tg-invalid-fg); }
116
+ 70% { background: var(--tg-invalid-bg); box-shadow: inset 0 0 0 2px var(--tg-invalid-fg); }
117
+ 100% { background: transparent; box-shadow: none; }
118
+ }
119
+ @media (prefers-reduced-motion: reduce) { .tssgrid .tg-table td.tg-reject { animation-duration: .01s; } }
112
120
  .tssgrid .tg-table th.rowhead { background: var(--tg-rowhead-bg); width: 40px; text-align: center; color: var(--tg-rowhead-fg); position: sticky; left: 0; z-index: 2; }
113
121
  .tssgrid .tg-table thead th.corner { z-index: 7; } /* 左上の角は最前面(top+left 固定) */
114
122
  /* 列固定: 左から frozenCols 列を sticky で固定(left は JS が設定)。z は 選択オーバーレイ(3)より下に */
package/src/tssgrid.js CHANGED
@@ -113,6 +113,7 @@
113
113
  // parse/format を付けるか picker:false にするとテキスト入力(並び順を自分で決められる)。
114
114
  // data: オブジェクト配列で渡す時の**バインド先キー**(例 {data:'品番'})。getRows/getValue(r,'品番') で使う。
115
115
  this.onInvalid = opts.onInvalid || null; // (rejections, source) 検証で弾かれた時
116
+ this.flashInvalid = opts.flashInvalid; // 既定 undefined=点滅ON(不正で巻き戻した時にセルを短く赤く)。false で無効
116
117
  // 読み取り専用: グリッド全体(opts.readOnly)/ 列単位(columns[c].readOnly)。編集と全変更経路を拒否。
117
118
  this.readOnly = !!opts.readOnly;
118
119
  this.onReadOnly = opts.onReadOnly || null; // (blocked, source) 読み取り専用セルへの変更を弾いた時
@@ -2348,6 +2349,7 @@
2348
2349
  }
2349
2350
  for (let i = changes.length - 1; i >= 0; i--) if (changes[i].neu === changes[i].old) changes.splice(i, 1);
2350
2351
  if (rejections.length && this.onInvalid) { try { this.onInvalid(rejections, source); } catch (_) {} }
2352
+ if (rejections.length) this._flashInvalid(rejections); // 不正で巻き戻した/赤くしたセルを短く点滅して「知らせる」
2351
2353
  if (!changes.length) { this.renderDump(); this.focusAndSelect(selBefore); return; }
2352
2354
  }
2353
2355
  // onBeforeChange: 検証 / 整形 / 取消。値は既に適用済みなので、取消は old へ巻き戻す。
@@ -2379,6 +2381,20 @@
2379
2381
  if (this.onAfterChange) { try { this.onAfterChange(this._pubChanges(changes, source), source); } catch (_) {} }
2380
2382
  this._syncHeaderCheckboxes(); // ヘッダ全選択チェックの見た目を同期
2381
2383
  }
2384
+ // 不正で巻き戻した(または赤くした)セルを短く点滅して利用者に知らせる。確定後のレンダ確定を待って付与。
2385
+ _flashInvalid(cells) {
2386
+ if (this.flashInvalid === false || !cells || !cells.length) return;
2387
+ const grid = this;
2388
+ setTimeout(function () {
2389
+ cells.forEach(function (rc) {
2390
+ const td = grid.cellEl(rc.r, rc.c);
2391
+ if (!td) return;
2392
+ td.classList.remove('tg-reject'); void td.offsetWidth; // 連続でも毎回アニメを再発火
2393
+ td.classList.add('tg-reject');
2394
+ setTimeout(function () { try { td.classList.remove('tg-reject'); } catch (e) {} }, 550);
2395
+ });
2396
+ }, 0);
2397
+ }
2382
2398
  commit() {
2383
2399
  const wasEditing = this.mode === 'edit';
2384
2400
  const r = this.active.r, c = this.active.c, oldValue = this.data[r][c];
@@ -3315,6 +3331,10 @@
3315
3331
  if (t === 'checkbox') { this._toggleCheckbox(r, c); return; }
3316
3332
  if (t === 'dropdown') { this._openSelect(); return; }
3317
3333
  this.toEdit(this._editText(r, c), true);
3334
+ // selectOnEdit: クリック/F2 の編集開始で中身を全選択=打てば丸ごと置き換わる(時刻/日付ピッカー等)。
3335
+ // 列の selectOnEdit を最優先、無ければエディタ申告(editor.selectOnEdit)に従う。
3336
+ const _se = this.colCfg(c).selectOnEdit;
3337
+ if ((_se != null ? _se : (_ed && _ed.selectOnEdit)) && this.editor.select) { try { this.editor.select(); } catch (_) {} }
3318
3338
  }
3319
3339
  // カスタムエディタ口(base-editor 相当)。columns[c].editor = オブジェクト or ()=>オブジェクト。
3320
3340
  // 契約: editor.open({ grid, r, c, value, td, commit(value), cancel() }) / 任意で editor.close()。
package/vue/index.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ // TssGridVue — TssGrid の薄い Vue 3 アダプタの型。
2
+ import { DefineComponent } from 'vue';
3
+ import { TssGrid, TssGridOptions } from '../src/tssgrid';
4
+
5
+ export type TssGridVueProps = Partial<TssGridOptions> & { options?: TssGridOptions };
6
+
7
+ // expose: grid() で grid 本体(命令API)を返す。
8
+ export interface TssGridVueExposed {
9
+ grid(): TssGrid | null;
10
+ }
11
+
12
+ declare const TssGridVue: DefineComponent<TssGridVueProps>;
13
+
14
+ export default TssGridVue;
15
+ export { TssGridVue };
package/vue/index.js ADDED
@@ -0,0 +1,56 @@
1
+ /*! TssGridVue — TssGrid の薄い Vue 3 アダプタ(UMD・ノービルド・vue は peerDependency)
2
+ *
3
+ * 方針(React アダプタと同じ): グリッドはアンコントロールド。マウントで生成・アンマウントで destroy()。
4
+ * 値の読み書きは expose した grid 本体(命令API)+ on* コールバック。data プロップは「差し替え」用。
5
+ *
6
+ * 使い方:
7
+ * import { TssGridVue } from '@threestarsoftware/tssgrid/vue';
8
+ * import '@threestarsoftware/tssgrid/tssgrid.css';
9
+ * <TssGridVue :columns="cols" :data="rows" :plugins="[...]" :options="{ onAfterChange }" ref="g" />
10
+ * // 命令API: this.$refs.g.grid().sortBy('col','desc') など(grid 本体を返す)
11
+ *
12
+ * 注意: on* コールバックは :options(例 :options="{ onAfterChange: fn }")か、@after-change などの属性で渡せます。
13
+ * data は参照が変わった時だけ setData(毎回新配列はリセット=カーソルが飛ぶ)。頻繁な更新は grid の命令APIで。
14
+ */
15
+ (function (root, factory) {
16
+ if (typeof module !== 'undefined' && module.exports) {
17
+ module.exports = factory(require('vue'), require('../src/tssgrid.js'));
18
+ } else {
19
+ root.TssGridVue = factory(root.Vue, { TssGrid: root.TssGrid });
20
+ }
21
+ })(typeof self !== 'undefined' ? self : this, function (Vue, core) {
22
+ 'use strict';
23
+ var TssGrid = core && (core.TssGrid || core);
24
+ var PASS = ['columns', 'data', 'plugins', 'headers', 'name', 'width', 'height', 'rowHeight', 'rowHeaders', 'colHeaders', 'minSpareRows', 'maxRows', 'history', 'virtual', 'hiddenColumns'];
25
+
26
+ var TssGridVue = Vue.defineComponent({
27
+ name: 'TssGridVue',
28
+ inheritAttrs: false, // on* 属性を div に二重付けしない
29
+ props: {
30
+ columns: Array, data: Array, plugins: Array, options: Object, headers: Array,
31
+ name: String, width: [Number, String], height: [Number, String],
32
+ rowHeight: Number, rowHeaders: { type: Boolean, default: undefined }, minSpareRows: Number,
33
+ },
34
+ setup: function (props, ctx) {
35
+ var el = Vue.ref(null);
36
+ var grid = null;
37
+ function buildOptions() {
38
+ var o = {};
39
+ if (props.options) for (var k in props.options) o[k] = props.options[k];
40
+ PASS.forEach(function (key) { if (props[key] !== undefined) o[key] = props[key]; });
41
+ var attrs = ctx.attrs || {};
42
+ for (var a in attrs) { if (/^on[A-Z]/.test(a) && typeof attrs[a] === 'function') o[a] = attrs[a]; } // @after-change 等=attrs の onAfterChange
43
+ return o;
44
+ }
45
+ Vue.onMounted(function () { grid = new TssGrid(el.value, buildOptions()); });
46
+ Vue.onBeforeUnmount(function () { if (grid) { try { grid.destroy(); } catch (e) {} grid = null; } });
47
+ Vue.watch(function () { return props.data; }, function (d) { if (grid && d != null) grid.setData(d); }); // 参照が変わったら差し替え
48
+ ctx.expose({ grid: function () { return grid; } }); // grid 本体を命令API として公開
49
+ return function () { return Vue.h('div', { ref: el }); };
50
+ },
51
+ });
52
+
53
+ TssGridVue.TssGridVue = TssGridVue;
54
+ TssGridVue.default = TssGridVue;
55
+ return TssGridVue;
56
+ });