@aiquants/spreadsheet 0.10.0 → 0.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/spreadsheet",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Excel-grade spreadsheet grid for React: multi-cell selection, TSV/HTML clipboard, in-place editing on top of @aiquants/virtualscroll",
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -217,6 +217,43 @@ export type SpreadsheetProps = {
217
217
  * 宣言の不在信号 (エンジン既定) で、本パッケージでの値フォールバックなし。
218
218
  */
219
219
  tapScrollCircleOptions?: ScrollBarTapCircleOptions
220
+ /**
221
+ * Row-axis overscan pass-through (the VirtualGrid `overscanRows` knob; LIVE prop): rows
222
+ * rendered beyond each vertical viewport edge. This slack is the only thing absorbing the
223
+ * engine's one-frame rendering-window lag during fast scrolling (the blank-band remedy —
224
+ * the slack in px is overscan × row height per edge). Undefined ⇒ the engine default (3).
225
+ * The engine clamps invalid values silently, so THIS surface owns the fail-fast: a
226
+ * non-integer or negative value throws a RangeError at render. Cost multiplies with the
227
+ * column axis (bounded by the engine cell cap).
228
+ * 行軸 overscan の素通し (VirtualGrid `overscanRows`。ライブ prop): 縦 viewport 端の外側へ
229
+ * 描画する行数。高速スクロール時の描画窓 1 フレーム遅れを吸収する唯一の余裕 (白帯対策 —
230
+ * 余裕 px は片端あたり overscan × 行高)。undefined はエンジン既定 (3)。エンジンは不正値を
231
+ * 無言クランプするため fail-fast は本層所有 — 非整数・負値は render 時 RangeError。費用は
232
+ * 列軸との積で増幅 (エンジンのセル上限で有界)。
233
+ */
234
+ overscanRows?: number
235
+ /**
236
+ * Column-axis overscan pass-through (the VirtualGrid `overscanCols` knob; LIVE prop) — the
237
+ * column twin of `overscanRows`, same validation contract (non-negative integer or
238
+ * RangeError; undefined ⇒ engine default 3).
239
+ * 列軸 overscan の素通し (VirtualGrid `overscanCols`。ライブ prop) — `overscanRows` の
240
+ * 列双子。検証契約は同文 (非負整数、それ以外 RangeError。undefined ⇒ エンジン既定 3)。
241
+ */
242
+ overscanCols?: number
243
+ /**
244
+ * Background layer rendered behind the scroll-band rows, inside the engine content element
245
+ * (the VirtualGrid `background` pass-through; LIVE prop). VIEWPORT-PINNED: the engine
246
+ * translates only its row wrapper, so this layer does NOT follow the scroll offset —
247
+ * periodic row ruling placed here slides against the real rows while scrolling. Suited to
248
+ * a static texture that reads as "content still arriving" in the overscan-exhausted band,
249
+ * not to row-aligned gridlines.
250
+ * スクロール帯行の背後・エンジンコンテンツ要素内に描画する背景レイヤー (VirtualGrid
251
+ * `background` の素通し。ライブ prop)。viewport 固定: エンジンが translate するのは行
252
+ * ラッパーだけで、この層はスクロール量に追従しない — 周期的な行罫線を置くとスクロール中に
253
+ * 実際の行へ対して滑る。overscan が尽きた帯で「まだ到着中」と読める静的テクスチャ向きで、
254
+ * 行整合の罫線には不向き。
255
+ */
256
+ background?: ReactNode
220
257
  /**
221
258
  * Identity-stable contract (same as adapter): an inline arrow here defeats the CellView memo
222
259
  * and turns every host re-render into a full visible re-slice (~800 cells at 16k columns).
@@ -473,6 +510,21 @@ const ZOOM_MAX = 4
473
510
  * fail-fast — Math.min/max は NaN を素通しし、全 ÷z 境界の汚染と同値バウンド無効化 (NaN 同士は
474
511
  * 不一致) による onZoomChange(NaN) 連射を招くため。
475
512
  */
513
+ /**
514
+ * Validates one overscan prop and returns it unchanged (fail-fast — the engine clamps invalid
515
+ * overscan silently, so rejection is owned by this surface). Undefined is the declared absence
516
+ * signal (engine default) and is exempt. Throws RangeError on a non-integer or negative value.
517
+ * overscan prop 1 つの検証 (値はそのまま返す。fail-fast — エンジンは不正 overscan を無言
518
+ * クランプするため拒否は本層所有)。undefined は宣言不在信号 (エンジン既定) で対象外。非整数・
519
+ * 負値は RangeError。
520
+ */
521
+ const validateOverscan = (name: "overscanRows" | "overscanCols", value: number | undefined): number | undefined => {
522
+ if (value !== undefined && !(Number.isInteger(value) && value >= 0)) {
523
+ throw new RangeError(`[spreadsheet] ${name} must be a non-negative integer (got ${value})`)
524
+ }
525
+ return value
526
+ }
527
+
476
528
  const clampZoom = (value: number): number => {
477
529
  if (!Number.isFinite(value)) {
478
530
  throw new RangeError(`[spreadsheet] zoom must be a finite number (got ${value})`)
@@ -619,6 +671,9 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
619
671
  frozenTrailingColumns = 0,
620
672
  frozenTrailingRows = 0,
621
673
  tapScrollCircleOptions,
674
+ overscanRows,
675
+ overscanCols,
676
+ background,
622
677
  renderCell,
623
678
  onSelectionChange,
624
679
  onCellContextMenu,
@@ -2577,6 +2632,9 @@ export const Spreadsheet = forwardRef<SpreadsheetHandle, SpreadsheetProps & Spre
2577
2632
  frozenTrailingColumns={frozenTrailingColumns}
2578
2633
  frozenTrailingRows={frozenTrailingRows}
2579
2634
  tapScrollCircleOptions={tapScrollCircleOptions}
2635
+ overscanRows={validateOverscan("overscanRows", overscanRows)}
2636
+ overscanCols={validateOverscan("overscanCols", overscanCols)}
2637
+ background={background}
2580
2638
  renderCell={renderCell}
2581
2639
  onScroll={onScroll}
2582
2640
  onRangeChange={onRangeChange}
@@ -318,6 +318,22 @@ type GridBodyProps = {
318
318
  * キー同乗のままエンジン宣言の不在信号 (エンジン既定) — この層での値フォールバックなし。
319
319
  */
320
320
  tapScrollCircleOptions?: ScrollBarTapCircleOptions
321
+ /**
322
+ * Row-axis overscan (the engine `overscanRows` pass-through; the Spreadsheet surface owns
323
+ * the fail-fast validation — the engine clamps silently). Undefined ⇒ engine default (3).
324
+ * 行軸 overscan (エンジン `overscanRows` の素通し。fail-fast 検証は Spreadsheet 面所有 —
325
+ * エンジンは無言クランプ)。undefined ⇒ エンジン既定 (3)。
326
+ */
327
+ overscanRows?: number
328
+ /** Column-axis overscan — the column twin of `overscanRows`, same contract. / 列軸 overscan — `overscanRows` の列双子 (同契約)。 */
329
+ overscanCols?: number
330
+ /**
331
+ * Background layer behind the scroll-band rows (the engine `background` pass-through;
332
+ * viewport-pinned — the engine translates only its row wrapper).
333
+ * スクロール帯行背後の背景レイヤー (エンジン `background` の素通し。viewport 固定 —
334
+ * エンジンが translate するのは行ラッパーのみ)。
335
+ */
336
+ background?: ReactNode
321
337
  }
322
338
 
323
339
  /**
@@ -348,6 +364,9 @@ const GridBodyInner = ({
348
364
  cfMemoRef,
349
365
  isPointing,
350
366
  tapScrollCircleOptions,
367
+ overscanRows,
368
+ overscanCols,
369
+ background,
351
370
  }: GridBodyProps): ReactNode => {
352
371
  const internalBodyRef = useRef<HTMLDivElement | null>(null)
353
372
  // 外部 ref (エンジン結線用) と内部 ref の合成
@@ -517,6 +536,9 @@ const GridBodyInner = ({
517
536
  contentProps={contentProps}
518
537
  behaviorOptions={behaviorOptions}
519
538
  scrollBarOptions={scrollBarOptions}
539
+ overscanRows={overscanRows}
540
+ overscanCols={overscanCols}
541
+ background={background}
520
542
  callbackThrottleMs={0}
521
543
  onScroll={onScroll}
522
544
  onRangeChange={onRangeChange}