[Haik]: pt2 of going thru knip errors

This commit is contained in:
haikdc
2026-03-30 23:21:22 -07:00
parent de47fc06e6
commit 0dd56bb599
5 changed files with 28 additions and 35 deletions
@@ -5,7 +5,7 @@ export const SELECT_ID_ATTR = 'data-select-id';
export const SELECT_META_ATTR = 'data-select-meta';
const DRAG_SELECT_TYPES = ['agent-card', 'view-card', 'browser-card'] as const;
export const DRAG_SELECTOR = DRAG_SELECT_TYPES.map((t) => `[${SELECT_ATTR}="${t}"]`).join(',');
const DRAG_SELECTOR = DRAG_SELECT_TYPES.map((t) => `[${SELECT_ATTR}="${t}"]`).join(',');
export interface OverlayState {
visible: boolean;
@@ -27,6 +27,15 @@ export interface DragRect {
export const EMPTY_OVERLAY: OverlayState = { visible: false, top: 0, left: 0, width: 0, height: 0, label: '' };
export const EMPTY_DRAG: DragRect = { visible: false, top: 0, left: 0, width: 0, height: 0 };
export interface SelectMeta {
name?: string;
role?: string;
content?: string;
label?: string;
tool?: string;
[key: string]: unknown;
}
const SEMANTIC_LABELS: Record<string, string> = {
'agent-card': 'Agent',
'message': 'Message',
@@ -48,7 +57,7 @@ export function findSelectableAncestor(target: Element, excludeId?: string | nul
return null;
}
export function buildSemanticLabel(type: string, meta: Record<string, any>): string {
export function buildSemanticLabel(type: string, meta: SelectMeta): string {
const prefix = SEMANTIC_LABELS[type] || type;
if (meta.name) return `${prefix}: ${meta.name}`;
if (meta.role && meta.content) {
@@ -60,7 +69,7 @@ export function buildSemanticLabel(type: string, meta: Record<string, any>): str
return prefix;
}
export function rectsIntersect(
function rectsIntersect(
a: { top: number; left: number; bottom: number; right: number },
b: { top: number; left: number; bottom: number; right: number },
): boolean {
@@ -70,8 +79,8 @@ export function rectsIntersect(
export function buildSelectedElement(el: Element): SelectedElement {
const type = el.getAttribute(SELECT_ATTR) || '';
const selectId = el.getAttribute(SELECT_ID_ATTR) || '';
let meta: Record<string, any> = {};
try { meta = JSON.parse(el.getAttribute(SELECT_META_ATTR) || '{}'); } catch {}
let meta: SelectMeta = {};
try { meta = JSON.parse(el.getAttribute(SELECT_META_ATTR) || '{}'); } catch { /* malformed JSON defaults to empty object */ }
const rect = el.getBoundingClientRect();
const semanticLabel = buildSemanticLabel(type, meta);
@@ -123,8 +132,8 @@ export function computeDragPreview(
if (seen.has(selectId)) return;
seen.add(selectId);
const type = el.getAttribute(SELECT_ATTR) || '';
let meta: Record<string, any> = {};
try { meta = JSON.parse(el.getAttribute(SELECT_META_ATTR) || '{}'); } catch {}
let meta: SelectMeta = {};
try { meta = JSON.parse(el.getAttribute(SELECT_META_ATTR) || '{}'); } catch { /* malformed JSON defaults to empty object */ }
preview.push({
selectId,
top: rect.top,
@@ -16,6 +16,4 @@ export const SUBSCRIPTION_PROVIDERS = [
{ id: 'gemini-cli', name: 'Gemini', desc: 'Gemini 2.5 Pro & Flash', color: '#4285F4', preview: true },
{ id: 'codex', name: 'ChatGPT', desc: 'GPT-5.4, o3, o4-mini', color: '#74AA9C', preview: true },
{ id: 'github', name: 'GitHub Copilot', desc: 'Claude + GPT models', color: '#8B949E', preview: true },
];
export type SubscriptionProvider = typeof SUBSCRIPTION_PROVIDERS[number];
];
@@ -1,5 +1,5 @@
export const SKILL_PILL_ATTR = 'data-skill-id';
export const SKILL_COLOR = '#7B61BD';
const SKILL_COLOR = '#7B61BD';
export interface AttachedSkill {
id: string;
@@ -1,14 +1,14 @@
import { useEffect, useRef, useState, useCallback } from 'react';
import { useElementSelection } from './ElementSelectionContext';
import {
type OverlayState, type DragRect, type DragPreviewElement, type DomSelectorState,
type OverlayState, type DragRect, type DragPreviewElement, type DomSelectorState, type SelectMeta,
EMPTY_OVERLAY, EMPTY_DRAG, DRAG_THRESHOLD,
SELECT_ATTR, SELECT_ID_ATTR, SELECT_META_ATTR,
findSelectableAncestor, buildSemanticLabel, buildSelectedElement,
computeDragPreview, processDragSelection,
} from './domSelectorHelpers';
export type { OverlayState, DragRect, DragPreviewElement, DomSelectorState } from './domSelectorHelpers';
export type { OverlayState, DragRect, DragPreviewElement } from './domSelectorHelpers';
export function useDomElementSelector(): DomSelectorState {
const ctx = useElementSelection();
@@ -98,8 +98,8 @@ export function useDomElementSelector(): DomSelectorState {
rafRef.current = requestAnimationFrame(() => {
const rect = selectable.getBoundingClientRect();
const type = selectable.getAttribute(SELECT_ATTR) || '';
let meta: Record<string, any> = {};
try { meta = JSON.parse(selectable.getAttribute(SELECT_META_ATTR) || '{}'); } catch {}
let meta: SelectMeta = {};
try { meta = JSON.parse(selectable.getAttribute(SELECT_META_ATTR) || '{}'); } catch { /* malformed meta */ }
const label = buildSemanticLabel(type, meta);
setOverlay({
visible: true,
@@ -177,17 +177,7 @@ export function useDomElementSelector(): DomSelectorState {
}, [ctx]);
useEffect(() => {
if (!ctx?.selectMode) {
setOverlay(EMPTY_OVERLAY);
setDragRect(EMPTY_DRAG);
setDragPreview([]);
hoveredRef.current = null;
dragOriginRef.current = null;
dragBoundsRef.current = null;
isDraggingRef.current = false;
preDragFocusRef.current = null;
return;
}
if (!ctx?.selectMode) return;
const prevUserSelect = document.body.style.userSelect;
document.body.style.userSelect = 'none';
@@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from 'react';
import React, { useState, useRef, useEffect, useId, forwardRef, useImperativeHandle } from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import CircularProgress from '@mui/material/CircularProgress';
@@ -16,11 +16,7 @@ import AttachmentChips from './AttachmentChips';
import ModelModeSelector from './ModelModeSelector';
import { useChatSubmit } from './hooks/useChatSubmit';
export type { AttachedImage } from './ImageAttachments';
export type { ForcedToolGroup } from './AttachmentChips';
export type { AttachedSkill } from '@/app/components/richEditorUtils';
export interface Props {
interface Props {
onSend: (message: string, images?: Array<{ data: string; media_type: string }>, contextPaths?: ContextPath[], forcedTools?: string[], attachedSkills?: Array<{ id: string; name: string; content: string }>, selectedBrowserIds?: string[]) => void;
disabled?: boolean;
mode: string; onModeChange: (mode: string) => void;
@@ -48,15 +44,15 @@ const ChatInput = forwardRef<ChatInputHandle, Props>(({
const generalFileInputRef = useRef<HTMLInputElement>(null);
const elementSelection = useElementSelection();
const fallbackOwnerIdRef = useRef(`input-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`);
const ownerId = sessionId || fallbackOwnerIdRef.current;
const fallbackOwnerId = useId();
const ownerId = sessionId || fallbackOwnerId;
useEffect(() => { if (autoFocus) editorRef.current?.focus(); }, [autoFocus]);
const [hasContent, setHasContent] = useState(false);
const [attachedSkills, setAttachedSkills] = useState<Record<string, AttachedSkill>>({});
const attachedSkillsRef = useRef(attachedSkills);
attachedSkillsRef.current = attachedSkills;
useEffect(() => { attachedSkillsRef.current = attachedSkills; });
const [picker, setPicker] = useState<TriggerState>(EMPTY_TRIGGER);
const skills = useAppSelector((state) => state.skills.items);
const modesMap = useAppSelector((state) => state.modes.items);