@arqel-dev/hooks — Referencia de API
10 Hooks reutilizables. 11 entry points tree-shakeables por subpath.
import { useResource, useArqelForm, useCanAccess, useFlash, useTable,
useAction, useFieldDependencies, useNavigation, useBreakpoint,
useArqelOptimistic } from '@arqel-dev/hooks';useResource<T>()
Lee props de la página + ResourceContext, retorna una forma unificada.
const { resource, record, fields, form, table } = useResource<Post>();useArqelForm({ fields, record? })
Wrapper del useForm de Inertia con defaults vía buildInitialFormState.
const form = useArqelForm({ fields, record });
form.data.title // typed via FormValues
form.setData(name, v)
form.processing
form.errors
form.submit('post', route('arqel.resources.store'), { onSuccess: () => {} });Nota técnica: El
useForm<T>de Inertia sufre de "type instantiation excessively deep" conRecord<string, FormDataConvertible>—useArqelFormhace un cast puenteuseForm as unknown as (data: FormValues) => InertiaFormProps<FormValues>para evitar TS2589 preservando el tipo de retorno público.
useCanAccess(ability, record?)
const canEdit = useCanAccess('update', post);
const canExport = useCanAccess('exportData'); // global abilityLas abilities a nivel de registro tienen precedencia sobre las globales (solo UX — ADR-017).
useFlash({ onMessage })
Callback once-per-new-message vía useRef.
useFlash({
onMessage: ({ kind, text }) => toast(text, { type: kind })
});useTable()
Sort/filters/selección locales (URL sync diferido al follow-up HOOKS-004).
const { sort, setSort, filters, setFilter, selection, toggleSelection, clearSelection } = useTable();useAction(action)
Wrapper de router.visit con un flag processing.
const { invoke, processing } = useAction(action);
<button onClick={() => invoke({ record })} disabled={processing}>...useFieldDependencies()
Recarga parcial de Inertia con debounce de 300ms para fields.<name>.options.
useFieldDependencies(); // injected in <FieldRenderer>Se dispara cuando un field marcado con dependsOn(['country']) re-resuelve options server-side vía Resource.handleDependencyUpdate.
useNavigation()
Lee el prop compartido de Inertia panel.navigation (poblado server-side por HandleArqelInertiaRequests::buildNavigation()).
const { items } = useNavigation();
// items: NavigationItemPayload[]NavigationItemPayload:
type NavigationItemPayload = {
label: string;
url: string;
icon: string | null; // lucide-react ID
group: string | null; // grouping label, null = top-level
sort: number;
active: boolean; // resolved server-side via current request
};Consumido por <Sidebar> (bloque shadcn sidebar-07) — los items se agrupan por group al renderizar.
useTheme()
Re-exportado desde @arqel-dev/theme. Requiere <ThemeProvider> en el árbol (incluido automáticamente en <ArqelProvider> / createArqelApp). Sin el Provider, lanza un error descriptivo.
const { theme, resolved, setTheme, toggle } = useTheme();useBreakpoint()
Breakpoint de Tailwind v4 vía matchMedia. SSR-safe.
const bp = useBreakpoint();
// { current: 'sm' | 'md' | 'lg' | 'xl' | '2xl', isMobile: boolean }useArqelOptimistic()
Wrapper del useOptimistic de React 19.
const [optimisticPosts, addOptimistic] = useArqelOptimistic(posts, (state, newPost) => [...state, newPost]);Relacionado
- SKILL:
packages-js/hooks/SKILL.md - Siguiente:
@arqel-dev/ui