mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-14 09:11:54 +00:00
refactor(web): consume DS primitives, remove local component copies
Replace locally-forked UI components and hooks with their newly
promoted counterparts from @nous-research/ui:
Deleted local components (now in DS):
- components/ui/input.tsx, label.tsx, separator.tsx, card.tsx,
confirm-dialog.tsx
- components/Toast.tsx, BottomPickSheet.tsx, NouiTypography.tsx
- hooks/useToast.ts, useModalBehavior.ts, useBelowBreakpoint.ts,
useConfirmDelete.ts
Import updates across 25 files to use DS deep imports:
- @nous-research/ui/ui/components/{input,label,separator,card,
confirm-dialog,toast,bottom-sheet}
- @nous-research/ui/ui/components/typography (replaces NouiTypography)
- @nous-research/ui/hooks/{use-toast,use-modal-behavior,
use-below-breakpoint,use-confirm-delete}
Requires design-language >= feat/promote-hermes-web-primitives.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a84cec61ca
commit
c9e5a9bb08
36 changed files with 77 additions and 759 deletions
|
|
@ -1,19 +0,0 @@
|
|||
import { useEffect, useState } from "react";
|
||||
|
||||
/** True when viewport width is strictly below `px` (matches Tailwind `min-width: px`). */
|
||||
export function useBelowBreakpoint(px: number) {
|
||||
const query = `(max-width: ${px - 1}px)`;
|
||||
const [matches, setMatches] = useState(() =>
|
||||
typeof window !== "undefined" ? window.matchMedia(query).matches : false,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const mql = window.matchMedia(query);
|
||||
const sync = () => setMatches(mql.matches);
|
||||
sync();
|
||||
mql.addEventListener("change", sync);
|
||||
return () => mql.removeEventListener("change", sync);
|
||||
}, [query]);
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
import { useCallback, useState } from "react";
|
||||
|
||||
export function useConfirmDelete<TId>({
|
||||
onDelete,
|
||||
}: {
|
||||
onDelete: (id: TId) => Promise<void>;
|
||||
}) {
|
||||
const [pendingId, setPendingId] = useState<TId | null>(null);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
const requestDelete = useCallback((id: TId) => {
|
||||
setPendingId(id);
|
||||
}, []);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
if (!isDeleting) setPendingId(null);
|
||||
}, [isDeleting]);
|
||||
|
||||
const confirm = useCallback(async () => {
|
||||
if (pendingId === null) return;
|
||||
const id = pendingId;
|
||||
setIsDeleting(true);
|
||||
try {
|
||||
await onDelete(id);
|
||||
setPendingId(null);
|
||||
} catch {
|
||||
// Dialog stays open; caller can surface errors in onDelete before rethrowing
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
}, [pendingId, onDelete]);
|
||||
|
||||
return {
|
||||
cancel,
|
||||
confirm,
|
||||
isDeleting,
|
||||
isOpen: pendingId !== null,
|
||||
pendingId,
|
||||
requestDelete,
|
||||
} as const;
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import { useEffect, useRef } from "react";
|
||||
|
||||
/**
|
||||
* Hook that adds standard modal behaviors when `open` is true:
|
||||
* - Escape key calls `onClose`
|
||||
* - Body scroll is locked
|
||||
* - Focus is restored to the previously focused element on close
|
||||
*
|
||||
* Returns a ref to attach to the modal container (for optional future focus trapping).
|
||||
*/
|
||||
export function useModalBehavior({
|
||||
open,
|
||||
onClose,
|
||||
}: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
|
||||
const prevActive = document.activeElement as HTMLElement | null;
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", onKey);
|
||||
const prevOverflow = document.body.style.overflow;
|
||||
document.body.style.overflow = "hidden";
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", onKey);
|
||||
document.body.style.overflow = prevOverflow;
|
||||
prevActive?.focus?.();
|
||||
};
|
||||
}, [open, onClose]);
|
||||
|
||||
return containerRef;
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import { useCallback, useState } from "react";
|
||||
|
||||
export function useToast(duration = 3000) {
|
||||
const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null);
|
||||
|
||||
const showToast = useCallback(
|
||||
(message: string, type: "success" | "error") => {
|
||||
setToast({ message, type });
|
||||
setTimeout(() => setToast(null), duration);
|
||||
},
|
||||
[duration],
|
||||
);
|
||||
|
||||
return { toast, showToast };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue