Başlarken
Kurulum
Terminalinize şunları girin:
# npm
npm i effdnd
# pnpm
pnpm add effdnd
# yarn
yarn add effdndHızlı başlangıç
Özetle effdnd, iki özel web bileşeni kullanır:
effdnd-trigger, sürükle-bırak işlemini başlatır;effdnd-actor, düzen içerisinde sürükle-bırak sürecine dahil olacak (kendi rollerini üstlenecek) alanları belirtir.
effdnd-actor web bileşeni çeşitli roller üstlenebilir:
item- taşınan öğe,target- taşıma hedefi,scope- hareket sınırları.
Bir rol atamak için, effdnd-actor öğesi üzerinde aynı isimli özniteliği (attribute) ayarlamanız gerekir. Tek bir öğeye birden fazla rol tanımlanabilir.
Sürükle-bırak işlemi başladığında, effdnd-trigger web bileşeni, sürecin katılımcılarını (aktörlerini) belirlemek için kendi özniteliklerini kullanır:
itemözniteliği, taşınacak öğeyi seçmenizi sağlar. Eğer bu öznitelik belirtilmemişse, DOM ağacında yukarı doğru gidildiğinde karşılaşılan,itemözniteliğine sahip ilk<effdnd-actor>öğesi kullanılır. Eğer öznitelik değeri olarak#atanmışsa (<effdnd-trigger item='#'>) veya DOM ağacının üst kısımlarında herhangi bir<effdnd-actor item='...'>öğesi bulunmuyorsa, bu durumda tetikleyicinin (trigger) kendisi taşınır;scopeözniteliği, hareketin gerçekleşebileceği alanı seçmenizi sağlar. Eğer bu öznitelik belirtilmemişse, DOM ağacında yukarı doğru gidildiğinde karşılaşılan,scopeözniteliğine sahip ilk<effdnd-actor>öğesi kullanılır. Eğer öznitelik değeri olarak#atanmışsa (<effdnd-trigger scope='#'>) veya DOM ağacının üst kısımlarında herhangi bir<effdnd-actor scope='...'>öğesi bulunmuyorsa, hareket alanı olarakdocument.bodykabul edilir;targetözniteliği, hareketin hedeflenebileceği alanları seçmenizi sağlar. Hareket hedefleri, üzerlerinde bir sürükle-bırak işlemi sonlandığında özel olaylar (events) tetikler.scopealanı içinde yer alan tüm<effdnd-actor target='...'>öğeleri, isimleri tetikleyicinin (trigger)targetözniteliğinin değeriyle başlayan hareket hedefleri olarak kabul edilecektir. Bu, söz konusu özniteliğin belirtilmediği durumlarda, mevcut<effdnd-actor scope='...'>kapsamındaki tüm<effdnd-actor target='...'>öğelerinin hareket hedefi olarak kullanılabileceği anlamına gelir.
Her iki web bileşenini de tanımlamak için useDnD işlevini çağırmanız ve bu çağrının sonuçlarını olay dinleyicileri (event listeners) aracılığıyla takip etmeniz yeterlidir:
import { useRef } from 'react';
import { useDnD } from 'effdnd';
const { observe } = useDnD();
export const Component = () => {
const ref = useRef();
useEffect(() => {
// Sürükle-bırak (Drag-and-Drop) olaylarına abone olabilirsiniz.
const unobserve = observe((e) => {
// etkinlik burada işleniyor
}, ref.current);
// ve abonelikten çıkabilirsiniz
return () => unobserve();
});
return <effdnd-actor scope='top' ref={ref} >
<div className="targets-wrapper">
<effdnd-actor target='target-1'>...</effdnd-actor>
<effdnd-actor target='target-2'>...</effdnd-actor>
</div>
<div id="items-wrapper">
<effdnd-actor item='item-1'>
<effdnd-trigger>Trigger #1</effdnd-trigger>
</effdnd-actor>
<effdnd-actor item='item-2'>
<effdnd-trigger>Trigger #2</effdnd-trigger>
</effdnd-actor>
</div>
</effdnd-actor>;
}Aktif ve pasif öğeler
Sürükle-bırak işlemi sırasında effdnd-trigger, seçilen effdnd-actor öğeleri üzerinde dinamik bir state (durum) özniteliği ayarlar. Yani, süreç en başında tetikleyici (trigger); neyin taşındığını (item), nereye taşınabileceğini (scope) ve nereye taşınması gerektiğini (target) belirler. Öğeler şu durumlarda olabilir:
- herhangi bir durum olmaksızın,
- pasif durumda (
state="passive"), - aktif durumda (
state="active").
item rolüne sahip bir öğe, taşındığı sırada aktiftir. Ayrıca, item rolündeki bir öğe, kendisinden oluşturulan bir kopya (clone) aktifse, kopyalanmış durumda (state="cloned") olabilir. Bir öğeyi kopyalamak için item-mode="cloned" modunu etkinleştirin.
scope rolüne sahip bir öğe, item onun içinde hareket ederken pasiftir. Bu durum, yer değiştirme alanının sınırlarını belirler.
scope rolündeki bir öğe, eğer pasif durumdaysa ve item bu sınırların dışına çıkmaya çalışırsa aktif hale gelir. Bu durum, kullanıcıya imlecin kabul edilebilir sınırların dışına çıktığını gösterir.
target rolüne sahip bir öğe, aktif veya pasif durumdaki bir scope içinde yer aldığında pasiftir. Bu durum, item öğesinin nereye taşınabileceğini gösterir.
target rolündeki bir öğe, eğer pasif durumdaysa ve item öğesini taşıyan imleç onun üzerindeyse aktif hale gelir. Bu durum, target öğesinin item öğesini kabul etmeye hazırlandığını gösterir.
Rol modları
Kütüphanenin temel davranış biçimi oldukça düşük seviyelidir; bu nedenle, her bir rolün modu aracılığıyla kullanım senaryosunu özelleştirmek mümkündür:
item-mode,item(öğe) modunu tanımlar ve şu değerleri alabilir:item-mode="keep"-itemöğesi, taşındıktan sonra yeni koordinatlarını korur;item-mode="clone"-itemöğesinin bir kopyası (klonu) oluşturulur ve hareket eden bu kopya olur;
target-mode, seçildikten sonratarget(hedef) modunu tanımlar ve şu değerleri alabilir:target-mode="prepend"-itemöğesi,targetiçine ilk alt öğe olarak eklenir;target-mode="append"-itemöğesi,targetiçine son alt öğe olarak eklenir;target-mode="remove"-itemöğesi DOM ağacından kaldırılır;
scope-mode, sürükle-bırak işlemi sırasındascope(kapsam) modunu tanımlar ve şu değerleri alabilir:scope-mode="order-x"-scopeöğesi,itemöğelerininxekseni boyunca yeniden düzenlenmesine olanak tanır;scope-mode="order-y"-scopeöğesi,itemöğelerininyekseni boyunca yeniden düzenlenmesine olanak tanır.
Stiller
<effdnd-actor item='...'> öğesinin görünümü, hareket sırasında kullanılan öznitelikler (attributes) aracılığıyla belirlenir. Ayrıca animasyon parametrelerini, hareket eksenini ve tetikleme için gereken minimum mesafeyi ayarlamak amacıyla da bu özniteliklerden yararlanabilirsiniz.
export interface ITriggerAttrs {
/**
* Item name
* @description
* If the value is "#" then it will use `effnd-trigger` as item
*/
item?: string;
/**
* Bounding scope name
* @description
* If the value is "#" then it will use `document.body` as scope
*/
scope?: string;
/**
* Target name or its prefix
*/
target?: string;
/**
* Triggering distance
*/
dist?: string;
/**
* Triggering mouse button
* @description
* Any mouse button if not specified
*/
btn?: '0' | '1' | '2';
/**
* DnD axis
*/
axis?: string;
/**
* Triggering event
* @description
* Both 'touch' and 'mouse' by default
*/
event?: 'touch' | 'mouse';
/**
* Transition duration
*/
dur?: string;
/**
* Transition delay
*/
del?: string;
/**
* Transition timing-function
*/
tf?: string;
}Varsayılan olarak, boş tetikleyicinin (trigger) içinde, görünümü axis özniteliğine bağlı olan bir SVG hareket simgesi kullanılır. Bu simgeyi gizlemek için effdnd-trigger öğesinin içinde kendi içeriğinizi kullanabilirsiniz.
effdnd-actor web bileşeni, rollerin pasif ve aktif durumlarına ilişkin temel stilleri halihazırda içerir; ancak unstyled özniteliğini kullanarak bu stilleri devre dışı bırakmanıza da olanak tanır. Örneğin, <effdnd-actor unstyled="target"> yalnızca target öğesine ait yerleşik stilleri, <effdnd-actor unstyled="scope"> yalnızca scope öğesine ait yerleşik stilleri kaldırırken; <effdnd-actor unstyled> kullanımı tüm yerleşik stilleri devre dışı bırakır.
/**
* DnD actor attributes
*/
export interface IActorAttrs {
/**
* Item name
*/
item?: string;
/**
* Scope name
*/
scope?: string;
/**
* Target name
*/
target?: string;
/**
* Actor state
*/
state?: 'active' | 'passive';
/**
* Reset target state styles
*/
unstyled?: boolean | 'target' | 'scope';
/**
* Display contents
*/
contents?: boolean;
/**
* Item mode
*/
'item-mode'?: 'keep' | 'clone';
/**
* Target mode
*/
'target-mode'?: 'append' | 'prepend' | 'remove';
/**
* Scope mode
*/
'scope-mode'?: 'order-x' | 'order-y';
/**
* Scope transition duration
*/
'scope-dur'?: number;
/**
* Scope transition delay
*/
'scope-del'?: number;
/**
* Scope transition timing-function
*/
'scope-tf'?: string;
}scope rolüne sahip bir öğe için kullanılan scope-dur, scope-del ve scope-del öznitelikleri, CSS transition özelliğinin varsayılan değerlerini belirler.
contents özniteliği, display:contents; stilini ayarlamanıza olanak tanır.
Ayrıca, farklı durumlar için kendi CSS stillerinizi de tanımlayabilirsiniz:
effdnd-actor[target][state=passive] .custom-dnd-target {
outline: 4px solid #646cffaa;
}
effdnd-actor[target][state=active] .custom-dnd-target {
outline: 4px solid #646cffaa;
background: #646cffaa;
}Sunucu taraflı işleme (Server-side rendering)
Sunucu taraflı işleme kullanıyorsanız, düzeninizi korumak için HTML head kısmına effdnd bildirimini içeren bir script etiketi eklemeniz yeterlidir:
<head>
<script src="https://cdn.jsdelivr.net/npm/effdnd@3.1.0/dist/use.js"></script>
</head>Bu betik, effdnd öğesini genel bir değişken olarak kullanmanıza da olanak tanıyacaktır:
import { TUseDnD } from 'effdnd';
declare global {
interface Window {
effdnd: ReturnType<TUseDnD>;
}
};
const unobserve = window.effdnd.observe(() => console.log('effdnd'));useDnD
İşlev, effdnd-trigger ve effdnd-actor adlı web bileşenlerini tanımlar ve ayrıca özel olaylara (custom events) abone olunmasını sağlayan işleyiciler (handlers) döndürür:
export type TEventDetail = {
type: TEventType;
refs: TRefs;
keys: TKeys;
event: MouseEvent | TouchEvent;
};
interface TDnDEvent extends CustomEvent {
detail: TEventDetail;
}
export type TDnDCallback = (event: TDnDEvent) => void;
export type TUseDnD = () => {
/**
* Observe DnD events
* @param callback - event handler
* @param element - HTML element
*/
observe: (callback: TDnDCallback, element?: HTMLElement) => () => void;
/**
* Unobserve DnD events
* @param callback - event handler
* @param element - HTML element
*/
unobserve: (callback: TDnDCallback, element?: HTMLElement) => void;
};effdnd-trigger
Tetikleyici web bileşeni, çeşitli yararlı metotlar ve özellikler içerir:
/**
* DnD trigger element
*/
export interface ITriggerElement extends HTMLElement {
/**
* Is trigger active
*/
isActive: boolean;
/**
* DnD item y-offset
*/
dndY: number;
/**
* DnD item x-offset
*/
dndX: number;
/**
* DnD item
*/
dndItem: HTMLElement;
/**
* DnD scope
*/
dndScope: HTMLElement;
/**
* DnD targets
*/
dndTargets: Set<HTMLElement>;
/**
* Reset DnD translate
*/
resetDnD(): void;
}