-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add components required for estimates (#4690)
* Add sortable, radio and typography components * Remove stray css classes * Prevent drag of items from other draggable * Minor cleanup * Update yarn.lock * Remove radio input component as it was build on headless ui v2.0.0 and now we are using v1.7.0 * Fix build errors * Update dependencies in use memo.
- Loading branch information
1 parent
42b1a1a
commit c0bd74e
Showing
9 changed files
with
196 additions
and
4 deletions.
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
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,62 @@ | ||
import React, { useEffect, useRef, useState } from "react"; | ||
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; | ||
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; | ||
import { isEqual } from "lodash"; | ||
import { cn } from "../../helpers"; | ||
import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; | ||
import { DropIndicator } from "../drop-indicator"; | ||
|
||
type Props = { | ||
children: React.ReactNode; | ||
data: any; //@todo make this generic | ||
className?: string; | ||
}; | ||
const Draggable = ({ children, data, className }: Props) => { | ||
const ref = useRef<HTMLDivElement>(null); | ||
const [dragging, setDragging] = useState<boolean>(false); // NEW | ||
const [isDraggedOver, setIsDraggedOver] = useState(false); | ||
|
||
const [closestEdge, setClosestEdge] = useState<string | null>(null); | ||
useEffect(() => { | ||
const el = ref.current; | ||
|
||
if (el) { | ||
combine( | ||
draggable({ | ||
element: el, | ||
onDragStart: () => setDragging(true), // NEW | ||
onDrop: () => setDragging(false), // NEW | ||
getInitialData: () => data, | ||
}), | ||
dropTargetForElements({ | ||
element: el, | ||
onDragEnter: (args) => { | ||
setIsDraggedOver(true); | ||
setClosestEdge(extractClosestEdge(args.self.data)); | ||
}, | ||
onDragLeave: () => setIsDraggedOver(false), | ||
onDrop: () => { | ||
setIsDraggedOver(false); | ||
}, | ||
canDrop: ({ source }) => !isEqual(source.data, data) && source.data.__uuid__ === data.__uuid__, | ||
getData: ({ input, element }) => | ||
attachClosestEdge(data, { | ||
input, | ||
element, | ||
allowedEdges: ["top", "bottom"], | ||
}), | ||
}) | ||
); | ||
} | ||
}, [data]); | ||
|
||
return ( | ||
<div ref={ref} className={cn(dragging && "opacity-25", className)}> | ||
{<DropIndicator isVisible={isDraggedOver && closestEdge === "top"} />} | ||
{children} | ||
{<DropIndicator isVisible={isDraggedOver && closestEdge === "bottom"} />} | ||
</div> | ||
); | ||
}; | ||
|
||
export { Draggable }; |
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,2 @@ | ||
export * from "./sortable"; | ||
export * from "./draggable"; |
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,32 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import React from "react"; | ||
import { Draggable } from "./draggable"; | ||
import { Sortable } from "./sortable"; | ||
|
||
const meta: Meta<typeof Sortable> = { | ||
title: "Sortable", | ||
component: Sortable, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof Sortable>; | ||
|
||
const data = [ | ||
{ id: "1", name: "John Doe" }, | ||
{ id: "2", name: "Jane Doe 2" }, | ||
{ id: "3", name: "Alice" }, | ||
{ id: "4", name: "Bob" }, | ||
{ id: "5", name: "Charlie" }, | ||
]; | ||
export const Default: Story = { | ||
args: { | ||
data, | ||
render: (item: any) => ( | ||
// <Draggable data={item} className="rounded-lg"> | ||
<div className="border ">{item.name}</div> | ||
// </Draggable> | ||
), | ||
onChange: (data) => console.log(data.map(({ id }) => id)), | ||
keyExtractor: (item: any) => item.id, | ||
}, | ||
}; |
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,79 @@ | ||
import React, { Fragment, useEffect, useMemo } from "react"; | ||
import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; | ||
import { Draggable } from "./draggable"; | ||
|
||
type Props<T> = { | ||
data: T[]; | ||
render: (item: T, index: number) => React.ReactNode; | ||
onChange: (data: T[]) => void; | ||
keyExtractor: (item: T, index: number) => string; | ||
containerClassName?: string; | ||
id: string; | ||
}; | ||
|
||
const moveItem = <T,>( | ||
data: T[], | ||
source: T, | ||
destination: T & Record<symbol, string>, | ||
keyExtractor: (item: T, index: number) => string | ||
) => { | ||
const sourceIndex = data.indexOf(source); | ||
if (sourceIndex === -1) return data; | ||
|
||
const destinationIndex = data.findIndex((item, index) => keyExtractor(item, index) === keyExtractor(destination, 0)); | ||
|
||
if (destinationIndex === -1) return data; | ||
|
||
const symbolKey = Reflect.ownKeys(destination).find((key) => key.toString() === "Symbol(closestEdge)"); | ||
const position = symbolKey ? destination[symbolKey as symbol] : "bottom"; // Add 'as symbol' to cast symbolKey to symbol | ||
const newData = [...data]; | ||
const [movedItem] = newData.splice(sourceIndex, 1); | ||
|
||
let adjustedDestinationIndex = destinationIndex; | ||
if (position === "bottom") { | ||
adjustedDestinationIndex++; | ||
} | ||
|
||
// Prevent moving item out of bounds | ||
if (adjustedDestinationIndex > newData.length) { | ||
adjustedDestinationIndex = newData.length; | ||
} | ||
|
||
newData.splice(adjustedDestinationIndex, 0, movedItem); | ||
|
||
return newData; | ||
}; | ||
|
||
export const Sortable = <T,>({ data, render, onChange, keyExtractor, containerClassName, id }: Props<T>) => { | ||
useEffect(() => { | ||
const unsubscribe = monitorForElements({ | ||
onDrop({ source, location }) { | ||
const destination = location?.current?.dropTargets[0]; | ||
if (!destination) return; | ||
onChange(moveItem(data, source.data as T, destination.data as T & { closestEdge: string }, keyExtractor)); | ||
}, | ||
}); | ||
|
||
// Clean up the subscription on unmount | ||
return () => { | ||
if (unsubscribe) unsubscribe(); | ||
}; | ||
}, [data, keyExtractor, onChange]); | ||
|
||
const enhancedData = useMemo(() => { | ||
const uuid = id ? id : Math.random().toString(36).substring(7); | ||
return data.map((item) => ({ ...item, __uuid__: uuid })); | ||
}, [data, id]); | ||
|
||
return ( | ||
<> | ||
{enhancedData.map((item, index) => ( | ||
<Draggable key={keyExtractor(item, index)} data={item} className={containerClassName}> | ||
<Fragment>{render(item, index)} </Fragment> | ||
</Draggable> | ||
))} | ||
</> | ||
); | ||
}; | ||
|
||
export default Sortable; |
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 @@ | ||
export * from "./sub-heading"; |
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,15 @@ | ||
import React from "react"; | ||
import { cn } from "../../helpers"; | ||
|
||
type Props = { | ||
children: React.ReactNode; | ||
className?: string; | ||
noMargin?: boolean; | ||
}; | ||
const SubHeading = ({ children, className, noMargin }: Props) => ( | ||
<h3 className={cn("text-xl font-medium text-custom-text-200 block leading-7", !noMargin && "mb-2", className)}> | ||
{children} | ||
</h3> | ||
); | ||
|
||
export { SubHeading }; |
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