Comments (2)
Hey. 😁
Can you let me now which version you're using?
When the error is seen? (is it when the cursor moves after starting a drag?)
And if possible, whip up an example of your code?
Since this has only started happening since you moved to typescript then I imagine the issue could be caused by something in your build/typescript config (however there are a number of things that could have caused it).
Side note: I plan to re-write this lib in typescript, just haven't found the need/time yet. 😊
from react-reorder.
Thanks for the response!
Can you let me now which version you're using?
^3.0.0-alpha.7
When the error is seen? (is it when the cursor moves after starting a drag?)
Yes; the error is seen when the cursor moves after a drag has been started. It only occurs after the hold time has passed and the component is actually mobile.
And if possible, whip up an example of your code?
Sure, here's the relevant code (can't give access to the repo):
// src/components/LayerInfo/LayerInfo.tsx
import React from "react";
import styles from "./LayerInfo.module.sass";
import widgetStyles from "../WidgetWrapper/WidgetWrapper.module.sass";
import {ForegroundContainer} from "../../shared/components/ForegroundContainer/ForegroundContainer";
import Reorder, {reorder, reorderFromToImmutable, reorderImmutable} from "react-reorder";
import {WidgetWrapper} from "../WidgetWrapper/WidgetWrapper";
import {IssueProgressWidget} from "../../widgets/IssueProgressWidget/IssueProgressWidget";
import {EmptyWidget} from "../../widgets/EmptyWidget/EmptyWidget";
// import "./dragged.css";
interface Props {
reorder_group_id: string
}
// TODO: This is duplicated
interface ListItem {
index: number
widget_type: string
}
interface State {
list: Array<ListItem>
[name: string]: any
}
// TODO: See https://github.com/JakeSidSmith/react-reorder/issues/101#issuecomment-847201025
class LayerInfo extends React.Component<Props, State> {
state: Readonly<State> = {
list: []
}
constructor(props: Props) {
super(props);
this.onReorder = this.onReorder.bind(this);
// Example TODO: Database
let list: Array<ListItem> = [
{
index: 0,
widget_type: "IssueProgressWidget",
},
{
index: 1,
widget_type: "EmptyWidget",
},
];
this.state = {
list: list
}
}
renderWidget(item: ListItem) {
// TODO: Use database
switch (item.widget_type) {
case "EmptyWidget":
return (
<EmptyWidget/>
);
case "IssueProgressWidget":
return (
<IssueProgressWidget/>
);
default:
// TODO: Error
return (
<div>Hello :)</div>
);
}
}
render() {
return (
<div className={styles.FlexContainer}>
<ForegroundContainer
title={"Widgets"}
margin_bottom={true}
margin_top={true}
flex={true}
widgets={true}
padding={8}
scroll={true}
>
<Reorder
reorderId={this.props.reorder_group_id} // Unique ID that is used internally to track this list (required)
reorderGroup="widgets" // A group ID that allows items to be dragged between lists of the same group (optional)
// getRef={this.storeRef.bind(this)} // Function that is passed a reference to the root node when mounted (optional)
component="div" // Tag name or Component to be used for the wrapping element (optional), defaults to 'div'
placeholderClassName={widgetStyles.Placeholder}
// draggedClassName={"dragged"}
draggedClassName={widgetStyles.Dragged}
// lock="horizontal" // Lock the dragging direction (optional): vertical, horizontal (do not use with groups)
touchHoldTime={500} // Hold time before dragging begins on touch devices (optional), defaults to holdTime
mouseHoldTime={500} // Hold time before dragging begins with mouse (optional), defaults to holdTime
onReorder={this.onReorder.bind(this)} // Callback when an item is dropped (you will need this to update your state)
autoScroll={false} // Enable auto-scrolling when the pointer is close to the edge of the Reorder component (optional), defaults to true
disabled={false} // Disable reordering (optional), defaults to false
disableContextMenus={true} // Disable context menus when holding on touch devices (optional), defaults to true
>
{
this.state.list.map((item: ListItem) => (
<div key={item.index}>
<WidgetWrapper>
{this.renderWidget(item)}
</WidgetWrapper>
</div>
))
}
</Reorder>
</ForegroundContainer>
</div>
)
}
onReorder (event: any, previousIndex: number, nextIndex: number, _fromId: string, _toId: string) {
this.setState({
list: reorder(this.state.list, previousIndex, nextIndex)
});
// TODO: Save
}
onReorderGroup (event: any, previousIndex: number, nextIndex: number, fromId: string, toId: string) {
if (fromId === toId) {
const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex);
this.setState({
[fromId]: list
});
} else {
const lists = reorderFromToImmutable({
from: this.state[fromId],
to: this.state[toId]
}, previousIndex, nextIndex);
this.setState({
[fromId]: lists.from,
[toId]: lists.to
});
}
}
}
export {LayerInfo}
My tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"baseUrl": "./",
"noImplicitAny": false // TODO: Remove
},
"include": [
"src"
],
"typesRoot": [
"node_modules/@types",
"src/@custom_types/react-reorder"
],
"exclude": [
"node_modules",
"src/@custom_types"
]
}
src/components/WidgetWrapper/WidgetWrapper.tsx:
import React, {useCallback, useEffect} from "react";
import styles from "./WidgetWrapper.module.sass";
const WidgetWrapper = (props: any) => {
// Whether or not to mirror react-reorder's behavior of resetting the hold time when the mouse moves
const useReoderRules = true;
// States
const [isMouseDown, setIsMouseDown] = React.useState(false);
const [isHovering, setIsHovering] = React.useState(false);
const [mouseLeftDuringPress, setMouseLeftDuringPress] = React.useState(false);
const [waitingForDone, setWaitingForDone] = React.useState(false);
// Event handlers
const onMouseDown = () => {
setIsMouseDown(true); // Fact
}
const onMouseUp = () => {
setIsMouseDown(false); // Fact
}
// NOTE: onMouseEnter does not bubble and would be unreliable for widgets with child elements.
const onMouseMove = useCallback(() => {
if (isHovering) {
if (isMouseDown && useReoderRules) {
// react-reorder resets the hold time when the mouse is moved during a drag. Use the else clause if this is
// ever fixed (I suppose it's a matter of personal preference).
setMouseLeftDuringPress(true);
setIsMouseDown(false);
} else if (mouseLeftDuringPress) {
// Require continuous press; pretend like the button was released.
setMouseLeftDuringPress(false);
setIsMouseDown(false);
}
} else {
setIsHovering(true);
}
}, [isHovering, isMouseDown, mouseLeftDuringPress, useReoderRules])
const onMouseLeave = () => {
setIsHovering(false);
setMouseLeftDuringPress(isMouseDown);
}
const onMouseEnter = () => {
setIsHovering(true);
}
// Misc
const reset = () => {
// NOTE: Do not set isHovering = false (the state of isHovering is always semantically true and accurate)
setIsMouseDown(false);
setMouseLeftDuringPress(false);
setWaitingForDone(false);
setWaitingForDone(false);
}
// Logic
let pressedIndicatorClsNames = [styles.PressedIndicator];
let pressing = false;
if (mouseLeftDuringPress) {
pressedIndicatorClsNames.push(styles.PressedUnknown);
} else if (isMouseDown && isHovering) {
pressing = true;
pressedIndicatorClsNames.push(styles.Pressed);
}
let wrapperClsNames = [styles.WidgetWrapper]
if (isHovering) { wrapperClsNames.push(styles.Hovering); }
useEffect(() => {
if (pressing && !waitingForDone) {
setTimeout(() => {
onMouseMove();
reset();
}, 500);
setWaitingForDone(true);
}
}, [pressing, waitingForDone, onMouseMove])
return (
<div
className={wrapperClsNames.join(" ")}
onMouseDown={_e => onMouseDown()}
onMouseUp={_e => onMouseUp()}
onMouseLeave={_e => onMouseLeave()}
onMouseEnter={_e => onMouseEnter()}
onMouseMove={_e => onMouseMove()}
>
{props.children}
<div className={pressedIndicatorClsNames.join(" ")}/>
</div>
)
}
export {WidgetWrapper}
WidgetWrapper.module.sass:
.WidgetWrapper
width: 100%
background-color: white
min-height: 50px
user-select: none
box-sizing: border-box
position: relative
border-radius: 5px
border: 1px solid gray
z-index: 1
margin-bottom: 10px
.PressedIndicator
width: 0
height: 8px
bottom: -4px
left: -1px
right: 1px
z-index: -1
background-color: #1a85ff
content: ''
transition: width
border-bottom-left-radius: 5px // TODO: Display below parent element somehow
position: absolute
.Hovering // TODO: Try to remove
z-index: 2
.Placeholder
@extend .WidgetWrapper
background-color: transparent
box-shadow: 0 0 5px rgba(26, 133, 255, 0.7)
opacity: 0.2
// For when we know for sure that the component is being pressed (building up to drag).
// Applies to the "pressed indicator."
.Pressed
width: 100%
transition-delay: 150ms
transition-duration: 250ms
// For when we don't know if the component is being dragged because the mouse left the component.
// Applies to the "pressed indicator."
.PressedUnknown
width: 0
z-index: 2
transition-duration: 0ms
.Dragged > .WidgetWrapper
border: 1px solid #1a85ff
z-index: 2
I'm new to Typescript, so you're probably right about the issue being something I'm doing wrong. It's unlike any other typed language I've used.
(Almost) everything should be up to date, as I (recently) created the app using the latest version of create-react-app with the typescript template and node.js, only adding latest (or latest stable) versions of packages.
Side note: I plan to re-write this lib in typescript, just haven't found the need/time yet. 😊
Totally understand. Even just adding type declarations for now would help, ie.:
(Note that my type declarations are not great and that they only work for my project specifically, but they allow me to use react-reorder without disabling all type checking globally.)
// index.d.ts
declare module "react-reorder" {
// TODO: This is duplicated
export interface ListItem {
index: number
widget_type: string
}
export function reorder(list: Array<ListItem>, prevIndex: number, nextIndex: number): Array<ListItem>;
export function reorderImmutable(item: ListItem, prevIndex: number, nextIndex: number): Array<ListItem>;
export function reorderFromToImmutable(from_to: Object, prevIndex: number, nextIndex: number): { from: string, to: string };
// @ts-ignore TODO: Fix
import React from 'react';
export interface ReorderComponentProps {
reorderId: string // Unique ID that is used internally to track this list (required)
reorderGroup?: string // A group ID that allows items to be dragged between lists of the same group (optional)
getRef?: Function // Function that is passed a reference to the root node when mounted (optional)
component?: string // Tag name or Component to be used for the wrapping element (optional), defaults to 'div'
placeholderClassName: string // The class name to use for styling the placeholder
draggedClassName: string // The class name to use for styling dragged components
lock?: boolean // Lock the dragging direction (optional): vertical, horizontal (do not use with groups)
touchHoldTime?: number // Hold time before dragging begins on touch devices (optional), defaults to holdTime
mouseHoldTime?: number // Hold time before dragging begins with mouse (optional), defaults to holdTime
onReorder: Function // Callback when an item is dropped (you will need this to update your state)
autoScroll?: boolean // Enable auto-scrolling when the pointer is close to the edge of the Reorder component (optional), defaults to true
disabled?: boolean // Disable reordering (optional), defaults to false
disableContextMenus?: boolean // Disable context menus when holding on touch devices (optional), defaults to true
children?: any
}
const Reorder: (props: ReorderComponentProps) => React.ReactElement<ReorderComponentProps>;
export default Reorder;
}
from react-reorder.
Related Issues (20)
- Unable to make 3.0.0-alpha.7 work with react 16.9 HOT 5
- Less performant deeper in the dom? HOT 1
- Please add events on "drag start" and "drag end" HOT 3
- Can't disable auto scroll HOT 7
- Another complete re-write in TypeScript, with hooks, React 16-17 support, and more HOT 4
- can't reorder
- Update PropTypes HOT 1
- Warning: This synthetic event is reused for performance reasons. HOT 3
- placeholder class is not added when dragging input fields HOT 3
- Overriding sorting behavior HOT 10
- V3 Alpha Issues HOT 47
- Warning with react 15.5.0 HOT 12
- can't control dragged div HOT 17
- Images Reloading/Flashing HOT 9
- Error: Expected reorderId to be a string. Instead got undefined HOT 12
- Tidy up prop documentation in readme (v3) HOT 2
- Support React v16 HOT 11
- Issues with embedded images? HOT 6
- Unable to set reorder to a button HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-reorder.