cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - Activehtmlicon-personicon-teamoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External CSS

These stylesheets will be added in this order and before the code you write in the CSS editor. You can also add another Pen here, and it will pull the CSS from it. Try typing "font" or "ribbon" below.

Quick-add: + add another resource

Add External JavaScript

These scripts will run in this order and before the code in the JavaScript editor. You can also link to another Pen here, and it will run the JavaScript from it. Also try typing the name of any popular library.

Quick-add: + add another resource

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

            
              $green: #B0DE6B
$blue: #76C9DE
$dark-gray: #948F8F
$light-gray: #ddd

body
  background: $light-gray

*
  box-sizing: border-box

.dnd-example
  display: flex
  flex-wrap: wrap
  width: 740px
  padding: 30px
  margin: 100px auto 0
  background: white
  font-family: sans-serif
  font-size: 19px
  text-align: center

  &,
  div
    border-radius: 10px
    user-select: none

  &.dragging *
    cursor: grabbing

.drop-description
  width: 100%
  font-weight: 300
  margin: 1em 0 0

.dnd-source-objects
  margin-right: 30px

.dnd-source-object
  width: 240px
  line-height: 38px
  border-radius: 10px
  font-weight: bold
  font-size: 24px
  color: rgba(0,0,0,.2)
  cursor: grab

  &:not(:last-child)
    margin: 0 0 10px

  &.green
    background: $green

  &.blue
    background: $blue

.dnd-drop-targets
  background: $dark-gray
  flex: 1
  padding: 15px

.dnd-drop-target
  position: relative
  background: white
  line-height: 50px
  font-weight: 300
  overflow: hidden

  &:not(:last-child)
    margin: 0 0 10px

  &.green:before,
  &.blue:after
    content: ''
    position: absolute
    left: 0
    width: 20px
    height: 100%
    background: $green

  &.blue:after
    background: $blue

  &.green.blue:after
    left: 20px

  &.active.hover
    &:after,
    &:before
      display: none

  &.active-green.active
    box-shadow: 0 0 0 3px $dark-gray, 0 0 0 4px $green
    &.hover
      background: $green

  &.active-blue.active
    box-shadow: 0 0 0 3px $dark-gray, 0 0 0 4px $blue
    &.hover
      background: $blue

  &.disabled
    opacity: .2
    cursor: no-drop

.dnd-draggable.dragging
  z-index: 1
  pointer-events: none
  box-shadow: 0 2px 5px rgba(0,0,0,.8)
            
          
!
            
              {div, p} = React.DOM

LEFT_BUTTON = 0
DRAG_THRESHOLD = 3 # pixels

document.addEventListener 'DOMContentLoaded', ->
  React.renderComponent Example(), document.body

Example = React.createClass
  getInitialState: ->
    currentDragItem: null

  render: ->
    div
      className: "dnd-example #{'dragging' if @state.currentDragItem}"
      children: [
        SourceObjects
          onDragStart: @onDragStart
          onDragStop: @onDragStop
        DropTargets
          currentDragItem: @state.currentDragItem
          onDrop: @onDrop
        @dropDescription()
      ]

  onDragStart: (details) ->
    @setState currentDragItem: details

  onDragStop: ->
    @setState currentDragItem: null

  onDrop: (target) ->
    @setState lastDrop:
      source: @state.currentDragItem
      target: target

  dropDescription: ->
    if drop = @state.lastDrop
      p
        className: 'drop-description'
        children: "Dropped source #{drop.source.type}-#{drop.source.index} on target #{drop.target.index}"

SourceObjects = React.createClass
  render: ->
    div
      className: 'dnd-source-objects'
      children: for object, i in @objects()
        SourceObject
          type: object.type
          index: i + 1
          children: i + 1
          onDragStart: @props.onDragStart
          onDragStop: @props.onDragStop

  objects: ->
    _.flatten [
      { type: 'green' } for i in [0..2]
      { type: 'blue' } for i in [0..2]
    ]

SourceObject = React.createClass
  render: ->
    Draggable
      className: "dnd-source-object #{@props.type}"
      children: @props.children
      onDragStart: @props.onDragStart
      onDragStop: @props.onDragStop
      dragData: @dragData

  dragData: ->
    type: @props.type
    index: @props.index

Draggable = React.createClass
  getInitialState: ->
    mouseDown: false
    dragging: false

  render: ->
    @transferPropsTo div
      style: @style()
      className: "dnd-draggable #{'dragging' if @state.dragging}"
      children: @props.children
      onMouseDown: @onMouseDown

  style: ->
    if @state.dragging
      position: 'absolute'
      left: @state.left
      top: @state.top
    else
      {}

  onMouseDown: (event) ->
    if event.button == LEFT_BUTTON
      event.stopPropagation()
      @addEvents()
      pageOffset = @getDOMNode().getBoundingClientRect()
      @setState
        mouseDown: true
        originX: event.pageX
        originY: event.pageY
        elementX: pageOffset.left
        elementY: pageOffset.top

  onMouseMove: (event) ->
    deltaX = event.pageX - @state.originX
    deltaY = event.pageY - @state.originY
    distance = Math.abs(deltaX) + Math.abs(deltaY)

    if !@state.dragging and distance > DRAG_THRESHOLD
      @setState dragging: true
      @props.onDragStart? @props.dragData?()

    if @state.dragging
      @setState
        left: @state.elementX + deltaX + document.body.scrollLeft
        top: @state.elementY + deltaY + document.body.scrollTop

  onMouseUp: ->
    @removeEvents()
    if @state.dragging
      @props.onDragStop()
      @setState dragging: false

  addEvents: ->
    document.addEventListener 'mousemove', @onMouseMove
    document.addEventListener 'mouseup', @onMouseUp

  removeEvents: ->
    document.removeEventListener 'mousemove', @onMouseMove
    document.removeEventListener 'mouseup', @onMouseUp

DropTargets = React.createClass
  render: ->
    div
      className: 'dnd-drop-targets'
      children: for target, i in @targets()
        DropTarget
          target: target
          index: i
          currentDragItem: @props.currentDragItem
          onDrop: @props.onDrop

  targets: ->
    [
      { accepts: ['blue'] }
      { accepts: ['green'] }
      { accepts: ['blue', 'green'] }
      { accepts: [] }
    ]

DropTarget = React.createClass
  getInitialState: ->
    hover: false

  render: ->
    div
      className: @classes()
      children: 'accepts ' + @acceptsDescription()
      onMouseEnter: => @setState hover: true
      onMouseLeave: => @setState hover: false
      onMouseUp: @onDrop

  classes: ->
    [
      'dnd-drop-target'
      "#{@props.target.accepts.join ' '}"
      'active' if @active()
      'active-green' if @active() and @props.currentDragItem.type == 'green'
      'active-blue' if @active() and @props.currentDragItem.type == 'blue'
      'disabled' if @disabled()
      'hover' if @state.hover
    ].join ' '

  active: ->
    item = @props.currentDragItem
    item and item.type in @props.target.accepts

  disabled: ->
    item = @props.currentDragItem 
    item and item.type not in @props.target.accepts

  acceptsDescription: ->
    if @props.target.accepts.length > 0
      @props.target.accepts.join ' & '
    else
      'nothing'

  onDrop: ->
    if @active()
      @props.onDrop? index: @props.index + 1

            
          
!
999px
Close

Asset uploading is a PRO feature.

As a PRO member, you can drag-and-drop upload files here to use as resources. Images, Libraries, JSON data... anything you want. You can even edit them anytime, like any other code on CodePen.

Go PRO

Loading ..................

Console