React
DragSelect works well with any library out of the box. But for your convenience we created this example page to see how we use it in the "react way"!
PS: We are looking into creating custom wrappers for libraries. We will update this guide as soon as available.
1. Create a context
Feel free to copy+paste the code:
- TypeScript
- JavaScript
import React, { createContext, useState, useEffect, useContext } from "react";
import DragSelect, { DSInputElement } from "dragselect";
type ProviderProps = {
children: React.ReactNode;
settings?: ConstructorParameters<typeof DragSelect<DSInputElement>>[0];
};
const Context = createContext<DragSelect<DSInputElement> | undefined>(
undefined
);
function DragSelectProvider({ children, settings = {} }: ProviderProps) {
const [ds, setDS] = useState<DragSelect<DSInputElement>>();
useEffect(() => {
setDS((prevState) => {
if (prevState) return prevState;
return new DragSelect({});
});
return () => {
if (ds) {
ds.stop();
setDS(undefined);
}
};
}, [ds]);
useEffect(() => {
ds?.setSettings(settings);
}, [ds, settings]);
return <Context.Provider value={ds}>{children}</Context.Provider>;
}
function useDragSelect() {
return useContext(Context);
}
export { DragSelectProvider, useDragSelect };
import React, { createContext, useState, useEffect, useContext } from "react";
import DragSelect from "dragselect";
const Context = createContext(undefined);
function DragSelectProvider({ children, settings = {} }) {
const [ds, setDS] = useState();
useEffect(() => {
setDS((prevState) => {
if (prevState) return prevState;
return new DragSelect({});
});
return () => {
if (ds) {
ds.stop();
setDS(undefined);
}
};
}, [ds]);
useEffect(() => {
ds?.setSettings(settings);
}, [ds, settings]);
return <Context.Provider value={ds}>{children}</Context.Provider>;
}
function useDragSelect() {
return useContext(Context);
}
export { DragSelectProvider, useDragSelect };
2. Wrap it
import React from "react";
import { DragSelectProvider } from "./DragSelectContext";
export const MyComponent = () => (
// you can add initial settings by passing a settings object
<DragSelectProvider settings={{ selectorClass: styles.selector }}>
<SomeOtherComponentsThatNeedsDragSelect />
</DragSelectProvider>
);
3. Use it
import React, { useEffect, useRef } from "react";
import { useDragSelect } from "./DragSelectContext";
export const SomeOtherComponentsThatNeedsDragSelect = () => {
const ds = useDragSelect();
const inputEl = useRef(null);
// adding a selectable element
useEffect(() => {
const element = inputEl.current as unknown as HTMLElement;
if (!element || !ds) return;
ds.addSelectables(element);
}, [ds, inputEl]);
// subscribing to a callback
useEffect(() => {
if (!ds) return;
const id = ds.subscribe("DS:end", (e) => {
// do something
console.log(e);
});
return () => ds.unsubscribe("DS:end", null, id!);
}, [ds]);
return (
<button ref={inputEl} aria-labelledby="Selectable">
Selectable
</button>
);
};
DragSelect also exports some helper types for type safety, i.e. DSPubCallback
which you can pass in the subscriber for the callback type safety:
import { DSPubCallback } from "dragselect";
const cb: DSPubCallback<"DS:end"> = ({ items = [] }) => {
console.log("CALLBACK", items);
setSelectedAmount(items.length);
};
You can see this example in use within this docusaurus project. I.e. the context provider here and a random useage example here