-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #634 from sebgroup/develop
release beta 16
- Loading branch information
Showing
12 changed files
with
1,107 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import React from "react"; | ||
import Docs from "@common/Docs"; | ||
import { SortableList } from "@sebgroup/react-components/SortableList"; | ||
import { useDynamicForm } from "@sebgroup/react-components/hooks/useDynamicForm"; | ||
import { SortableItem } from "@sebgroup/react-components/SortableList/SortableItem"; | ||
import { Checkbox } from "@sebgroup/react-components/Checkbox"; | ||
|
||
const importString: string = require("!raw-loader!@sebgroup/react-components/SortableList/SortableList"); | ||
const code: string = `<SortableList> | ||
<SortableItem uniqueKey="item1">item 1</SortableItem> | ||
<SortableItem uniqueKey="item2">item 2</SortableItem> | ||
<SortableItem uniqueKey="item3" disabled>item 3</SortableItem> | ||
</SortableList>`; | ||
|
||
type Example = { | ||
label: string; | ||
value: string; | ||
checked: boolean; | ||
disabled?: boolean; | ||
}; | ||
|
||
const SortableListPage: React.FC = (): React.ReactElement<void> => { | ||
const [value, setValue] = React.useState<number>(null); | ||
const [array, setArray] = React.useState<Example[]>([ | ||
{ | ||
label: "Name", | ||
value: "1", | ||
checked: false, | ||
}, | ||
{ | ||
label: "Age", | ||
value: "2", | ||
checked: false, | ||
}, | ||
{ | ||
label: "Company", | ||
value: "3", | ||
checked: false, | ||
}, | ||
{ | ||
label: "Address", | ||
value: "4", | ||
checked: false, | ||
}, | ||
]); | ||
|
||
const [renderControls, { controls }] = useDynamicForm([ | ||
{ | ||
key: "controls", | ||
items: [ | ||
{ key: "disabled", label: "disabled", controlType: "Checkbox" }, | ||
{ key: "disabledItem", label: "disable one random item", controlType: "Checkbox" }, | ||
{ key: "simple", label: "simple usage", controlType: "Checkbox" }, | ||
], | ||
}, | ||
]); | ||
|
||
React.useEffect(() => { | ||
setValue(controls.disabledItem ? Math.floor(Math.random() * (array.length - 1 - 0 + 1)) + 0 : null); | ||
}, [controls.disabledItem]); | ||
|
||
return ( | ||
<Docs | ||
mainFile={importString} | ||
example={ | ||
<div className="w-100 d-flex justify-content-center"> | ||
<SortableList | ||
disabled={controls.disabled} | ||
onSort={(list: string[]) => setArray((oldArray: Example[]) => oldArray.sort((a: Example, b: Example) => list.indexOf(a.value) - list.indexOf(b.value)))} | ||
> | ||
{array.map((item: Example, index: number) => ( | ||
<SortableItem key={index} uniqueKey={item.value} disabled={index === value}> | ||
{controls.simple ? ( | ||
item.label | ||
) : ( | ||
<Checkbox | ||
name="test" | ||
value={item.value} | ||
checked={item.checked} | ||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => { | ||
setArray((oldArray: Example[]) => | ||
oldArray.map((checkbox: Example) => ({ | ||
...checkbox, | ||
checked: item.value === checkbox.value ? event.target.checked : checkbox.checked, | ||
})) | ||
); | ||
}} | ||
> | ||
{item.label} | ||
</Checkbox> | ||
)} | ||
</SortableItem> | ||
))} | ||
</SortableList> | ||
</div> | ||
} | ||
code={code} | ||
controls={<>{renderControls()}</>} | ||
/> | ||
); | ||
}; | ||
|
||
export default SortableListPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React from "react"; | ||
import { SortableItem, SortableItemProps } from "."; | ||
import { unmountComponentAtNode, render } from "react-dom"; | ||
import { act } from "react-dom/test-utils"; | ||
|
||
describe("Component: SortableItem", () => { | ||
let container: HTMLDivElement = null; | ||
const props: SortableItemProps = { uniqueKey: "1" }; | ||
|
||
beforeEach(() => { | ||
container = document.createElement("div"); | ||
document.body.appendChild(container); | ||
}); | ||
|
||
afterEach(() => { | ||
unmountComponentAtNode(container); | ||
container.remove(); | ||
container = null; | ||
}); | ||
|
||
it("Should render", () => { | ||
act(() => { | ||
render(<SortableItem {...props} />, container); | ||
}); | ||
expect(container.querySelector(".sortable-item")).not.toBeNull(); | ||
}); | ||
|
||
it("Should pass a custom class and id", () => { | ||
const className: string = "mySortableItemClass"; | ||
const id: string = "mySortableItemId"; | ||
act(() => { | ||
render(<SortableItem {...props} className={className} id={id} />, container); | ||
}); | ||
expect(container.querySelector(`.${className}`)).not.toBeNull(); | ||
expect(container.querySelector(`#${id}`)).not.toBeNull(); | ||
}); | ||
|
||
it("Should set children to disabled if disabled prop is passed", () => { | ||
act(() => { | ||
render( | ||
<SortableItem {...props} disabled> | ||
<input /> | ||
test | ||
</SortableItem>, | ||
container | ||
); | ||
}); | ||
expect(container.querySelector(`input`).hasAttribute("disabled")).toBeTruthy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from "react"; | ||
import classnames from "classnames"; | ||
|
||
export type SortableItemProps = Omit<JSX.IntrinsicElements["div"], "onDragStart" | "onDragOver" | "onDragEnd"> & { | ||
uniqueKey: string; | ||
disabled?: boolean; | ||
}; | ||
|
||
const SortableItem: React.FC<SortableItemProps> = React.forwardRef( | ||
({ className, disabled, children, uniqueKey, ...props }: React.PropsWithChildren<SortableItemProps>, ref: React.ForwardedRef<HTMLDivElement>) => { | ||
return ( | ||
<div {...props} ref={ref} className={classnames("rc", "sortable-item", className)}> | ||
{React.Children.map(children, (Child: React.ReactElement) => { | ||
return React.isValidElement<React.FC<any>>(Child) | ||
? React.cloneElement(Child, { | ||
disabled, | ||
"aria-disabled": disabled, | ||
} as any) | ||
: Child; | ||
})} | ||
</div> | ||
); | ||
} | ||
); | ||
|
||
SortableItem.displayName = "SortableItem"; | ||
|
||
export { SortableItem }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import React from "react"; | ||
import { SortableList, SortableItem, SortableItemProps, SortableListProps } from "."; | ||
import { unmountComponentAtNode, render } from "react-dom"; | ||
import { act, Simulate } from "react-dom/test-utils"; | ||
|
||
describe("Component: SortableList", () => { | ||
let container: HTMLDivElement = null; | ||
const props: SortableListProps = { onSort: jest.fn() }; | ||
|
||
beforeEach(() => { | ||
container = document.createElement("div"); | ||
document.body.appendChild(container); | ||
}); | ||
|
||
afterEach(() => { | ||
unmountComponentAtNode(container); | ||
container.remove(); | ||
container = null; | ||
}); | ||
|
||
it("Should render", () => { | ||
act(() => { | ||
render( | ||
<SortableList {...props}> | ||
<SortableItem uniqueKey="1" /> | ||
</SortableList>, | ||
container | ||
); | ||
}); | ||
expect(container.querySelector(".sortable-list")).not.toBeNull(); | ||
}); | ||
|
||
it("Should pass a custom class and id", () => { | ||
const className: string = "mySortableListClass"; | ||
const id: string = "mySortableListId"; | ||
act(() => { | ||
render( | ||
<SortableList {...props} className={className} id={id}> | ||
<SortableItem uniqueKey="1" /> | ||
</SortableList>, | ||
container | ||
); | ||
}); | ||
expect(container.querySelector(`.${className}`)).not.toBeNull(); | ||
expect(container.querySelector(`#${id}`)).not.toBeNull(); | ||
}); | ||
|
||
it("Should set children to disabled if disabled prop is passed", () => { | ||
act(() => { | ||
render( | ||
<SortableList {...props} disabled> | ||
<SortableItem uniqueKey="1"> | ||
<input /> | ||
test | ||
</SortableItem> | ||
</SortableList>, | ||
container | ||
); | ||
}); | ||
expect(container.querySelector(`.disabled`)).not.toBeNull(); | ||
expect(container.querySelector(`input`).hasAttribute("disabled")).toBeTruthy(); | ||
}); | ||
|
||
it("Should allow to sort children by drag and drop", () => { | ||
const children: { key: string; label: string }[] = [ | ||
{ key: "1", label: "1" }, | ||
{ key: "2", label: "2" }, | ||
{ key: "3", label: "3" }, | ||
]; | ||
act(() => { | ||
render( | ||
<SortableList {...props}> | ||
{children.map((item) => ( | ||
<SortableItem key={item.key} uniqueKey={item.key}> | ||
{item.label} | ||
</SortableItem> | ||
))} | ||
</SortableList>, | ||
container | ||
); | ||
}); | ||
const node: HTMLElement = container.querySelector(".sortable-item-wrapper"); | ||
(node.getBoundingClientRect as any) = jest.fn(() => { | ||
return { top: 50, bottom: 500, right: 400, left: 200, height: 100, width: 50 }; | ||
}); | ||
act(() => { | ||
Simulate.mouseDown(container.querySelector(".drag-icon"), { target: node, pageX: 50, pageY: 50 }); | ||
}); | ||
act(() => { | ||
Simulate.dragStart(container.querySelector(".drag-icon"), { dataTransfer: { setDragImage: jest.fn() } } as any); | ||
}); | ||
act(() => { | ||
Simulate.dragOver(container.querySelectorAll(".sortable-item-wrapper")[1], { dataTransfer: {}, clientY: 50, target: node } as any); | ||
}); | ||
act(() => { | ||
Simulate.transitionEnd(container.querySelectorAll(".sortable-item-wrapper")[1]); | ||
}); | ||
act(() => { | ||
Simulate.dragEnd(container.querySelector(".drag-icon")); | ||
}); | ||
expect(props.onSort).toBeCalledWith(["2", "1", "3"]); | ||
}); | ||
|
||
it("Should throw error if no sortable item passed", () => { | ||
const spyConsole: jest.SpyInstance = jest.spyOn(console, "warn"); | ||
act(() => { | ||
render( | ||
<SortableList {...props} disabled> | ||
test | ||
</SortableList>, | ||
container | ||
); | ||
}); | ||
expect(spyConsole).toBeCalled(); | ||
}); | ||
}); |
Oops, something went wrong.