diff --git a/ordinis-admin-ui/src/routes/dictionaries.$name.tsx b/ordinis-admin-ui/src/routes/dictionaries.$name.tsx index 382f277..007404a 100644 --- a/ordinis-admin-ui/src/routes/dictionaries.$name.tsx +++ b/ordinis-admin-ui/src/routes/dictionaries.$name.tsx @@ -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 к нативному , но `indeterminate` это JS DOM-only prop + // (не HTML attribute), нужен manual sync. + const selectAllRef = useRef(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() { { - if (el) el.indeterminate = someVisibleSelected - }} + ref={selectAllRef} onChange={toggleSelectAll} />