Port some stuff from sync PR

This commit is contained in:
Gregory Schier
2024-12-05 11:27:49 -08:00
parent 2b61257e50
commit a79578142d
5 changed files with 57 additions and 51 deletions

View File

@@ -31,7 +31,7 @@ export function ResizeHandle({
onDoubleClick={onReset} onDoubleClick={onReset}
className={classNames( className={classNames(
className, className,
'group z-10 flex', 'group z-10 flex select-none',
// 'bg-fg-info', // For debugging // 'bg-fg-info', // For debugging
vertical ? 'w-full h-3 cursor-row-resize' : 'h-full w-3 cursor-col-resize', vertical ? 'w-full h-3 cursor-row-resize' : 'h-full w-3 cursor-col-resize',
justify === 'center' && 'justify-center', justify === 'center' && 'justify-center',

View File

@@ -1,28 +1,27 @@
import classNames from 'classnames'; import classNames from 'classnames';
import type { ReactNode } from 'react';
import { Icon } from './Icon'; import { Icon } from './Icon';
import { HStack } from './Stacks'; import { HStack } from './Stacks';
interface Props { export interface CheckboxProps {
checked: boolean; checked: boolean | 'indeterminate';
title: string; title: ReactNode;
onChange: (checked: boolean) => void; onChange: (checked: boolean) => void;
disabled?: boolean;
className?: string; className?: string;
disabled?: boolean;
inputWrapperClassName?: string; inputWrapperClassName?: string;
indeterminate?: boolean;
hideLabel?: boolean; hideLabel?: boolean;
} }
export function Checkbox({ export function Checkbox({
checked, checked,
indeterminate,
onChange, onChange,
className, className,
inputWrapperClassName, inputWrapperClassName,
disabled, disabled,
title, title,
hideLabel, hideLabel,
}: Props) { }: CheckboxProps) {
return ( return (
<HStack <HStack
as="label" as="label"
@@ -38,10 +37,13 @@ export function Checkbox({
)} )}
type="checkbox" type="checkbox"
disabled={disabled} disabled={disabled}
onChange={() => onChange(!checked)} onChange={() => onChange(checked === 'indeterminate' ? true : !checked)}
/> />
<div className="absolute inset-0 flex items-center justify-center"> <div className="absolute inset-0 flex items-center justify-center">
<Icon size="sm" icon={indeterminate ? 'minus' : checked ? 'check' : 'empty'} /> <Icon
size="sm"
icon={checked === 'indeterminate' ? 'minus' : checked ? 'check' : 'empty'}
/>
</div> </div>
</div> </div>
{!hideLabel && title} {!hideLabel && title}

View File

@@ -96,7 +96,7 @@ export function Dialog({
<div <div
className={classNames( className={classNames(
'h-full w-full grid grid-cols-[minmax(0,1fr)]', 'h-full w-full grid grid-cols-[minmax(0,1fr)] grid-rows-1',
!noPadding && 'px-6 py-2', !noPadding && 'px-6 py-2',
!noScroll && 'overflow-y-auto overflow-x-hidden', !noScroll && 'overflow-y-auto overflow-x-hidden',
)} )}

View File

@@ -58,7 +58,6 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
labelClassName, labelClassName,
labelPosition = 'top', labelPosition = 'top',
leftSlot, leftSlot,
name,
onBlur, onBlur,
onChange, onChange,
onFocus, onFocus,
@@ -91,7 +90,7 @@ export const Input = forwardRef<EditorView | undefined, InputProps>(function Inp
onBlur?.(); onBlur?.();
}, [onBlur]); }, [onBlur]);
const id = `input-${name}`; const id = `input-${label}`;
const editorClassName = classNames( const editorClassName = classNames(
className, className,
'!bg-transparent min-w-0 h-auto w-full focus:outline-none placeholder:text-placeholder', '!bg-transparent min-w-0 h-auto w-full focus:outline-none placeholder:text-placeholder',

View File

@@ -1,51 +1,54 @@
import classNames from 'classnames'; 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 { useStateWithDeps } from '../../hooks/useStateWithDeps';
import { IconButton } from './IconButton'; import { IconButton } from './IconButton';
import type { InputProps } from './Input'; import type { InputProps } from './Input';
import { HStack } from './Stacks'; import { HStack } from './Stacks';
export type PlainInputProps = Omit<InputProps, 'wrapLines' | 'onKeyDown' | 'type'> & { export type PlainInputProps = Omit<InputProps, 'wrapLines' | 'onKeyDown' | 'type'> &
type?: 'text' | 'password' | 'number'; Pick<HTMLAttributes<HTMLInputElement>, 'onKeyDownCapture'> & {
step?: number; type?: 'text' | 'password' | 'number';
}; step?: number;
};
export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function Input( export function PlainInput({
{ className,
className, containerClassName,
containerClassName, defaultValue,
defaultValue, forceUpdateKey,
forceUpdateKey, hideLabel,
hideLabel, label,
label, labelClassName,
labelClassName, labelPosition = 'top',
labelPosition = 'top', leftSlot,
leftSlot, name,
name, onBlur,
onBlur, onChange,
onChange, onFocus,
onFocus, onPaste,
onPaste, placeholder,
placeholder, require,
require, rightSlot,
rightSlot, size = 'md',
size = 'md', type = 'text',
type = 'text', validate,
validate, autoSelect,
autoSelect, step,
...props autoFocus,
}: PlainInputProps, readOnly,
ref, }: PlainInputProps) {
) {
const [obscured, setObscured] = useStateWithDeps(type === 'password', [type]); const [obscured, setObscured] = useStateWithDeps(type === 'password', [type]);
const [currentValue, setCurrentValue] = useState(defaultValue ?? ''); const [currentValue, setCurrentValue] = useState(defaultValue ?? '');
const [focused, setFocused] = useState(false); const [focused, setFocused] = useState(false);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const handleFocus = useCallback(() => { const handleFocus = useCallback(() => {
setFocused(true); setFocused(true);
if (autoSelect) { if (autoSelect) {
inputRef.current?.select(); inputRef.current?.select();
textareaRef.current?.select();
} }
onFocus?.(); onFocus?.();
}, [autoSelect, onFocus]); }, [autoSelect, onFocus]);
@@ -56,9 +59,9 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
}, [onBlur]); }, [onBlur]);
const id = `input-${name}`; const id = `input-${name}`;
const inputClassName = classNames( const commonClassName = classNames(
className, 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', 'px-2 text-xs font-mono cursor-text',
); );
@@ -122,7 +125,7 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
)} )}
> >
<input <input
ref={ref} ref={inputRef}
key={forceUpdateKey} key={forceUpdateKey}
id={id} id={id}
type={type === 'password' && !obscured ? 'text' : type} type={type === 'password' && !obscured ? 'text' : type}
@@ -133,10 +136,12 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
autoCorrect="off" autoCorrect="off"
onChange={(e) => handleChange(e.target.value)} onChange={(e) => handleChange(e.target.value)}
onPaste={(e) => onPaste?.(e.clipboardData.getData('Text'))} onPaste={(e) => onPaste?.(e.clipboardData.getData('Text'))}
className={inputClassName} className={classNames(commonClassName, 'h-auto')}
onFocus={handleFocus} onFocus={handleFocus}
onBlur={handleBlur} onBlur={handleBlur}
{...props} autoFocus={autoFocus}
step={step}
readOnly={readOnly}
/> />
</HStack> </HStack>
{type === 'password' && ( {type === 'password' && (
@@ -154,7 +159,7 @@ export const PlainInput = forwardRef<HTMLInputElement, PlainInputProps>(function
</HStack> </HStack>
</div> </div>
); );
}); }
function validateRequire(v: string) { function validateRequire(v: string) {
return v.length > 0; return v.length > 0;