Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/__tests__/components/MorphemeBox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// <reference types="@testing-library/jest-dom" />

import { useLocalizedStrings } from '@papi/frontend/react';
import { render, screen } from '@testing-library/react';
import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { MorphemeAnalysis, Token } from 'interlinearizer';
import * as AnalysisStore from '../../components/AnalysisStore';
Expand Down Expand Up @@ -118,6 +118,36 @@ describe('MorphemeBox', () => {
expect(onEditBreakdown).toHaveBeenCalledTimes(1);
});

it('calls onEditBreakdown when a non-first form cell is clicked', async () => {
// Non-first cells are spans, not buttons, so they need their own coverage.
const onEditBreakdown = jest.fn();
renderBox({ onEditBreakdown });
await userEvent.click(screen.getByText('-lo'));
expect(onEditBreakdown).toHaveBeenCalledTimes(1);
});

it('stops a non-first form cell mousedown from bubbling to an ancestor handler', () => {
// Regression test: an ancestor onMouseDown (e.g. TokenChip's label) would otherwise focus the
// gloss input, since a span (unlike a button) doesn't match its input/button guard.
const onAncestorMouseDown = jest.fn();
render(
// Stand-in for an ancestor React handler, not real UI.
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div onMouseDown={onAncestorMouseDown}>
<MorphemeBox
analysisLanguage="en"
disabled={false}
morphemes={MORPHEMES}
onEditBreakdown={jest.fn()}
popoverOpen={false}
token={WORD_TOKEN}
/>
</div>,
);
fireEvent.mouseDown(screen.getByText('-lo'));
expect(onAncestorMouseDown).not.toHaveBeenCalled();
});

it('does not call onEditBreakdown when disabled', async () => {
const onEditBreakdown = jest.fn();
renderBox({ disabled: true, onEditBreakdown });
Expand Down
5 changes: 4 additions & 1 deletion src/components/MorphemeBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,11 @@ export function MorphemeBox({
key={m.id}
aria-hidden="true"
className={formClassName}
style={formStyle}
onClick={handleClick}
// Not a button, so stop mousedown from bubbling to TokenChip's label handler (which
// would otherwise focus the gloss input).
onMouseDown={(e) => e.stopPropagation()}
style={formStyle}
>
{m.form}
</span>
Expand Down
6 changes: 4 additions & 2 deletions src/components/TokenChip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,10 @@ export function TokenChip({
* The input is looked up by id rather than `querySelector('input')` because the morpheme gloss
* inputs precede it inside the label when morphology is shown. A mouse-down on any input is left
* to that input's own handling ({@link handleMouseDown} for the gloss input, which bubbles here
* after already handling it); a mouse-down on a morpheme form cell or the unanalyzed "define"
* trigger (all `button`s) is left to that button's own click handler, which opens the popover.
* after already handling it); a mouse-down on the first morpheme form cell or the unanalyzed
* "define" trigger (both real `button`s) is left to that button's own click handler. The
* remaining morpheme form cells are `span`s that stop their own mousedown from bubbling here
* instead (see {@link MorphemeBox}).
*
* @param e - The label's mouse-down event.
*/
Expand Down