Skip to content

Başlarken ​

Kurulum ​

Terminalinize şunları girin:

sh
# npm
npm i effdnd

# pnpm
pnpm add effdnd

# yarn
yarn add effdnd

Hı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ı olarak document.body kabul 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. scope alanı 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:

jsx
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 sonra target (hedef) modunu tanımlar ve şu değerleri alabilir:
    • target-mode="prepend" - item öğesi, target içine ilk alt öğe olarak eklenir;
    • target-mode="append" - item öğesi, target iç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ında scope (kapsam) modunu tanımlar ve şu değerleri alabilir:
    • scope-mode="order-x" - scope öğesi, item öğelerinin x ekseni boyunca yeniden düzenlenmesine olanak tanır;
    • scope-mode="order-y" - scope öğesi, item öğelerinin y ekseni 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.

ts
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.

ts
/**
 * 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:

css
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:

html
<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:

ts
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:

ts
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:

ts
/**
 * 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;
}

Apache Lisansı 2.0 altında yayınlanmıştır