From 05f5448cb1bc084a10eb730e5589be1b16963dd1 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Wed, 13 Aug 2025 09:15:52 -0700 Subject: [PATCH] feat: make description of ChatItemFormItemsWrapper collapsible --- .../chat-item/chat-item-form-items.ts | 49 +++++++++++-- src/styles/components/_detailed-list.scss | 2 +- src/styles/components/_form-input.scss | 68 +++++++++++++++++++ 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/components/chat-item/chat-item-form-items.ts b/src/components/chat-item/chat-item-form-items.ts index d691c14c2..6752b6811 100644 --- a/src/components/chat-item/chat-item-form-items.ts +++ b/src/components/chat-item/chat-item-form-items.ts @@ -22,7 +22,9 @@ import { TextArea } from '../form-items/text-area'; import { TextInput } from '../form-items/text-input'; import { Icon, MynahIcons } from '../icon'; import { Overlay, OverlayHorizontalDirection, OverlayVerticalDirection } from '../overlay'; +import { MoreContentIndicator } from '../more-content-indicator'; const TOOLTIP_DELAY = 350; +const FORM_DESCRIPTION_COLLAPSED_HEIGHT_RATIO = 16; // Show less content when collapsed export interface ChatItemFormItemsWrapperProps { tabId: string; chatItem: Partial; @@ -75,16 +77,53 @@ export class ChatItemFormItemsWrapper { chatItemOption.value = chatItemOption.options?.[0]?.value; } } - let description; + let description: ExtendedHTMLElement | undefined; if (chatItemOption.description != null) { - description = DomBuilder.getInstance().build({ + const descriptionContent = DomBuilder.getInstance().build({ type: 'span', + classNames: [ 'mynah-ui-form-item-description-content' ], + children: [ chatItemOption.description ] + }); + + description = DomBuilder.getInstance().build({ + type: 'div', testId: testIds.chatItem.chatItemForm.description, classNames: [ 'mynah-ui-form-item-description' ], - children: [ - chatItemOption.description, - ] + children: [ descriptionContent ] }); + + // Add MoreContentIndicator for long descriptions + const moreContentIndicator = new MoreContentIndicator({ + icon: MynahIcons.DOWN_OPEN, + border: false, + onClick: () => { + if (description?.hasClass('mynah-ui-form-item-description-collapsed') === true) { + description.removeClass('mynah-ui-form-item-description-collapsed'); + moreContentIndicator.update({ icon: MynahIcons.UP_OPEN }); + } else { + description?.addClass('mynah-ui-form-item-description-collapsed'); + moreContentIndicator.update({ icon: MynahIcons.DOWN_OPEN }); + } + }, + testId: `${testIds.chatItem.chatItemForm.description}-more-content-indicator` + }); + + description.insertChild('beforeend', moreContentIndicator.render); + + // Check if content needs collapsing after a short delay + setTimeout(() => { + const collapsedHeight = window.innerHeight / FORM_DESCRIPTION_COLLAPSED_HEIGHT_RATIO; + + // Show MoreContentIndicator if content exceeds the collapsed max-height + if (descriptionContent.scrollHeight > collapsedHeight) { + description?.addClass('mynah-ui-form-item-description-auto-collapse'); + description?.addClass('mynah-ui-form-item-description-collapsed'); + // Set the collapsed height dynamically + description?.style.setProperty('--form-description-collapsed-height', `${collapsedHeight}px`); + } else { + moreContentIndicator.render.addClass('hidden'); + } + }, 50); } const fireModifierAndEnterKeyPress = (): void => { if ((chatItemOption as TextBasedFormItem).checkModifierEnterKeyPress === true && this.isFormValid()) { diff --git a/src/styles/components/_detailed-list.scss b/src/styles/components/_detailed-list.scss index 581f9589c..507b8e79e 100644 --- a/src/styles/components/_detailed-list.scss +++ b/src/styles/components/_detailed-list.scss @@ -39,7 +39,7 @@ display: none; } > .mynah-chat-item-form-items-container { - gap: var(--mynah-sizing-4); + gap: var(--mynah-sizing-5); } } > .mynah-detailed-list-filter-actions-wrapper { diff --git a/src/styles/components/_form-input.scss b/src/styles/components/_form-input.scss index 8610da86c..bd5687055 100644 --- a/src/styles/components/_form-input.scss +++ b/src/styles/components/_form-input.scss @@ -26,8 +26,76 @@ } } .mynah-ui-form-item-description { + position: relative; font-size: var(--mynah-font-size-small); color: var(--mynah-color-text-weak); + + .mynah-ui-form-item-description-content { + display: block; + line-height: 1.4; + } + + &.mynah-ui-form-item-description-auto-collapse { + .mynah-ui-form-item-description-content { + position: relative; + + // Default state - no fade effect + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 1rem; + background: linear-gradient(transparent, var(--mynah-color-bg)); + pointer-events: none; + opacity: 0; + transition: opacity 0.15s ease-in-out; + } + } + + // Only show fade effect when collapsed + &.mynah-ui-form-item-description-collapsed { + .mynah-ui-form-item-description-content { + max-height: var(--form-description-collapsed-height, 3.125vh); // window.innerHeight / 32 + overflow: hidden; + transition: max-height 0.3s ease-in-out; + + &::after { + opacity: 1; + } + } + } + + // When expanded, ensure no fade and smooth transition + &:not(.mynah-ui-form-item-description-collapsed) { + .mynah-ui-form-item-description-content { + max-height: none; + overflow: visible; + transition: max-height 0.3s ease-in-out; + + &::after { + opacity: 0; + } + } + } + } + + .more-content-indicator { + margin-top: var(--mynah-sizing-1); + + &.hidden { + display: none; + } + } + + // Only remove shadow when expanded (not collapsed) + &:not(.mynah-ui-form-item-description-collapsed) { + .more-content-indicator { + box-shadow: none; + background-color: transparent; + } + } } .mynah-form-input-container { position: relative;