Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DEVHUB-1898, UP-6913] Add Hotkey Indicator to Chat InputBar Component #2476

Merged
merged 18 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/stupid-toes-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lg-chat/input-bar': minor
---

Add `shouldRenderHotkeyIndicator` prop to InputBar component which determines if hotkey indicator is rendered
21 changes: 11 additions & 10 deletions chat/input-bar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,17 @@ return <InputBar badgeText="Beta" />;

## Properties

| Prop | Type | Description | Default |
| ---------------------- | --------------------------------------------- | -------------------------------------------------------------- | ------- |
| `badgeText` | `string` | If provided, renders a badge with text next to the wizard icon | |
| `darkMode` | `boolean` | Determines if the component will render in dark mode | `false` |
| `onMessageSend` | `(messageBody: string, e: FormEvent) => void` | Callback fired when message is sent | |
| `shouldRenderGradient` | `boolean` | Determines if component renders with gradient box-shadow | `true` |
| `textAreaProps` | `TextareaAutosizeProps` | `TextareaAutosize` props spread on textarea component | |
| `disabled` | `boolean` | Determines whether the user can interact with the InputBar | |
| `disableSend` | `boolean` | When defined as `true`, disables the send action and button | |
| `...` | `HTMLElementProps<'form'>` | Props spread on the root element | |
| Prop | Type | Description | Default |
| ----------------------------- | --------------------------------------------- | -------------------------------------------------------------- | ------- |
| `badgeText` | `string` | If provided, renders a badge with text next to the wizard icon | |
| `darkMode` | `boolean` | Determines if the component will render in dark mode | `false` |
| `onMessageSend` | `(messageBody: string, e: FormEvent) => void` | Callback fired when message is sent | |
| `shouldRenderGradient` | `boolean` | Determines if component renders with gradient box-shadow | `true` |
| `shouldRenderHotkeyIndicator` | `boolean` | Determines if component renders with hotkey indicator | `false` |
| `textAreaProps` | `TextareaAutosizeProps` | `TextareaAutosize` props spread on textarea component | |
| `disabled` | `boolean` | Determines whether the user can interact with the InputBar | |
| `disableSend` | `boolean` | When defined as `true`, disables the send action and button | |
| `...` | `HTMLElementProps<'form'>` | Props spread on the root element | |

## TextareaAutosizeProps

Expand Down
5 changes: 5 additions & 0 deletions chat/input-bar/src/InputBar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ WithBadge.args = {
badgeText: 'Beta',
};

export const WithHotkeyIndicator = Template.bind({});
WithHotkeyIndicator.args = {
shouldRenderHotkeyIndicator: true,
};

export const WithDropdown = Template.bind({});
WithDropdown.args = {
children: (
Expand Down
15 changes: 15 additions & 0 deletions chat/input-bar/src/InputBar/InputBar.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,19 @@ describe('packages/input-bar', () => {

expect(screen.getByText('beta')).toBeInTheDocument();
});

test('Hotkey Indicator is rendered when the prop is set', () => {
render(<InputBar shouldRenderHotkeyIndicator />);

expect(screen.getByTestId('lg-chat-hotkey-indicator')).toBeInTheDocument();
});

test('Hotkey Indicator is hidden when InputBar is focused', async () => {
render(<InputBar shouldRenderHotkeyIndicator />);
const textarea = screen.getByRole('textbox');
textarea.focus();
// Wait for CSS transition
await new Promise(r => setTimeout(r, 200));
expect(screen.getByTestId('lg-chat-hotkey-indicator')).not.toBeVisible();
});
});
33 changes: 33 additions & 0 deletions chat/input-bar/src/InputBar/InputBar.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Theme } from '@leafygreen-ui/lib';
import { palette } from '@leafygreen-ui/palette';
import {
BaseFontSize,
borderRadius,
focusRing,
fontFamilies,
fontWeights,
Expand Down Expand Up @@ -221,6 +222,38 @@ export const sendButtonDisabledStyles = css`
}
`;

export const baseHotkeyIndicatorStyles = css`
padding: ${spacing[100]}px ${spacing[400]}px;
border-radius: ${borderRadius[400]}px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
cursor: default;
transition: opacity ${transitionDuration.default}ms ease-in-out;
user-select: none;
`;

export const themedHotkeyIndicatorStyles = {
[Theme.Dark]: css`
background-color: ${palette.gray.dark4};
border: 1px solid ${palette.gray.dark2};
color: ${palette.gray.light2};
`,
[Theme.Light]: css`
background-color: ${palette.gray.light2};
border: 1px solid ${palette.gray.light2};
color: ${palette.green.dark2};
`,
};
export const hotkeyIndicatorUnfocusedStyles = css`
opacity: 1;
`;

export const hotkeyIndicatorFocusedStyles = css`
opacity: 0;
`;

export const getIconFill = (theme: Theme, disabled?: boolean) => {
if (theme === Theme.Dark) {
if (disabled) {
Expand Down
20 changes: 20 additions & 0 deletions chat/input-bar/src/InputBar/InputBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { breakpoints } from '@leafygreen-ui/tokens';
import { setReactTextAreaValue } from '../utils/setReactTextAreaValue';

import {
baseHotkeyIndicatorStyles,
baseStyles,
contentWrapperFocusStyles,
contentWrapperStyles,
Expand All @@ -48,11 +49,14 @@ import {
focusStyles,
getIconFill,
gradientAnimationStyles,
hotkeyIndicatorFocusedStyles,
hotkeyIndicatorUnfocusedStyles,
inputStyles,
inputThemeStyles,
leftContentStyles,
rightContentStyles,
sendButtonDisabledStyles,
themedHotkeyIndicatorStyles,
} from './InputBar.styles';
import { ReturnIcon } from './ReturnIcon';
import { SparkleIcon } from './SparkleIcon';
Expand All @@ -65,6 +69,7 @@ export const InputBar = forwardRef<HTMLFormElement, InputBarProps>(
textareaProps,
onMessageSend,
onSubmit,
shouldRenderHotkeyIndicator = false,
shouldRenderGradient: shouldRenderGradientProp = true,
badgeText,
darkMode: darkModeProp,
Expand Down Expand Up @@ -382,6 +387,21 @@ export const InputBar = forwardRef<HTMLFormElement, InputBarProps>(
ref={textareaRef}
/>
<div className={rightContentStyles}>
{shouldRenderHotkeyIndicator && !disabled && (
<div
data-testid="lg-chat-hotkey-indicator"
className={cx(
baseHotkeyIndicatorStyles,
themedHotkeyIndicatorStyles[theme],
{
[hotkeyIndicatorFocusedStyles]: isFocused,
[hotkeyIndicatorUnfocusedStyles]: !isFocused,
},
)}
>
/
</div>
)}
<Button
size="small"
rightGlyph={
Expand Down
5 changes: 5 additions & 0 deletions chat/input-bar/src/InputBar/InputBar.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export type InputBarProps = HTMLElementProps<'form'> &
messageBody: string,
e?: FormEvent<HTMLFormElement>,
) => void;
/**
* Toggles the hotkey indicator on the right side of the input
* @default false
*/
shouldRenderHotkeyIndicator?: boolean;
/**
* Toggles the gradient animation around the input
* @default true
Expand Down
Loading