Giter VIP home page Giter VIP logo

react-reorder's Introduction

React Reorder (v2)

Drag & drop, touch enabled, reorder / sortable list, React component

If you are using v3 alpha, please refer to this documentation.

About

React Reorder is a React component that allows the user to drag-and-drop items in a list (horizontal / vertical) or a grid.

It fully supports touch devices and auto-scrolls when a component is being dragged (check out the demo, link below).

It also allows the user to set a hold time (duration before drag begins) allowing additional events like clicking / tapping to be applied.

Although this project is very new, it has been thoroughly tested in all modern browsers (see supported browsers).

Demo

Installation

  • Using npm

    npm install react-reorder

    Add --save or -S to update your package.json

  • Using bower

    bower install react-reorder

    Add --save or -S to update your bower.json

Example

  1. If using requirejs: add react-reorder to your require.config

    paths:
      // <name> : <path/to/module>
      'react-reorder': 'react-reorder/reorder'
    }
  2. If using a module loader (requirejs / browserfiy / commonjs): require react-reorder where it will be used in your project

    var Reorder = require('react-reorder');

    If using requirejs you'll probably want to wrap your module e.g.

    define(function (require) {
      // Require react-reorder here
    });
  3. Configuration

    Note: If your array is an array of primitives (e.g. strings) then itemKey is not required as the string itself will be used as the key, however item keys must be unique in any case

    1. Using JSX

      <Reorder
        // The key of each object in your list to use as the element key
        itemKey='name'
        // Lock horizontal to have a vertical list
        lock='horizontal'
        // The milliseconds to hold an item for before dragging begins
        holdTime='500'
        // The list to display
        list={[
          {name: 'Item 1'},
          {name: 'Item 2'},
          {name: 'Item 3'}
        ]}
        // A template to display for each list item
        template={ListItem}
        // Function that is called once a reorder has been performed
        callback={this.callback}
        // Class to be applied to the outer list element
        listClass='my-list'
        // Class to be applied to each list item's wrapper element
        itemClass='list-item'
        // A function to be called if a list item is clicked (before hold time is up)
        itemClicked={this.itemClicked}
        // The item to be selected (adds 'selected' class)
        selected={this.state.selected}
        // The key to compare from the selected item object with each item object
        selectedKey='uuid'
        // Allows reordering to be disabled
        disableReorder={false}
      />
    2. Using standard Javascript

      React.createElement(Reorder, {
        // The key of each object in your list to use as the element key
        itemKey: 'name',
        // Lock horizontal to have a vertical list
        lock: 'horizontal',
        // The milliseconds to hold an item for before dragging begins
        holdTime: '500',
        // The list to display
        list: [
          {name: 'Item 1'},
          {name: 'Item 2'},
          {name: 'Item 3'}
        ],
        // A template to display for each list item
        template: ListItem,
        // Function that is called once a reorder has been performed
        callback: this.callback,
        // Class to be applied to the outer list element
        listClass: 'my-list',
        // Class to be applied to each list item's wrapper element
        itemClass: 'list-item',
        // A function to be called if a list item is clicked (before hold time is up)
        itemClicked: this.itemClicked,
        // The item to be selected (adds 'selected' class)
        selected: this.state.selected,
        // The key to compare from the selected item object with each item object
        selectedKey: 'uuid',
        // Allows reordering to be disabled
        disableReorder: false
      })
  4. Callback functions

    1. The callback function that is called once a reorder has been performed

      function callback(event, itemThatHasBeenMoved, itemsPreviousIndex, itemsNewIndex, reorderedArray) {
        // ...
      }
    2. The itemClicked function that is called when an item is clicked before any dragging begins

      function itemClicked(event, itemThatHasBeenClicked, itemsIndex) {
        // ...
      }

      Note: event will be the synthetic React event for either mouseup or touchend, and both contain clientX & clientY values (for ease of use)

Compatibility / Requirements

  • Version 2.x tested and working with React 0.14

  • Versions 1.x tested and working with React 0.12 - 0.13

  • requirejs / commonjs / browserify (Optional, but recommended*)

* Has only been tested with requirejs & browserify

Supported Browsers

Desktop

  • Internet Explorer 9+ (may support IE8**)

  • Google Chrome (tested in version 39.0.2171.95(64-bit))

  • Mozilla Firefox (tested in version 33.0)

  • Opera (tested in version 26.0.1656.60)

  • Safari (tested in version 7.1.2 (9537.85.11.5))

** Have not had a chance to test in IE8, but IE8 is supported by React

Mobile

  • Chrome (tested in version 40.0.2214.89)

  • Safari (tested on iOS 8)

Untested Browsers

  • Internet Explorer 8*** (the lowest version that React supports)

*** If anyone could confirm that this works in IE8, that'd be awesome

react-reorder's People

Contributors

hribb avatar jakesidsmith avatar zazzlealex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

react-reorder's Issues

TypeError: this.state.draggedStyle is null

UPDATE 3
Unfortunately, I was unable to find the root cause. If you see an issue with my code, please let me know. I will try to find the time to make a minimal, reproducible example. The fact that draggedStyle is set correctly every second mouse event leads me to believe that this is a bug in react-reorder. The only workaround I found involved forking react-reorder, I opted to use react-dnd instead, which is a lot more complicated, but it works.

UPDATE 2
I couldn't tell you the root problem. I'm also having a different issue causing me to be unable to debug the application (connection refused), so I'm relying on console.log. Logging every time draggedStyle is written to with something vs. null, I would not expect it to be null when this error occurs, but it is. Every second time. However, this seems to fix the issue:

if (this.state.draggedStyle === null) {
  console.log("Skipping because draggedStyle is null.");
  return;
}

this.state.draggedStyle.transform = createOffsetStyles(event, this.props);
store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, this.state.draggedStyle);

This seems to have no side-effects, and reordering, drag and drop are perfectly smooth.

My only issue now is one that I also had before this: If I drag an item from "left-side" to "right-side" or vice versa, the component disappears from the source list and its "ghost" (my translucent clone placeholder) appears in the destination list (as expected) while still dragging. When I release it, it goes back to its source list, in the same position. Note that both lists have the same components.

UPDATE 1
Second time writing this update for some reason. Props are set correctly, and the stylesheet is also loaded. The names match up, and the bug has nothing to do with draggedClassName. I noticed something weird when inspecting state where the error occurs: It's only sometimes undefined. I narrowed it down to not being set on children in render:

// index.js
var isDragged = this.isDragging() && this.isDraggingFrom() && index === this.state.draggedIndex;
var draggedStyle = isDragged ? assign({}, child.props.style, this.state.draggedStyle) : child.props.style;

In the above code, draggedStyle will be undefined if child.props.style is undefined and isDragged is false. The child would be my WidgetWrapper, which in the default state has no style. I thought the fix would be:

          var childStyle = child.props.style ?? {};  // <-- here
          var draggedStyle = isDragged ? assign({}, childStyle, this.state.draggedStyle) : childStyle;

But this still isn't working. The expectation that style.transform is defined also needs to be dealt with. Still investigating.

ORIGINAL BODY
Edit: Irrelevant info removed
I'm using react-reorder with Typescript and self-declared types (please add types!). Before migrating to Typescript, it was working fine. Now, when I drag a component, I get this output in the console:

Uncaught TypeError: this.state.draggedStyle is null
    onWindowMove index.js:647
    componentDidMount index.js:688
    chainedFunction factory.js:741
    React 6
    unstable_runWithPriority scheduler.development.js:468
    React 9
    tsx index.tsx:7
    tsx main.chunk.js:2609
    Webpack 7
        __webpack_require__
        fn
        1
        __webpack_require__
        checkDeferredModules
        webpackJsonpCallback
        <anonymous>

I'm using a Reorder component with draggedClassName={widgetStyles.Dragged}, where widgetStyles is a sass stylesheet imported as widgetStyles. widgetStyles.Dragged resolves to something like WidgetWrapper_Dragged__3VyWh, but even using a regular css stylesheet with just .dragged { styles go here } and using "dragged" as draggedClassName results in the same error.

The console prints the error on every mouse event (edit: turns out to be every second mouse event) and it's very laggy. Traceback excerpt:

  644 | 
  645 | }
  646 | 
> 647 | this.state.draggedStyle.transform = createOffsetStyles(event, this.props);
      | ^  648 | store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, this.state.draggedStyle);
  649 | 
  650 | mouseOffset = {

Freezes window scroll on touch

I am unable to window scroll when dragging on the list on a touch screen. The window scroll event is swallowed and all I can do is reorder. If I move the list to a div that scrolls, it works fine.

Input elements lose their value while being dragged

If the template element has an input element when it is dragged the value is lost and brought back again when the drag is released. As far as I can tell this is due to how the reorder component renders a new "template" element for each drag.

Error: Expected reorderId to be a string. Instead got undefined

I'm running into this issue and didn't find any information about it in the documentation.

I tried a lot of different configurations with the same result. When I add reorderId='_id' to my list of props, I lose the warning and a div is created, but nothing is inside.

Reorder is added to my component this way: import Reorder from 'react-reorder'

And in the render:

<Reorder 
    itemKey='_id'
    lock='horizontal'
    holdTime={0}
    list={this.props.user.mylist}
    template={Listing}
    listClass='my-list'
    itemClass='list-item'
    callback={this.callback}
    listClass='my-list'
    itemClass='list-item'
    itemClicked={this.itemClicked}
    selected={this.state.selected}
    selectedKey='_id'
    disableReorder={false}
/>

Please add events on "drag start" and "drag end"

Hi,

could you please add the following events, so we can for instance set class names for a parent component to "parentelement-children-dragging" and "parentelement-children-normal".

That way we can set all other child elements semi-transparent, and draggable element full opacity.

Support React v16

Now with React v16
it will throw exception createClass not a function.

Less performant deeper in the dom?

Great component. Is there any reason why this would perform worse at higher dom depths?

Debugging some performance issues and removing divs so far has been the only solution (and performance issues roughly scale with how deep it is). Looking at dev tools performance tab, looks like all the time is spent in script and not rendering.

I'm returning another in the same component at a shallower depth and it's silky smooth (and removing this one doesn't affect the performance of the other).

My reorder:

<Reorder placeholder={<div className="placeholder"/>} lock="vertical" reorderId={`reorder-small`} onReorder={(ev, prevIdx, nextIdx) => onReorderPhotos(prevIdx, nextIdx)}>
	{
		photoUrls.map((url, idx) => (
			<div style={{ backgroundImage:`url(${url})` }} className={'reorder-item'} key={idx} >

			</div>
		))
	}
</Reorder>

Sorry for limited info. I'm on 3.0.0-alpha.7. Thanks!

IE8 support

Tested IE8 with Windows XP and Windows Vista. Both gave the same error:

screen shot 2015-04-01 at 15 16 57

Looks like React issue, but you asked to confirm whether it works on IE8, so I fire this issue here =)

Use iterator for `itemKey`

I'm working on a list of todos that are stored in localStorage as an array of objects. Instead of having to try to create a unique itemKey property on each of the todo objects, I'd like to leverage the iterator of my Reorder list. Is this possible?

Individual hold times

Add configuration for desktop & mobile hold times individually.

holdTimeTouch and holdTimeMouse

holdTime sets both.

Can't disable auto scroll

Hello, I want to disable auto scroll but it doesn't seem to be working. I wanted to implement by own auto scrolling because I find the default to be way too fast, and because it didn't seem to work when scrolling down. I am on version 3.0.0-alpha.7.

Code:

const reorder = (event: React.MouseEvent, from: number, to: number) => {
        setContainers((prev) => {
            const newState = [...prev]
            newState.splice(to, 0, newState.splice(from, 1)[0])
            return newState
        })
}

return (
        <Reorder reorderId="file-containers" component="ul" autoScroll={false} holdTime={50} onReorder={reorder}>{
            containers.map((c) => (
                <li key={c.id}>
                    {c.jsx}
                </li>
            ))
        }</Reorder>
)

Unable to make 3.0.0-alpha.7 work with react 16.9

I have the following code:

const MyComponent = props =>
  <div>
    <Reorder
      reorderId="research"
      className={"reorder"}
      lock="horizontal"
      holdTime={500}
      onReorder={() => {console.log("reorder")}}
      autoScroll={true}
      disabled={false}
      disableContextMenus={true}>
        {["1","2","3","4"].map(v => <Cell key={v} name={v} />)}
    </Reorder>
  </div>

const Cell = props =>
  <div style={{
    backgroundColor: "lightpink", 
    border: "1px solid green", 
    padding: 20, 
    userSelect: "none"}}>{props.name}</div>

It doesn't seem to work and I feel stupid for asking but am I missing something?

Very slow in development with redux DevTools and HMR

First of all, thanks for this nice lib ;) Haven't tested it much yet, but so far I really like react-reorder. However, drag-drop is horrrribly slow in development. I use redux with DevTools with React Hot Loader and it's practically unusable. Could be related to #56, because I believe that calling this.setState() triggers a re-render of component. It works OK in production.

@JakeSidSmith let me know how I can help

Drag between multiple lists

Do you have any insights (or pointers to things to change within the library) into how I'd be able to achieve dragging an item from one reorderable list into another reorderable list?

Images Reloading/Flashing

Hi!

I am using React-Reorder with <img/> and whenever I reorder items, there's a flash as the images would have reloaded each time they are reordered.

Is there a way to prevent this from happening?

Warning: This synthetic event is reused for performance reasons.

Hey

I'm seeing this warning on "mobile", via chrome developer tools.

Warning: This synthetic event is reused for performance reasons.
If you're seeing this, you're adding a new property in the synthetic event object.
The property is never released.

See https://fb.me/react-event-pooling for more information.

In handleTouchEvents you're adding clientX and clientY to the event object, which I guess is bad in React.

itemDown: function (item, index, event) {
  this.handleTouchEvents(event);
  ...
}

handleTouchEvents: function (event) {
  if (event.touches && event.touches.length) {
    event.clientX = event.touches[0].clientX;
    event.clientY = event.touches[0].clientY;
  }
},

Maybe you can include that in the rewrite? Otherwise I can take a look and make a PR.

React should not be a dependency

This is working great with react 0.14.6 (apart from some warnings!), but only if I manually delete node_modules/react-reorder/node_modules/react. Otherwise, it throws horrible errors about "something is calling a react component directly", because react-reorder has it's own react 0.12 dependency (at least on the npm version. On github this is react < 0.14, which would still have the same problem).

Please could the react dependency either be removed, changed to a peerDependency (strongly recommended), and/or made much much more lenient (like react >= 0.12 or react *). At the moment it's better to risk getting an incompatible react version than to end up with multiple copies of react in the tree.

Thanks.

Publish to npm

Can you publish this to npm? It is hard to include otherwise. :)

Unable to set reorder to a button

Im trying to reorder the elements by using a specific button in the child Component. Im not sure how to do this? Sorry for posting this as an issue. Could somebody help me out as to how to do this?/ Thanks in advance.

Rethink

Refactor:

  • No mutation (as in #63)
  • Remove setState where component updates are not required
  • Support immutablejs
  • No new list in callback? Provide only previous and next indices?
  • Allow defining listComponent and itemComponent (default to ul and li)
  • Allow defining listProps and itemProps which will be applied to these components
  • Allow itemKey to be a function (for getting keys from immutable objects)
  • Clone item components for rendering, or use functional components?
  • Multi-select components to reorder
/* Work in progress */

const Item = (props) => (
  <div {...props}>

  </div>
);

class App extends Component {
  render() {
    return (
      <Reorder
        listComponent="div"
        itemComponent={Item}

      />
    );
  }
}

Warning with react 15.5.0

Warning: Reorder: React.createClass is deprecated and will be removed in version 16. Use plain JavaScript classes instead. If you're not yet ready to migrate, create-react-class is available on npm as a drop-in replacement.

V3 Alpha Issues

If you've been testing out the V3 alpha, please post your issues here.

It'd also be good to know if V3 has fixed any existing issues you've had.

Reported issues

  • Remove engines from package.json (stupid yarn)
  • Unknown reorderId error when unmounting a group
  • Dragging to a space between items in another group should still place the item in this group
  • Auto-scroll toGroup when dragging to another group (not fromGroup)
  • Do not drag to new group if outside visible area (check root node collision)
  • Serious performance issues with 30+ reorder components
  • Inputs do not retain DOM state when dragging between lists
  • Gatsby window is not defined (move listeners to componentDidMount)
  • Avoid use of deprecated methods

Requested features

  • Option to start reorder only after movement
  • Handle / draggable area

Issues with embedded images?

Hi, we've been using this component for quite some time, but I just noticed some odd behavior in production.

We render a map of an array of "cards", each one is basically an image with a header and a footer.

<Card>
  <Header />
  <img />
  <Footer />
</Card>

The card behaves as expected (and as it has in the past) when dragged from the header or footer, but no longer reorders when dragged from the img (the body of the card). It appears that Reorder is competing with the standard web drag of an image. The card will never find a new home and it is still in active reorder mode when releasing the click. At first, the image moves separately from the card and then the card jumps around.

The reordering still works as expected on mobile - you can touch the image and drag the card.

Has there been anything that has changed recently that would stop the previous functionality? I don't think anything in our production code has changed.

Thanks!

Change disableReorder

Change disableReorder to disabled.

Add warning message of deprecation.

Could this mess up stuff if people are already using disabled?

Cannot sort via touch due to page scroll

The demos work well on mobile devices, but if you remove the fixed height on the container it becomes impossible to reorder. As you drag an item, the entire page scrolls in the opposite direction and the element stays in the same position.

One way to fix this is to set window.ontouchmove = (e) => e.preventDefault() while an item is being dragged.

Overriding sorting behavior

Hi @JakeSidSmith, sorry, I forgot to create an issue to continue our discussion in #71 but here it is now :)

To recap, in my use case, if a user drops an item in between others, it sorts the list but if the item is dropped on top of another, I can perform a different operation. So, to do this, I would need to know if an item is dropped on top of another ( or within certain boundaries of the new item and then not calculate new position in this case), or above or below the other (calculate new position in this case).

So, as I see it, the cleanest way, in terms of API might look something like this -

  1. A prop, lets say sortZoneLimitPercent passed to Reorder that indicates what % area of the item to limit the dropzone to. So, by default, today that is 100%. If it is passed as 60, that means the top and bottom 20% of the item would not be considered as 'sortZone`.

  2. An additional prop added to onReorder and onReorderGroup callback that indicates whether the item was dropped within the boundaries of an item, or outside, i.e. if sortZone is true or not.

Thoughts?

Update PropTypes

Is this library still maintained?

You want to upgrade PropTypes in the dependencies list. At least make non-strict version (e.g. ^15.6.0)
15.6.0 have known vulnerabilities (prop-types - fb.js - ... - node-fetch) and automatic scanning tools like WhiteSource are failing.

Using 3.0.0.alpha7

Store state in component (not state)

Lots of the state is stored in state, when it need not be. Basically the only thing that really needs to be stored is the currently dragged item & it's position.

var root = this || window; causes compile error

This is causing a window is not defined error on line 459. I am using it in a universal web app. I removed the reference to window, and all seems to be fine. Has anyone else ran into this issue?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.