diff --git a/package-lock.json b/package-lock.json index d5addf2749b..82d3324a9b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,6 @@ "configs/*", "scripts" ], - "dependencies": { - "electron": "^23.3.12" - }, "devDependencies": { "@babel/core": "7.16.0", "@babel/parser": "7.16.0", diff --git a/packages/compass-components/src/components/feedback-popover.spec.tsx b/packages/compass-components/src/components/feedback-popover.spec.tsx new file mode 100644 index 00000000000..6daed4ea5dc --- /dev/null +++ b/packages/compass-components/src/components/feedback-popover.spec.tsx @@ -0,0 +1,72 @@ +import React, { useState } from 'react'; +import { expect } from 'chai'; +import { render, screen, cleanup, fireEvent } from '@testing-library/react'; + +import { FeedbackPopover } from './feedback-popover'; + +function FeedbackPopoverRenderer( + props: Partial> +) { + const buttonRef = React.createRef(); + const [open, setOpen] = useState(false); + + return ( +
+ + { + /* no-op */ + }} + {...props} + /> +
+ ); +} + +const renderFeedbackPopover = ( + props: Partial> +) => { + render(); +}; + +describe('FeedbackPopover', function () { + afterEach(function () { + cleanup(); + }); + + it('renders the popover and passes feedback when submitted', async function () { + let feedbackText = ''; + renderFeedbackPopover({ + onSubmitFeedback: (text: string) => { + feedbackText = text; + }, + }); + + expect(screen.queryByRole('textbox')).to.not.exist; + + screen.getByTestId('open-feedback-button').click(); + + const textArea = screen.getByTestId('feedback-popover-textarea'); + expect(textArea).to.be.visible; + fireEvent.change(textArea, { + target: { value: 'pineapple' }, + }); + + screen.getByText('Submit').click(); + // Wait for the event to go through. + await new Promise((resolve) => setTimeout(resolve, 3)); + + expect(feedbackText).to.equal('pineapple'); + }); +}); diff --git a/packages/compass-components/src/components/feedback-popover.tsx b/packages/compass-components/src/components/feedback-popover.tsx new file mode 100644 index 00000000000..7994f5d56e1 --- /dev/null +++ b/packages/compass-components/src/components/feedback-popover.tsx @@ -0,0 +1,103 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import { GuideCue as LGGuideCue } from '@leafygreen-ui/guide-cue'; + +import { TextArea, css, spacing, useId } from '..'; + +const guideCueStyles = css({ + minWidth: spacing[7] * 4, +}); + +type LGGuideCueProps = React.ComponentProps; + +// Omit the props we are handling. +export type FeedbackPopoverProps = Omit< + LGGuideCueProps, + 'currentStep' | 'numberOfSteps' | 'children' | 'title' +> & { + onSubmitFeedback: (text: string) => void; + placeholder: string; + label: string; +}; + +export const FeedbackPopover = ({ + onSubmitFeedback, + label, + placeholder, + setOpen, + refEl, + open, + ...props +}: FeedbackPopoverProps) => { + const [feedbackText, setFeedbackText] = useState(''); + const feedbackPopoverId = useId(); + + useEffect(() => { + if (!open) { + return; + } + const listener = (event: MouseEvent) => { + const popover = document.querySelector( + `[data-popoverid="feedback-popover-${feedbackPopoverId}"]` + ); + if (!popover) { + return; + } + + // Clicked within popover or the trigger. + if ( + event.composedPath().includes(popover) || + event.composedPath().includes(refEl.current!) + ) { + return; + } + + setOpen(false); + }; + + document.addEventListener('mousedown', listener); + return () => { + document.removeEventListener('mousedown', listener); + }; + }, [feedbackPopoverId, open, setOpen]); + + const onTextAreaKeyDown = useCallback( + (evt: React.KeyboardEvent) => { + if (evt.key === 'Enter' && !evt.shiftKey) { + evt.preventDefault(); + onSubmitFeedback(feedbackText); + } else if (evt.key === 'Escape') { + evt.preventDefault(); + setOpen(false); + } + }, + [feedbackText, setOpen, onSubmitFeedback] + ); + + return ( + onSubmitFeedback(feedbackText)} + buttonText="Submit" + setOpen={setOpen} + open={open} + {...props} + > +