diff --git a/src-web/components/ResizeHandle.tsx b/src-web/components/ResizeHandle.tsx index 3e86009a..1b204539 100644 --- a/src-web/components/ResizeHandle.tsx +++ b/src-web/components/ResizeHandle.tsx @@ -31,7 +31,7 @@ export function ResizeHandle({ onDoubleClick={onReset} className={classNames( className, - 'group z-10 flex', + 'group z-10 flex select-none', // 'bg-fg-info', // For debugging vertical ? 'w-full h-3 cursor-row-resize' : 'h-full w-3 cursor-col-resize', justify === 'center' && 'justify-center', diff --git a/src-web/components/core/Checkbox.tsx b/src-web/components/core/Checkbox.tsx index ea749dcc..3f6ecd6f 100644 --- a/src-web/components/core/Checkbox.tsx +++ b/src-web/components/core/Checkbox.tsx @@ -1,28 +1,27 @@ import classNames from 'classnames'; +import type { ReactNode } from 'react'; import { Icon } from './Icon'; import { HStack } from './Stacks'; -interface Props { - checked: boolean; - title: string; +export interface CheckboxProps { + checked: boolean | 'indeterminate'; + title: ReactNode; onChange: (checked: boolean) => void; - disabled?: boolean; className?: string; + disabled?: boolean; inputWrapperClassName?: string; - indeterminate?: boolean; hideLabel?: boolean; } export function Checkbox({ checked, - indeterminate, onChange, className, inputWrapperClassName, disabled, title, hideLabel, -}: Props) { +}: CheckboxProps) { return ( onChange(!checked)} + onChange={() => onChange(checked === 'indeterminate' ? true : !checked)} />
- +
{!hideLabel && title} diff --git a/src-web/components/core/Dialog.tsx b/src-web/components/core/Dialog.tsx index a84aa33b..398a20e8 100644 --- a/src-web/components/core/Dialog.tsx +++ b/src-web/components/core/Dialog.tsx @@ -96,7 +96,7 @@ export function Dialog({
(function Inp labelClassName, labelPosition = 'top', leftSlot, - name, onBlur, onChange, onFocus, @@ -91,7 +90,7 @@ export const Input = forwardRef(function Inp onBlur?.(); }, [onBlur]); - const id = `input-${name}`; + const id = `input-${label}`; const editorClassName = classNames( className, '!bg-transparent min-w-0 h-auto w-full focus:outline-none placeholder:text-placeholder', diff --git a/src-web/components/core/PlainInput.tsx b/src-web/components/core/PlainInput.tsx index 991e1b4a..c1eb34e1 100644 --- a/src-web/components/core/PlainInput.tsx +++ b/src-web/components/core/PlainInput.tsx @@ -1,51 +1,54 @@ import classNames from 'classnames'; -import { forwardRef, useCallback, useMemo, useRef, useState } from 'react'; +import type { HTMLAttributes } from 'react'; +import { useCallback, useMemo, useRef, useState } from 'react'; import { useStateWithDeps } from '../../hooks/useStateWithDeps'; import { IconButton } from './IconButton'; import type { InputProps } from './Input'; import { HStack } from './Stacks'; -export type PlainInputProps = Omit & { - type?: 'text' | 'password' | 'number'; - step?: number; -}; +export type PlainInputProps = Omit & + Pick, 'onKeyDownCapture'> & { + type?: 'text' | 'password' | 'number'; + step?: number; + }; -export const PlainInput = forwardRef(function Input( - { - className, - containerClassName, - defaultValue, - forceUpdateKey, - hideLabel, - label, - labelClassName, - labelPosition = 'top', - leftSlot, - name, - onBlur, - onChange, - onFocus, - onPaste, - placeholder, - require, - rightSlot, - size = 'md', - type = 'text', - validate, - autoSelect, - ...props - }: PlainInputProps, - ref, -) { +export function PlainInput({ + className, + containerClassName, + defaultValue, + forceUpdateKey, + hideLabel, + label, + labelClassName, + labelPosition = 'top', + leftSlot, + name, + onBlur, + onChange, + onFocus, + onPaste, + placeholder, + require, + rightSlot, + size = 'md', + type = 'text', + validate, + autoSelect, + step, + autoFocus, + readOnly, +}: PlainInputProps) { const [obscured, setObscured] = useStateWithDeps(type === 'password', [type]); const [currentValue, setCurrentValue] = useState(defaultValue ?? ''); const [focused, setFocused] = useState(false); const inputRef = useRef(null); + const textareaRef = useRef(null); const handleFocus = useCallback(() => { setFocused(true); if (autoSelect) { inputRef.current?.select(); + textareaRef.current?.select(); } onFocus?.(); }, [autoSelect, onFocus]); @@ -56,9 +59,9 @@ export const PlainInput = forwardRef(function }, [onBlur]); const id = `input-${name}`; - const inputClassName = classNames( + const commonClassName = classNames( className, - '!bg-transparent min-w-0 h-auto w-full focus:outline-none placeholder:text-placeholder', + '!bg-transparent min-w-0 w-full focus:outline-none placeholder:text-placeholder', 'px-2 text-xs font-mono cursor-text', ); @@ -122,7 +125,7 @@ export const PlainInput = forwardRef(function )} > (function autoCorrect="off" onChange={(e) => handleChange(e.target.value)} onPaste={(e) => onPaste?.(e.clipboardData.getData('Text'))} - className={inputClassName} + className={classNames(commonClassName, 'h-auto')} onFocus={handleFocus} onBlur={handleBlur} - {...props} + autoFocus={autoFocus} + step={step} + readOnly={readOnly} /> {type === 'password' && ( @@ -154,7 +159,7 @@ export const PlainInput = forwardRef(function
); -}); +} function validateRequire(v: string) { return v.length > 0;