Merge branch 'fix/checkbox-indeterminate-sync' into 'main'

fix(admin-ui): Checkbox indeterminate stale state

See merge request 2-6/2-6-4/terravault/ordinis!22
This commit is contained in:
Александр Зимин
2026-05-10 18:53:07 +00:00
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import axios from 'axios'
@@ -288,6 +288,19 @@ function DictionaryDetail() {
const someVisibleSelected =
!allVisibleSelected && visibleKeys.some((k) => selection.has(k))
// Native checkbox indeterminate state — sync через useEffect, не callback ref.
// Callback ref срабатывает только на mount/unmount → state становится stale
// когда user toggle'ает selection per-row. useEffect re-runs на изменение
// someVisibleSelected. См. design handoff review #17 + Checkbox в @nstart/ui:
// ref forwarded к нативному <input>, но `indeterminate` это JS DOM-only prop
// (не HTML attribute), нужен manual sync.
const selectAllRef = useRef<HTMLInputElement>(null)
useEffect(() => {
if (selectAllRef.current) {
selectAllRef.current.indeterminate = someVisibleSelected
}
}, [someVisibleSelected])
const toggleSelect = (key: string) => {
setSelection((prev) => {
const next = new Set(prev)
@@ -737,10 +750,7 @@ function DictionaryDetail() {
<Checkbox
aria-label={t('dict.bulk.selectAll')}
checked={allVisibleSelected}
// Native checkbox indeterminate через ref — для partial select
ref={(el) => {
if (el) el.indeterminate = someVisibleSelected
}}
ref={selectAllRef}
onChange={toggleSelectAll}
/>
</TableHeaderCell>