Skip to content

You should focus the features of your app, not DnD boilerplate.

License

Notifications You must be signed in to change notification settings

ThaddeusJiang/react-sortable-list

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Welcome to @thaddeusjiang/react-sortable-list πŸ‘‹

You should focus the features of your app, not DnD boilerplate.

Version Documentation Maintenance License: MIT Twitter: ThaddeusJiang

Features

  • Easy Drag & Drop sort items
  • Both Render Props and Children
  • Custom Drag Handler
  • Horizontal Sortable List

🏠 Homepage

Install

npm install @thaddeusjiang/react-sortable-list

Usage

Usage

if you don't use Tailwind CSS

import { SortableList } from '@thaddeusjiang/react-sortable-list';
import '@thaddeusjiang/react-sortable-list/dist/index.css';

<SortableList ... />

if you use Tailwind CSS

import { SortableList } from '@thaddeusjiang/react-sortable-list';

<SortableList ...>

modify tailwind.config.js

// tailwind.config.js
+ const path = require("path");

module.exports = {
  content: [
    "./src/**/*{js,ts,jsx,tsx}",
+    path.join(
+      require.resolve("@thaddeusjiang/react-sortable-list"),
+      "../**/*.{js,ts,jsx,tsx}"
+    ),
  ],
  theme: {},
  plugins: [],
};

Use Case: ItemRender

export const ItemRenderExample: React.VFC = () => {
  const [items, setItems] = useState<SortableItemProps[]>([
    { id: '1', name: 'Item 1' },
    { id: '2', name: 'Item 2' },
    { id: '3', name: 'Item 3' },
  ]);
  return (
    <SortableList
      items={items}
      setItems={setItems}
      itemRender={({ item }: ItemRenderProps) => (
        <div className="w-1/2 h-10 m-8 bg-blue-400 text-center">
          {item.name}
        </div>
      )}
    />
  );
};

Use Case: Children

export const ChildrenExample: React.VFC = () => {
  const [items, setItems] = useState<SortableItemProps[]>([
    { id: '1', name: 'Item 1' },
    { id: '2', name: 'Item 2' },
  ]);

  return (
    <SortableList items={items} setItems={setItems}>
      {({ items }: { items: SortableItemProps[] }) => (
        <>
          {items.map((item: SortableItemProps) => (
            <SortableItem key={item.id} id={item.id}>
              {item.name}
            </SortableItem>
          ))}
        </>
      )}
    </SortableList>
  );
};

Use Case: Custom Drag Handler

const DragHandler = (props) => (
  <div
    {...props}
    className=" flex justify-center items-center h-8 w-8 rounded border m-4 transition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 hover:bg-blue-500 hover:text-white duration-300"
  >
    <div className="" title="drag handler">
      <svg
        xmlns="http://www.w3.org/2000/svg"
        fill="none"
        viewBox="0 0 24 24"
        strokeWidth={1.5}
        stroke="currentColor"
        className="w-6 h-6"
      >
        <path
          strokeLinecap="round"
          strokeLinejoin="round"
          d="M3 7.5L7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5"
        />
      </svg>
    </div>
  </div>
);

export const DragHandlerExample: React.VFC = () => {
  const [items, setItems] = useState<SortableItemProps[]>([
    { id: '1', name: 'Item 1' },
    { id: '2', name: 'Item 2' },
    { id: '3', name: 'Item 3' },
  ]);

  return (
    <SortableList items={items} setItems={setItems}>
      {({ items }: { items: SortableItemProps[] }) => (
        <div className="space-y-4">
          {items.map((item: SortableItemProps) => (
            <SortableItem
              key={item.id}
              id={item.id}
              DragHandler={DragHandler}
              className="flex border items-center w-40"
            >
              <div>{item.name}</div>
            </SortableItem>
          ))}
        </div>
      )}
    </SortableList>
  );
};

Use Case: Complex Component

Custom Event would work as well in SortableItem Component with DragHandler.

export const ComplexComponentExample: React.VFC = () => {
  const [items, setItems] = useState<SortableItemProps[]>([
    { id: '1', name: 'Item 1' },
    { id: '2', name: 'Item 2' },
    { id: '3', name: 'Item 3' },
  ]);

  return (
    <SortableList items={items} setItems={setItems}>
      {({ items }: { items: SortableItemProps[] }) => (
        <div className="space-y-4">
          {items.map((item: SortableItemProps) => (
+           <SortableItem
              key={item.id}
              id={item.id}
              className="..."
+             DragHandler={DragHandler}
            >
              <input
                type="text"
                className="..."
                id={item.id}
                value={item.name}
+               onChange={(event) => {
+                 const newItems = [...items];
+                 const index = newItems.findIndex(
+                   (item) => item.id === event.target.id
+                 );
+                 newItems[index].name = event.target.value;
+                 setItems(newItems);
+               }}
              />
              <button
                className="..."
+               onClick={() => {
+                 alert('delete');
+               }}
              >
                {/* delete icon */}
              </button>
            </SortableItem>
          ))}
        </div>
      )}
    </SortableList>
  );
};

Use Case: Horizontal Sortable List

export const HorizontalExample: React.VFC = () => {
  const [items, setItems] = useState<SortableItemProps[]>([
    { id: '1', name: 'Item 1' },
    { id: '2', name: 'Item 2' },
    { id: '3', name: 'Item 3' },
  ]);
  return (
    <div className="flex space-x-4">
      <SortableList
        items={items}
        setItems={setItems}
        itemRender={({ item }: ItemRenderProps) => <Item name={item.name} />}
        horizontal
      />
    </div>
  );
};

Optional: disabled Drag and Drop

export const ItemRenderExample: React.VFC = () => {
  const [items, setItems] = useState<SortableItemProps[]>([
    { id: '1', name: 'Item 1' },
    { id: '2', name: 'Item 2' },
    { id: '3', name: 'Item 3' },
  ]);
  return (
    <SortableList
+     disabled
      items={items}
      setItems={setItems}
      itemRender={({ item }: ItemRenderProps) => (
        <div className="w-1/2 h-10 m-8 bg-blue-400 text-center">
          {item.name}
        </div>
      )}
    />
  );
};

Development

Storybook

Run inside another terminal:

npm run storybook

Example

Then run the example inside another:

npm run link

cd example
npm run link "@thaddeusjiang/react-sortable-list"
npm install
npm run start

Run tests

npm run run test

Author

πŸ‘€ Thaddeus Jiang

🀝 Contributing

Contributions, issues and feature requests are welcome!
Feel free to check issues page. You can also take a look at the contributing guide.

Show your support

Give a ⭐️ if this project helped you!

πŸ“ License

Copyright Β© 2022 Thaddeus Jiang.
This project is MIT licensed.


This README was generated with ❀️ by readme-md-generator

About

You should focus the features of your app, not DnD boilerplate.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published