Inline base64 source maps had been checked into tracked src files. This strips those comments from the repository without changing runtime behavior or adding ongoing guardrails, per the requested one-time cleanup scope. Constraint: Keep this change limited to tracked source cleanup only Rejected: Add CI/source verification guard | user requested one-time cleanup only Confidence: high Scope-risk: narrow Reversibility: clean Directive: If these directives reappear, fix the producing transform instead of reintroducing repo-side cleanup code Tested: rg -n "sourceMappingURL" ., bun run smoke, bun run verify:privacy, bun run test:provider, npm run test:provider-recommendation Not-tested: bun run typecheck (repository has many pre-existing unrelated failures) Co-authored-by: anandh8x <test@example.com>
488 lines
16 KiB
TypeScript
488 lines
16 KiB
TypeScript
import { c as _c } from "react-compiler-runtime";
|
|
import React, { type ReactNode, useEffect, useRef, useState } from 'react';
|
|
// eslint-disable-next-line custom-rules/prefer-use-keybindings -- UP arrow exit not in Attachments bindings
|
|
import { Box, Text, useInput } from '../../ink.js';
|
|
import { useKeybinding, useKeybindings } from '../../keybindings/useKeybinding.js';
|
|
import type { PastedContent } from '../../utils/config.js';
|
|
import { getImageFromClipboard } from '../../utils/imagePaste.js';
|
|
import type { ImageDimensions } from '../../utils/imageResizer.js';
|
|
import { ClickableImageRef } from '../ClickableImageRef.js';
|
|
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
|
|
import { Byline } from '../design-system/Byline.js';
|
|
import TextInput from '../TextInput.js';
|
|
import type { OptionWithDescription } from './select.js';
|
|
import { SelectOption } from './select-option.js';
|
|
type Props<T> = {
|
|
option: Extract<OptionWithDescription<T>, {
|
|
type: 'input';
|
|
}>;
|
|
isFocused: boolean;
|
|
isSelected: boolean;
|
|
shouldShowDownArrow: boolean;
|
|
shouldShowUpArrow: boolean;
|
|
maxIndexWidth: number;
|
|
index: number;
|
|
inputValue: string;
|
|
onInputChange: (value: string) => void;
|
|
onSubmit: (value: string) => void;
|
|
onExit?: () => void;
|
|
layout: 'compact' | 'expanded';
|
|
children?: ReactNode;
|
|
/**
|
|
* When true, shows the label before the input field.
|
|
* When false (default), uses the label as the placeholder.
|
|
*/
|
|
showLabel?: boolean;
|
|
/**
|
|
* Callback to open external editor for editing the input value.
|
|
* When provided, ctrl+g will trigger this callback with the current value
|
|
* and a setter function to update the internal state.
|
|
*/
|
|
onOpenEditor?: (currentValue: string, setValue: (value: string) => void) => void;
|
|
/**
|
|
* When true, automatically reset cursor to end of line when:
|
|
* - Option becomes focused
|
|
* - Input value changes
|
|
* This prevents cursor position bugs when the input value updates asynchronously.
|
|
*/
|
|
resetCursorOnUpdate?: boolean;
|
|
/**
|
|
* Optional callback when an image is pasted into the input.
|
|
*/
|
|
onImagePaste?: (base64Image: string, mediaType?: string, filename?: string, dimensions?: ImageDimensions, sourcePath?: string) => void;
|
|
/**
|
|
* Pasted content to display inline above the input when focused.
|
|
*/
|
|
pastedContents?: Record<number, PastedContent>;
|
|
/**
|
|
* Callback to remove a pasted image by its ID.
|
|
*/
|
|
onRemoveImage?: (id: number) => void;
|
|
/**
|
|
* Whether image selection mode is active.
|
|
*/
|
|
imagesSelected?: boolean;
|
|
/**
|
|
* Currently selected image index within the image attachments array.
|
|
*/
|
|
selectedImageIndex?: number;
|
|
/**
|
|
* Callback to set image selection mode on/off.
|
|
*/
|
|
onImagesSelectedChange?: (selected: boolean) => void;
|
|
/**
|
|
* Callback to change the selected image index.
|
|
*/
|
|
onSelectedImageIndexChange?: (index: number) => void;
|
|
};
|
|
export function SelectInputOption(t0) {
|
|
const $ = _c(100);
|
|
const {
|
|
option,
|
|
isFocused,
|
|
isSelected,
|
|
shouldShowDownArrow,
|
|
shouldShowUpArrow,
|
|
maxIndexWidth,
|
|
index,
|
|
inputValue,
|
|
onInputChange,
|
|
onSubmit,
|
|
onExit,
|
|
layout,
|
|
children,
|
|
showLabel: t1,
|
|
onOpenEditor,
|
|
resetCursorOnUpdate: t2,
|
|
onImagePaste,
|
|
pastedContents,
|
|
onRemoveImage,
|
|
imagesSelected,
|
|
selectedImageIndex: t3,
|
|
onImagesSelectedChange,
|
|
onSelectedImageIndexChange
|
|
} = t0;
|
|
const showLabelProp = t1 === undefined ? false : t1;
|
|
const resetCursorOnUpdate = t2 === undefined ? false : t2;
|
|
const selectedImageIndex = t3 === undefined ? 0 : t3;
|
|
let t4;
|
|
if ($[0] !== pastedContents) {
|
|
t4 = pastedContents ? Object.values(pastedContents).filter(_temp) : [];
|
|
$[0] = pastedContents;
|
|
$[1] = t4;
|
|
} else {
|
|
t4 = $[1];
|
|
}
|
|
const imageAttachments = t4;
|
|
const showLabel = showLabelProp || option.showLabelWithValue === true;
|
|
const [cursorOffset, setCursorOffset] = useState(inputValue.length);
|
|
const isUserEditing = useRef(false);
|
|
let t5;
|
|
if ($[2] !== inputValue.length || $[3] !== isFocused || $[4] !== resetCursorOnUpdate) {
|
|
t5 = () => {
|
|
if (resetCursorOnUpdate && isFocused) {
|
|
if (isUserEditing.current) {
|
|
isUserEditing.current = false;
|
|
} else {
|
|
setCursorOffset(inputValue.length);
|
|
}
|
|
}
|
|
};
|
|
$[2] = inputValue.length;
|
|
$[3] = isFocused;
|
|
$[4] = resetCursorOnUpdate;
|
|
$[5] = t5;
|
|
} else {
|
|
t5 = $[5];
|
|
}
|
|
let t6;
|
|
if ($[6] !== inputValue || $[7] !== isFocused || $[8] !== resetCursorOnUpdate) {
|
|
t6 = [resetCursorOnUpdate, isFocused, inputValue];
|
|
$[6] = inputValue;
|
|
$[7] = isFocused;
|
|
$[8] = resetCursorOnUpdate;
|
|
$[9] = t6;
|
|
} else {
|
|
t6 = $[9];
|
|
}
|
|
useEffect(t5, t6);
|
|
let t7;
|
|
if ($[10] !== inputValue || $[11] !== onInputChange || $[12] !== onOpenEditor) {
|
|
t7 = () => {
|
|
onOpenEditor?.(inputValue, onInputChange);
|
|
};
|
|
$[10] = inputValue;
|
|
$[11] = onInputChange;
|
|
$[12] = onOpenEditor;
|
|
$[13] = t7;
|
|
} else {
|
|
t7 = $[13];
|
|
}
|
|
const t8 = isFocused && !!onOpenEditor;
|
|
let t9;
|
|
if ($[14] !== t8) {
|
|
t9 = {
|
|
context: "Chat",
|
|
isActive: t8
|
|
};
|
|
$[14] = t8;
|
|
$[15] = t9;
|
|
} else {
|
|
t9 = $[15];
|
|
}
|
|
useKeybinding("chat:externalEditor", t7, t9);
|
|
let t10;
|
|
if ($[16] !== onImagePaste) {
|
|
t10 = () => {
|
|
if (!onImagePaste) {
|
|
return;
|
|
}
|
|
getImageFromClipboard().then(imageData => {
|
|
if (imageData) {
|
|
onImagePaste(imageData.base64, imageData.mediaType, undefined, imageData.dimensions);
|
|
}
|
|
});
|
|
};
|
|
$[16] = onImagePaste;
|
|
$[17] = t10;
|
|
} else {
|
|
t10 = $[17];
|
|
}
|
|
const t11 = isFocused && !!onImagePaste;
|
|
let t12;
|
|
if ($[18] !== t11) {
|
|
t12 = {
|
|
context: "Chat",
|
|
isActive: t11
|
|
};
|
|
$[18] = t11;
|
|
$[19] = t12;
|
|
} else {
|
|
t12 = $[19];
|
|
}
|
|
useKeybinding("chat:imagePaste", t10, t12);
|
|
let t13;
|
|
if ($[20] !== imageAttachments || $[21] !== onRemoveImage) {
|
|
t13 = () => {
|
|
if (imageAttachments.length > 0 && onRemoveImage) {
|
|
onRemoveImage(imageAttachments.at(-1).id);
|
|
}
|
|
};
|
|
$[20] = imageAttachments;
|
|
$[21] = onRemoveImage;
|
|
$[22] = t13;
|
|
} else {
|
|
t13 = $[22];
|
|
}
|
|
const t14 = isFocused && !imagesSelected && inputValue === "" && imageAttachments.length > 0 && !!onRemoveImage;
|
|
let t15;
|
|
if ($[23] !== t14) {
|
|
t15 = {
|
|
context: "Attachments",
|
|
isActive: t14
|
|
};
|
|
$[23] = t14;
|
|
$[24] = t15;
|
|
} else {
|
|
t15 = $[24];
|
|
}
|
|
useKeybinding("attachments:remove", t13, t15);
|
|
let t16;
|
|
let t17;
|
|
if ($[25] !== imageAttachments.length || $[26] !== onSelectedImageIndexChange || $[27] !== selectedImageIndex) {
|
|
t16 = () => {
|
|
if (imageAttachments.length > 1) {
|
|
onSelectedImageIndexChange?.((selectedImageIndex + 1) % imageAttachments.length);
|
|
}
|
|
};
|
|
t17 = () => {
|
|
if (imageAttachments.length > 1) {
|
|
onSelectedImageIndexChange?.((selectedImageIndex - 1 + imageAttachments.length) % imageAttachments.length);
|
|
}
|
|
};
|
|
$[25] = imageAttachments.length;
|
|
$[26] = onSelectedImageIndexChange;
|
|
$[27] = selectedImageIndex;
|
|
$[28] = t16;
|
|
$[29] = t17;
|
|
} else {
|
|
t16 = $[28];
|
|
t17 = $[29];
|
|
}
|
|
let t18;
|
|
if ($[30] !== imageAttachments || $[31] !== onImagesSelectedChange || $[32] !== onRemoveImage || $[33] !== onSelectedImageIndexChange || $[34] !== selectedImageIndex) {
|
|
t18 = () => {
|
|
const img = imageAttachments[selectedImageIndex];
|
|
if (img && onRemoveImage) {
|
|
onRemoveImage(img.id);
|
|
if (imageAttachments.length <= 1) {
|
|
onImagesSelectedChange?.(false);
|
|
} else {
|
|
onSelectedImageIndexChange?.(Math.min(selectedImageIndex, imageAttachments.length - 2));
|
|
}
|
|
}
|
|
};
|
|
$[30] = imageAttachments;
|
|
$[31] = onImagesSelectedChange;
|
|
$[32] = onRemoveImage;
|
|
$[33] = onSelectedImageIndexChange;
|
|
$[34] = selectedImageIndex;
|
|
$[35] = t18;
|
|
} else {
|
|
t18 = $[35];
|
|
}
|
|
let t19;
|
|
if ($[36] !== onImagesSelectedChange) {
|
|
t19 = () => {
|
|
onImagesSelectedChange?.(false);
|
|
};
|
|
$[36] = onImagesSelectedChange;
|
|
$[37] = t19;
|
|
} else {
|
|
t19 = $[37];
|
|
}
|
|
let t20;
|
|
if ($[38] !== t16 || $[39] !== t17 || $[40] !== t18 || $[41] !== t19) {
|
|
t20 = {
|
|
"attachments:next": t16,
|
|
"attachments:previous": t17,
|
|
"attachments:remove": t18,
|
|
"attachments:exit": t19
|
|
};
|
|
$[38] = t16;
|
|
$[39] = t17;
|
|
$[40] = t18;
|
|
$[41] = t19;
|
|
$[42] = t20;
|
|
} else {
|
|
t20 = $[42];
|
|
}
|
|
const t21 = isFocused && !!imagesSelected;
|
|
let t22;
|
|
if ($[43] !== t21) {
|
|
t22 = {
|
|
context: "Attachments",
|
|
isActive: t21
|
|
};
|
|
$[43] = t21;
|
|
$[44] = t22;
|
|
} else {
|
|
t22 = $[44];
|
|
}
|
|
useKeybindings(t20, t22);
|
|
let t23;
|
|
if ($[45] !== onImagesSelectedChange) {
|
|
t23 = (_input, key) => {
|
|
if (key.upArrow) {
|
|
onImagesSelectedChange?.(false);
|
|
}
|
|
};
|
|
$[45] = onImagesSelectedChange;
|
|
$[46] = t23;
|
|
} else {
|
|
t23 = $[46];
|
|
}
|
|
const t24 = isFocused && !!imagesSelected;
|
|
let t25;
|
|
if ($[47] !== t24) {
|
|
t25 = {
|
|
isActive: t24
|
|
};
|
|
$[47] = t24;
|
|
$[48] = t25;
|
|
} else {
|
|
t25 = $[48];
|
|
}
|
|
useInput(t23, t25);
|
|
let t26;
|
|
let t27;
|
|
if ($[49] !== imagesSelected || $[50] !== isFocused || $[51] !== onImagesSelectedChange) {
|
|
t26 = () => {
|
|
if (!isFocused && imagesSelected) {
|
|
onImagesSelectedChange?.(false);
|
|
}
|
|
};
|
|
t27 = [isFocused, imagesSelected, onImagesSelectedChange];
|
|
$[49] = imagesSelected;
|
|
$[50] = isFocused;
|
|
$[51] = onImagesSelectedChange;
|
|
$[52] = t26;
|
|
$[53] = t27;
|
|
} else {
|
|
t26 = $[52];
|
|
t27 = $[53];
|
|
}
|
|
useEffect(t26, t27);
|
|
const descriptionPaddingLeft = layout === "expanded" ? maxIndexWidth + 3 : maxIndexWidth + 4;
|
|
const t28 = layout === "compact" ? 0 : undefined;
|
|
const t29 = `${index}.`;
|
|
let t30;
|
|
if ($[54] !== maxIndexWidth || $[55] !== t29) {
|
|
t30 = t29.padEnd(maxIndexWidth + 2);
|
|
$[54] = maxIndexWidth;
|
|
$[55] = t29;
|
|
$[56] = t30;
|
|
} else {
|
|
t30 = $[56];
|
|
}
|
|
let t31;
|
|
if ($[57] !== t30) {
|
|
t31 = <Text dimColor={true}>{t30}</Text>;
|
|
$[57] = t30;
|
|
$[58] = t31;
|
|
} else {
|
|
t31 = $[58];
|
|
}
|
|
let t32;
|
|
if ($[59] !== cursorOffset || $[60] !== imagesSelected || $[61] !== inputValue || $[62] !== isFocused || $[63] !== onExit || $[64] !== onImagePaste || $[65] !== onInputChange || $[66] !== onSubmit || $[67] !== option || $[68] !== showLabel) {
|
|
t32 = showLabel ? <><Text color={isFocused ? "suggestion" : undefined}>{option.label}</Text>{isFocused ? <><Text color="suggestion">{option.labelValueSeparator ?? ", "}</Text><TextInput value={inputValue} onChange={value => {
|
|
isUserEditing.current = true;
|
|
onInputChange(value);
|
|
option.onChange(value);
|
|
}} onSubmit={onSubmit} onExit={onExit} placeholder={option.placeholder} focus={!imagesSelected} showCursor={true} multiline={true} cursorOffset={cursorOffset} onChangeCursorOffset={setCursorOffset} columns={80} onImagePaste={onImagePaste} onPaste={pastedText => {
|
|
isUserEditing.current = true;
|
|
const before = inputValue.slice(0, cursorOffset);
|
|
const after = inputValue.slice(cursorOffset);
|
|
const newValue = before + pastedText + after;
|
|
onInputChange(newValue);
|
|
option.onChange(newValue);
|
|
setCursorOffset(before.length + pastedText.length);
|
|
}} /></> : inputValue && <Text>{option.labelValueSeparator ?? ", "}{inputValue}</Text>}</> : isFocused ? <TextInput value={inputValue} onChange={value_0 => {
|
|
isUserEditing.current = true;
|
|
onInputChange(value_0);
|
|
option.onChange(value_0);
|
|
}} onSubmit={onSubmit} onExit={onExit} placeholder={option.placeholder || (typeof option.label === "string" ? option.label : undefined)} focus={!imagesSelected} showCursor={true} multiline={true} cursorOffset={cursorOffset} onChangeCursorOffset={setCursorOffset} columns={80} onImagePaste={onImagePaste} onPaste={pastedText_0 => {
|
|
isUserEditing.current = true;
|
|
const before_0 = inputValue.slice(0, cursorOffset);
|
|
const after_0 = inputValue.slice(cursorOffset);
|
|
const newValue_0 = before_0 + pastedText_0 + after_0;
|
|
onInputChange(newValue_0);
|
|
option.onChange(newValue_0);
|
|
setCursorOffset(before_0.length + pastedText_0.length);
|
|
}} /> : <Text color={inputValue ? undefined : "inactive"}>{inputValue || option.placeholder || option.label}</Text>;
|
|
$[59] = cursorOffset;
|
|
$[60] = imagesSelected;
|
|
$[61] = inputValue;
|
|
$[62] = isFocused;
|
|
$[63] = onExit;
|
|
$[64] = onImagePaste;
|
|
$[65] = onInputChange;
|
|
$[66] = onSubmit;
|
|
$[67] = option;
|
|
$[68] = showLabel;
|
|
$[69] = t32;
|
|
} else {
|
|
t32 = $[69];
|
|
}
|
|
let t33;
|
|
if ($[70] !== children || $[71] !== t28 || $[72] !== t31 || $[73] !== t32) {
|
|
t33 = <Box flexDirection="row" flexShrink={t28}>{t31}{children}{t32}</Box>;
|
|
$[70] = children;
|
|
$[71] = t28;
|
|
$[72] = t31;
|
|
$[73] = t32;
|
|
$[74] = t33;
|
|
} else {
|
|
t33 = $[74];
|
|
}
|
|
let t34;
|
|
if ($[75] !== isFocused || $[76] !== isSelected || $[77] !== shouldShowDownArrow || $[78] !== shouldShowUpArrow || $[79] !== t33) {
|
|
t34 = <SelectOption isFocused={isFocused} isSelected={isSelected} shouldShowDownArrow={shouldShowDownArrow} shouldShowUpArrow={shouldShowUpArrow} declareCursor={false}>{t33}</SelectOption>;
|
|
$[75] = isFocused;
|
|
$[76] = isSelected;
|
|
$[77] = shouldShowDownArrow;
|
|
$[78] = shouldShowUpArrow;
|
|
$[79] = t33;
|
|
$[80] = t34;
|
|
} else {
|
|
t34 = $[80];
|
|
}
|
|
let t35;
|
|
if ($[81] !== descriptionPaddingLeft || $[82] !== isFocused || $[83] !== isSelected || $[84] !== option.description || $[85] !== option.dimDescription) {
|
|
t35 = option.description && <Box paddingLeft={descriptionPaddingLeft}><Text dimColor={option.dimDescription !== false} color={isSelected ? "success" : isFocused ? "suggestion" : undefined}>{option.description}</Text></Box>;
|
|
$[81] = descriptionPaddingLeft;
|
|
$[82] = isFocused;
|
|
$[83] = isSelected;
|
|
$[84] = option.description;
|
|
$[85] = option.dimDescription;
|
|
$[86] = t35;
|
|
} else {
|
|
t35 = $[86];
|
|
}
|
|
let t36;
|
|
if ($[87] !== descriptionPaddingLeft || $[88] !== imageAttachments || $[89] !== imagesSelected || $[90] !== isFocused || $[91] !== selectedImageIndex) {
|
|
t36 = imageAttachments.length > 0 && <Box flexDirection="row" gap={1} paddingLeft={descriptionPaddingLeft}>{imageAttachments.map((img_0, idx) => <ClickableImageRef key={img_0.id} imageId={img_0.id} isSelected={!!imagesSelected && idx === selectedImageIndex} />)}<Box flexGrow={1} justifyContent="flex-start" flexDirection="row"><Text dimColor={true}>{imagesSelected ? <Byline>{imageAttachments.length > 1 && <><ConfigurableShortcutHint action="attachments:next" context="Attachments" fallback={"\u2192"} description="next" /><ConfigurableShortcutHint action="attachments:previous" context="Attachments" fallback={"\u2190"} description="prev" /></>}<ConfigurableShortcutHint action="attachments:remove" context="Attachments" fallback="backspace" description="remove" /><ConfigurableShortcutHint action="attachments:exit" context="Attachments" fallback="esc" description="cancel" /></Byline> : isFocused ? "(\u2193 to select)" : null}</Text></Box></Box>;
|
|
$[87] = descriptionPaddingLeft;
|
|
$[88] = imageAttachments;
|
|
$[89] = imagesSelected;
|
|
$[90] = isFocused;
|
|
$[91] = selectedImageIndex;
|
|
$[92] = t36;
|
|
} else {
|
|
t36 = $[92];
|
|
}
|
|
let t37;
|
|
if ($[93] !== layout) {
|
|
t37 = layout === "expanded" && <Text> </Text>;
|
|
$[93] = layout;
|
|
$[94] = t37;
|
|
} else {
|
|
t37 = $[94];
|
|
}
|
|
let t38;
|
|
if ($[95] !== t34 || $[96] !== t35 || $[97] !== t36 || $[98] !== t37) {
|
|
t38 = <Box flexDirection="column" flexShrink={0}>{t34}{t35}{t36}{t37}</Box>;
|
|
$[95] = t34;
|
|
$[96] = t35;
|
|
$[97] = t36;
|
|
$[98] = t37;
|
|
$[99] = t38;
|
|
} else {
|
|
t38 = $[99];
|
|
}
|
|
return t38;
|
|
}
|
|
function _temp(c) {
|
|
return c.type === "image";
|
|
}
|