From b2000d4616422f8c9e48cfa3dd07890ca1ee4da0 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Wed, 10 Jul 2024 12:39:47 +0200 Subject: [PATCH 01/10] feat: allows nested elements to also expand in steps --- .../document-fields-toggle-group.tsx | 4 +- .../document-list/document.spec.tsx | 55 ++++- .../src/components/document-list/document.tsx | 41 ++-- .../src/components/document-list/element.tsx | 96 ++++++-- packages/hadron-document/src/document.ts | 22 ++ .../hadron-document/src/element-events.ts | 1 + packages/hadron-document/src/element.ts | 36 ++- packages/hadron-document/src/index.ts | 8 +- .../hadron-document/test/document.test.ts | 101 ++++++++ packages/hadron-document/test/element.test.ts | 218 +++++++++++++++++- 10 files changed, 541 insertions(+), 41 deletions(-) diff --git a/packages/compass-components/src/components/document-list/document-fields-toggle-group.tsx b/packages/compass-components/src/components/document-list/document-fields-toggle-group.tsx index b51ba530577..eef91d156ee 100644 --- a/packages/compass-components/src/components/document-list/document-fields-toggle-group.tsx +++ b/packages/compass-components/src/components/document-list/document-fields-toggle-group.tsx @@ -21,6 +21,7 @@ const DocumentFieldsToggleGroup: React.FunctionComponent<{ totalSize: number; minSize?: number; step?: number; + style?: React.CSSProperties; onSizeChange(newSize: number): void; }> = ({ showHideButton = true, @@ -28,6 +29,7 @@ const DocumentFieldsToggleGroup: React.FunctionComponent<{ totalSize, minSize = 25, step = 1000, + style, onSizeChange, }) => { const showSizeDiff = useMemo(() => { @@ -59,7 +61,7 @@ const DocumentFieldsToggleGroup: React.FunctionComponent<{ } return ( -
+
{isShowButtonVisible && (
); }; diff --git a/packages/compass-components/src/components/document-list/element.tsx b/packages/compass-components/src/components/document-list/element.tsx index 7b2502d79f0..c5b2ba51571 100644 --- a/packages/compass-components/src/components/document-list/element.tsx +++ b/packages/compass-components/src/components/document-list/element.tsx @@ -27,7 +27,7 @@ import { css, cx } from '@leafygreen-ui/emotion'; import { palette } from '@leafygreen-ui/palette'; import { Icon } from '../leafygreen'; import { useDarkMode } from '../../hooks/use-theme'; -import DocumentFieldsToggleGroup from './document-fields-toggle-group'; +import VisibleFieldsToggle from './visible-field-toggle'; function getEditorByType(type: HadronElementType['type']) { switch (type) { @@ -687,7 +687,8 @@ export const HadronElement: React.FunctionComponent<{ > ); })} - + > )} diff --git a/packages/compass-components/src/components/document-list/index.ts b/packages/compass-components/src/components/document-list/index.ts index cd11603f6b7..38b67e68498 100644 --- a/packages/compass-components/src/components/document-list/index.ts +++ b/packages/compass-components/src/components/document-list/index.ts @@ -1,4 +1,4 @@ export { default as DocumentActionsGroup } from './document-actions-group'; -export { default as DocumentFieldsToggleGroup } from './document-fields-toggle-group'; +export { default as VisibleFieldsToggle } from './visible-field-toggle'; export { default as Document } from './document'; export { default as DocumentEditActionsFooter } from './document-edit-actions-footer'; diff --git a/packages/compass-components/src/components/document-list/document-fields-toggle-group.tsx b/packages/compass-components/src/components/document-list/visible-field-toggle.tsx similarity index 52% rename from packages/compass-components/src/components/document-list/document-fields-toggle-group.tsx rename to packages/compass-components/src/components/document-list/visible-field-toggle.tsx index eef91d156ee..b45dd1c19f2 100644 --- a/packages/compass-components/src/components/document-list/document-fields-toggle-group.tsx +++ b/packages/compass-components/src/components/document-list/visible-field-toggle.tsx @@ -1,7 +1,8 @@ import React, { useCallback, useMemo } from 'react'; -import { css } from '@leafygreen-ui/emotion'; +import { css, cx } from '@leafygreen-ui/emotion'; import { spacing } from '@leafygreen-ui/tokens'; -import { Button, Icon } from '../leafygreen'; +import { Icon, Link } from '../leafygreen'; +import { documentTypography } from './typography'; const container = css({ display: 'flex', @@ -11,12 +12,24 @@ const container = css({ paddingRight: spacing[3], }); -const button = css({ - flex: 'none', +const linkButtonStyles = css({ + border: 'none', + background: 'none', + padding: 0, + fontFamily: documentTypography.fontFamily, + fontSize: `${documentTypography.fontSize}px`, + lineHeight: `${documentTypography.lineHeight}px`, + '& > span': { + display: 'inline-flex', + alignItems: 'center', + gap: spacing[100], + }, }); -const DocumentFieldsToggleGroup: React.FunctionComponent<{ +const VisibleFieldsToggle: React.FunctionComponent<{ showHideButton?: boolean; + buttonClassName?: string; + parentFieldName?: string; currentSize: number; totalSize: number; minSize?: number; @@ -25,6 +38,8 @@ const DocumentFieldsToggleGroup: React.FunctionComponent<{ onSizeChange(newSize: number): void; }> = ({ showHideButton = true, + buttonClassName, + parentFieldName, currentSize, totalSize, minSize = 25, @@ -60,32 +75,41 @@ const DocumentFieldsToggleGroup: React.FunctionComponent<{ return null; } + const showButtonText = `Show ${showSizeDiff} more ${ + showSizeDiff === 1 ? 'field' : 'fields' + }${parentFieldName ? ` in ${parentFieldName}` : ''}`; + const hideButtonText = `Hide ${hideSizeDiff} ${ + hideSizeDiff === 1 ? 'field' : 'fields' + }${parentFieldName ? ` in ${parentFieldName}` : ''}`; + return (
{isShowButtonVisible && ( - + + {showButtonText} + )} {isHideButtonVisible && ( - + + {hideButtonText} + )}
); }; -export default DocumentFieldsToggleGroup; +export default VisibleFieldsToggle; diff --git a/packages/compass-components/src/components/document-list/document-fields-toggle-group.spec.tsx b/packages/compass-components/src/components/document-list/visible-fields-toggle.spec.tsx similarity index 78% rename from packages/compass-components/src/components/document-list/document-fields-toggle-group.spec.tsx rename to packages/compass-components/src/components/document-list/visible-fields-toggle.spec.tsx index 8538a9a5ee1..c66451ac6ab 100644 --- a/packages/compass-components/src/components/document-list/document-fields-toggle-group.spec.tsx +++ b/packages/compass-components/src/components/document-list/visible-fields-toggle.spec.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { expect } from 'chai'; import { cleanup, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import DocumentFieldsToggleGroup from './document-fields-toggle-group'; +import VisibleFieldsToggle from './visible-field-toggle'; function TestComponent({ initialSize = 10, @@ -10,20 +10,29 @@ function TestComponent({ totalSize = Infinity, minSize = 10, step = 10, + parentFieldName, +}: { + initialSize?: number; + showHideButton?: boolean; + totalSize?: number; + minSize?: number; + step?: number; + parentFieldName?: string; }) { const [size, setSize] = useState(initialSize); return (
Showing {size} items
- + parentFieldName={parentFieldName} + >
); } @@ -41,6 +50,17 @@ describe('DocumentFieldsToggleGroup', function () { expect(screen.getByText('Hide 10 fields')).to.exist; }); + it('should include parentFieldName in the label when provided', function () { + render( + + ); + expect(screen.getByText('Hide 10 fields in reviews')).to.exist; + }); + it('should show more items when "Show items" is clicked', function () { render(); expect(screen.getByText('Showing 10 items')).to.exist; From c3199517cffdf075a6a5ade13e2eff9e9588a647 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 12 Jul 2024 12:07:22 +0200 Subject: [PATCH 08/10] chore: restore test-id for e2e tests --- .../src/components/document-list/visible-field-toggle.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/compass-components/src/components/document-list/visible-field-toggle.tsx b/packages/compass-components/src/components/document-list/visible-field-toggle.tsx index b45dd1c19f2..0c21397299c 100644 --- a/packages/compass-components/src/components/document-list/visible-field-toggle.tsx +++ b/packages/compass-components/src/components/document-list/visible-field-toggle.tsx @@ -91,6 +91,7 @@ const VisibleFieldsToggle: React.FunctionComponent<{ className={cx(linkButtonStyles, buttonClassName)} onClick={onShowClick} aria-label={showButtonText} + data-testid="show-more-fields-button" > {showButtonText} @@ -103,6 +104,7 @@ const VisibleFieldsToggle: React.FunctionComponent<{ className={cx(linkButtonStyles, buttonClassName)} onClick={onHideClick} aria-label={hideButtonText} + data-testid="hide-fields-button" > {hideButtonText} From 04e716b2043d05030574b54a49b05e622b2e1f95 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 19 Jul 2024 13:59:02 +0200 Subject: [PATCH 09/10] chore: addresses PR feedback about design and isExpandable --- .../src/components/document-list/document.tsx | 20 +++++- .../src/components/document-list/element.tsx | 65 +++++++++++++------ .../document-list/visible-field-toggle.tsx | 10 ++- packages/hadron-document/src/element.ts | 2 +- 4 files changed, 68 insertions(+), 29 deletions(-) diff --git a/packages/compass-components/src/components/document-list/document.tsx b/packages/compass-components/src/components/document-list/document.tsx index 2ae1eda6af0..e1f42bc5e69 100644 --- a/packages/compass-components/src/components/document-list/document.tsx +++ b/packages/compass-components/src/components/document-list/document.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { css } from '@leafygreen-ui/emotion'; import type { default as HadronDocumentType, @@ -11,7 +11,7 @@ import { } from 'hadron-document'; import { AutoFocusContext } from './auto-focus-context'; import { useForceUpdate } from './use-force-update'; -import { HadronElement } from './element'; +import { calculateShowMoreToggleOffset, HadronElement } from './element'; import { usePrevious } from './use-previous'; import VisibleFieldsToggle from './visible-field-toggle'; import { documentTypography } from './typography'; @@ -105,6 +105,19 @@ const HadronDocument: React.FunctionComponent<{ [document] ); + // To render the "Show more" toggle for the document we need to calculate a + // proper offset so that it aligns with the expand icon of top level fields + // Note: We're not sharing the logic with element + const showMoreToggleOffset = useMemo( + () => + calculateShowMoreToggleOffset({ + editable, + level: 0, + alignWithNestedExpandIcon: false, + }), + [editable] + ); + return (
); diff --git a/packages/compass-components/src/components/document-list/element.tsx b/packages/compass-components/src/components/document-list/element.tsx index c5b2ba51571..de3e51e54c2 100644 --- a/packages/compass-components/src/components/document-list/element.tsx +++ b/packages/compass-components/src/components/document-list/element.tsx @@ -363,6 +363,38 @@ const elementKeyDarkMode = css({ color: palette.gray.light2, }); +const calculateElementSpacerWidth = (editable: boolean, level: number) => { + return (editable ? spacing[200] : 0) + spacing[400] * level; +}; + +export const calculateShowMoreToggleOffset = ({ + editable, + level, + alignWithNestedExpandIcon, +}: { + editable: boolean; + level: number; + alignWithNestedExpandIcon: boolean; +}) => { + // the base padding that we have on all elements rendered in the document + const BASE_PADDING_LEFT = spacing[200]; + const OFFSET_WHEN_EDITABLE = editable + ? // space taken by element actions + spacing[400] + + // space and margin taken by line number element + spacing[400] + + spacing[100] + + // element spacer width that we render + calculateElementSpacerWidth(editable, level) + : 0; + const EXPAND_ICON_SIZE = spacing[400]; + return ( + BASE_PADDING_LEFT + + OFFSET_WHEN_EDITABLE + + (alignWithNestedExpandIcon ? EXPAND_ICON_SIZE : 0) + ); +}; + export const HadronElement: React.FunctionComponent<{ value: HadronElementType; editable: boolean; @@ -412,27 +444,22 @@ export const HadronElement: React.FunctionComponent<{ return spacing[400]; }, [lineNumberSize, editingEnabled]); - const elementSpacerWidth = useMemo(() => { - return (editable ? spacing[200] : 0) + spacing[400] * level; - }, [editable, level]); + const elementSpacerWidth = useMemo( + () => calculateElementSpacerWidth(editable, level), + [editable, level] + ); // To render the "Show more" toggle for the nested expandable elements we need // to calculate a proper offset so that it aligns with the nesting level - const nestedElementsVisibilityToggleOffset = useMemo(() => { - // the base padding that we have on all elements rendered in the document - const BASE_PADDING_LEFT = spacing[200]; - const OFFSET_WHEN_EDITABLE = editable - ? // space taken by element actions - spacing[400] + - // space and margin taken by line number element - spacing[400] + - spacing[100] + - // element spacer width that we render - elementSpacerWidth - : 0; - const EXPAND_ICON_SIZE = spacing[400]; - return BASE_PADDING_LEFT + OFFSET_WHEN_EDITABLE + EXPAND_ICON_SIZE; - }, [editable, elementSpacerWidth]); + const nestedElementsVisibilityToggleOffset = useMemo( + () => + calculateShowMoreToggleOffset({ + editable, + level, + alignWithNestedExpandIcon: true, + }), + [editable, level] + ); const isValid = key.valid && value.valid; const shouldShowActions = editingEnabled; @@ -704,8 +731,6 @@ export const HadronElement: React.FunctionComponent<{ onSizeChange={handleVisibleElementsChanged} style={{ paddingLeft: nestedElementsVisibilityToggleOffset, - paddingTop: spacing[100], - paddingBottom: spacing[100], }} > diff --git a/packages/compass-components/src/components/document-list/visible-field-toggle.tsx b/packages/compass-components/src/components/document-list/visible-field-toggle.tsx index 0c21397299c..a0ffcdccb49 100644 --- a/packages/compass-components/src/components/document-list/visible-field-toggle.tsx +++ b/packages/compass-components/src/components/document-list/visible-field-toggle.tsx @@ -6,10 +6,8 @@ import { documentTypography } from './typography'; const container = css({ display: 'flex', - gap: spacing[2], - paddingTop: spacing[3], - paddingLeft: spacing[3], - paddingRight: spacing[3], + gap: spacing[200], + paddingTop: spacing[200], }); const linkButtonStyles = css({ @@ -93,7 +91,7 @@ const VisibleFieldsToggle: React.FunctionComponent<{ aria-label={showButtonText} data-testid="show-more-fields-button" > - + {showButtonText} )} @@ -106,7 +104,7 @@ const VisibleFieldsToggle: React.FunctionComponent<{ aria-label={hideButtonText} data-testid="hide-fields-button" > - + {hideButtonText} )} diff --git a/packages/hadron-document/src/element.ts b/packages/hadron-document/src/element.ts index 9bbb52ef5bf..9898ed76bc6 100644 --- a/packages/hadron-document/src/element.ts +++ b/packages/hadron-document/src/element.ts @@ -858,7 +858,7 @@ export class Element extends EventEmitter { } setMaxVisibleElementsCount(newCount: number) { - if (!this._isExpandable(this.originalExpandableValue)) { + if (!this._isExpandable()) { return; } this.maxVisibleElementsCount = newCount; From 69e779a57e1b4e5cd314159ca3505192aaa0dcf7 Mon Sep 17 00:00:00 2001 From: Himanshu Singh Date: Fri, 19 Jul 2024 14:09:24 +0200 Subject: [PATCH 10/10] chore: fixes comment --- .../compass-components/src/components/document-list/document.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/compass-components/src/components/document-list/document.tsx b/packages/compass-components/src/components/document-list/document.tsx index e1f42bc5e69..d7bef7101be 100644 --- a/packages/compass-components/src/components/document-list/document.tsx +++ b/packages/compass-components/src/components/document-list/document.tsx @@ -107,7 +107,6 @@ const HadronDocument: React.FunctionComponent<{ // To render the "Show more" toggle for the document we need to calculate a // proper offset so that it aligns with the expand icon of top level fields - // Note: We're not sharing the logic with element const showMoreToggleOffset = useMemo( () => calculateShowMoreToggleOffset({