React Dnd useDrag is not working properly? - reactjs

I'm using react dnd and it's useDrag method not working properly. Let me elaborate the situation:
User will drag list item from left to right as stated below:
Final outcome of right side will be like this below pic,
every list items list 1, 2, 3 will be draggable everywhere and droppable.
The list items List 1 useDrag code is :
const [{ isDragging }, drag, preview] = useDrag({
item: {
type: 'tool',
id: id
},
canDrag: true,
begin(props, monitor, component) {
document.querySelectorAll(".rowWrapper").forEach(function(item){
item.classList.add("rowBorder", "pd-row-drag", "mb-row-drag");
});
document.querySelectorAll(".drop-area").forEach(function(element) {
element.classList.add("dropAreaPosition");
});
document.querySelectorAll(".rowBorderOverlay").forEach(function(element) {
element.classList.add("hideElement");
});
document.querySelectorAll(".rowActions").forEach(function(element) {
element.classList.add("hideElement");
});
},
end(props, monitor, component) {
document.querySelectorAll(".rowWrapper").forEach(function(element) {
element.classList.remove("rowBorder", "pd-row-drag", "mb-row-drag");
});
document.querySelectorAll(".dropZone").forEach(function(element) {
element.classList.remove("showDropZone");
});
document.querySelectorAll(".drop-area").forEach(function(element) {
element.classList.remove("placeHolder","dropAreaPosition");
});
document.querySelectorAll(".rowActions").forEach(function(element) {
element.classList.remove("hideElement");
});
},
collect: monitor => ({
item: monitor.getItem(),
isDragging: !!monitor.isDragging()
}),
});
What I'm doing here is, when dragging begins I'm doing the above stuff like adding classes/removing. By doing like this, useDrag is not working properly when you drag list 1 the full container is not draggable only the portion of it.
if I remove begin, end I can drag the entire container, I don't know what's causing the problem here ?
Any help on this really appreciable ? or how do I do the stuff like adding classes/removing whild dragging or drag begin ?

Related

how to collapse objects in storybook controls

I searched through storybook's documentation for react and I can't seem to find how to make the object control for my argument appear collapsed by default instead of having to collapse it manually.
this is what I did
data: {
control: { type: 'object' },
table: { defaultValue: { summary: 'Object' } },
collapsed: true, // I want to find out if there is something like this
},
and this is what I was expecting
The option to configure this does not exist, unfortunately. Inspired by this comment regarding having the RAW-view open by default, I made a somewhat hacky solution, query all the spans at the top level for collapsing their content and trigger a click using JavaScript.
In the file manager.js add the following to make this work:
const observer = new MutationObserver(() => {
// Query the spans for collapsing objects.
const objectCollapseSpans = [...document.querySelectorAll('.rejt-tree > .rejt-object-node > span')];
// Query the spans for collapsing array of objects.
const arrayCollapseSpans = [...document.querySelectorAll('.rejt-tree > .rejt-array-node > span')];
const collapseSpans = [...arrayCollapseSpans, ...objectCollapseSpans];
for (const span of collapseSpans) {
if (span.className !== 'closed') {
span.click();
}
span.className = 'closed'
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
})

Apollo cache.modify update slower than setState while using in React Beautiful Drag and Drop

I'm fetching a query, and modifying the order of the list in it, using cache.modify on the drag end.
This does modify cache, as it should but, it takes milliseconds to do that.
How to reproduce the issue:
I'm using react beautiful dnd, to make drag-n-drop card.
It provides onDragEnd handler, where we can specify what happens when the user stops dragging.
In this case, I want to reorder the list on the drag end.
Cache modify:
cache.modify({
id: cache.identify(data.pod),
fields: {
stories(existingStoriesRefs, { readField }) {
return reorder(existingStoriesRefs, sourceIndex, destinationIndex);
},
},
});
Reorder logic:
const reorder = (list: any[], startIndex: number, endIndex: number) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
This is correctly working and rendering using stories in setState.
But, instead of copying Apollo data, to a new state, I think it's better to directly modify the cache.
But, using cache.modify, it works but, rendering is kind of glitchy. It seems, it first renders the existing list and then, modify cache in the next render. The glitch is around less than a second, but visible to the user.
I fixed it using cache.modify inside, mutation, and using optimistic update.
moveStoryMutation({
variables: {
id: stories[sourceIndex].id,
sourceIndex,
destinationIndex,
},
optimisticResponse: {
__typename: "Mutation",
moveStory: true,
},
update: (proxy) => {
proxy.modify({
id: proxy.identify(pod),
fields: {
stories(existingStoryRefs) {
return reorder(
existingStoryRefs,
sourceIndex,
destinationIndex
);
},
},
});

Fluent UI DetailsList - Is there a way to add filters to each column

I am using Fluent UI DetailsList. My table looks like below:
I need filters below every column (text or drop-down) as shown below:
Please let me know if this is possible? Or maybe a way to display custom header (using html) ?
This actually turned out to be easier than I thought it'd be...
If you're ok with clicking the column header to reveal the choices (vs having the dropdown directly under the title) then this can be achieved using the ContextualMenu component in conjunction with DetailsList. I got it working by tweaking from the variable row height example in the official docs: https://developer.microsoft.com/en-us/fluentui#/controls/web/detailslist/variablerowheights.
Add a ContextualMenu underneath your DetailsList:
<DetailsList
items={items}
columns={columns}
/>
{this.state.contextualMenuProps && <ContextualMenu {...this.state.contextualMenuProps} />}
Inside your column definition, set the hasDropdown action so the user gets a UI indicator that they can/should click the header, and call a contextMenu method (note I'm using onColumnContextMenu as well as onColumnClick so it doesn't matter if they left or right click the header:
{
key: 'dept',
name: 'Department',
fieldName: 'dept',
minWidth: 125,
maxWidth: 200,
onColumnContextMenu: (column, ev) => {
this.onColumnContextMenu(column, ev);
},
onColumnClick: (ev, column) => {
this.onColumnContextMenu(column, ev);
},
columnActionsMode: ColumnActionsMode.hasDropdown,
}
When the onColumnContextMenu method gets invoked, we need to build the context menu properties that will get consumed by the ContextualMenu component. Note the dismissal method as well, which clears out the state so the menu is hidden.
private onContextualMenuDismissed = (): void => {
this.setState({
contextualMenuProps: undefined,
});
}
private onColumnContextMenu = (column: IColumn, ev: React.MouseEvent<HTMLElement>): void => {
if (column.columnActionsMode !== ColumnActionsMode.disabled) {
this.setState({
contextualMenuProps: this.getContextualMenuProps(ev, column),
});
}
};
Finally, inside of getContextualMenuProps you need to determine what the options should be for the user to click. In this example, I'm simply giving sort options (you'll need to add an onClick handler to actually do something when the user clicks the item), but I'll use the column to determine what those items should actually be and paint the filters into the items collection so the user can select one to filter.
private getContextualMenuProps = (ev: React.MouseEvent<HTMLElement>, column: IColumn): IContextualMenuProps => {
const items: IContextualMenuItem[] = [
{
key: 'aToZ',
name: 'A to Z',
iconProps: { iconName: 'SortUp' },
canCheck: true,
checked: column.isSorted && !column.isSortedDescending,
},
{
key: 'zToA',
name: 'Z to A',
iconProps: { iconName: 'SortDown' },
canCheck: true,
checked: column.isSorted && column.isSortedDescending,
}
];
return {
items: items,
target: ev.currentTarget as HTMLElement,
directionalHint: DirectionalHint.bottomLeftEdge,
gapSpace: 10,
isBeakVisible: true,
onDismiss: this.onContextualMenuDismissed,
}
}
Note the target on the ContextualMenuProps object, which is what tells the ContextualMenu where to lock itself onto (in this case, the column header that you clicked to instantiate the menu.
Detail list filter for each column without context menu -
https://codesandbox.io/s/rajesh-patil74-jzuiy?file=/src/DetailsList.CustomColumns.Example.tsx
For instance - Providing filter in text field associated with each column will apply filter on color column.

Google charts how to get crosshairs to remain after selection in React

I've searched extensively for this issue here and haven't been able to figure this out. I have a google chart in my app and have a callback function in place to get the details of each point when selected so that I can update a modal to display more info elsewhere.
However, when I have this callback activated and the user clicks the item, the crosshairs do not stay. When I don't have the callback active, they do remain and I get a nice small circle around the selected point like this:
image of crosshairs
Here are the chartevent details I have in place which are working to return the details of the point. Is the chartevent option perhaps overriding a crosshair default?
Grateful for any advice.
Cheers.
const chartEvents = [{
eventName: "select",
options: {
tooltip: {
trigger: "selection"
}
},
callback: ({ chartWrapper }) => {
const chart = chartWrapper.getChart().getSelection()[0].row;
this.setState((prevState) => ({ selectedMonth: chart }))
this.setChangedMonth()
}
}]

Facebook like infinite scrolling

Will it be possible to implement facebook or linked in like infinite scrolling using EXT-JS API. I am aware of infinite grid although my requirement is to scroll panels infinitely just like facebook or linked in allows us. As of now I am working on EXT version 5.
Any link/white paper will greatly be appreciated.
Thanks in advance
Samir
You can use a dataview with a store tied to it to load the initial data in the wall. Then, in a controller add a listener to the scroll event and check when the scroll has reached the end.
I previously was creating a reddit app with that exact functionality though it was never completed/fully vetted. Here is a snippet of the scroll callback, basically I kicked off an ajax request and then load the returned data to the end of the current store's data:
mainPanelRendered: function () {
var p = Ext.ComponentQuery.query('yourDataView')[0];
var s = p.getStore();
//check on scroll if we've reached the end of the dataview
p.getTargetEl().on('scroll', function (e, t) {
var height = p.getTargetEl().getHeight();
if (height + t.scrollTop >= t.scrollHeight) { //Fire method to load more data to the store.
p.setLoading(true);
Ext.data.JsonP.request({
callbackKey:'jsonp',
url: s.proxy.url,
params: {
'count': 25,
'after': p.after
},
headers: { 'Content-type': 'text/json; charset=utf-8', 'Accepts': 'text/json' },
reader: {
type: 'json',
root: 'data.children',
successProperty: 'success'
},
success: function (response) {
p.after = response.data.after;
//now that you have more data add it to the store
Ext.each(response.data.children, function (article) {
var data = article.data;
try{
s.add({
id: data.id,
domain: data.domain,
subreddit: data.subreddit,
author: data.author,
over_18: data.over_18,
thumbnail: data.thumbnail,
subreddit_id: data.subreddit_id,
downs: data.downs,
ups: data.ups,
permalink: data.permalink,
name: data.name,
url: data.url,
title: data.title,
num_comments: data.num_comments,
score: data.score
});
} catch (ex) {
//do nothing the item already existed
}
//s.add(item);
//newItems[i] = item;
//i++;
});
p.setLoading(false);
//p.after = p.response.data.after;
}
});
}
});
},
And here is a link to my not-so-complete app's source. Again, it certainly isn't fully vetted but should give you an idea how you could add an infinite scroll. Checkout the mainPanel in the view and the render event in the controller.

Resources