Skip to content

Commit fd7d2bd

Browse files
authored
Merge pull request #1063 from org2AI/fix/session-creator-drag-double-border
fix(session-creator): show one drag border on composer
2 parents 3ec311f + e3b06a7 commit fd7d2bd

6 files changed

Lines changed: 35 additions & 32 deletions

File tree

src/app/root/services/GlobalDragDrop/index.scss

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
transform 0.15s ease;
77
}
88

9+
// One border layer only: the element's own border + ring. No inset ::after
10+
// duplicate — a second line inside the shell reads as a double border on the
11+
// session-creator composer.
912
body[data-chat-file-dragging="true"] [data-chat-drop-target] {
1013
border-color: var(--color-primary-6) !important;
1114
box-shadow:
@@ -17,12 +20,3 @@ body[data-chat-file-dragging="true"] [data-chat-drop-target] {
1720
var(--color-bg-1)
1821
) !important;
1922
}
20-
21-
body[data-chat-file-dragging="true"] [data-chat-drop-target]::after {
22-
content: "";
23-
position: absolute;
24-
inset: 0;
25-
border: 1px solid var(--color-primary-6);
26-
border-radius: inherit;
27-
pointer-events: none;
28-
}

src/config/inputAreaTokens.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ export const INPUT_AREA = {
4343
shellInteractionClasses:
4444
"border border-solid border-border-2 transition-[border-color,box-shadow] duration-200 ease-in-out focus-within:border-primary-6 focus-within:shadow-[0_0_0_2px_color-mix(in_srgb,var(--color-primary-6)_15%,transparent)] [&:not(:focus-within):hover]:border-border-3",
4545

46+
/**
47+
* Drag-over highlight — primary border, tinted background, soft 2px primary
48+
* ring. Every composer shell with `data-chat-drop-target` must apply this
49+
* while a drag is over it: the `!` marks let it beat the focus/hover
50+
* interaction classes above and GlobalDragDrop's scss fallback shadow, so
51+
* the shell shows one ring instead of a stacked double border.
52+
*/
53+
shellDragOverClasses:
54+
"!border-primary-6 !bg-[color-mix(in_srgb,var(--color-primary-6)_5%,var(--color-chat-input))] !shadow-[0_0_0_2px_color-mix(in_srgb,var(--color-primary-6)_20%,transparent)]",
55+
4656
/**
4757
* Sent user-message card in chat history — border only, no shadow, no focus
4858
* ring, no primary glow. Hover shows border-3. Click opens edit mode; while

src/engines/ChatPanel/InputArea/components/InputAreaChrome.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from "react";
22
import { useTranslation } from "react-i18next";
33

4+
import { INPUT_AREA } from "@src/config/inputAreaTokens";
45
import { ChatStatusSegmentedBar } from "@src/engines/ChatPanel/components/ChatStatusBanners";
56

67
import ChatHeader from "../ChatHeader";
@@ -152,7 +153,7 @@ export const getComposerShellClassName = ({
152153
quietEditSurface: boolean;
153154
}): string | undefined => {
154155
if (isDragOver) {
155-
return "!border-primary-6 !bg-[color-mix(in_srgb,var(--color-primary-6)_5%,var(--color-chat-input))] !shadow-[0_0_0_2px_color-mix(in_srgb,var(--color-primary-6)_20%,transparent)]";
156+
return INPUT_AREA.shellDragOverClasses;
156157
}
157158
if (!isEditMode) return "composer-breathing";
158159
if (quietEditSurface) {

src/engines/ChatPanel/InputArea/hooks/useContainerDrag.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@ import { useTabDragHover } from "./useTabDragHover";
2626
* over the chat panel. GlobalDragDrop sets `data-chat-file-dragging="true"` on
2727
* `document.body` during Tauri native drag events so we observe that attribute
2828
* via a MutationObserver rather than relying on unavailable HTML5 drag events.
29+
*
30+
* Exported so every composer shell with `data-chat-drop-target` can swap in
31+
* the same React drag highlight during OS file drags. A shell that skips this
32+
* shows GlobalDragDrop's scss fallback (hard 1px ring + inset `::after` line)
33+
* stacked on its own border — which reads as a double border.
2934
*/
30-
function useExternalFileDragOver(
31-
containerRef: React.RefObject<HTMLDivElement | null>
35+
export function useExternalFileDragOver(
36+
containerRef: React.RefObject<HTMLElement | null>
3237
): boolean {
3338
const [isExternalDragOver, setIsExternalDragOver] = useState(false);
3439

src/features/SessionCreator/components/EditorArea.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,30 @@ import ComposerShell from "@src/components/ComposerShell";
1717
import Message from "@src/components/Message";
1818
import { VoiceInputButton, VoiceRecordingBar } from "@src/components/Voice";
1919
import {
20+
INPUT_AREA,
2021
INPUT_AREA_EDITOR_CLASS,
2122
INPUT_AREA_EDITOR_HEIGHT,
2223
} from "@src/config/inputAreaTokens";
2324
import { capPillText, storePillText } from "@src/config/pillTokens";
2425
import type { ComposerModeEntry } from "@src/config/sessionCreatorConfig";
2526
import ContextMenuPortal from "@src/engines/ChatPanel/InputArea/components/ContextMenuPortal";
2627
import SlashCommandPortal from "@src/engines/ChatPanel/InputArea/components/SlashCommandPortal";
28+
import { useExternalFileDragOver } from "@src/engines/ChatPanel/InputArea/hooks/useContainerDrag";
29+
import { useTabDragHover } from "@src/engines/ChatPanel/InputArea/hooks/useTabDragHover";
2730
import { type VoiceInputError, useVoiceInput } from "@src/hooks/voice";
2831
import i18n from "@src/i18n";
2932
import {
3033
clearReferenceDragData,
3134
getReferenceDragPillData,
3235
hasReferenceDragData,
3336
} from "@src/shared/dnd/referenceDragData";
37+
import { useTabDragEndToPill } from "@src/shared/dnd/useTabDragEndToPill";
3438
import { chatAppearanceAtom } from "@src/store/config/configAtom";
3539
import { voiceInputEnabledAtom } from "@src/store/platform/voiceInputAtom";
3640
import type { RepoKind } from "@src/store/repo/types";
3741
import type { ChatImageAttachment } from "@src/store/ui/chatImageAtom";
3842
import type { SlashItem } from "@src/types/extensions";
3943

40-
import { useTabDragDrop } from "../hooks/useTabDragDrop";
4144
import type { AdvancedConfig, UploadedFile } from "../types";
4245
import ControlButtons, { type DropdownDirection } from "./ControlButtons";
4346
import ImageThumbnailRow from "./ImageThumbnailRow";
@@ -300,9 +303,15 @@ const EditorArea: React.FC<EditorAreaProps> = ({
300303
const voiceFeatureEnabled = useAtomValue(voiceInputEnabledAtom);
301304
const { sendOnEnter } = useAtomValue(chatAppearanceAtom);
302305

303-
const isTabDragOver = useTabDragDrop(editorContainerRef, composerInputRef);
306+
const isTabDragOver = useTabDragHover(editorContainerRef);
307+
useTabDragEndToPill(editorContainerRef, composerInputRef);
308+
// OS file drags never fire HTML5 drag events here (Tauri swallows them), so
309+
// without this the shell keeps its rest border while GlobalDragDrop's scss
310+
// fallback paints a second ring on top — the double-border regression.
311+
const isExternalFileDragOver = useExternalFileDragOver(editorContainerRef);
304312
const [isReferenceDragOver, setIsReferenceDragOver] = useState(false);
305-
const isDragOver = isTabDragOver || isReferenceDragOver;
313+
const isDragOver =
314+
isTabDragOver || isReferenceDragOver || isExternalFileDragOver;
306315

307316
const hasReferenceDrag = useCallback(
308317
(types?: readonly string[]) => hasReferenceDragData(types),
@@ -518,9 +527,7 @@ const EditorArea: React.FC<EditorAreaProps> = ({
518527
data-chat-drop-target
519528
className={[
520529
"wp_text_area",
521-
isDragOver
522-
? "!border-primary-6 !bg-[color-mix(in_srgb,var(--color-primary-6)_5%,var(--color-chat-input))] !shadow-[0_0_0_2px_color-mix(in_srgb,var(--color-primary-6)_20%,transparent)]"
523-
: "",
530+
isDragOver ? INPUT_AREA.shellDragOverClasses : "",
524531
headerContent ? "!pt-1.5" : "",
525532
shellClassName ?? "",
526533
]

src/features/SessionCreator/hooks/useTabDragDrop.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)