-
Notifications
You must be signed in to change notification settings - Fork 79
[LG-5439] feat: ChatLayout integration branch #3289
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
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
3a72e78
feat(chat-layout): new @lg-chat/chat-layout package with ChatLayout a…
stephl3 681d5e7
[LG-5645] feat(chat-layout): implement ChatMain component (#3252)
stephl3 aa3b990
[LG-5646] feat(chat-layout): implement ChatSideNav component with Hea…
stephl3 e9ded93
[LG-5649] feat(chat-layout): add SideNavItem subcomponent (#3273)
stephl3 c37ed39
[LG-5650] feat(chat-layout): add hover expand and collapse functional…
stephl3 b30aa68
fix(chat-layout): peer dep and init changeset
stephl3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| --- | ||
| '@lg-chat/chat-layout': minor | ||
| --- | ||
|
|
||
| Initial release with `ChatLayout`, `ChatMain`, and `ChatSideNav` | ||
| - `ChatSideNav` is a compound component with the following subcomponents: | ||
| - `ChatSideNav.Header` | ||
| - `ChatSideNav.Content` | ||
| - `ChatSideNav.SideNavItem` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@lg-chat/input-bar': patch | ||
| --- | ||
|
|
||
| Remove redundant `z-index: 2;` in `InputBar` content wrapping node. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| # Chat Layout | ||
|
|
||
|  | ||
|
|
||
| #### [View on MongoDB.design](https://www.mongodb.design/component/chat-layout/live-example/) | ||
|
|
||
| ## Installation | ||
|
|
||
| ### PNPM | ||
|
|
||
| ```shell | ||
| pnpm add @lg-chat/chat-layout | ||
| ``` | ||
|
|
||
| ### Yarn | ||
|
|
||
| ```shell | ||
| yarn add @lg-chat/chat-layout | ||
| ``` | ||
|
|
||
| ### NPM | ||
|
|
||
| ```shell | ||
| npm install @lg-chat/chat-layout | ||
| ``` | ||
|
|
||
| ## Overview | ||
|
|
||
| `@lg-chat/chat-layout` provides a CSS Grid-based layout system for building full-screen chat interfaces with a side nav that can be collapsed or pinned. | ||
|
|
||
| This package exports: | ||
|
|
||
| - `ChatLayout`: The grid container and context provider | ||
| - `ChatMain`: The primary content area of the chat interface, automatically positioned within the grid layout. | ||
| - `ChatSideNav`: A compound component representing the side navigation, exposing subcomponents such as `ChatSideNav.Header`, `ChatSideNav.Content`, and `ChatSideNav.SideNavItem` for flexible composition. | ||
| - `useChatLayoutContext`: Hook for accessing layout state | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Basic | ||
|
|
||
| ```tsx | ||
| import { useState } from 'react'; | ||
| import { ChatLayout, ChatMain, ChatSideNav } from '@lg-chat/chat-layout'; | ||
|
|
||
| function MyChatApp() { | ||
| const [activeChatId, setActiveChatId] = useState('1'); | ||
|
|
||
| const chatItems = [ | ||
| { id: '1', name: 'MongoDB Atlas Setup', href: '/chat/1' }, | ||
| { id: '2', name: 'Database Query Help', href: '/chat/2' }, | ||
| { id: '3', name: 'Schema Design Discussion', href: '/chat/3' }, | ||
| ]; | ||
|
|
||
| const handleNewChat = () => { | ||
| console.log('Start new chat'); | ||
| }; | ||
|
|
||
| return ( | ||
| <ChatLayout> | ||
| <ChatSideNav> | ||
| <ChatSideNav.Header onClickNewChat={handleNewChat} /> | ||
| <ChatSideNav.Content> | ||
| {chatItems.map(({ href, id, item, name }) => ( | ||
| <ChatSideNav.SideNavItem | ||
| key={id} | ||
| href={href} | ||
| active={id === activeChatId} | ||
| onClick={e => { | ||
| e.preventDefault(); | ||
| setActiveChatId(id); | ||
| }} | ||
| > | ||
| {name} | ||
| </ChatSideNav.SideNavItem> | ||
| ))} | ||
| </ChatSideNav.Content> | ||
| </ChatSideNav> | ||
| <ChatMain>{/* Main chat content here */}</ChatMain> | ||
| </ChatLayout> | ||
| ); | ||
| } | ||
| ``` | ||
|
|
||
| ### With Initial State and Toggle Pinned Callback | ||
|
|
||
| ```tsx | ||
| import { ChatLayout, ChatMain, ChatSideNav } from '@lg-chat/chat-layout'; | ||
|
|
||
| function MyChatApp() { | ||
| const handleTogglePinned = (isPinned: boolean) => { | ||
| console.log('Side nav is now:', isPinned ? 'pinned' : 'collapsed'); | ||
| }; | ||
|
|
||
| return ( | ||
| <ChatLayout initialIsPinned={false} onTogglePinned={handleTogglePinned}> | ||
| <ChatSideNav>{/* Side nav subcomponents */}</ChatSideNav> | ||
| <ChatMain>{/* Main chat content */}</ChatMain> | ||
| </ChatLayout> | ||
| ); | ||
| } | ||
| ``` | ||
|
|
||
| ## Properties | ||
|
|
||
| ### ChatLayout | ||
|
|
||
| | Prop | Type | Description | Default | | ||
| | ------------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------- | ------- | | ||
| | `children` | `ReactNode` | The content to render inside the grid layout (`ChatSideNav` and `ChatMain` components) | - | | ||
| | `className` _(optional)_ | `string` | Custom CSS class to apply to the grid container | - | | ||
| | `initialIsPinned` _(optional)_ | `boolean` | Initial state for whether the side nav is pinned (expanded) | `true` | | ||
| | `onTogglePinned` _(optional)_ | `(isPinned: boolean) => void` | Callback fired when the side nav is toggled. Receives the new `isPinned` state as an argument | - | | ||
|
|
||
| All other props are passed through to the underlying `<div>` element. | ||
|
|
||
| ### ChatMain | ||
|
|
||
| | Prop | Type | Description | Default | | ||
| | ---------- | ----------- | -------------------------- | ------- | | ||
| | `children` | `ReactNode` | The main content to render | - | | ||
|
|
||
| All other props are passed through to the underlying `<div>` element. | ||
|
|
||
| **Note:** `ChatMain` must be used as a direct child of `ChatLayout` to work correctly within the grid system. | ||
|
|
||
| ### ChatSideNav | ||
|
|
||
| | Prop | Type | Description | Default | | ||
| | ------------------------ | ------------------------- | -------------------------------------------------------------- | ------- | | ||
| | `children` | `ReactNode` | Should include `ChatSideNav.Header` and `ChatSideNav.Content`. | - | | ||
| | `className` _(optional)_ | `string` | Root class name | - | | ||
| | `...` | `HTMLElementProps<'nav'>` | Props spread on the root `<nav>` element | - | | ||
|
|
||
| ### ChatSideNav.Header | ||
|
|
||
| | Prop | Type | Description | Default | | ||
| | ----------------------------- | -------------------------------------- | ------------------------------------------- | ------- | | ||
| | `onClickNewChat` _(optional)_ | `MouseEventHandler<HTMLButtonElement>` | Fired when the "New Chat" button is clicked | - | | ||
| | `className` _(optional)_ | `string` | Header class name | - | | ||
| | `...` | `HTMLElementProps<'div'>` | Props spread on the header container | - | | ||
|
|
||
| ### ChatSideNav.Content | ||
|
|
||
| | Prop | Type | Description | Default | | ||
| | ------------------------ | ------------------------- | ------------------------------------- | ------- | | ||
| | `className` _(optional)_ | `string` | Content class name | - | | ||
| | `...` | `HTMLElementProps<'div'>` | Props spread on the content container | - | | ||
|
|
||
| ### ChatSideNav.SideNavItem | ||
|
|
||
| | Prop | Type | Description | Default | | ||
| | ------------------------ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | ||
| | `active` _(optional)_ | `boolean` | Whether or not the component should be rendered in an active state. When active, applies active styling and sets `aria-current="page"` | `false` | | ||
| | `as` _(optional)_ | `React.ElementType` | When provided, the component will be rendered as the component or html tag indicated by this prop. Other additional props will be spread on the element. For example, `Link` or `a` tags can be supplied. Defaults to `'a'` | - | | ||
| | `children` | `ReactNode` | Content that will be rendered inside the root-level element (typically the chat name) | - | | ||
| | `className` _(optional)_ | `string` | Class name that will be applied to the root-level element | - | | ||
| | `href` _(optional)_ | `string` | The URL that the hyperlink points to. When provided, the component will be rendered as an anchor element | - | | ||
| | `onClick` _(optional)_ | `MouseEventHandler` | The event handler function for the 'onclick' event. Receives the associated `event` object as the first argument | - | | ||
|
|
||
| ## Context API | ||
|
|
||
| ### useChatLayoutContext | ||
|
|
||
| Hook that returns the current chat layout context: | ||
|
|
||
| ```tsx | ||
| const { | ||
| isPinned, | ||
| togglePin, | ||
| isSideNavHovered, | ||
| setIsSideNavHovered, | ||
| shouldRenderExpanded, | ||
| } = useChatLayoutContext(); | ||
| ``` | ||
|
|
||
| **Returns:** | ||
|
|
||
| | Property | Type | Description | | ||
| | ---------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------- | | ||
| | `isPinned` | `boolean` | Whether the side nav is currently pinned | | ||
| | `togglePin` | `() => void` | Function to toggle the pinned state | | ||
| | `isSideNavHovered` | `boolean` | Whether the side nav is currently being hovered | | ||
| | `setIsSideNavHovered` | `(isHovered: boolean) => void` | Function to set the hover state of the side nav | | ||
| | `shouldRenderExpanded` | `boolean` | Whether the side nav should render in expanded state. This is `true` when the nav is pinned OR hovered. | | ||
|
|
||
| ## Behavior | ||
|
|
||
| ### State Management | ||
|
|
||
| - `ChatLayout` manages the `isPinned` and `isSideNavHovered` state internally and provides it to all descendants via `ChatLayoutContext` | ||
| - `shouldRenderExpanded` is computed as `isPinned || isSideNavHovered` and provided in the context for convenience | ||
| - When `togglePin` is called: | ||
| 1. The `isPinned` state updates | ||
| 2. Grid columns resize smoothly via CSS transition | ||
| 3. The `onTogglePinned` callback fires (if provided) with the new state value | ||
| - Descendant components can consume the context to: | ||
| - Read the current `isPinned` state | ||
| - Call `togglePin()` to toggle the sidebar | ||
| - Read the current `isSideNavHovered` state | ||
| - Call `setIsSideNavHovered()` to update the hover state | ||
| - Use `shouldRenderExpanded` to determine if the side nav should render in expanded state | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
|
|
||
| { | ||
| "name": "@lg-chat/chat-layout", | ||
| "version": "0.0.1", | ||
| "description": "LeafyGreen UI Kit Chat Layout", | ||
| "main": "./dist/umd/index.js", | ||
| "module": "./dist/esm/index.js", | ||
| "types": "./dist/types/index.d.ts", | ||
| "license": "Apache-2.0", | ||
| "exports": { | ||
| ".": { | ||
| "require": "./dist/umd/index.js", | ||
| "import": "./dist/esm/index.js", | ||
| "types": "./dist/types/index.d.ts" | ||
| }, | ||
| "./testing": { | ||
| "require": "./dist/umd/testing/index.js", | ||
| "import": "./dist/esm/testing/index.js", | ||
| "types": "./dist/types/testing/index.d.ts" | ||
| } | ||
| }, | ||
| "scripts": { | ||
| "build": "lg-build bundle", | ||
| "tsc": "lg-build tsc", | ||
| "docs": "lg-build docs" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "dependencies": { | ||
| "@leafygreen-ui/avatar": "workspace:^", | ||
| "@leafygreen-ui/button": "workspace:^", | ||
| "@leafygreen-ui/compound-component": "workspace:^", | ||
| "@leafygreen-ui/emotion": "workspace:^", | ||
| "@leafygreen-ui/icon": "workspace:^", | ||
| "@leafygreen-ui/lib": "workspace:^", | ||
| "@leafygreen-ui/palette": "workspace:^", | ||
| "@leafygreen-ui/polymorphic": "workspace:^", | ||
| "@leafygreen-ui/tokens": "workspace:^", | ||
| "@leafygreen-ui/typography": "workspace:^", | ||
| "@lg-tools/test-harnesses": "workspace:^" | ||
| }, | ||
| "peerDependencies": { | ||
| "@leafygreen-ui/leafygreen-provider": "workspace:^3.2.0 || workspace:^4.0.0 || workspace:^5.0.0", | ||
| "@lg-chat/leafygreen-chat-provider": "workspace:^" | ||
| }, | ||
| "devDependencies": { | ||
| "@lg-chat/chat-window": "workspace:^", | ||
| "@lg-chat/input-bar": "workspace:^", | ||
| "@lg-chat/message": "workspace:^", | ||
| "@lg-chat/message-feed": "workspace:^", | ||
| "@lg-chat/title-bar": "workspace:^" | ||
| }, | ||
| "homepage": "https://github.com/mongodb/leafygreen-ui/tree/main/chat/chat-layout", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/mongodb/leafygreen-ui" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://jira.mongodb.org/projects/LG/summary" | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The destructured property
itemis not used in the map callback and appears to be a typo or leftover from refactoring. It should be removed from the destructuring.