OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Draggable items break styles on dragging

  • Thread starter Thread starter Lvasche
  • Start date Start date
L

Lvasche

Guest
I'm creating a sequence quiz and chose @hello-pangea/dnd package (which is rewritten react-beautiful-dnd and I succeeded to create a simple component but I faced a problem that when I grab draggable item it breaks other items styles:

Normal state:

enter image description here

While dragging:

enter image description here

Here are 2 columns:

Left column - simple div with indexes as I received not to create 4 droppable columns but create 1 column where I'll just reorder items

Right Column - droppable column

Components​


sequence.tsx:

Code:
'use client';

import { UUID } from 'crypto';
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd';
import { useState } from 'react';

import { Button, CardLayout } from '@/components';
import { SequenceOptions } from './sequence-options';

import s from './sequence.module.scss';

export const Sequence = ({
   options: opts,
   title,
   description,
   footerColor,
   headerColor,
}: TSequenceProps) => {
   const [options, setOptions] = useState<{ id: UUID | string; label: string }[]>(
      opts.map((opt, index) => ({
         id: `${index}`,
         label: opt,
      })),
   );

   const onDragEnd: OnDragEndResponder = ({ destination, source }) => {
      if (!destination) return;
      if (destination.index === source.index) return;
      if (destination.droppableId !== source.droppableId) return;

      const newOptions = Array.from(options);
      const [removed] = newOptions.splice(source.index, 1);
      newOptions.splice(destination.index, 0, removed);

      setOptions(newOptions);
   };

   return (
      <DragDropContext onDragEnd={onDragEnd}>
         <CardLayout footerColor={footerColor} headerColor={headerColor}>
            <section className={s.wrapper}>
               <section className={s.textWrapper}>
                  <h1 className={s.title}>{title}</h1>
                  <p className={s.title}><p>I'm creating a sequence quiz and chose <strong><a href="https://www.npmjs.com/package/@hello-pangea/dnd" rel="nofollow noreferrer">@hello-pangea/dnd</a></strong> package (which is rewritten <strong><a href="https://www.npmjs.com/package/react-beautiful-dnd/v/11.0.2" rel="nofollow noreferrer">react-beautiful-dnd</a></strong> and I succeeded to create a simple component but I faced a problem that when I grab draggable item it breaks other items styles:</p>
<p><strong>Normal state:</strong></p>
<p><a href="https://i.sstatic.net/LRvTsJid.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/LRvTsJid.png" alt="enter image description here" /></a></p>
<p><strong>While dragging:</strong></p>
<p><a href="https://i.sstatic.net/yvnY7K0w.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/yvnY7K0w.png" alt="enter image description here" /></a></p>
<p>Here are 2 columns:</p>
<p><strong>Left column</strong> - simple div with indexes as I received not to create 4 <code>droppable</code> columns but create 1 column where I'll just reorder items</p>
<p><strong>Right Column</strong> - <code>droppable</code> column</p>
<h2>Components</h2>
<p><strong>sequence.tsx:</strong></p>
<pre class="lang-js prettyprint-override"><code>'use client';

import { UUID } from 'crypto';
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd';
import { useState } from 'react';

import { Button, CardLayout } from '@/components';
import { SequenceOptions } from './sequence-options';

import s from './sequence.module.scss';

export const Sequence = ({
   options: opts,
   title,
   description,
   footerColor,
   headerColor,
}: TSequenceProps) => {
   const [options, setOptions] = useState<{ id: UUID | string; label: string }[]>(
      opts.map((opt, index) => ({
         id: `${index}`,
         label: opt,
      })),
   );

   const onDragEnd: OnDragEndResponder = ({ destination, source }) => {
      if (!destination) return;
      if (destination.index === source.index) return;
      if (destination.droppableId !== source.droppableId) return;

      const newOptions = Array.from(options);
      const [removed] = newOptions.splice(source.index, 1);
      newOptions.splice(destination.index, 0, removed);

      setOptions(newOptions);
   };

   return (
      <DragDropContext onDragEnd={onDragEnd}>
         <CardLayout footerColor={footerColor} headerColor={headerColor}>
            <section className={s.wrapper}>
               <section className={s.textWrapper}>
                  <h1 className={s.title}>{title}</h1>
                  <p className={s.title}>{description}</p>
               </section>

               <section className={s.sequenceWrapper}>
                  <div className={s.indexes}>
                     {options.map((_, index) => (
                        <p className={s.index} key={index}>
                           <span>{index + 1}</span>
                        </p>
                     ))}
                  </div>

                  <SequenceOptions options={options} />
               </section>

               <Button onClick={() => {}} size="s">
                  Confirm
               </Button>
            </section>
         </CardLayout>
      </DragDropContext>
   );
};
</code></pre>
<p><strong>sequence-options.module.scss:</strong></p>
<pre class="lang-scss prettyprint-override"><code>@import 'styles';

.wrapper {
   @include flex(column, center, center, 12px);
}
</code></pre>
<p><strong>sequence-options.tsx:</strong></p>
<pre class="lang-js prettyprint-override"><code>'use client';

import { UUID } from 'crypto';
import { Droppable } from '@hello-pangea/dnd';
import { DraggableItem } from '@/components';

import s from './sequence-options.module.scss';

export const SequenceOptions = ({
   options,
}: {
   options: { label: string; id: UUID | string }[];
}) => {
   return (
      <Droppable droppableId={'sequence'}>
         {provided => (
            <div
               ref={provided.innerRef}
               {...provided.droppableProps}
               className={s.wrapper}
            >
               {options.map((option, index) => (
                  <DraggableItem
                     label={option.label}
                     id={option.id}
                     index={index}
                     key={option.id}
                  />
               ))}
            </div>
         )}
      </Droppable>
   );
};
</code></pre>
<p><strong>draggable-item.tsx:</strong></p>
<pre class="lang-js prettyprint-override"><code>'use client';

import { Draggable } from '@hello-pangea/dnd';
import clsx from 'clsx';

import { RubicSquareIcon } from '@/icons';

import s from './draggable-item.module.scss';

export const DraggableItem = ({
   id,
   index = 0,
   label = '',
   disabled = false,
   dragging = false,
}: TDraggableItemProps) => {
   return (
      <Draggable isDragDisabled={disabled} draggableId={id} index={index}>
         {provided => (
            <div
               {...provided.dragHandleProps}
               {...provided.draggableProps}
               ref={provided.innerRef}
               className={clsx(s.item, dragging && s.dragging, disabled && s.disabled)}
            >
               <RubicSquareIcon className={s.icon} />

               <p className={s.label}>{label}</p>
            </div>
         )}
      </Draggable>
   );
};
</code></pre>
<p><strong>draggable-item.module.scss:</strong></p>
<pre class="lang-scss prettyprint-override"><code>@import 'styles';

.item {
   @include flex($align: center, $gap: 8px);

   width: 220px;
   height: 48px;

   box-sizing: border-box;

   padding: 16px;

   border-radius: 4px;

   background-color: $primary;

   cursor: grab;

   .icon {
      @include set-size(16px);

      path {
         fill: rgba($white, 0.4);

         transition: fill 0.15s ease-in-out;
      }
   }

   .label {
      text-transform: capitalize;
      font-family: $soraRegular;
      font-size: 16px;
      color: $white;
   }
}

/* STATES */

.dragging {
   .icon {
      path {
         fill: $white;
      }
   }
}

.disabled {
   opacity: 0.4;

   cursor: not-allowed;
}
</code></pre></p>
               </section>

               <section className={s.sequenceWrapper}>
                  <div className={s.indexes}>
                     {options.map((_, index) => (
                        <p className={s.index} key={index}>
                           <span>{index + 1}</span>
                        </p>
                     ))}
                  </div>

                  <SequenceOptions options={options} />
               </section>

               <Button onClick={() => {}} size="s">
                  Confirm
               </Button>
            </section>
         </CardLayout>
      </DragDropContext>
   );
};

sequence-options.module.scss:

Code:
@import 'styles';

.wrapper {
   @include flex(column, center, center, 12px);
}

sequence-options.tsx:

Code:
'use client';

import { UUID } from 'crypto';
import { Droppable } from '@hello-pangea/dnd';
import { DraggableItem } from '@/components';

import s from './sequence-options.module.scss';

export const SequenceOptions = ({
   options,
}: {
   options: { label: string; id: UUID | string }[];
}) => {
   return (
      <Droppable droppableId={'sequence'}>
         {provided => (
            <div
               ref={provided.innerRef}
               {...provided.droppableProps}
               className={s.wrapper}
            >
               {options.map((option, index) => (
                  <DraggableItem
                     label={option.label}
                     id={option.id}
                     index={index}
                     key={option.id}
                  />
               ))}
            </div>
         )}
      </Droppable>
   );
};

draggable-item.tsx:

Code:
'use client';

import { Draggable } from '@hello-pangea/dnd';
import clsx from 'clsx';

import { RubicSquareIcon } from '@/icons';

import s from './draggable-item.module.scss';

export const DraggableItem = ({
   id,
   index = 0,
   label = '',
   disabled = false,
   dragging = false,
}: TDraggableItemProps) => {
   return (
      <Draggable isDragDisabled={disabled} draggableId={id} index={index}>
         {provided => (
            <div
               {...provided.dragHandleProps}
               {...provided.draggableProps}
               ref={provided.innerRef}
               className={clsx(s.item, dragging && s.dragging, disabled && s.disabled)}
            >
               <RubicSquareIcon className={s.icon} />

               <p className={s.label}>{label}</p>
            </div>
         )}
      </Draggable>
   );
};

draggable-item.module.scss:

Code:
@import 'styles';

.item {
   @include flex($align: center, $gap: 8px);

   width: 220px;
   height: 48px;

   box-sizing: border-box;

   padding: 16px;

   border-radius: 4px;

   background-color: $primary;

   cursor: grab;

   .icon {
      @include set-size(16px);

      path {
         fill: rgba($white, 0.4);

         transition: fill 0.15s ease-in-out;
      }
   }

   .label {
      text-transform: capitalize;
      font-family: $soraRegular;
      font-size: 16px;
      color: $white;
   }
}

/* STATES */

.dragging {
   .icon {
      path {
         fill: $white;
      }
   }
}

.disabled {
   opacity: 0.4;

   cursor: not-allowed;
}

<p>I'm creating a sequence quiz and chose <strong><a href="https://www.npmjs.com/package/@hello-pangea/dnd" rel="nofollow noreferrer">@hello-pangea/dnd</a></strong> package (which is rewritten <strong><a href="https://www.npmjs.com/package/react-beautiful-dnd/v/11.0.2" rel="nofollow noreferrer">react-beautiful-dnd</a></strong> and I succeeded to create a simple component but I faced a problem that when I grab draggable item it breaks other items styles:</p>
<p><strong>Normal state:</strong></p>
<p><a href="https://i.sstatic.net/LRvTsJid.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/LRvTsJid.png" alt="enter image description here" /></a></p>
<p><strong>While dragging:</strong></p>
<p><a href="https://i.sstatic.net/yvnY7K0w.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/yvnY7K0w.png" alt="enter image description here" /></a></p>
<p>Here are 2 columns:</p>
<p><strong>Left column</strong> - simple div with indexes as I received not to create 4 <code>droppable</code> columns but create 1 column where I'll just reorder items</p>
<p><strong>Right Column</strong> - <code>droppable</code> column</p>
<h2>Components</h2>
<p><strong>sequence.tsx:</strong></p>
<pre class="lang-js prettyprint-override"><code>'use client';

import { UUID } from 'crypto';
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd';
import { useState } from 'react';

import { Button, CardLayout } from '@/components';
import { SequenceOptions } from './sequence-options';

import s from './sequence.module.scss';

export const Sequence = ({
options: opts,
title,
description,
footerColor,
headerColor,
}: TSequenceProps) => {
const [options, setOptions] = useState<{ id: UUID | string; label: string }[]>(
opts.map((opt, index) => ({
id: `${index}`,
label: opt,
})),
);

const onDragEnd: OnDragEndResponder = ({ destination, source }) => {
if (!destination) return;
if (destination.index === source.index) return;
if (destination.droppableId !== source.droppableId) return;

const newOptions = Array.from(options);
const [removed] = newOptions.splice(source.index, 1);
newOptions.splice(destination.index, 0, removed);

setOptions(newOptions);
};

return (
<DragDropContext onDragEnd={onDragEnd}>
<CardLayout footerColor={footerColor} headerColor={headerColor}>
<section className={s.wrapper}>
<section className={s.textWrapper}>
<h1 className={s.title}>{title}</h1>
<p className={s.title}>{description}</p>
</section>

<section className={s.sequenceWrapper}>
<div className={s.indexes}>
{options.map((_, index) => (
<p className={s.index} key={index}>
<span>{index + 1}</span>
</p>
))}
</div>

<SequenceOptions options={options} />
</section>

<Button onClick={() => {}} size="s">
Confirm
</Button>
</section>
</CardLayout>
</DragDropContext>
);
};
</code></pre>
<p><strong>sequence-options.module.scss:</strong></p>
<pre class="lang-scss prettyprint-override"><code>@import 'styles';

.wrapper {
@include flex(column, center, center, 12px);
}
</code></pre>
<p><strong>sequence-options.tsx:</strong></p>
<pre class="lang-js prettyprint-override"><code>'use client';

import { UUID } from 'crypto';
import { Droppable } from '@hello-pangea/dnd';
import { DraggableItem } from '@/components';

import s from './sequence-options.module.scss';

export const SequenceOptions = ({
options,
}: {
options: { label: string; id: UUID | string }[];
}) => {
return (
<Droppable droppableId={'sequence'}>
{provided => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
className={s.wrapper}
>
{options.map((option, index) => (
<DraggableItem
label={option.label}
id={option.id}
index={index}
key={option.id}
/>
))}
</div>
)}
</Droppable>
);
};
</code></pre>
<p><strong>draggable-item.tsx:</strong></p>
<pre class="lang-js prettyprint-override"><code>'use client';

import { Draggable } from '@hello-pangea/dnd';
import clsx from 'clsx';

import { RubicSquareIcon } from '@/icons';

import s from './draggable-item.module.scss';

export const DraggableItem = ({
id,
index = 0,
label = '',
disabled = false,
dragging = false,
}: TDraggableItemProps) => {
return (
<Draggable isDragDisabled={disabled} draggableId={id} index={index}>
{provided => (
<div
{...provided.dragHandleProps}
{...provided.draggableProps}
ref={provided.innerRef}
className={clsx(s.item, dragging && s.dragging, disabled && s.disabled)}
>
<RubicSquareIcon className={s.icon} />

<p className={s.label}>{label}</p>
</div>
)}
</Draggable>
);
};
</code></pre>
<p><strong>draggable-item.module.scss:</strong></p>
<pre class="lang-scss prettyprint-override"><code>@import 'styles';

.item {
@include flex($align: center, $gap: 8px);

width: 220px;
height: 48px;

box-sizing: border-box;

padding: 16px;

border-radius: 4px;

background-color: $primary;

cursor: grab;

.icon {
@include set-size(16px);

path {
fill: rgba($white, 0.4);

transition: fill 0.15s ease-in-out;
}
}

.label {
text-transform: capitalize;
font-family: $soraRegular;
font-size: 16px;
color: $white;
}
}

/* STATES */

.dragging {
.icon {
path {
fill: $white;
}
}
}

.disabled {
opacity: 0.4;

cursor: not-allowed;
}
</code></pre>
 

Latest posts

I
Replies
0
Views
1
Isaac P. Liu
I
U
Replies
0
Views
1
user3658366
U
G
Replies
0
Views
1
Giampaolo Levorato
G
M
Replies
0
Views
1
Marcelo Rodrigo Nascimento
M
Top