From 41b97112383134d78b0311842aa371905d33bf96 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Mon, 15 Dec 2025 19:04:52 +0100 Subject: [PATCH 1/2] fix: use details/summary for accordion COMPASS-9734 --- .../src/components/accordion.spec.tsx | 22 ++++++------ .../src/components/accordion.tsx | 35 ++++++++++--------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/packages/compass-components/src/components/accordion.spec.tsx b/packages/compass-components/src/components/accordion.spec.tsx index 878bc04d5f8..2b3e0ec7506 100644 --- a/packages/compass-components/src/components/accordion.spec.tsx +++ b/packages/compass-components/src/components/accordion.spec.tsx @@ -20,9 +20,9 @@ describe('Accordion Component', function () { renderAccordion(); expect(screen.getByTestId('my-test-id')).to.exist; - const button = screen.getByText('Accordion Test'); - userEvent.click(button); - expect(screen.getByText('Hello World')).to.be.visible; + const summary = screen.getByText('Accordion Test'); + userEvent.click(summary); + expect(summary.closest('details')).to.have.attribute('open'); }); it('should close the accordion on click - default open', function () { @@ -31,22 +31,22 @@ describe('Accordion Component', function () { }); expect(screen.getByTestId('my-test-id')).to.exist; - const button = screen.getByText('Accordion Test'); + const summary = screen.getByText('Accordion Test'); expect(screen.getByText('Hello World')).to.be.visible; - userEvent.click(button); + userEvent.click(summary); - expect(screen.queryByText('Hello World')).not.to.exist; + expect(summary.closest('details')).to.not.have.attribute('open'); }); it('should close the accordion after clicking to open then close', function () { renderAccordion(); expect(screen.getByTestId('my-test-id')).to.exist; - const button = screen.getByText('Accordion Test'); - userEvent.click(button); - expect(screen.getByText('Hello World')).to.be.visible; - userEvent.click(button); - expect(screen.queryByText('Hello World')).to.not.exist; + const summary = screen.getByText('Accordion Test'); + userEvent.click(summary); + expect(summary.closest('details')).to.have.attribute('open'); + userEvent.click(summary); + expect(summary.closest('details')).to.not.have.attribute('open'); }); it('should show a hint', function () { diff --git a/packages/compass-components/src/components/accordion.tsx b/packages/compass-components/src/components/accordion.tsx index a43959046a3..40d9d7a7aa5 100644 --- a/packages/compass-components/src/components/accordion.tsx +++ b/packages/compass-components/src/components/accordion.tsx @@ -96,19 +96,23 @@ function Accordion({ const darkMode = useDarkMode(); const [localOpen, setLocalOpen] = useState(_open ?? defaultOpen); const setOpenRef = useCurrentValueRef(_setOpen); - const onOpenChange = useCallback(() => { - setLocalOpen((prevValue) => { - const newValue = !prevValue; - setOpenRef.current?.(newValue); - return newValue; - }); - }, [setOpenRef]); + const onOpenChange = useCallback( + (e: React.SyntheticEvent) => { + e.preventDefault(); + setLocalOpen((prevValue) => { + const newValue = !prevValue; + setOpenRef.current?.(newValue); + return newValue; + }); + }, + [setOpenRef] + ); const regionId = useId(); const labelId = useId(); const open = typeof _open !== 'undefined' ? _open : localOpen; return ( - <> - + - {open && ( -
- {props.children} -
- )} - +
+ {props.children} +
+ ); } From e54f147d9a97fb4898594016fe871ff5b51f8aad Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 22 Jan 2026 15:50:00 +0100 Subject: [PATCH 2/2] cleanup --- .../src/components/accordion.tsx | 78 ++++++++----------- .../drawer/drawer-section-components.tsx | 2 +- .../src/components/create-shard-key-form.tsx | 3 - .../create-index-form/create-index-form.tsx | 2 +- .../advanced-connection-options.tsx | 8 +- .../csfle-tab/csfle-tab.tsx | 4 +- .../src/components/connection-form.tsx | 7 +- 7 files changed, 42 insertions(+), 62 deletions(-) diff --git a/packages/compass-components/src/components/accordion.tsx b/packages/compass-components/src/components/accordion.tsx index 40d9d7a7aa5..e7b2a9a812e 100644 --- a/packages/compass-components/src/components/accordion.tsx +++ b/packages/compass-components/src/components/accordion.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback } from 'react'; import { spacing } from '@leafygreen-ui/tokens'; import { css, cx } from '@leafygreen-ui/emotion'; import { palette } from '@leafygreen-ui/palette'; @@ -6,9 +6,8 @@ import { useId } from '@react-aria/utils'; import { useDarkMode } from '../hooks/use-theme'; import { Description, Icon } from './leafygreen'; -import { useCurrentValueRef } from '../hooks/use-current-value-ref'; -const buttonStyles = css({ +const summaryStyles = css({ fontWeight: 'bold', display: 'flex', alignItems: 'center', @@ -28,7 +27,7 @@ const buttonStyles = css({ }, }); -const buttonVariantStyles = { +const summaryVariantStyles = { default: css({ fontSize: 14, lineHeight: `${spacing[500]}px`, @@ -44,26 +43,29 @@ const iconVariantSizes = { small: 14, }; -const buttonLightThemeStyles = css({ +const summaryLightThemeStyles = css({ color: palette.gray.dark2, }); -const buttonDarkThemeStyles = css({ +const summaryDarkThemeStyles = css({ color: palette.white, }); -const buttonIconContainerStyles = css({ +const summaryIconContainerStyles = css({ fontSize: 0, lineHeight: 0, padding: 0, paddingRight: spacing[150], + 'details[open] > summary & svg': { + transform: 'rotate(90deg)', + }, }); -const buttonTextStyles = css({ +const summaryTextStyles = css({ textAlign: 'left', }); -const buttonHintStyles = css({ +const summaryHintStyles = css({ margin: 0, marginLeft: spacing[100], padding: 0, @@ -71,14 +73,13 @@ const buttonHintStyles = css({ }); interface AccordionProps - extends Omit, 'size'> { + extends Omit, 'size'> { text: string | React.ReactNode; hintText?: string; textClassName?: string; - buttonTextClassName?: string; - open?: boolean; + summaryTextClassName?: string; defaultOpen?: boolean; - setOpen?: (newValue: boolean) => void; + onOpenToggle?: (newValue: boolean) => void; size?: 'default' | 'small'; } @@ -86,61 +87,46 @@ function Accordion({ text, hintText, textClassName, - buttonTextClassName, - open: _open, - setOpen: _setOpen, + summaryTextClassName, defaultOpen = false, + onOpenToggle, size = 'default', ...props }: React.PropsWithChildren): React.ReactElement { const darkMode = useDarkMode(); - const [localOpen, setLocalOpen] = useState(_open ?? defaultOpen); - const setOpenRef = useCurrentValueRef(_setOpen); - const onOpenChange = useCallback( - (e: React.SyntheticEvent) => { - e.preventDefault(); - setLocalOpen((prevValue) => { - const newValue = !prevValue; - setOpenRef.current?.(newValue); - return newValue; - }); + const labelId = useId(); + const handleToggle = useCallback( + (event: React.SyntheticEvent) => { + const isOpen = (event.target as HTMLDetailsElement).open; + onOpenToggle?.(isOpen); }, - [setOpenRef] + [onOpenToggle] ); - const regionId = useId(); - const labelId = useId(); - const open = typeof _open !== 'undefined' ? _open : localOpen; return ( -
+
- - + + -
+
{text} {hintText && ( - {hintText} + {hintText} )}
-
+
{props.children}
diff --git a/packages/compass-data-modeling/src/components/drawer/drawer-section-components.tsx b/packages/compass-data-modeling/src/components/drawer/drawer-section-components.tsx index b7782c85ce1..b5a134bba76 100644 --- a/packages/compass-data-modeling/src/components/drawer/drawer-section-components.tsx +++ b/packages/compass-data-modeling/src/components/drawer/drawer-section-components.tsx @@ -43,7 +43,7 @@ export const DMDrawerSection: React.FC<{ text={label} defaultOpen={true} textClassName={accordionTitleStyles} - buttonTextClassName={buttonStyles} + summaryTextClassName={buttonStyles} size="small" > {children} diff --git a/packages/compass-global-writes/src/components/create-shard-key-form.tsx b/packages/compass-global-writes/src/components/create-shard-key-form.tsx index c45f5b2e503..092b33d8e32 100644 --- a/packages/compass-global-writes/src/components/create-shard-key-form.tsx +++ b/packages/compass-global-writes/src/components/create-shard-key-form.tsx @@ -123,7 +123,6 @@ export function CreateShardKeyForm({ isCancellingSharding, onCreateShardKey, }: CreateShardKeyFormProps) { - const [isAdvancedOptionsOpen, setIsAdvancedOptionsOpen] = useState(false); const [selectedAdvancedOption, setSelectedAdvancedOption] = useState('default'); const fields = useAutocompleteFields(namespace); @@ -221,8 +220,6 @@ export function CreateShardKeyForm({ { + onOpenToggle={() => { track('Options Clicked', { context: 'Create Index Modal', }); diff --git a/packages/connection-form/src/components/advanced-connection-options.tsx b/packages/connection-form/src/components/advanced-connection-options.tsx index 64cadae0b43..fbb1d780912 100644 --- a/packages/connection-form/src/components/advanced-connection-options.tsx +++ b/packages/connection-form/src/components/advanced-connection-options.tsx @@ -33,8 +33,7 @@ function AdvancedConnectionOptions({ errors, updateConnectionFormField, connectionOptions, - open, - setOpen, + onOpenToggle, openSettingsModal, }: { errors: ConnectionFormError[]; @@ -44,14 +43,13 @@ function AdvancedConnectionOptions({ openSettingsModal?: (tab?: string) => void; } & Pick< React.ComponentProps, - 'open' | 'setOpen' + 'onOpenToggle' >): React.ReactElement { return (
{disabled && ( diff --git a/packages/connection-form/src/components/advanced-options-tabs/csfle-tab/csfle-tab.tsx b/packages/connection-form/src/components/advanced-options-tabs/csfle-tab/csfle-tab.tsx index 223d57f606f..7f0dbd10b2a 100644 --- a/packages/connection-form/src/components/advanced-options-tabs/csfle-tab/csfle-tab.tsx +++ b/packages/connection-form/src/components/advanced-options-tabs/csfle-tab/csfle-tab.tsx @@ -242,7 +242,9 @@ function CSFLETab({ return (
onOpenAccordion(kmsProviderType, open)} + onOpenToggle={(open) => + onOpenAccordion(kmsProviderType, open) + } data-testid={`csfle-kms-provider-${kmsProviderType}`} text={accordionTitle} > diff --git a/packages/connection-form/src/components/connection-form.tsx b/packages/connection-form/src/components/connection-form.tsx index 2cbb4c19a8a..7cf9919194b 100644 --- a/packages/connection-form/src/components/connection-form.tsx +++ b/packages/connection-form/src/components/connection-form.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useMemo } from 'react'; import type { ConnectionInfo, ConnectionFavoriteOptions, @@ -357,12 +357,10 @@ function ConnectionForm({ onAdvancedOptionsToggle, openSettingsModal, }: ConnectionFormPropsWithoutSettings): React.ReactElement { - const [advancedOpen, setAdvancedOpen] = useState(false); const isDarkMode = useDarkMode(); const onAdvancedChange = useCallback( (newState: boolean) => { - setAdvancedOpen(newState); onAdvancedOptionsToggle?.(newState); }, [onAdvancedOptionsToggle] @@ -594,8 +592,7 @@ function ConnectionForm({ protectConnectionStrings || disableEditingConnectedConnection ) && (