[Curation] Add support for a custom drag handle to the Result component (#94652)

* Update Result component to render a custom drag handle

* Update Result library with a draggable example

- note: this doesn't actually handle reorder logic, it's purely a UI/UX example

* Update CurationResult to pass dragHandleProps through to Result
This commit is contained in:
Constance 2021-03-16 08:30:32 -07:00 committed by GitHub
parent c937f2648e
commit badf38b0cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 7 deletions

View file

@ -8,6 +8,7 @@
import { setMockValues } from '../../../../../__mocks__';
import React from 'react';
import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd';
import { shallow, ShallowWrapper } from 'enzyme';
@ -29,12 +30,15 @@ describe('CurationResult', () => {
{ title: 'add', iconType: 'plus', onClick: () => {} },
{ title: 'remove', iconType: 'minus', onClick: () => {} },
];
const mockDragging = {} as DraggableProvidedDragHandleProps; // Passed from EuiDraggable
let wrapper: ShallowWrapper;
beforeAll(() => {
setMockValues(values);
wrapper = shallow(<CurationResult result={mockResult} actions={mockActions} />);
wrapper = shallow(
<CurationResult result={mockResult} actions={mockActions} dragHandleProps={mockDragging} />
);
});
it('passes EngineLogic state', () => {
@ -42,8 +46,9 @@ describe('CurationResult', () => {
expect(wrapper.find(Result).prop('schemaForTypeHighlights')).toEqual('some mock schema');
});
it('passes result and actions props', () => {
it('passes result, actions, and dragHandleProps props', () => {
expect(wrapper.find(Result).prop('result')).toEqual(mockResult);
expect(wrapper.find(Result).prop('actions')).toEqual(mockActions);
expect(wrapper.find(Result).prop('dragHandleProps')).toEqual(mockDragging);
});
});

View file

@ -6,6 +6,7 @@
*/
import React from 'react';
import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd';
import { useValues } from 'kea';
@ -18,9 +19,10 @@ import { Result as ResultType, ResultAction } from '../../../result/types';
interface Props {
result: ResultType;
actions: ResultAction[];
dragHandleProps?: DraggableProvidedDragHandleProps;
}
export const CurationResult: React.FC<Props> = ({ result, actions }) => {
export const CurationResult: React.FC<Props> = ({ result, actions, dragHandleProps }) => {
const {
isMetaEngine,
engine: { schema },
@ -33,6 +35,7 @@ export const CurationResult: React.FC<Props> = ({ result, actions }) => {
actions={actions}
isMetaEngine={isMetaEngine}
schemaForTypeHighlights={schema}
dragHandleProps={dragHandleProps}
/>
<EuiSpacer size="m" />
</>

View file

@ -14,6 +14,9 @@ import {
EuiTitle,
EuiPageContentBody,
EuiPageContent,
EuiDragDropContext,
EuiDroppable,
EuiDraggable,
} from '@elastic/eui';
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
@ -228,6 +231,28 @@ export const Library: React.FC = () => {
<Result {...props} actions={actions} shouldLinkToDetailPage />
<EuiSpacer />
<EuiSpacer />
<EuiTitle size="s">
<h3>With a drag handle</h3>
</EuiTitle>
<EuiSpacer />
<EuiDragDropContext onDragEnd={() => {}}>
<EuiDroppable spacing="m" droppableId="DraggableResultsTest">
{[1, 2, 3].map((_, i) => (
<EuiDraggable
spacing="m"
key={`draggable-${i}`}
index={i}
draggableId={`draggable-${i}`}
customDragHandle
>
{(provided) => <Result {...props} dragHandleProps={provided.dragHandleProps} />}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
<EuiSpacer />
<EuiSpacer />
<EuiTitle size="s">
<h3>With field value type highlights</h3>

View file

@ -1,10 +1,10 @@
.appSearchResult {
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: 1fr auto;
grid-template-columns: auto 1fr auto;
grid-template-rows: auto 1fr auto;
grid-template-areas:
'content actions'
'toggle actions';
'drag content actions'
'drag toggle actions';
overflow: hidden; // Prevents child background-colors from clipping outside of panel border-radius
&__content {
@ -52,6 +52,15 @@
background-color: $euiPageBackgroundColor;
}
}
&__dragHandle {
grid-area: drag;
display: flex;
justify-content: center;
align-items: center;
width: $euiSizeXL;
border-right: $euiBorderThin;
}
}
/**

View file

@ -6,6 +6,7 @@
*/
import React from 'react';
import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd';
import { shallow, ShallowWrapper } from 'enzyme';
@ -129,6 +130,20 @@ describe('Result', () => {
});
});
describe('dragging', () => {
// In the real world, the drag library sets data attributes, role, tabIndex, etc.
const mockDragHandleProps = ({
someMockProp: true,
} as unknown) as DraggableProvidedDragHandleProps;
it('will render a drag handle with the passed props', () => {
const wrapper = shallow(<Result {...props} dragHandleProps={mockDragHandleProps} />);
expect(wrapper.find('.appSearchResult__dragHandle')).toHaveLength(1);
expect(wrapper.find('.appSearchResult__dragHandle').prop('someMockProp')).toEqual(true);
});
});
it('will render field details with type highlights if schemaForTypeHighlights has been provided', () => {
const wrapper = shallow(
<Result {...props} shouldLinkToDetailPage schemaForTypeHighlights={schema} />

View file

@ -6,6 +6,7 @@
*/
import React, { useState, useMemo } from 'react';
import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd';
import classNames from 'classnames';
@ -31,6 +32,7 @@ interface Props {
shouldLinkToDetailPage?: boolean;
schemaForTypeHighlights?: Schema;
actions?: ResultAction[];
dragHandleProps?: DraggableProvidedDragHandleProps;
}
const RESULT_CUTOFF = 5;
@ -42,6 +44,7 @@ export const Result: React.FC<Props> = ({
shouldLinkToDetailPage = false,
schemaForTypeHighlights,
actions = [],
dragHandleProps,
}) => {
const [isOpen, setIsOpen] = useState(false);
@ -87,6 +90,11 @@ export const Result: React.FC<Props> = ({
values: { id: result[ID].raw },
})}
>
{dragHandleProps && (
<div {...dragHandleProps} className="appSearchResult__dragHandle">
<EuiIcon type="grab" />
</div>
)}
{conditionallyLinkedArticle(
<>
<ResultHeader