Skip to content

Commit 43eb4a3

Browse files
committed
First version, refactor AIChatInput
1 parent edfd1cd commit 43eb4a3

File tree

2 files changed

+45
-118
lines changed

2 files changed

+45
-118
lines changed

packages/gitbook/src/components/AIChat/AIChatInput.tsx

Lines changed: 13 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,28 @@ export function AIChatInput(props: {
5858

5959
return (
6060
<Input
61+
data-testid="ai-chat-input"
62+
name="ai-chat-input"
6163
multiline
62-
label="Assistant input"
64+
label="Assistant chat input"
6365
placeholder={tString(language, 'ai_chat_input_placeholder')}
6466
onChange={handleInput}
6567
onSubmit={() => onSubmit(value)}
6668
value={value}
67-
leading="magnifying-glass"
6869
submitButton={{
6970
label: tString(language, 'send'),
7071
}}
72+
className="animate-blur-in-slow bg-tint-base/9 backdrop-blur-lg contrast-more:bg-tint-base"
73+
rows={1}
7174
keyboardShortcut={
72-
<div className="peer-focus:hidden">
73-
<KeyboardShortcut keys={['mod', 'i']} className="bg-tint-base" />
74-
</div>
75+
!value && !disabled && !loading ? (
76+
<div className="group-focus-within/input:hidden">
77+
<KeyboardShortcut keys={['mod', 'i']} className="bg-tint-base" />
78+
</div>
79+
) : undefined
7580
}
81+
disabled={disabled || loading}
82+
aria-busy={loading}
7683
ref={inputRef}
7784
trailing={
7885
<HoverCardRoot openDelay={500}>
@@ -102,7 +109,7 @@ export function AIChatInput(props: {
102109
</div>
103110
</HoverCard>
104111
<HoverCardTrigger>
105-
<div className="-ml-2 flex cursor-help items-center gap-1 circular-corners:rounded-2xl rounded-corners:rounded-md px-2.5 py-1.5 text-tint/7 text-xs transition-all hover:bg-tint">
112+
<div className="flex cursor-help items-center gap-1 circular-corners:rounded-2xl rounded-corners:rounded-md px-2.5 py-1.5 text-tint/7 text-xs transition-all hover:bg-tint">
106113
<span className="-ml-1 circular-corners:rounded-2xl rounded-corners:rounded-sm bg-tint-11/7 px-1 py-0.5 font-mono font-semibold text-[0.65rem] text-contrast-tint-11 leading-none">
107114
{t(language, 'ai_chat_context_badge')}
108115
</span>{' '}
@@ -115,103 +122,5 @@ export function AIChatInput(props: {
115122
</HoverCardRoot>
116123
}
117124
/>
118-
// <div className="depth-subtle:has-[textarea:focus]:-translate-y-px relative flex animate-blur-in-slow flex-col overflow-hidden circular-corners:rounded-3xl rounded-corners:rounded-xl bg-tint-base/9 depth-subtle:shadow-sm shadow-tint/6 ring-1 ring-tint-subtle backdrop-blur-lg transition-all depth-subtle:has-[textarea:focus]:shadow-lg has-[textarea:focus]:shadow-primary-subtle has-[textarea:focus]:ring-2 has-[textarea:focus]:ring-primary-hover contrast-more:bg-tint-base dark:shadow-tint-1">
119-
// {/* <textarea
120-
// ref={inputRef}
121-
// disabled={disabled || loading}
122-
// data-loading={loading}
123-
// data-testid="ai-chat-input"
124-
// className={tcls(
125-
// 'resize-none',
126-
// 'focus:outline-hidden',
127-
// 'focus:ring-0',
128-
// 'w-full',
129-
// 'px-3',
130-
// 'py-3',
131-
// 'pb-12',
132-
// 'h-auto',
133-
// 'bg-transparent',
134-
// 'peer',
135-
// 'max-h-64',
136-
// 'placeholder:text-tint/8',
137-
// 'transition-colors',
138-
// 'disabled:bg-tint-subtle',
139-
// 'delay-300',
140-
// 'disabled:delay-0',
141-
// 'disabled:cursor-not-allowed',
142-
// 'data-[loading=true]:cursor-progress',
143-
// 'data-[loading=true]:opacity-50'
144-
// )}
145-
// value={value}
146-
// rows={1}
147-
// placeholder={tString(language, 'ai_chat_input_placeholder')}
148-
// onChange={handleInput}
149-
// onKeyDown={(event) => {
150-
// if (event.key === 'Escape') {
151-
// event.preventDefault();
152-
// event.currentTarget.blur();
153-
// return;
154-
// }
155-
156-
// if (event.key === 'Enter' && !event.shiftKey && value.trim()) {
157-
// event.preventDefault();
158-
// event.currentTarget.style.height = 'auto';
159-
// onSubmit(value);
160-
// }
161-
// }}
162-
// /> */}
163-
// {/* {!disabled ? (
164-
// <div className="absolute top-2.5 right-3 animate-[fadeIn_0.2s_0.5s_ease-in-out_both] peer-focus:hidden">
165-
// <KeyboardShortcut keys={['mod', 'i']} className="bg-tint-base" />
166-
// </div>
167-
// ) : null} */}
168-
// <div className="absolute inset-x-0 bottom-0 flex items-center gap-2 px-2 py-2">
169-
// <HoverCardRoot openDelay={500}>
170-
// <HoverCard
171-
// className="max-w-xs bg-tint p-2 text-sm text-tint"
172-
// arrow={{ className: 'fill-tint-3' }}
173-
// >
174-
// <div className="flex flex-col gap-3 p-2">
175-
// <p className="font-semibold">
176-
// {t(language, 'ai_chat_context_description')}
177-
// </p>
178-
// <ul className="flex flex-col gap-2">
179-
// <li className="flex items-center gap-2">
180-
// <Icon icon="memo" className="size-3.5 opacity-7" />
181-
// {t(language, 'ai_chat_context_pages_youve_read')}
182-
// </li>
183-
// <li className="flex items-center gap-2">
184-
// <Icon icon="user" className="size-3.5 opacity-7" />
185-
// {t(language, 'ai_chat_context_info_provided_by_the_site')}
186-
// </li>
187-
// <li className="flex items-center gap-2">
188-
// <Icon icon="message-question" className="size-3.5 opacity-7" />
189-
// {t(language, 'ai_chat_context_previous_messages')}
190-
// </li>
191-
// </ul>
192-
// <p>{t(language, 'ai_chat_context_disclaimer')}</p>
193-
// </div>
194-
// </HoverCard>
195-
// <HoverCardTrigger>
196-
// <div className="flex cursor-help items-center gap-1 circular-corners:rounded-2xl rounded-corners:rounded-md px-2.5 py-1.5 text-tint/7 text-xs transition-all hover:bg-tint">
197-
// <span className="-ml-1 circular-corners:rounded-2xl rounded-corners:rounded-sm bg-tint-11/7 px-1 py-0.5 font-mono font-semibold text-[0.65rem] text-contrast-tint-11 leading-none">
198-
// {t(language, 'ai_chat_context_badge')}
199-
// </span>{' '}
200-
// <span className="leading-none">
201-
// {t(language, 'ai_chat_context_title')}
202-
// </span>
203-
// <Icon icon="question-circle" className="size-3 shrink-0" />
204-
// </div>
205-
// </HoverCardTrigger>
206-
// </HoverCardRoot>
207-
// <Button
208-
// label={tString(language, 'send')}
209-
// size="medium"
210-
// className="ml-auto"
211-
// disabled={disabled || !value.trim()}
212-
// onClick={() => onSubmit(value)}
213-
// />
214-
// </div>
215-
// </div>
216125
);
217126
}

packages/gitbook/src/components/primitives/Input.tsx

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ export const Input = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, In
3636
submitButton,
3737
label,
3838
'aria-label': ariaLabel,
39+
'aria-busy': ariaBusy,
3940
placeholder,
4041
keyboardShortcut,
42+
disabled,
4143
onSubmit,
4244
onChange,
4345
...rest
@@ -64,20 +66,26 @@ export const Input = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, In
6466
const handleSubmit = () => {
6567
if (hasValue) {
6668
onSubmit(value);
69+
setValue('');
6770
}
6871
};
6972

7073
const input = (
7174
<input
72-
className="peer grow resize-none overflow-visible outline-none placeholder:text-tint"
75+
className="peer -m-2 max-h-64 grow resize-none p-3 outline-none placeholder:text-tint/8 aria-busy:cursor-progress"
7376
ref={ref as React.Ref<HTMLInputElement>}
7477
value={value}
7578
onKeyDown={(event) => {
76-
if (event.key === 'Enter') {
79+
if (event.key === 'Enter' && !event.shiftKey && value.toString().trim()) {
7780
event.preventDefault();
7881
handleSubmit();
7982
}
83+
if (event.key === 'Escape') {
84+
event.preventDefault();
85+
event.currentTarget.blur();
86+
}
8087
}}
88+
aria-busy={ariaBusy}
8189
onChange={(event) => {
8290
setValue(event.target.value);
8391
onChange?.(
@@ -87,15 +95,21 @@ export const Input = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, In
8795
}}
8896
aria-label={ariaLabel ?? label}
8997
placeholder={placeholder ? placeholder : label}
98+
disabled={disabled}
9099
{...(rest as React.InputHTMLAttributes<HTMLInputElement>)}
91100
/>
92101
);
93102

94103
return (
95104
<div
96105
className={tcls(
97-
'relative flex max-h-64 min-h-min gap-2 overflow-auto circular-corners:rounded-3xl rounded-corners:rounded-xl border border-tint-subtle bg-tint-base p-3 transition-[outline,border] focus-within:outline-2 focus-within:outline-primary-hover hover:cursor-text hover:border-tint-hover',
98-
multiline ? 'resize-y flex-col' : 'flex-row',
106+
'group/input relative flex min-h-min gap-2 overflow-hidden circular-corners:rounded-3xl rounded-corners:rounded-xl border border-tint-subtle bg-tint-base p-2 shadow-tint/6 ring-primary-hover transition-all dark:shadow-tint-1',
107+
'depth-subtle:focus-within:-translate-y-px depth-subtle:shadow-sm depth-subtle:focus-within:shadow-lg',
108+
disabled
109+
? 'cursor-not-allowed border-tint-subtle bg-tint-subtle'
110+
: 'focus-within:shadow-primary-subtle focus-within:ring-2 hover:cursor-text hover:border-tint-hover',
111+
multiline ? 'flex-col' : 'flex-row',
112+
ariaBusy ? 'cursor-progress' : '',
99113
className
100114
)}
101115
onClick={handleClick}
@@ -105,9 +119,7 @@ export const Input = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, In
105119
}
106120
}}
107121
>
108-
<div
109-
className={tcls('flex grow gap-2', multiline ? 'items-start' : 'items-center')}
110-
>
122+
<div className={tcls('flex grow gap-2', multiline ? '' : 'items-center')}>
111123
{leading ? (
112124
typeof leading === 'string' ? (
113125
<Icon icon={leading as IconName} className="my-0.5 size-4 shrink-0" />
@@ -116,13 +128,19 @@ export const Input = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, In
116128
)
117129
) : null}
118130
{multiline ? <textarea {...input.props} /> : input}
119-
{keyboardShortcut !== false ? (
120-
typeof keyboardShortcut === 'object' ? (
121-
keyboardShortcut
122-
) : hasValue ? (
123-
<KeyboardShortcut keys={['ENTER']} />
124-
) : null
125-
) : null}
131+
132+
<div className={multiline ? 'absolute top-2.5 right-2.5' : ''}>
133+
{keyboardShortcut !== false ? (
134+
typeof keyboardShortcut === 'object' ? (
135+
keyboardShortcut
136+
) : hasValue ? (
137+
<KeyboardShortcut
138+
keys={['ENTER']}
139+
className="hidden group-focus-within/input:block"
140+
/>
141+
) : null
142+
) : null}
143+
</div>
126144
</div>
127145
<div className="flex items-center gap-2">
128146
{trailing ? trailing : null}

0 commit comments

Comments
 (0)