diff --git a/applications/GettingStartedWith/Draggable/index.css b/applications/GettingStartedWith/Draggable/index.css new file mode 100644 index 0000000000..ab55db37be --- /dev/null +++ b/applications/GettingStartedWith/Draggable/index.css @@ -0,0 +1,118 @@ +body { + padding: 0; +} + +.demo-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 0 40px; + height: 524px; +} + +.boundary-text { + height: 16px; + line-height: 16px; + text-align: center; + vertical-align: middle; + padding-top: 17px; + padding-bottom: 17px; + color: var(--dx-color-icon) +} + +.board { + background-color: light-dark(#F5F5F5, #141414); + outline: 1px dashed light-dark(#E0E0E0, #525252); + max-width: 1000px; + min-width: 320px; + width: 100%; + height: 500px; + display: grid; + grid-template-columns: repeat(4, 1fr); + align-content: start; + gap: 8px; + border-radius: 8px; + padding: 12px; +} + +@media (width < 850px) { + .board { + grid-template-columns: repeat(3, 1fr); + } +} + +@media (width < 650px) { + .board { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (width < 475px) { + .board { + grid-template-columns: 1fr; + } +} + +.card { + z-index: 0; + max-width: 320px; + min-width: 180px; + width: 100%; + min-height: 84px; + max-height: 84px; + border-radius: 8px; + background-color: light-dark(#FFF, #292929); + display: flex; + box-shadow: 0 0 2px rgba(0 0 0 / 24%); + transition: box-shadow 0.1s ease-in-out; +} + +.color-indicator { + margin: 8px; + height: 68px; + width: 4px; + border-radius: 4px; +} + +.color-indicator.blue { + background-color: var(--dx-color-primary); +} + +.color-indicator.green { + background-color: var(--dx-color-success); +} + +.color-indicator.red { + background-color: var(--dx-color-danger); +} + +.color-indicator.yellow { + background-color: var(--dx-color-warning); +} + +.text-container { + margin-top: 8px; + margin-bottom: 8px; + margin-right: 8px; + height: 68px; + display: flex; + flex-direction: column; +} + +.body-text-box { + height: 40px; +} + +.detail-text-box { + margin-top: auto; + color: light-dark(#707070, #999); +} + +.card.dx-draggable-dragging { + box-shadow: 0 4px 8px rgba(0 0 0 / 28%); +} + +.card.overlapped { + outline: 1px dashed var(--dx-color-primary); +} \ No newline at end of file diff --git a/applications/GettingStartedWith/Draggable/index.html b/applications/GettingStartedWith/Draggable/index.html new file mode 100644 index 0000000000..22576b71d9 --- /dev/null +++ b/applications/GettingStartedWith/Draggable/index.html @@ -0,0 +1,39 @@ +
+
Dragging Boundary
+
+ +
+
+
+
Install New Router in Dev Room
+
Amelia Harper
+
+
+ +
+
+
+
👨‍💻 Launch New Website
+
Brett Wade
+
+
+ +
+
+
+
Prepare 2026 Marketing Plan
+
Robert Reagan
+
+
+ +
+
+
+
🖥️ Approve Personal Computer Upgrade Plan
+
Bart Arnaz
+
+
+ +
+
Dragging Boundary
+
\ No newline at end of file diff --git a/applications/GettingStartedWith/Draggable/index.js b/applications/GettingStartedWith/Draggable/index.js new file mode 100644 index 0000000000..463ae549b8 --- /dev/null +++ b/applications/GettingStartedWith/Draggable/index.js @@ -0,0 +1,68 @@ +$(() => { + let z = 1; + + $("#note-1").dxDraggable({ + onDragStart: handleDragStart, + boundary: ".board", + group: "cards", + }).on({ + "click": handleClick, + "dxdragenter": handleDragEnter, + "dxdragleave": handleDragStop, + "dxdrop": handleDragStop, + }); + + $("#note-2").dxDraggable({ + onDragStart: handleDragStart, + group: "cards", + boundary: ".board", + }).on({ + "click": handleClick, + "dxdragenter": handleDragEnter, + "dxdragleave": handleDragStop, + "dxdrop": handleDragStop, + }); + + $("#note-3").dxDraggable({ + onDragStart: handleDragStart, + group: "cards", + boundary: ".board", + }).on({ + "click": handleClick, + "dxdragenter": handleDragEnter, + "dxdragleave": handleDragStop, + "dxdrop": handleDragStop, + }); + + $("#note-4").dxDraggable({ + onDragStart: handleDragStart, + boundary: ".board", + group: "cards", + }).on({ + "click": handleClick, + "dxdragenter": handleDragEnter, + "dxdragleave": handleDragStop, + "dxdrop": handleDragStop, + }); + + function changeZIndex(el) { + el.css("z-index", z); + z++; + } + + function handleClick(e) { + changeZIndex($(e.currentTarget)); + } + + function handleDragStart(e) { + changeZIndex($(e.element[0])); + } + + function handleDragEnter(e) { + e.target.classList.add('overlapped'); + } + + function handleDragStop(e) { + e.target.classList.remove('overlapped'); + } +}); diff --git a/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/00 Getting Started with Draggable.md b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/00 Getting Started with Draggable.md new file mode 100644 index 0000000000..a8d659f59d --- /dev/null +++ b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/00 Getting Started with Draggable.md @@ -0,0 +1,15 @@ +#include tutorials-intro-installationnote + +This tutorial guides you through the following steps: + +- Add a Draggable to a page. +- Configure Draggable options. +- Handle events (specific to Draggable, as well as common events). + +
+ +Each section in this tutorial covers a single configuration step. You can find the complete source code in the following GitHub repository: + +#include btn-open-github with { + href: "https://github.com/DevExpress-Examples/devextreme-getting-started-with-draggable" +} \ No newline at end of file diff --git a/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/05 Create Draggable.md b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/05 Create Draggable.md new file mode 100644 index 0000000000..1a79f86f69 --- /dev/null +++ b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/05 Create Draggable.md @@ -0,0 +1,342 @@ +--- + +##### jQuery + +[Add DevExtreme to your jQuery application](/concepts/58%20jQuery%20Components/05%20Add%20DevExtreme%20to%20a%20jQuery%20Application/00%20Add%20DevExtreme%20to%20a%20jQuery%20Application.md '/Documentation/Guide/jQuery_Components/Add_DevExtreme_to_a_jQuery_Application/') and use the following code to create a Draggable: + + + $(function() { + $("#draggable").dxDraggable({}); + }); + + + + + + + + + + + +
+ + + +##### Angular + +[Add DevExtreme to your Angular application](/concepts/40%20Angular%20Components/10%20Getting%20Started/03%20Add%20DevExtreme%20to%20an%20Angular%20CLI%20Application '/Documentation/Guide/Angular_Components/Getting_Started/Add_DevExtreme_to_an_Angular_CLI_Application/') and use the following code to create a Draggable: + + + + + + import { Component } from '@angular/core'; + import { type DxDraggableTypes } from 'devextreme-angular/ui/draggable'; + + + import { NgModule } from '@angular/core'; + import { BrowserModule } from '@angular/platform-browser'; + import { DxDraggableModule } from 'devextreme-angular'; + import { AppRoutingModule } from './app-routing.module'; + import { AppComponent } from './app.component'; + + @NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule, + AppRoutingModule, + DxDraggableModule + ], + providers: [], + bootstrap: [AppComponent] + }) + export class AppModule { } + + + { + // ... + "styles": [ + "node_modules/devextreme/dist/css/dx.fluent.blue.light.css", + ], + } + +##### Vue + +[Add DevExtreme to your Vue application](/concepts/55%20Vue%20Components/05%20Add%20DevExtreme%20to%20a%20Vue%20Application/00%20Add%20DevExtreme%20to%20a%20Vue%20Application.md '/Documentation/Guide/Vue_Components/Add_DevExtreme_to_a_Vue_Application/') and use the following code to create a Draggable: + + + + + + +##### React + +[Add DevExtreme to your React application](/concepts/50%20React%20Components/05%20Add%20DevExtreme%20to%20a%20React%20Application/00%20Add%20DevExtreme%20to%20a%20React%20Application.md '/Documentation/Guide/React_Components/Add_DevExtreme_to_a_React_Application/') and use the following code to create a Draggable: + + + import React, { JSX, useState } from 'react'; + import { Draggable, type DraggableTypes } from 'devextreme-react/draggable'; + import 'devextreme/dist/css/dx.fluent.blue.light.css'; + + function App(): JSX.Element { + return ( + + ); + } + + export default App; + +--- + +Draggable does not include default visual elements. Specify custom markup as follows: + +--- + +##### jQuery + + + $(function() { + $("#note-1").dxDraggable({}); + }); + + + + + + + + + + + +
+
+
+
Install New Router in Dev Room
+
Amelia Harper
+
+
+ + + +##### Angular + + + +
+
+
Install New Router in Dev Room
+
Amelia Harper
+
+
+ +##### Vue + + + + +##### React + + + import { Draggable } from 'devextreme-react/draggable'; + + function App(): JSX.Element { + return ( + +
+
+
Install New Router in Dev Room
+
Amelia Harper
+
+
+ ); + } + +--- + +This example creates four Draggable components inside a common `.board` container: + +--- + +##### jQuery + + + $(function() { + $("#note-1").dxDraggable({}); + $("#note-2").dxDraggable({}); + $("#note-3").dxDraggable({}); + $("#note-4").dxDraggable({}); + }); + + +
+
+
+
+
Install New Router in Dev Room
+
Amelia Harper
+
+
+ +
+
+
+
👨‍💻 Launch New Website
+
Brett Wade
+
+
+ +
+
+
+
Prepare 2026 Marketing Plan
+
Robert Reagan
+
+
+ +
+
+
+
🖥️ Approve Personal Computer Upgrade Plan
+
Bart Arnaz
+
+
+
+ +##### Angular + + +
+ +
+
+
Install New Router in Dev Room
+
Amelia Harper
+
+
+ + +
+
+
👨‍💻 Launch New Website
+
Brett Wade
+
+
+ + +
+
+
Prepare 2026 Marketing Plan
+
Robert Reagan
+
+
+ + +
+
+
🖥️ Approve Personal Computer Upgrade Plan
+
Bart Arnaz
+
+
+
+ +##### Vue + + + + +##### React + + + import { Draggable } from 'devextreme-react/draggable'; + + function App(): JSX.Element { + return ( +
+ +
+
+
Install New Router in Dev Room
+
Amelia Harper
+
+
+ + +
+
+
👨‍💻 Launch New Website
+
Brett Wade
+
+
+ + +
+
+
Prepare 2026 Marketing Plan
+
Robert Reagan
+
+
+ + +
+
+
🖥️ Approve Personal Computer Upgrade Plan
+
Bart Arnaz
+
+
+
+ ); + } + +--- diff --git a/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/10 Configure Draggable Options.md b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/10 Configure Draggable Options.md new file mode 100644 index 0000000000..57c78fecc2 --- /dev/null +++ b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/10 Configure Draggable Options.md @@ -0,0 +1,69 @@ +This example specifies the [boundary](/Documentation/ApiReference/UI_Components/dxDraggable/Configuration/#boundary/) property to constrain Draggable movement inside the `.board` container: + +--- + +##### jQuery + + + $(function() { + $("#note-1").dxDraggable({ + boundary: '.board' + }); + + // ... + }); + +##### Angular + + +
+ + + + + +
+ +##### Vue + + + + +##### React + + + import { Draggable } from 'devextreme-react/draggable'; + + function App(): JSX.Element { + return ( +
+ + {/* ... */} + + + {/* ... */} +
+ ); + } + +--- diff --git a/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/15 Handle Events.md b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/15 Handle Events.md new file mode 100644 index 0000000000..724db5cd14 --- /dev/null +++ b/concepts/05 UI Components/Draggable/05 Getting Started with Draggable/15 Handle Events.md @@ -0,0 +1,296 @@ +This example specifies an [onDragStart](/Documentation/ApiReference/UI_Components/dxDraggable/Configuration/#onDragStart) handler to update card overlapping as follows: + +--- + +##### jQuery + + + $(function() { + let z = 1; + + $("#note-1").dxDraggable({ + onDragStart(e) { + changeZIndex($(e.element[0])); + } + // ... + }); + + function changeZIndex(el) { + el.css("z-index", z); + z++; + } + }); + +##### Angular + + +
+ + + +
+ + + import { type DxDraggableTypes } from 'devextreme-angular/ui/draggable'; + + // ... + export class AppComponent { + z = 1; + + changeZIndex(element: HTMLElement) { + element.style.zIndex = this.z.toString(); + this.z++; + } + + handleDragStart(e: DxDraggableTypes.DragStartEvent) { + this.changeZIndex(e.element); + } + } + +##### Vue + + + + + + +##### React + + + import React, { JSX, useState, useCallback } from 'react'; + import { Draggable, type DraggableTypes } from 'devextreme-react/draggable'; + + function App(): JSX.Element { + const [, setZ] = useState(1); + + const changeZIndex = useCallback((element: HTMLElement) => { + setZ((prevValue) => { + element.style.zIndex = prevValue.toString(); + return prevValue + 1; + }); + }, []); + + const handleDragStart = useCallback((e: DraggableTypes.DragStartEvent) => { + changeZIndex(e.element); + }, []); + + return ( +
+ + + {/* ... */} +
+ ); + } + +--- + +This example also specifies handlers for four common events (not specific to Draggable): + +- `click` +- `dxdragenter` +- `dxdragleave` +- `dxdrop` + +--- + +##### jQuery + +To attach handlers to common events, call [Draggable.on()](/Documentation/ApiReference/UI_Components/dxDraggable/Methods/#onevents) as follows: + + + $(function() { + $("#note-1").dxDraggable({ + group: 'cards', + + // ... + }).on({ + "click": handleClick, + "dxdragenter": handleDragEnter, + "dxdragleave": handleDragStop, + "dxdrop": handleDragStop, + }); + + // ... + + function handleClick(e) { + changeZIndex($(e.currentTarget)); + } + + function handleDragEnter(e) { + e.target.classList.add('overlapped'); + } + + function handleDragStop(e) { + e.target.classList.remove('overlapped'); + } + }); + +##### Angular + +To attach handlers to common events, call the [on()](/Documentation/ApiReference/Common/Utils/events/#onelement_eventName_handler) utility method within [Draggable.onInitialized()](/Documentation/ApiReference/UI_Components/dxDraggable/Configuration/#onInitialized) as follows: + + +
+ + + +
+ + + import { type DxDraggableTypes } from 'devextreme-angular/ui/draggable'; + import { EventObject } from 'devextreme/common/core/events'; + import { on } from "devextreme/events"; + + // ... + export class AppComponent { + handleClick(e: EventObject) { + this.changeZIndex(e.currentTarget as HTMLElement); + } + + handleDragEnter(e: EventObject) { + const target: HTMLElement = e.target as HTMLElement; + + target.classList.add('overlapped'); + } + + handleDragStop(e: EventObject) { + const target: HTMLElement = e.target as HTMLElement; + + target.classList.remove('overlapped'); + } + + handleInit(e: DxDraggableTypes.InitializedEvent) { + on(e.element!, 'click', this.handleClick.bind(this)); + + on(e.element!, 'dxdragenter', this.handleDragEnter); + + on(e.element!, 'dxdragleave', this.handleDragStop); + on(e.element!, 'dxdrop', this.handleDragStop); + } + } + +##### Vue + +To attach handlers to common events, call the [on()](/Documentation/ApiReference/Common/Utils/events/#onelement_eventName_handler) utility method within [Draggable.onInitialized()](/Documentation/ApiReference/UI_Components/dxDraggable/Configuration/#onInitialized) as follows: + + + + + + +##### React + +To attach handlers to common events, call the [on()](/Documentation/ApiReference/Common/Utils/events/#onelement_eventName_handler) utility method within [Draggable.onInitialized()](/Documentation/ApiReference/UI_Components/dxDraggable/Configuration/#onInitialized) as follows: + + + import React, { JSX, useState, useCallback } from 'react'; + import { Draggable, type DraggableTypes } from 'devextreme-react/draggable'; + import { on } from 'devextreme/common/core/events'; + import { type EventObject } from 'devextreme/common/core/events'; + + function App(): JSX.Element { + const handleClick = useCallback((e: EventObject) => { + changeZIndex(e.currentTarget as HTMLElement); + }, []); + + const handleDragEnter = useCallback((e: EventObject) => { + const target: HTMLElement = e.target as HTMLElement; + target.classList.add('overlapped'); + }, []); + + const handleDragStop = useCallback((e: EventObject) => { + const target: HTMLElement = e.target as HTMLElement; + target.classList.remove('overlapped'); + }, []); + + const handleInit = useCallback((e: DraggableTypes.InitializedEvent) => { + on(e.element!, 'click', handleClick); + on(e.element!, 'dxdragenter', handleDragEnter); + on(e.element!, 'dxdragleave', handleDragStop); + on(e.element!, 'dxdrop', handleDragStop); + }, []); + + return ( +
+ + + {/* ... */} +
+ ); + } + +--- + +[note] Specify an identical [group](/Documentation/ApiReference/UI_Components/dxDraggable/Configuration/#group) value for all Draggable instances to ensure the components interact with each other (in `dxdragenter`, `dxdragleave`, and `dxdrop` handlers).