Full Code of Shopify/draggable for AI

main 8a1eed57f3ab cached
347 files
616.7 KB
167.5k tokens
631 symbols
1 requests
Download .txt
Showing preview only (695K chars total). Download the full file or copy to clipboard to get everything.
Repository: Shopify/draggable
Branch: main
Commit: 8a1eed57f3ab
Files: 347
Total size: 616.7 KB

Directory structure:
gitextract_gnoywtw_/

├── .changeset/
│   ├── README.md
│   └── config.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github/
│   ├── .probots.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yaml
│   └── workflows/
│       ├── changelog.yml
│       ├── ci.yml
│       ├── cla.yml
│       ├── release.yml
│       └── snapit.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── .vscode/
│   ├── extensions.json
│   ├── launch.json
│   └── settings.json
├── AUTHORS
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── babel.config.js
├── config/
│   └── typescript/
│       └── rollup-plugin-includepaths.d.ts
├── doc/
│   └── typescript.md
├── esdoc.json
├── examples/
│   ├── .babelrc
│   ├── .browserslistrc
│   ├── .editorconfig
│   ├── .eslintignore
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .nvmrc
│   ├── .prettierignore
│   ├── .prettierrc
│   ├── .stylelintignore
│   ├── .stylelintrc
│   ├── .vscode/
│   │   ├── extensions.json
│   │   └── settings.json
│   ├── README.md
│   ├── package.json
│   ├── postcss.config.js
│   ├── src/
│   │   ├── components/
│   │   │   ├── Analytics/
│   │   │   │   └── index.js
│   │   │   ├── Block/
│   │   │   │   ├── Block.html
│   │   │   │   ├── Block.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Brand/
│   │   │   │   ├── Brand.html
│   │   │   │   ├── Brand.scss
│   │   │   │   ├── Logo.html
│   │   │   │   ├── Wordmark.html
│   │   │   │   ├── keyframes.scss
│   │   │   │   └── props.scss
│   │   │   ├── Button/
│   │   │   │   ├── Button.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Document/
│   │   │   │   ├── Favicon.html
│   │   │   │   ├── Head.html
│   │   │   │   └── SocialShare.html
│   │   │   ├── GridOverlay/
│   │   │   │   └── GridOverlay.scss
│   │   │   ├── Hamburger/
│   │   │   │   ├── Hamburger.html
│   │   │   │   ├── Hamburger.scss
│   │   │   │   ├── keyframes.scss
│   │   │   │   └── props.scss
│   │   │   ├── Handle/
│   │   │   │   ├── DragHandle.scss
│   │   │   │   ├── NopeHandle.scss
│   │   │   │   └── props.scss
│   │   │   ├── Heading/
│   │   │   │   ├── Heading.scss
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Link/
│   │   │   │   └── Link.scss
│   │   │   ├── Main/
│   │   │   │   ├── Main.scss
│   │   │   │   └── props.scss
│   │   │   ├── MobileNav/
│   │   │   │   ├── index.js
│   │   │   │   └── props.scss
│   │   │   ├── Navigation/
│   │   │   │   ├── NavList.html
│   │   │   │   ├── Navigation.html
│   │   │   │   └── Navigation.scss
│   │   │   ├── Page/
│   │   │   │   └── Page.scss
│   │   │   ├── PageHeader/
│   │   │   │   ├── PageHeader.html
│   │   │   │   └── PageHeader.scss
│   │   │   ├── PaperStack/
│   │   │   │   ├── PaperStack.scss
│   │   │   │   ├── PaperStackItem.html
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Patterns/
│   │   │   │   ├── Patterns.scss
│   │   │   │   ├── keyframes.scss
│   │   │   │   └── props.scss
│   │   │   ├── PillSwitch/
│   │   │   │   ├── PillSwitch.html
│   │   │   │   ├── PillSwitch.scss
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Plate/
│   │   │   │   ├── Plate.html
│   │   │   │   ├── Plate.scss
│   │   │   │   ├── index.js
│   │   │   │   ├── keyframes.scss
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Sidebar/
│   │   │   │   ├── Sidebar.html
│   │   │   │   └── Sidebar.scss
│   │   │   ├── StackedList/
│   │   │   │   ├── StackedList.scss
│   │   │   │   ├── StackedListItem.html
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   └── Svg/
│   │   │       └── Svg.scss
│   │   ├── content/
│   │   │   ├── Draggable/
│   │   │   │   └── DragEvents/
│   │   │   │       ├── DragEvents.html
│   │   │   │       ├── DragEvents.scss
│   │   │   │       └── index.js
│   │   │   ├── Droppable/
│   │   │   │   └── UniqueDropzone/
│   │   │   │       ├── UniqueDropzone.html
│   │   │   │       ├── UniqueDropzone.scss
│   │   │   │       └── index.js
│   │   │   ├── Home/
│   │   │   │   ├── Home.html
│   │   │   │   ├── Home.scss
│   │   │   │   └── index.js
│   │   │   ├── Plugins/
│   │   │   │   ├── Collidable/
│   │   │   │   │   ├── Collidable.html
│   │   │   │   │   ├── Collidable.scss
│   │   │   │   │   ├── index.js
│   │   │   │   │   └── props.scss
│   │   │   │   ├── Snappable/
│   │   │   │   │   ├── Snappable.html
│   │   │   │   │   ├── Snappable.scss
│   │   │   │   │   └── index.js
│   │   │   │   ├── SortAnimation/
│   │   │   │   │   ├── SortAnimation.html
│   │   │   │   │   ├── SortAnimation.scss
│   │   │   │   │   └── index.js
│   │   │   │   └── SwapAnimation/
│   │   │   │       ├── SwapAnimation.html
│   │   │   │       ├── SwapAnimation.scss
│   │   │   │       └── index.js
│   │   │   ├── Sortable/
│   │   │   │   ├── MultipleContainers/
│   │   │   │   │   ├── MultipleContainers.html
│   │   │   │   │   ├── MultipleContainers.scss
│   │   │   │   │   └── index.js
│   │   │   │   ├── SimpleList/
│   │   │   │   │   ├── SimpleList.html
│   │   │   │   │   ├── SimpleList.scss
│   │   │   │   │   └── index.js
│   │   │   │   └── Transformed/
│   │   │   │       ├── Transformed.html
│   │   │   │       ├── Transformed.scss
│   │   │   │       └── index.js
│   │   │   ├── Swappable/
│   │   │   │   ├── Flexbox/
│   │   │   │   │   ├── Flexbox.html
│   │   │   │   │   ├── Flexbox.scss
│   │   │   │   │   └── index.js
│   │   │   │   ├── Floated/
│   │   │   │   │   ├── Floated.html
│   │   │   │   │   ├── Floated.scss
│   │   │   │   │   └── index.js
│   │   │   │   └── GridLayout/
│   │   │   │       ├── GridLayout.html
│   │   │   │       ├── GridLayout.scss
│   │   │   │       └── index.js
│   │   │   └── index.js
│   │   ├── scripts/
│   │   │   ├── examples-app.js
│   │   │   └── utils/
│   │   │       ├── debounce.js
│   │   │       └── flip-sign.js
│   │   ├── styles/
│   │   │   ├── examples-app.scss
│   │   │   ├── examples-theme/
│   │   │   │   ├── _border.scss
│   │   │   │   ├── _breakpoint.scss
│   │   │   │   ├── _color.scss
│   │   │   │   ├── _cursor.scss
│   │   │   │   ├── _duration.scss
│   │   │   │   ├── _easing.scss
│   │   │   │   ├── _font-stack.scss
│   │   │   │   ├── _layout-length.scss
│   │   │   │   ├── _spacing.scss
│   │   │   │   ├── _type-scale.scss
│   │   │   │   ├── _z-index.scss
│   │   │   │   └── examples-theme.scss
│   │   │   ├── reset.scss
│   │   │   └── utils/
│   │   │       ├── global/
│   │   │       │   ├── _animation.scss
│   │   │       │   ├── _layout.scss
│   │   │       │   ├── _typography.scss
│   │   │       │   └── global-utils.scss
│   │   │       └── shared/
│   │   │           ├── animation.scss
│   │   │           ├── functions.scss
│   │   │           ├── layout.scss
│   │   │           └── typography.scss
│   │   └── views/
│   │       ├── collidable.html
│   │       ├── data-pages.json
│   │       ├── drag-events.html
│   │       ├── flexbox.html
│   │       ├── floated.html
│   │       ├── grid-layout.html
│   │       ├── index.html
│   │       ├── multiple-containers.html
│   │       ├── simple-list.html
│   │       ├── snappable.html
│   │       ├── sort-animation.html
│   │       ├── swap-animation.html
│   │       ├── templates/
│   │       │   └── document.html
│   │       ├── transformed.html
│   │       └── unique-dropzone.html
│   └── tools/
│       ├── index.js
│       ├── server.js
│       ├── tasks/
│       │   ├── index.js
│       │   ├── scripts.js
│       │   ├── styles.js
│       │   └── views.js
│       ├── watch.js
│       ├── webpack.config.js
│       └── webpack.plugins.js
├── index.d.ts
├── jest.config.js
├── package.json
├── rollup.config.ts
├── rollup.development.config.ts
├── src/
│   ├── Draggable/
│   │   ├── DragEvent/
│   │   │   ├── DragEvent.ts
│   │   │   ├── README.md
│   │   │   ├── index.ts
│   │   │   └── tests/
│   │   │       └── DragEvent.test.ts
│   │   ├── Draggable.js
│   │   ├── DraggableEvent/
│   │   │   ├── DraggableEvent.ts
│   │   │   ├── README.md
│   │   │   └── index.ts
│   │   ├── Emitter/
│   │   │   ├── Emitter.ts
│   │   │   ├── index.ts
│   │   │   └── tests/
│   │   │       └── Emitter.test.ts
│   │   ├── Plugins/
│   │   │   ├── Announcement/
│   │   │   │   ├── Announcement.js
│   │   │   │   ├── README.md
│   │   │   │   └── index.js
│   │   │   ├── Focusable/
│   │   │   │   ├── Focusable.js
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── Focusable.test.js
│   │   │   ├── Mirror/
│   │   │   │   ├── Mirror.js
│   │   │   │   ├── MirrorEvent/
│   │   │   │   │   ├── MirrorEvent.ts
│   │   │   │   │   ├── README.md
│   │   │   │   │   └── index.ts
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── Mirror.test.js
│   │   │   ├── README.md
│   │   │   ├── Scrollable/
│   │   │   │   ├── README.md
│   │   │   │   ├── Scrollable.js
│   │   │   │   └── index.js
│   │   │   └── index.js
│   │   ├── README.md
│   │   ├── Sensors/
│   │   │   ├── DragSensor/
│   │   │   │   ├── DragSensor.js
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── DragSensor.test.js
│   │   │   ├── ForceTouchSensor/
│   │   │   │   ├── ForceTouchSensor.js
│   │   │   │   ├── README.md
│   │   │   │   └── index.js
│   │   │   ├── MouseSensor/
│   │   │   │   ├── MouseSensor.js
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── MouseSensor.test.js
│   │   │   ├── README.md
│   │   │   ├── Sensor/
│   │   │   │   ├── README.md
│   │   │   │   ├── Sensor.js
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── Sensor.test.js
│   │   │   ├── SensorEvent/
│   │   │   │   ├── README.md
│   │   │   │   ├── SensorEvent.ts
│   │   │   │   └── index.ts
│   │   │   ├── TouchSensor/
│   │   │   │   ├── README.md
│   │   │   │   ├── TouchSensor.js
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── TouchSensor.test.js
│   │   │   └── index.js
│   │   ├── index.js
│   │   └── tests/
│   │       └── Draggable.test.js
│   ├── Droppable/
│   │   ├── Droppable.js
│   │   ├── DroppableEvent/
│   │   │   ├── DroppableEvent.ts
│   │   │   ├── README.md
│   │   │   └── index.ts
│   │   ├── README.md
│   │   ├── index.js
│   │   └── tests/
│   │       └── Droppable.test.js
│   ├── Plugins/
│   │   ├── Collidable/
│   │   │   ├── Collidable.js
│   │   │   ├── CollidableEvent/
│   │   │   │   ├── CollidableEvent.ts
│   │   │   │   ├── README.md
│   │   │   │   └── index.ts
│   │   │   ├── README.md
│   │   │   └── index.js
│   │   ├── README.md
│   │   ├── ResizeMirror/
│   │   │   ├── README.md
│   │   │   ├── ResizeMirror.ts
│   │   │   ├── index.ts
│   │   │   └── tests/
│   │   │       └── ResizeMirror.test.ts
│   │   ├── Snappable/
│   │   │   ├── README.md
│   │   │   ├── Snappable.js
│   │   │   ├── SnappableEvent/
│   │   │   │   ├── README.md
│   │   │   │   ├── SnappableEvent.ts
│   │   │   │   └── index.ts
│   │   │   └── index.js
│   │   ├── SortAnimation/
│   │   │   ├── README.md
│   │   │   ├── SortAnimation.js
│   │   │   └── index.js
│   │   ├── SwapAnimation/
│   │   │   ├── README.md
│   │   │   ├── SwapAnimation.ts
│   │   │   └── index.ts
│   │   └── index.js
│   ├── Sortable/
│   │   ├── README.md
│   │   ├── Sortable.js
│   │   ├── SortableEvent/
│   │   │   ├── README.md
│   │   │   ├── SortableEvent.ts
│   │   │   └── index.ts
│   │   ├── index.js
│   │   └── tests/
│   │       └── Sortable.test.js
│   ├── Swappable/
│   │   ├── README.md
│   │   ├── Swappable.js
│   │   ├── SwappableEvent/
│   │   │   ├── README.md
│   │   │   ├── SwappableEvent.ts
│   │   │   └── index.ts
│   │   ├── index.js
│   │   └── tests/
│   │       └── Swappable.test.js
│   ├── index.js
│   └── shared/
│       ├── AbstractEvent/
│       │   ├── AbstractEvent.ts
│       │   ├── README.md
│       │   ├── index.ts
│       │   └── tests/
│       │       └── AbstractEvent.test.ts
│       ├── AbstractPlugin/
│       │   ├── AbstractPlugin.ts
│       │   ├── README.md
│       │   └── index.ts
│       ├── README.md
│       ├── types.ts
│       └── utils/
│           ├── README.md
│           ├── closest/
│           │   ├── README.md
│           │   ├── closest.ts
│           │   ├── index.ts
│           │   └── tests/
│           │       └── closest.test.ts
│           ├── decorators/
│           │   ├── AutoBind.ts
│           │   └── index.ts
│           ├── distance/
│           │   ├── distance.ts
│           │   └── index.ts
│           ├── index.ts
│           ├── requestNextAnimationFrame/
│           │   ├── README.md
│           │   ├── index.ts
│           │   └── requestNextAnimationFrame.ts
│           └── touchCoords/
│               ├── index.ts
│               └── touchCoords.ts
├── test/
│   ├── environment.ts
│   ├── helper.ts
│   ├── helpers/
│   │   ├── constants.ts
│   │   ├── environment.ts
│   │   ├── event.ts
│   │   ├── index.ts
│   │   ├── module.ts
│   │   ├── plugin.ts
│   │   └── sensor.ts
│   ├── matchers/
│   │   ├── dom-event.ts
│   │   ├── event.ts
│   │   ├── index.ts
│   │   ├── order.ts
│   │   ├── sensor.ts
│   │   └── utils.ts
│   └── setup.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .changeset/README.md
================================================
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)


================================================
FILE: .changeset/config.json
================================================
{
  "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
  "changelog": ["@changesets/changelog-github", {"repo": "Shopify/draggable"}],
  "commit": false,
  "fixed": [],
  "linked": [],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": []
}


================================================
FILE: .editorconfig
================================================
# editorconfig.org
root = true

[*]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

# Markdown syntax specifies that trailing whitespaces can be meaningful,
# so let’s not trim those. e.g. 2 trailing spaces = linebreak (<br />)
# See https://daringfireball.net/projects/markdown/syntax#p
[*.md]
trim_trailing_whitespace = false


================================================
FILE: .eslintignore
================================================
build/


================================================
FILE: .eslintrc.js
================================================
const path = require('path');

module.exports = {
  extends: [
    'plugin:@shopify/typescript',
    'plugin:@shopify/jest',
    'plugin:@shopify/prettier',
  ],
  parser: '@typescript-eslint/parser',
  env: {
    browser: true,
    node: true,
  },
  rules: {
    'jest/valid-title': 'off',
  },
  settings: {
    'import/resolver': {
      node: {
        paths: [
          path.resolve(__dirname, 'src'),
          path.resolve(__dirname, 'test'),
        ],
      },
    },
  },
};


================================================
FILE: .github/.probots.yml
================================================
enabled:
  - cla


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
> Please use this template to help contributors get a detailed description of the issue or feature.

**For support questions, please use stackoverflow.** This repository's issues are reserved for feature requests and bug reports.

### 1. Apply either the `bug` or `feature-request` label

_Select appropriate label in right sidebar..._

### 2. Describe the `bug` or `feature`

_Feature or expected behaviour explanation..._

### 3. If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem

_Please remember that with sample code it's easier to reproduce the bug and it's much faster to fix it._

### 4. Please tell us about your environment:

- **Library version:** [1.X.X | v1 stable | etc...]
- **Browsers:** [all | Chrome vX | Firefox vX | Safari vX | Edge vX | iOS vX | Android vX | etc...]
- **Tech stack:** [all | TypeScript vX | ES6/7 | ES5 | React | etc...]
- **Other information:** [Detailed explanation | Stacktraces | Related issues | Suggestions how to fix | Links for us to have context | etc...]


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!-- Thank you for submitting a pull request! Please make sure you have read the [contribution guidelines](https://github.com/Shopify/draggable/blob/main/CONTRIBUTING.md) before proceeding. -->

### This PR implements or fixes...

<!-- Explain your changes -->

### This PR closes the following issues...

<!-- If applicable -->

### Does this PR require the Docs to be updated?

…

### Does this PR require new tests?

…

### This branch been tested on... _(click all that apply / add new items)_

**Browsers:**

- [ ] Chrome _version_
- [ ] Firefox _version_
- [ ] Safari _version_
- [ ] IE / Edge _version_
- [ ] iOS Browser _version_
- [ ] Android Browser _version_


================================================
FILE: .github/dependabot.yaml
================================================
version: 2
updates:
  - package-ecosystem: github-actions
    directory: "/"
    schedule:
      interval: weekly


================================================
FILE: .github/workflows/changelog.yml
================================================
name: Changelog

on:
  pull_request:
    types:
      - labeled
      - unlabeled
      - opened
      - synchronize
      - reopened

jobs:
  check:
    if: |
      !contains(github.event.pull_request.head.ref, 'changeset-release') &&
      !contains(github.event.pull_request.labels.*.name, '🤖Skip Changelog')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout branch
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
        with:
          node-version: 20.17.0

      - name: Check for Changeset
        run: npx @changesets/cli status --since="origin/main"


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout branch
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          fetch-depth: 2

      - uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
        with:
          node-version: '20.17.0'

      - name: Install dependencies
        run: yarn --frozen-lockfile

      - name: Lint
        run: yarn lint

      - name: Library typecheck
        run: yarn type-check

      - name: Build
        run: yarn build

      - name: Build Development
        run: yarn build:development

      - name: Test
        run: yarn test

      - name: Install dependencies
        working-directory: examples/
        run: yarn --frozen-lockfile

      - name: Build examples
        working-directory: examples/
        run: yarn build


================================================
FILE: .github/workflows/cla.yml
================================================
# .github/workflows/cla.yml
name: Contributor License Agreement (CLA)

on:
  pull_request_target:
    types: [opened, synchronize]
  issue_comment:
    types: [created]

jobs:
  cla:
    runs-on: ubuntu-latest
    if: |
      (github.event.issue.pull_request
        && !github.event.issue.pull_request.merged_at
        && contains(github.event.comment.body, 'signed')
      )
      || (github.event.pull_request && !github.event.pull_request.merged)
    steps:
      - uses: Shopify/shopify-cla-action@v1
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          cla-token: ${{ secrets.CLA_TOKEN }}

================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    branches:
      - main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
      id-token: write
    steps:
      - name: Checkout Repo
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Node.js
        uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
        with:
          node-version: '20.17.0'
          registry-url: 'https://registry.npmjs.org'
          cache: 'yarn'

      - name: Update NPM
        run: npm install -g npm@11.5.1

      - name: Install dependencies
        run: yarn --frozen-lockfile

      - name: Create release Pull Request or publish to NPM
        id: changesets
        uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc # v1.5.3
        with:
          publish: yarn release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/snapit.yml
================================================
name: Snapshot

on:
  issue_comment:
    types:
      - created

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  snapshot:
    name: Snapshot Release
    if: |
      github.event.issue.pull_request &&
      (startsWith(github.event.comment.body, '/snapit') || startsWith(github.event.comment.body, '/snapshot-release'))
    runs-on: ubuntu-latest
    steps:
      - name: Enforce permission requirement
        uses: prince-chrismc/check-actor-permissions-action@72c9eb81384517cbc49d765edc200af3131897ce # v1.0.0
        with:
          permission: write

      - name: Add initial reaction
        uses: peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d # v2.1.1
        with:
          comment-id: ${{ github.event.comment.id }}
          reactions: eyes

      - name: Get PR branch
        uses: xt0rted/pull-request-comment-branch@653a7d5ca8bd91d3c5cb83286063314d0b063b8e # v1.4.0
        id: comment-branch

      - name: Set latest commit status as pending
        uses: myrotvorets/set-commit-status-action@7b093ccbb10e14939b7a4ae2630fe4cbc67c0651 # v2.0.1
        with:
          sha: ${{ steps.comment-branch.outputs.head_sha }}
          token: ${{ secrets.GITHUB_TOKEN }}
          status: pending

      - name: Validate pull request
        uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
        id: pr_data
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          script: |
            try {
              const pullRequest = await github.rest.pulls.get({
                owner: context.repo.owner,
                repo: context.repo.repo,
                pull_number: context.issue.number,
              })

              // Pull request from fork
              if (context.payload.repository.full_name !== pullRequest.data.head.repo.full_name) {
                const errorMessage = '`/snapit` is not supported on pull requests from forked repositories.'

                await github.rest.issues.createComment({
                  issue_number: context.issue.number,
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  body: errorMessage,
                })

                core.setFailed(errorMessage)
              }
            } catch (err) {
              core.setFailed(`Request failed with error ${err}`)
            }

      - name: Checkout default branch
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0

      - name: Checkout pull request branch
        run: hub pr checkout ${{ github.event.issue.number }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Reset changeset entries on changeset-release/main branch
        run: |
          if [[ $(git branch --show-current) == 'changeset-release/main' ]]; then
            git checkout origin/main -- .changeset
          fi

      - name: Setup Node.js
        uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1
        with:
          node-version: '20.17.0'

      - name: Install dependencies
        run: yarn --frozen-lockfile

      - name: Create an .npmrc
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          cat << EOF > "$HOME/.npmrc"
            //registry.npmjs.org/:_authToken=$NPM_TOKEN
          EOF

      - name: Create and publish snapshot release
        uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
        id: snapshot-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          script: |
            const execa = require('execa')

            await execa.command('yarn changeset version --snapshot snapshot-release', { stdio: 'inherit' })

            const releaseProcess = execa.command('yarn release --no-git-tags --snapshot --tag snapshot-release')
            releaseProcess.stdout.pipe(process.stdout)

            const {stdout} = await releaseProcess

            const newTags = Array
              .from(stdout.matchAll(/New tag:\s+([^\s\n]+)/g))
              .map(([_, tag]) => tag)

            if (newTags.length) {
              const multiple = newTags.length > 1

              const body = (
                `🫰✨ **Thanks @${context.actor}! ` +
                `Your snapshot${multiple ? 's have' : ' has'} been published to npm.**\n\n` +
                `Test the snapshot${multiple ? 's' : ''} by updating your \`package.json\` ` +
                `with the newly published version${multiple ? 's' : ''}:\n` +
                newTags.map(tag => (
                  '```sh\n' +
                  `yarn add ${tag}\n` +
                  '```'
                )).join('\n')
              )
              await github.rest.issues.createComment({
                issue_number: context.issue.number,
                owner: context.repo.owner,
                repo: context.repo.repo,
                body,
              })
              core.setOutput('succeeded', 'true')
            } else {
              await github.rest.issues.createComment({
                issue_number: context.issue.number,
                owner: context.repo.owner,
                repo: context.repo.repo,
                body: `💥 **Snapshot release unsuccessful!** No tags have been found.\n\n` +
                      'Try running the command below and committing your changes.\n\n' +
                      '```sh\n' +
                      'yarn changeset\n' +
                      '```',
              })
              core.setOutput('succeeded', 'false')
            }

      - name: Add success reaction
        uses: peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d # v2.1.1
        if: ${{ steps.snapshot-release.outputs.succeeded == 'true' }}
        with:
          comment-id: ${{ github.event.comment.id }}
          reactions: rocket

      - name: Add failure reaction
        uses: peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d # v2.1.1
        if: ${{ steps.snapshot-release.outputs.succeeded == 'false' }}
        with:
          comment-id: ${{ github.event.comment.id }}
          reactions: confused

      - name: Fail workflow if snapshot failed
        uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
        if: ${{ steps.snapshot-release.outputs.succeeded == 'false' }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          script: |
            core.setFailed('No snapshot tags have been found')

      - name: Set latest commit status as ${{ job.status }}
        uses: myrotvorets/set-commit-status-action@7b093ccbb10e14939b7a4ae2630fe4cbc67c0651 # v2.0.1
        if: always()
        with:
          sha: ${{ steps.comment-branch.outputs.head_sha }}
          token: ${{ secrets.GITHUB_TOKEN }}
          status: ${{ job.status }}


================================================
FILE: .gitignore
================================================
# Ignore OS Specific files
.DS_Store

# Ignore the SASS cache
.sass-cache

# Logs
logs
*.log

# Dependency directory
# Deployed apps should consider commenting this line out:
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
node_modules

example.html

coverage/
docs/
build/
.rollup.cache/

.github/actions/**/*.js

# 'cause we are all yarny and stuff
package-lock.json


================================================
FILE: .nvmrc
================================================
v20.17.0


================================================
FILE: .prettierignore
================================================
build/


================================================
FILE: .prettierrc
================================================
"@shopify/prettier-config"


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "editorconfig.editorconfig",
    "esbenp.prettier-vscode"
  ]
}


================================================
FILE: .vscode/launch.json
================================================
{
  "version": "1.0.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Jest Tests",
      "program": "${workspaceRoot}/node_modules/.bin/jest",
      "console": "integratedTerminal",
      "args": [
          "-i",
          "--watchAll"
      ],
    }
  ]
}


================================================
FILE: .vscode/settings.json
================================================
{
  "files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true,
    "**/node_modules": true,
    ".rollup.cache": true,
    "coverage": true
  },
  "search.exclude": {
    "node_modules/**/*": true,
    ".rollup.cache/**/*": true,
    "coverage/**/*": true,
    "build/**/*": true,
    "docs/**/*": true
  },
  "[typescript]": {
    "editor.formatOnSave": false
  },
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "javascript.validate.enable": false,
  "eslint.validate": ["javascript"]
}


================================================
FILE: AUTHORS
================================================
Maintainer
----------
Shopify
https://github.com/Shopify

Original Authors
----------------
Max Hoffmann / max.hoffmann@shopify.com / @tsov
Curtis Dulmage / curtis.dulmage@shopify.com / @beefchimi


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 1.2.1

### Patch Changes

- [#661](https://github.com/Shopify/draggable/pull/661) [`f0194c4`](https://github.com/Shopify/draggable/commit/f0194c493f2e9dabd4267f3316995c153ed3d3eb) Thanks [@tsov](https://github.com/tsov)! - Removes npm token from release workflow

## 1.2.0

### Minor Changes

- [#658](https://github.com/Shopify/draggable/pull/658) [`bb778a4`](https://github.com/Shopify/draggable/commit/bb778a47a52c50e35fd20425e7e82280745a1e85) Thanks [@tsov](https://github.com/tsov)! - Upgrade to node version v20

## 1.1.4

### Patch Changes

- [#621](https://github.com/Shopify/draggable/pull/621) [`a14a290`](https://github.com/Shopify/draggable/commit/a14a2903032a02d160958d3e557ba8d09180c382) Thanks [@tsov](https://github.com/tsov)! - Add provenance statement

## 1.1.3

### Patch Changes

- [#586](https://github.com/Shopify/draggable/pull/586) [`c1df3a5`](https://github.com/Shopify/draggable/commit/c1df3a559ebd959a1054503ee423c6d76243fd0d) Thanks [@tsov](https://github.com/tsov)! - Adds AutoBind decorator

- [#590](https://github.com/Shopify/draggable/pull/590) [`f05efb3`](https://github.com/Shopify/draggable/commit/f05efb3850eb44d83a4de5c03f1ee526ea5e318b) Thanks [@tsov](https://github.com/tsov)! - Fixes VSCode search to exclude generated files/folders

- [#590](https://github.com/Shopify/draggable/pull/590) [`36e61b6`](https://github.com/Shopify/draggable/commit/36e61b6825c9c9911ce3ef5eb2ff962b091fd831) Thanks [@tsov](https://github.com/tsov)! - Converts ResizeMirror test to typescript

## 1.1.2

### Patch Changes

- [#579](https://github.com/Shopify/draggable/pull/579) [`bb23ff2`](https://github.com/Shopify/draggable/commit/bb23ff21f693b623e76c935d8ea4fb58ac57d36c) Thanks [@tsov](https://github.com/tsov)! - Convert CollidableEvent to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`9154a96`](https://github.com/Shopify/draggable/commit/9154a9683a0fecfdc4a4759319221ca59c43421a) Thanks [@tsov](https://github.com/tsov)! - Convert SensorEvent to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`74c35e5`](https://github.com/Shopify/draggable/commit/74c35e5aa4bd5c3bb7dcaf8cc432c4d5d932ee3f) Thanks [@tsov](https://github.com/tsov)! - Convert SwappableEvent to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`fb5354f`](https://github.com/Shopify/draggable/commit/fb5354ffc7688433ef12bcf8ca1b9f473f78cf06) Thanks [@tsov](https://github.com/tsov)! - Convert SortableEvent to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`7734961`](https://github.com/Shopify/draggable/commit/773496192fc9a56f6cd24ec7a45f34c79aec4a6d) Thanks [@tsov](https://github.com/tsov)! - Converts DragEvent tests to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`a0c3c90`](https://github.com/Shopify/draggable/commit/a0c3c90d8e93ac8ac0e19e5d37e271e6d97c4fa6) Thanks [@tsov](https://github.com/tsov)! - Convert DroppableEvent to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`527dcb6`](https://github.com/Shopify/draggable/commit/527dcb67d50978ac81576603a57e42d77fff1eec) Thanks [@tsov](https://github.com/tsov)! - Converts MirrorEvent to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`7219781`](https://github.com/Shopify/draggable/commit/721978147cef7f3cc5971fa0cbd636c87ddbe2c7) Thanks [@tsov](https://github.com/tsov)! - Convert SnappableEvent to typescript

- [#579](https://github.com/Shopify/draggable/pull/579) [`cc42520`](https://github.com/Shopify/draggable/commit/cc42520a2731191ae6459a22892d9c1da605b80d) Thanks [@tsov](https://github.com/tsov)! - Converts DraggableEvent to typescript

## 1.1.1

### Patch Changes

- [#580](https://github.com/Shopify/draggable/pull/580) [`873ef2b`](https://github.com/Shopify/draggable/commit/873ef2b59a10361ba4a0e885aaea51d2b2b5c298) Thanks [@tsov](https://github.com/tsov)! - Removes unused packages dependencies

- [#582](https://github.com/Shopify/draggable/pull/582) [`762ffbf`](https://github.com/Shopify/draggable/commit/762ffbf70d018fee101852c186e8d887d1127ce8) Thanks [@tsov](https://github.com/tsov)! - - Cleans up code comments from build folder
  - Also resolves absolute paths for ts build declarations
  - Renames build files with .cjs and .mjs

## 1.1.0

### Minor Changes

- [#574](https://github.com/Shopify/draggable/pull/574) [`b81e8f6`](https://github.com/Shopify/draggable/commit/b81e8f678f8e5b27392b6c56b6bb2684a48c0fe8) Thanks [@tsov](https://github.com/tsov)! - Converted build from webpack to rollout. Import paths have changed

## 1.0.1

### Patch Changes

- [#572](https://github.com/Shopify/draggable/pull/572) [`2a8ae0b`](https://github.com/Shopify/draggable/commit/2a8ae0b219beceb3338764afe25c2d6a9fe4f495) Thanks [@tsov](https://github.com/tsov)! - Converts ResizeMirror to typescript

## 1.0.0

### Patch Changes

- Adds changeset dependency for version management

## v1.0.0-beta.13 - 2021-05-17

### Added

- Add `mirror:moved` event
- Cancel Dragging on ESC key up

### Changed

- Fixes add missing exports `DelayOptions` and `DelayOptions`
- Fixes return early when the target isn't in handle or draggable elements sensor
- Fixes the argument type of the `trigger` method

## v1.0.0-beta.12 - 2020-09-29

### Added

- Added `drag:stopped` event that will be fired after drag finished
- Support specifying an array of class name to Draggable `classes` option

### Changed

- Fixes incorrect `oldIndex` value when working with **nested sortable**
- Fixes wrong same container checking bug when working with **nested sortable**
- Fixes bug `drag:start` event was triggered during the delay time
- Fixes missing `overContainer` property in **DragOutEvent**

## v1.0.0-beta.11 - 2020-07-14

### Added

- Added `exclude` option to allow disable default plugins and sensors
- Added missing plugin types
- Support set the type of callback function according to the event type

### Changed

- Fixes drag start concurrency (`delay` and `distance` options)
- Fixes text in mirror blurry
- Fixes accidently append mirror

## v1.0.0-beta.10 - 2020-06-18

### Added

- Added `SortAnimation` plugin
- Added `distance?: number` to DraggableOptions TS interface

### Changed

- Fix mirror dimensions when `constrainDimensions` is active and not using fixed item width

## v1.0.0-beta.9 - 2019-08-26

### Added

- Added `distance` option
- Added `thresholdX` and `thresholdY` mirror options

### Changed

- Fixes preventing of contextmenu in MouseSensor
- Fixes SortableEvent `over` and `overContainer` giving incorrect properties

## v1.0.0-beta.8 - 2018-09-07

### Changed

- Announcement plugin to use `textContent` instead of `innerHTML`

## v1.0.0-beta.7 - 2018-04-28

### Added

- ResizeMirror plugin

### Changed

- Fixed native drag events with draggable
- Mouse position bug in scrollable

## v1.0.0-beta.6 - 2018-04-04

### Added

- Focusable plugin
- Added DroppableStart event for `Droppable`
- Added DroppableStop event for `Droppable`
- Added recommended VSCode settings

### Changed

- Fixed `addContainer`/`removeContainer` api
- Touch sensor fixes (including iOS 11.3 issues)
- Renames `DroppableOver` to `DroppableDropped`
- Renames `DroppableOut` to `DroppableReturned`
- Fix legacy bundle
- Improved webpack building
- Using `console.error` instead of throwing error

## v1.0.0-beta.5 - 2018-03-02

### Added

- Increased Documentation coverage
- Increased Test coverage, including better testing environment
- Increased JSDoc coverage
- Added docblock section to `CONTRIBUTING.md`
- Added greenkeeper as integration for package dependency management
- Added codecov as integration for tracking test coverage
- Added github template issue
- Added github template PR
- Added yarn scripts for examples
- Added SensorEvent to exports
- Added yarn scripts for esdoc
- Added `Announcement` plugin for screen reader support
- Added cursor offset option for `Mirror` plugin
- Added `scrollableElements` option to `Scrollable` plugin
- Added `snappableElement` to `SnapEvent`
- Added examples to published package
- Added `Emitter` class for event emitting for draggable

### Changed

- Changed esdoc config
- Changed node version `8.9.1` to `8.9.4`
- Updated package dependencies
- Updated roadmap section in README
- Changed export statements
- Fixes draggable state after canceling `drag:start`
- Fixes `constrainDimensions` option for `Mirror` plugin
- Fixes mirror position with touch devices and `Scrollable`
- `AutoScroll` plugin has been renamed to `Scrollable`
- Fixes scrolling edge cases with `Scrollable`
- Fixes scrolling offset for touch devices in `Scrollable`
- Fixes npm install issue
- Fixes `overContainer` property for `DragOutContainerEvent`

## v1.0.0-beta.4 - 2018-01-15

### Added

- Default `Draggable` plugins get exposed statically on `Draggable.Plugins`
- Default `Scrollable` plugin for Draggable, which auto scrolls containers/viewport while dragging
- `yarn watch` task for auto-building the library
- `source:original` class option for Draggable
- `Draggable#getDraggableElementsForContainer` method, which returns all draggable elements for a given container
- `MirrorCreateEvent`, which allows for canceling mirror creation
- `AbstractPlugin` to use as Base class for all Draggable plugins
- More test coverage

### Changed

- Fixed `Sortable` sort logic by excluding mirror and original source elements in calculations
- `Draggable` `appendTo` option now uses sources parent element as default, instead of `document.body`
- `Draggable` appends over classes _after_ triggering over/out events
- `Draggable` appends source into empty containers
- Mirrors margin gets removed on creation in the mirror plugin
- Fix for mirror when drag start gets canceled
- Fixes memory leak in Draggable when calling `destroy()`
- Fixes race condition for the `source:placed` class
- Changed `AbstractEvent#_canceled` to use symbols for private instance variables
- Some fixes for the documentation READMEs

## v1.0.0-beta.3 - 2017-11-01

### Added

- Bundle split, draggable now exports multiple bundles
  - Adds JS bundle per module
  - Adds legacy bundle for IE11
- Adds axis & dimension constraint options for mirror plugin
- Basic swap animation plugin
- Draggables API is now accessible via inheritance for `Sortable`, `Swappable` and `Droppable`
- Draggables API extended
  - `addSensor` to add sensor dynamically
  - `removeSensor` to remove a sensor dynamically
  - `addPlugin` to add a plugin dynamically
  - `removePlugin` to remove a plugin dynamically
  - `addContainer` to add a container dynamically
  - `removeContainer` to remove a container dynamically
  - `isDragging` to check if instance is currently dragging
- New `sortable:sort` event that can be canceled to prevent sorting
- New `swappable:swap` event that can be canceled to prevent swapping
- Added more documentation

### Changes

- `SortableSortedEvent` (`sortable:sorted`) now returns correct indexes
- `SortableStartEvent` gets fired now
- Plugins and Sensors are exported with namespace
- Removes reflow by removing unused lookup of next scroll parent
- Draggable delay option is now `100` by default, instead of `0`
- Draggables private methods are now really private
- Sensor improvements
  - `TouchSensor` now prevents scrolling without preventDefault
  - `MouseSensor` now prevents native elements to start dragging during delay
  - All sensors now listen to document rather than each container

## v1.0.0-beta.2 - 2017-10-10

### Added

- Code of Conduct
- Contribution guidelines
- Documentation on `appendTo` option for `Draggable`
- Added concept of `originalSource`
- Fix for text selection issue
- Fix for native drag events firing for the `MouseSensor`
- Fix for missing `classes` option

### Changes

- README updates
- Touch improvements
- ForceTouchSensor is not included by default anymore
- Folder/File restructure
- Exports `AbstractEvent` as `BaseEvent`
- Update node version from `8.2.1` to `8.6.0`
- Clones event callbacks before triggering (to prevent mutation during iterations)
- Improvements to `closest` utils helper

## v1.0.0-beta - 2017-09-27

Initial release


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- The use of sexualized language or imagery and unwelcome sexual attention or
  advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
  address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at max.hoffmann@shopify.com or curtis.dulmage@shopify.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Draggable

Thank you for contributing to draggable :tada: Any contributions to draggable are
appreciated and encouraged.

## Table of contents

1. [Code of Conduct](#code-of-conduct)
2. [How to contribute](#how-to-contribute)
   1. [Creating issues](#creating-issues)
   2. [Opening pull requests](#opening-pull-requests)
   3. [JS Docblocks](#js-docblocks)
3. [How to run locally](#how-to-run-locally)

## Code of Conduct

This project and everyone participating in it is governed by the [Code of Conduct document](https://github.com/Shopify/draggable/blob/main/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable behaviour to max.hoffmann@shopify.com or curtis.dulmage@shopify.com.

## How to contribute

### Creating issues

Before submitting issues, please have a quick look if there is an existing open issue here: [Issues](https://github.com/Shopify/draggable/issues). If no related issue can be found,
please open a new issue with labels: `bug`, `documentation`, `feature-request` or `question`.

### Opening pull requests

Pull requests are more than welcome! Just make sure that to include a description of the problem and how you are attempting to fix the issue, or
simply follow the Pull Request description template.

We also require Pull Requests to sync with main via rebase (not merge). So when you need to sync up your branch with main use: `git pull --rebase origin main`,
or if you need to sync up with another branch `git pull --rebase origin some-other-branch-name`. Doing so will remove of an extra merge commit in the git history.
This will also require a force push to the branch, e.g. `git push -u origin +some-branch`. The `+` in the last command indicates that you are force pushing changes.

Additionally we require commits to be atomic and squashed where needed. This will keep the git history clean on main. To squash commits use the `git rebase -i @~2`
command to do an interactive rebase. This will allow you to merge multiple commits into one. To read up more on this please visit: [Git Tools Rewriting History](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)

### JS Docblocks

Please follow the libraries convention and use docblocks to document the code

Here are some sample docblocks for different types (methods, properties, constants, classes, constructors):

```js
/**
 * Some method description
 * @param {ParameterType} parameterName
 * @return {ReturnType}
 * @private
 * @static
 * @readonly
 */

/**
 * Some instance property description
 * @property {PropertyType} propertyName
 * @private
 * @static
 * @readonly
 */

/**
 * Some constant description
 * @const {ConstType} constName
 */

/**
 * Some class description
 * @class ClassName
 * @module ClassName
 * @extends BaseClassName
 */

/**
 * Constructor description
 * @constructs ClassName
 */
```

## How to run locally

Here some steps to run draggable locally:

**via yarn**

```
$ cd draggable
$ yarn install
$ yarn test
```

**via npm**

```
$ cd draggable
$ npm install
$ npm run test
```

We are still working on setting up interactive example pages.


================================================
FILE: LICENSE.md
================================================
MIT License

Copyright (c) 2018-present Shopify

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
[![npm version](https://img.shields.io/npm/v/@shopify/draggable.svg?label=@shopify/draggable)](https://www.npmjs.com/package/@shopify/draggable) [![CI](https://github.com/shopify/draggable/workflows/CI/badge.svg)](https://github.com/Shopify/draggable/actions?query=branch%3Amain) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Shopify/draggable/blob/main/CONTRIBUTING.md) ![Bundle size](https://img.shields.io/badge/Bundle%20size-16.2kB-red.svg)

<a href="https://shopify.github.io/draggable" title="Visit Draggable website">
  <img src="https://user-images.githubusercontent.com/643944/35602291-99e2c56e-0605-11e8-847f-95f1f6be1610.jpg" alt="">
</a>

# Development

**Draggable is no longer maintained by its original authors.** Maintenance of this repo has been passed on to new collaborators and is no longer worked on by anyone at Shopify.

**We are still looking for more maintainers!** If anyone is interested in answering / triaging issues, reviewing / rejecting / approving PRs, and authoring code for bug fixes / new features — please send an email to `max.hoffmann (at) shopify (dot) com`. You may be asked a few questions before obtaining collaboration permission, but if everything checks out, we will happily add you as a collaborator.

---

Get complete control over drag and drop behaviour with Draggable! Draggable abstracts
native browser events into a comprehensive API to create a custom drag and drop experience.
`Draggable` comes with additional modules: `Sortable`, `Droppable`, `Swappable`. Draggable
itself does not perform any sorting behaviour while dragging, but does the heavy lifting, e.g.
creates mirror, emits events, manages sensor events, makes elements draggable.

The additional modules are built on top of `Draggable` and therefore provide a similar API
interface, for more information read the documentation below.

**Features**

- Works with native drag, mouse, touch and force touch events
- Can extend dragging behaviour by hooking into draggables event life cycle
- Can extend drag detection by adding sensors to draggable
- The library is targeted ES6 first

## Table of Contents

- [Install](#install)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [Roadmap](#roadmap)
- [Copyright](#copyright)

## Install

You can install the library via npm.

```bash
npm install @shopify/draggable --save
```

or via yarn:

```bash
yarn add @shopify/draggable
```

or via CDN

```html
<!-- Entire bundle -->
<script type="module">
  import {
    Draggable,
    Sortable,
    Droppable,
    Swappable,
  } from 'https://cdn.jsdelivr.net/npm/@shopify/draggable/build/esm/index.mjs';
</script>
<!-- Draggable only -->
<script type="module">
  import Draggable from 'https://cdn.jsdelivr.net/npm/@shopify/draggable/build/esm/Draggable/Draggable.mjs';
</script>
<!-- Sortable only -->
<script type="module">
  import Sortable from 'https://cdn.jsdelivr.net/npm/@shopify/draggable/build/esm/Sortable/Sortable.mjs';
</script>
<!-- Droppable only -->
<script type="module">
  import Droppable from 'https://cdn.jsdelivr.net/npm/@shopify/draggable/build/esm/Droppable/Droppable.mjs';
</script>
<!-- Swappable only -->
<script type="module">
  import Swappable from 'https://cdn.jsdelivr.net/npm/@shopify/draggable/build/esm/Swappable/Swappable.mjs';
</script>
<!-- Plugins only -->
<script type="module">
  import * as Plugins from 'https://cdn.jsdelivr.net/npm/@shopify/draggable/build/esm/Plugins/index.mjs';
</script>
<!-- UMD browser -->
<script src="https://cdn.jsdelivr.net/npm/@shopify/draggable/build/umd/index.min.js"></script>
<script>
  console.log(window.Draggable);
</script>
```

## Browser Compatibility

Check the "browserlist" property in [package.json](https://github.com/Shopify/draggable/blob/main/package.json#L88) for more info

| ![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Edge](https://raw.github.com/alrra/browser-logos/master/src/edge/edge_48x48.png) |
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Last 3 versions ✔                                                                       | Last 3 versions ✔                                                                          | Last 3 versions ✔                                                                    | Last 3 versions ✔                                                                       | Last 3 versions ✔                                                                 |

## Documentation

You can find the documentation for each module within their respective directories.

- [Draggable](src/Draggable)
  - [DragEvent](src/Draggable/DragEvent)
  - [DraggableEvent](src/Draggable/DraggableEvent)
  - [Plugins](src/Draggable/Plugins)
    - [Announcement](src/Draggable/Plugins/Announcement)
    - [Focusable](src/Draggable/Plugins/Focusable)
    - [Mirror](src/Draggable/Plugins/Mirror)
    - [MirrorEvent](src/Draggable/Plugins/Mirror/MirrorEvent)
    - [Scrollable](src/Draggable/Plugins/Scrollable)
  - [Sensors](src/Draggable/Sensors)
    - [DragSensor](src/Draggable/Sensors/DragSensor)
    - [ForceTouchSensor](src/Draggable/Sensors/ForceTouchSensor)
    - [MouseSensor](src/Draggable/Sensors/MouseSensor)
    - [Sensor](src/Draggable/Sensors/Sensor)
    - [SensorEvent](src/Draggable/Sensors/SensorEvent)
    - [TouchSensor](src/Draggable/Sensors/TouchSensor)
- [Droppable](src/Droppable)
  - [DroppableEvent](src/Droppable/DroppableEvent)
- [Plugins](src/Plugins)
  - [Collidable](src/Plugins/Collidable)
  - [ResizeMirror](src/Plugins/ResizeMirror)
  - [Snappable](src/Plugins/Snappable)
  - [SwapAnimation](src/Plugins/SwapAnimation)
  - [SortAnimation](src/Plugins/SortAnimation)
- [Sortable](src/Sortable)
  - [SortableEvent](src/Sortable/SortableEvent)
- [Swappable](src/Swappable)
  - [SwappableEvent](src/Swappable/SwappableEvent)

### TypeScript

Draggable includes [TypeScript](http://typescriptlang.org) definitions.

[Documentation](doc/typescript.md)

## Running examples

To run the `examples` project locally, simply run the following from the `draggable` root:

```bash
yarn && yarn start
```

This will start a server that hosts the contents of `examples/`. It also watches for file
changes from both `src/` and `examples/src` and reloads the browser.

## Contributing

Contributions are more than welcome, the code base is still new and needs more love.

For more information, please checkout the [contributing document](https://github.com/Shopify/draggable/blob/main/CONTRIBUTING.md).

## Related resources

- [Ember CLI Shim](https://github.com/timrourke/ember-cli-shopify-draggable-shim) on Github by [@timrourke](https://github.com/timrourke)
- [Ember CLI Shim](https://www.npmjs.com/package/ember-cli-shopify-draggable-shim) on NPM by [@timrourke](https://github.com/timrourke)

## Copyright

Copyright (c) 2018-present Shopify. See LICENSE.md for further details.


================================================
FILE: babel.config.js
================================================
module.exports = function (api) {
  api.cache(true);

  return {
    presets: [
      [
        '@babel/preset-env',
        {useBuiltIns: 'entry', corejs: '3.0', bugfixes: true},
      ],
      ['@babel/preset-typescript'],
    ],
    plugins: [['@babel/plugin-proposal-decorators', {version: '2023-05'}]],
    assumptions: {
      setPublicClassFields: true,
      privateFieldsAsProperties: true,
      // nothing accesses `document.all`:
      noDocumentAll: true,
      // nothing relies on class constructors invoked without `new` throwing:
      noClassCalls: true,
      // nothing should be relying on tagged template strings being frozen:
      mutableTemplateObject: true,
      // nothing is relying on Function.prototype.length:
      ignoreFunctionLength: true,
      // nothing is relying on mutable re-exported bindings:
      constantReexports: true,
      // don't bother marking Module records non-enumerable:
      enumerableModuleMeta: true,
      // nothing uses [[Symbol.toPrimitive]]:
      // (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive)
      ignoreToPrimitiveHint: true,
      // nothing relies on spread copying Symbol keys:  ({...{ [Symbol()]: 1 }})
      objectRestNoSymbols: true,
      // nothing relies on `new (() => {})` throwing:
      noNewArrows: true,
      // transpile object spread to assignment instead of defineProperty():
      setSpreadProperties: true,
      // nothing should be using custom iterator protocol:
      skipForOfIteratorClosing: true,
      // nothing inherits from a constructor function with explicit return value:
      superIsCallableConstructor: true,
      // nothing relies on CJS-transpiled namespace imports having all properties prior to module execution completing:
      noIncompleteNsImportDetection: true,
    },
  };
};


================================================
FILE: config/typescript/rollup-plugin-includepaths.d.ts
================================================
declare module 'rollup-plugin-includepaths' {
  interface Options {
    include: {[key: string]: string};
    paths: string[];
    extensions: string[];
  }
  export = includePaths;
  function includePaths(object: Options);
}


================================================
FILE: doc/typescript.md
================================================
# Default usage

```typescript
import {Sortable} from '@shopify/draggable';

const sortable = new Sortable(document.querySelectorAll('ul'), {
  draggable: 'li',
});

// The type of the first argument is SortableEventNames
sortable.on('sortable:sort', (evt) => {
  // The type of evt is SortableSortEvent
});

// The type of the first argument is SortableEventNames
sortable.on('drag:out:container', (evt) => {
  // The type of evt is DragOutContainerEvent
});
```

# Using plugins

When creating an instance with plugins with events, you need to manually specify the event names.

```typescript
import {Droppable, Plugins} from '@shopify/draggable';

// 1. import the event names you need
import type {
  DroppableEventNames,
  CollidableEventNames,
} from "@shopify/draggable";

// 2. Specify the event names when create the instance
const droppable = new Droppable<DroppableEventNames | CollidableEventNames>(document.querySelectorAll('.container'), {
  draggable: '.item',
  dropzone: '.dropzone',
  collidables: '.other-list',
  plugins: [Plugins.Collidable],
});

// The type of the first argument can be DroppableEventNames or CollidableEventNames
droppable.on('droppable:dropped', (evt) => {
  // The type of evt is DroppableDroppedEvent
});

// The type of the first argument can be DroppableEventNames or CollidableEventNames
droppable.on('collidable:in', (evt) => {
  // The type of evt is CollidableInEvent
});
```


================================================
FILE: esdoc.json
================================================
{
  "source": "./src",
  "destination": "./docs",
  "plugins": [
    {"name": "esdoc-standard-plugin"},
    {"name": "esdoc-ecmascript-proposal-plugin", "option": {"all": true}}
  ]
}


================================================
FILE: examples/.babelrc
================================================
{
  "presets": [
    [
      "babel-preset-shopify/web",
      {
        "babel-preset-shopify/web": {
          "modules": false,
          "useBuiltIns": "entry"
        }
      }
    ]
  ]
}


================================================
FILE: examples/.browserslistrc
================================================
> 1%
Last 1 version


================================================
FILE: examples/.editorconfig
================================================
# editorconfig.org
root = true

[*]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

# Markdown syntax specifies that trailing whitespaces can be meaningful,
# so let’s not trim those. e.g. 2 trailing spaces = linebreak (<br />)
# See https://daringfireball.net/projects/markdown/syntax#p
[*.md]
trim_trailing_whitespace = false

# Disable trailing whitespace removal in diff files,
# where whitespace is meaningful
[*.diff]
trim_trailing_whitespace = false


================================================
FILE: examples/.eslintignore
================================================
node_modules
packages
dist
scrap
src/scripts/vendor


================================================
FILE: examples/.eslintrc.js
================================================
/* eslint-env node */
module.exports = {
  extends: ['plugin:shopify/esnext', 'plugin:shopify/webpack', 'plugin:shopify/prettier'],
  globals: {},
  rules: {
    'shopify/jsx-no-complex-expressions': 'off',
    'eslint-comments/no-unlimited-disable': 0,
    // 'import/no-default-export': ['error'],
    'lines-around-comment': [
      'error',
      {
        beforeBlockComment: false,
        allowBlockStart: false,
      },
    ],
    'no-console': 0,
    'no-negated-condition': 'off',
    // We are intentionally keeping `TODO` comments until a stable release
    'no-warning-comments': 'off',
    'import/no-cycle': 'off',
    // TODO: Disabling for now, but we will want to re-enable in the future.
    'import/no-default-export': 'off',
  },
  env: {
    browser: true,
  },
  // Required, else eslint will look at the parent config
  root: true,
};


================================================
FILE: examples/.gitignore
================================================
# OS files
.DS_Store

# Caches
.cache
.eslintcache
.sass-cache
.npm
*.tsbuildinfo

# Dev
.dev

# Environment
.env
.env.test

# Build
dist
scrap
packages

# Secrets
secrets.json

# Reports
assets-manifest.json
bundle-report.html

# Node/yarn
node_modules
.yarn-integrity

# Coverage
coverage
lib-cov
*.lcov

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock


================================================
FILE: examples/.nvmrc
================================================
v20.17.0


================================================
FILE: examples/.prettierignore
================================================
node_modules
packages
/.github
/assets-manifest.json
/bundle-report.html
/dist
/package.json


================================================
FILE: examples/.prettierrc
================================================
{
  "arrowParens": "always",
  "bracketSpacing": false,
  "printWidth": 100,
  "singleQuote": true,
  "trailingComma": "all"
}


================================================
FILE: examples/.stylelintignore
================================================
node_modules
packages
/.github
/assets-manifest.json
/bundle-report.html
/dist
/package.json


================================================
FILE: examples/.stylelintrc
================================================
{
  "extends": [
    "stylelint-config-shopify/prettier"
  ],
  "rules": {
    "shopify/content-no-strings": true,
    "scss/at-if-no-null": null,
    "scss/partial-no-import": null,
    "color-no-hex": null,
    "comment-empty-line-before": null,
    "scss/double-slash-comment-empty-line-before": null,
    "declaration-block-no-redundant-longhand-properties": [
      true,
      {
        ignoreShorthands: ["/^grid.*/"],
      },
    ],
    "declaration-property-value-blacklist": null,
    "font-weight-notation": null,
    "function-url-scheme-whitelist": null,
    "no-unknown-animations": null,
    "selector-class-pattern": null,
    "selector-id-pattern": null,
    "selector-max-class": 4,
    "selector-max-id": 1,
    "selector-max-type": 2,
    "selector-max-combinators": 3,
    "selector-max-compound-selectors": 4,
    "selector-max-specificity": "1,5,1",
    "selector-no-qualifying-type": null
  }
}


================================================
FILE: examples/.vscode/extensions.json
================================================
{
  "recommendations": [
    "christian-kohler.npm-intellisense",
    "christian-kohler.path-intellisense",
    "codezombiech.gitignore",
    "dbaeumer.vscode-eslint",
    "EditorConfig.editorconfig",
    "esbenp.prettier-vscode",
    "Gruntfuggly.todo-tree",
    "hex-ci.stylelint-plus",
    "mariusschulz.yarn-lock-syntax",
    "mrmlnc.vscode-scss",
    "ronnidc.nunjucks"
  ]
}


================================================
FILE: examples/.vscode/settings.json
================================================
{
  "css.validate": false,
  "scss.validate": false,
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  },
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
  "stylelint.enable": true,
  "stylelint.autoFixOnSave": true,
  "files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true,
    "**/node_modules": true,
    "lib": true
  },
  "search.exclude": {
    "**/node_modules": true,
    "lib": true,
    "dist/": true
  }
}


================================================
FILE: examples/README.md
================================================
![banner-examples](https://user-images.githubusercontent.com/643944/34655498-c9701942-f3d8-11e7-9dd5-6d225e7c5f6f.png)

> The Examples site has been made available to aid developers interested in building web apps with Draggable and/or contributing back to the library.

The Examples sandbox aims to answer common questions concerning Draggable’s implementation, as well as provide solutions to any conceivable drag and drop problem.

For instance, our solution to resolving touch events required duplicating the `source` node in the DOM. Depending on your design, this could cause friction as you attempt to maintain the correct layout while dragging. A bit of clever CSS can help resolve such layout issues. There are several examples in this repo that demonstrate solutions to this exact layout concern.

## Local development

1. Clone the `draggable` repo: `git clone git@github.com:Shopify/draggable.git`.
2. Run `yarn && yarn start` in the root `draggable` directory.
3. You can now access the local site at `http://localhost:3000` _(local address may vary - see console for correct url)_.

## Code style

This project uses Shopify’s [eslint](https://github.com/Shopify/eslint-plugin-shopify) and [stylelint](https://github.com/Shopify/stylelint-config-shopify) configs with a few alterations, defined in their respective `dot rc` file. If contributing back to this project, you must conform to the code style enforced by the config. If you are just playing around and don’t care about code style, just disable your editor’s linter.

## Project structure

This project uses a co-located component structure, meaning everything relating to an individual component should all be found in the same folder. For the most part, you will work only in the `src/components` and `src/content` folders.

The root directory contains many config files that you can safely ignore unless you aim to change how files are compiled. It is strongly recommended to read the `package.json` to familiarize yourself with the available `scripts`.

### `src/views`

This folder contains the top-level page templates. The project uses Nunjucks for a templating language.

There is only one layout template, `views/templates/document.html`, which is extended by all of the `.html` files in the root of `/views`. These root views do the following:

1. Import global components such as `Sidebar` and `PageHeader`
2. Define the `ViewAttr` for the view _(Page title, description, etc)_.
3. Import and render the content component for that view.

### `src/styles`

This is where “global” styles, along with the `examples-app.scss` manifest, are located. There shouldn’t be much reason to alter any of these files other than adding new imports to `examples-app.scss`.

This project uses [Threads](https://github.com/beefchimi/threads) to manage style properties. You can see all of the Threads theme values in `styles/themes/examples`.

### `src/scripts`

Just like with `styles/`, this is where our “global” scripts, along with the `examples-app.js` entry script is located. There shouldn’t be much reason to alter any of these files other than adding new imports and initializations to `examples-app.js`.

### `src/content`

This folder contains all the “content components”, which means all the code specific to an individual Example. Content is grouped by the “example type”: `Draggable`, `Droppable`, `Sortable`, `Swappable`, or `Plugins`. There is also a `Home` folder just for the landing page, and a `shared` folder for common functions and mixins that are reused across multiple content components.

Each individual example will have a single `.html` view, `.scss` file, and a `index.js`. The `index.js` is where you will initialize and author any `draggable` logic. The default function exported from each `index.js` file is imported and initialized in the `src/scripts/examples-app.js` entry file.

### `src/components`

Here are all of the shared components, such as the `Block` component, used in many examples as draggable elements.

Sometimes these are just `.scss` files, and the markup is written within a content component. If the styles contain values specific to that component, but need to be shared with other components, they will be split out into a `props.scss` file. Variant classes are split out into a `variants.scss` file.

Some components have a `.html` file, which uses Nunjucks macros to define reusable components. For example, `Block` has several variations that can be toggled through its component API. Once a `Block` is imported into a view, you can render using:

`{{ Block.render('one', {index: 1, draggable: true}) }}`

That will render all of the markup for a `Block` component, using the string `one` as its `Heading`, and appending the classes `Block--item1` and `Block--isDraggable`.

Some components will also have their own JavaScript logic, such as `Plate`, which manages how the `Plate` component gets transformed via a drag event.

### `src/root`

This folder simply contains any files that need to be copied to the root `dist/` folder, such as a `manifest.json` or `.htaccess`. There should be no reason to alter files in this folder.

### `tools`

All of the build scripts are found in this folder. You shouldn’t need to go in here unless you want to change how the code is compiled.

All JavaScript is generated with source maps, so you should be able to dig through errors and `console.log` statements without issue.

## Running a server / watching files

Running `yarn start` fires up a `browsersync` server to view the site. While running the server, when you add/make changes to any of the files in `src/`, the appropriate files will then be recompiled and output to the `dist/` folder. Once a file has been compiled, the browser will automatically reload the page. For `scss` changes, the new styles are injected into the page without causing a refresh.

The file watcher will also look for changes in the `draggable/lib` folder, which means you can be running the examples server and making changes to the core library at the same time. Scripts will get recompiled and the browser will reload.

## Contributing

If while using Draggable, you encounter something that is not already covered in the Examples, please contribute back by creating a new Example under the correct grouping.

We ask that you follow our code style config and try your best to make the example consistent with the design of the site. Lean on the components already created to compose your example. If required, you can design and build your own components.

There is an [open issue](https://github.com/Shopify/draggable/issues/110) for building a CLI generator for new pages. If you are interested in taking this on, please assign yourself to the issue.

If you are unsure if your example has merit, feel free to [open an issue](https://github.com/Shopify/draggable/issues) and propose your idea. Always ping [@tsov](https://github.com/tsov) and [@beefchimi](https://github.com/beefchimi) for issues and code review!


================================================
FILE: examples/package.json
================================================
{
  "name": "draggable-examples",
  "version": "1.1.0",
  "description": "Examples for draggable.js",
  "author": "Max Hoffmann and Curtis Dulmage",
  "homepage": "https://shopify.github.io/draggable",
  "license": "MIT",
  "main": "tools/index.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/Shopify/draggable.git"
  },
  "keywords": [
    "draggable",
    "javascript"
  ],
  "bugs": {
    "url": "https://github.com/Shopify/draggable/issues"
  },
  "config": {
    "tools": "--require @babel/register --gulpfile tools"
  },
  "scripts": {
    "clean": "rimraf dist bundle-report.html",
    "views": "NODE_OPTIONS=--openssl-legacy-provider gulp views $npm_package_config_tools",
    "scripts": "NODE_OPTIONS=--openssl-legacy-provider gulp scripts $npm_package_config_tools",
    "styles": "NODE_OPTIONS=--openssl-legacy-provider gulp styles $npm_package_config_tools",
    "start": "NODE_OPTIONS=--openssl-legacy-provider gulp start $npm_package_config_tools",
    "build": "NODE_OPTIONS=--openssl-legacy-provider yarn run clean && gulp build $npm_package_config_tools",
    "build:prod": "NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=production yarn run build",
    "lint:scss": "stylelint './src/**/*.scss'",
    "prettier:scss": "prettier-stylelint './src/**/*.scss' --write -q",
    "lint:js": "eslint './src/**/*.js' './tools/**/*.js' --max-warnings 0",
    "prettier:js": "yarn run lint:js --fix",
    "prepublish": "NODE_OPTIONS=--openssl-legacy-provider yarn run build"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "threads": "https://github.com/beefchimi/threads.git#v1.0.0-beta8"
  },
  "devDependencies": {
    "@babel/core": "^7.8.3",
    "@babel/register": "^7.8.3",
    "autoprefixer": "^9.8.6",
    "babel-loader": "^8.1.0",
    "babel-preset-shopify": "^21.0.0",
    "browser-sync": "^2.26.12",
    "cssnano": "^4.1.10",
    "cssnano-preset-advanced": "^4.0.7",
    "eslint": "^7.10.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-shopify": "^35.1.0",
    "gulp": "^4.0.2",
    "gulp-cli": "^2.3.0",
    "gulp-data": "^1.3.1",
    "gulp-htmlmin": "^5.0.1",
    "gulp-nunjucks": "^5.1.0",
    "gulp-postcss": "^9.0.0",
    "gulp-sass": "^4.1.0",
    "gulp-sourcemaps": "^2.6.5",
    "install": "^0.13.0",
    "nunjucks": "^3.2.2",
    "prettier": "^2.1.2",
    "prettier-stylelint": "^0.4.2",
    "rimraf": "^3.0.2",
    "stylelint": "^13.7.2",
    "stylelint-config-shopify": "^7.4.0",
    "webpack": "^4.44.2",
    "webpack-bundle-analyzer": "^3.9.0"
  },
  "resolutions": {
    "node-sass": "8.0.0"
  }
}


================================================
FILE: examples/postcss.config.js
================================================
/* eslint-env node */
module.exports = () => ({
  plugins: {
    autoprefixer: {},
    cssnano: {
      // reduceIdents causing problem with `grid-template-areas`
      preset: ['advanced', {reduceIdents: false}],
      autoprefixer: false,
    },
  },
});


================================================
FILE: examples/src/components/Analytics/index.js
================================================
function gtag() {
  window.dataLayer.push(arguments); // eslint-disable-line prefer-rest-params
}

export default class Analytics {
  constructor(ua) {
    this.ua = ua;
  }

  init() {
    if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
      console.log('🤖 Analytics disabled in local development.');
      return;
    }

    this._appendScript()
      .then(() => {
        window.dataLayer = window.dataLayer || [];

        gtag('js', new Date());
        gtag('config', this.ua);

        return window.dataLayer;
      })
      .catch((error) => console.warn(error));
  }

  _appendScript() {
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      document.body.appendChild(script);
      script.onload = resolve;
      script.onerror = reject;
      script.async = true;
      script.src = `https://www.googletagmanager.com/gtag/js?id=${this.ua}`;
    });
  }
}


================================================
FILE: examples/src/components/Block/Block.html
================================================
{% macro render(heading, options = {}) %}
  {% set classes = ['Block'] %}

  {% set classes = (classes.push('Block--typeShell') if options.shell, classes) %}

  {% if options.type and (
    options.type === 'Shell' or options.type === 'Hollow' or options.type === 'Stripes'
  ) %}
    {% set classes = (classes.push('Block--type' + options.type), classes) %}
  {% endif %}

  {% set classes = (classes.push('Block--item' + options.index) if options.index, classes) %}
  {% set classes = (classes.push('Block--isDraggable') if options.draggable, classes) %}
  {% set classes = (classes.push(options.classes | join(' ')) if options.classes, classes) %}
  {% set classes = classes | join(' ') | trim %}

  {% if options.draggable %}
    {% set openingTag = '<span class="' + classes + '" title="Click to drag">' %}
    {% set closingTag = '</span>' %}
  {% else %}
    {% set openingTag = '<span class="' + classes + '">' %}
    {% set closingTag = '</span>' %}
  {% endif %}

  {{ openingTag | safe }}
    <div class="BlockContent">
      {% if heading.length > 1 %}
        <h3 class="Heading Heading--size2 text-no-select">{{ heading }}</h3>
      {% endif %}

      {% if options.draggable %}
        <div class="Pattern Pattern--typeHalftone"></div>
        <div class="Pattern Pattern--typePlaced"></div>
      {% endif %}
    </div>
  {{ closingTag | safe }}
{% endmacro %}


================================================
FILE: examples/src/components/Block/Block.scss
================================================
////
/// Components
/// Block
////

@import 'utils/shared/functions';
@import 'utils/shared/layout';

.BlockWrapper {
  .Block {
    height: 100%;
  }
}

.Block {
  position: relative;
  display: block;
}

///
/// Block Content
.BlockContent {
  @include flex-center;
  position: relative;
  min-height: rows(2, true);
  height: 100%;
  color: white;
  background-color: get-color(coal, dark);
  border: get-border(thin) solid get-color(coal, dark);

  @media screen and (min-width: get-breakpoint(tablet)) {
    min-height: rows(2);
    border-width: get-border();
  }

  .Heading {
    // vertical alignment
    margin-top: -0.1em;
  }
}

@import 'variants';


================================================
FILE: examples/src/components/Block/variants.scss
================================================
////
/// Components
/// Block variants
////

@import 'utils/shared/layout';
@import 'components/Patterns/props';

///
/// BlockLayout
.BlockLayout--typeFlex,
.BlockLayout--typeFloat {
  margin-top: -(get-border(thin));
  margin-left: -(get-border(thin));

  > .BlockWrapper {
    margin-top: get-border(thin);
    margin-left: get-border(thin);
  }

  > .Block {
    padding-top: get-border(thin);
    padding-left: get-border(thin);
  }

  @media screen and (min-width: get-breakpoint(tablet)) {
    margin-top: -(get-border());
    margin-left: -(get-border());

    > .BlockWrapper {
      margin-top: get-border();
      margin-left: get-border();
    }

    > .Block {
      padding-top: get-border();
      padding-left: get-border();
    }
  }
}

.BlockLayout--typeFlex {
  display: flex;
  flex-wrap: wrap;

  .Block {
    flex: 1 1 100%;
  }
}

.BlockLayout--typeFloat {
  @include clearfix;

  .Block {
    float: left;
    width: 100%;
  }
}

.BlockLayout--typeGrid {
  display: grid;
  gap: get-border(thin);

  @media screen and (min-width: get-breakpoint(tablet)) {
    gap: get-border();
  }
}

.BlockLayout--typePositioned {
  position: relative;
}

///
/// Block types
.Block--typeShell {
  .BlockContent {
    color: get-color(coal, dark);
    background-color: white;
    border-color: currentColor;
  }
}

.Block--typeHollow {
  .BlockContent {
    color: get-color(ash, dark);
    background-color: white;
    border-color: currentColor;
  }
}

.Block--typeStripes {
  .BlockContent {
    @include stripes-bg;
    color: get-color(coal, dark);
    border-color: currentColor;
    transition: color get-duration(fast) get-easing();
  }
}

///
/// Draggable Blocks
.Block--isDraggable {
  cursor: get-cursor(drag);

  .BlockContent {
    color: get-color(coal, dark);
    background-color: white;
    border-color: currentColor;
    transition: color get-duration(fast) get-easing(),
      background-color get-duration(fast) get-easing(), transform get-duration() get-easing(bungie);
  }

  // interaction
  &:focus .BlockContent,
  &:hover .BlockContent {
    color: get-color(brand, blue);
  }

  &.draggable-source--is-dragging .BlockContent {
    color: get-color(brand, blue);

    .Pattern--typeHalftone {
      @include pattern-halftone-animated;
    }
  }

  &.draggable-source--placed .BlockContent {
    .Pattern--typePlaced {
      @include pattern-placed-animated;
    }
  }

  &.draggable-mirror {
    z-index: get-z-index(overlay);
    transition: width get-duration() get-easing(bungie), height get-duration() get-easing(bungie);

    .BlockContent {
      height: 100%;
      color: white;
      background-color: get-color(brand, blue);
      border-color: get-color(brand, blue);
      transform: scale(1.025);
    }
  }
}

///
/// Droppable
.BlockWrapper {
  position: relative;

  &.draggable-dropzone--occupied {
    .Block--typeHollow,
    .Block--typeStripes {
      @include position-cover;
    }
  }
}

///
/// Collidable
// stylelint-disable-next-line no-duplicate-selectors
.Block--typeStripes {
  // should be a native Draggable class name
  &.isColliding {
    .BlockContent {
      color: get-color(brand, red);
    }
  }
}


================================================
FILE: examples/src/components/Brand/Brand.html
================================================
<a href="./" class="Brand" title="Return to Examples index">
  <div class="SvgContainer BrandLogo">
    {% include 'components/Brand/Logo.html' %}
  </div>

  <div class="SvgContainer BrandWordmark">
    {% include 'components/Brand/Wordmark.html' %}
  </div>
</a>


================================================
FILE: examples/src/components/Brand/Brand.scss
================================================
////
/// Components
/// Brand
////

@import 'keyframes';
@import 'props';

.Brand {
  cursor: get-cursor(rock);
  display: flex;

  &:active {
    cursor: get-cursor(rock, active);
  }

  @media screen and (max-width: get-breakpoint() - 1px) {
    justify-content: center;
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    margin-left: -(get-spacing(tightest));
  }
}

.BrandLogo {
  flex: 0 0 $logo-width;
}

.BrandWordmark {
  flex: 0 0 $wordmark-width;
  margin-left: get-spacing(tighter);
}

.Svg--srcWordmark {
  fill: get-color(brand, yellow);
}

///
/// Logo
.Wave--colorMask {
  fill: get-color(coal, dark);
}

.Wave--colorPurple {
  fill: get-color(brand, purple);
}

.Wave--colorRed {
  fill: get-color(brand, red);
}

.Wave--colorOrange {
  fill: get-color(brand, orange);
}

.Hand {
  fill: get-color(brand, yellow);
}

// --- Interaction
// stylelint-disable-next-line no-duplicate-selectors
.Brand {
  &:hover {
    @include logo-animation;
  }

  // stylelint-disable-next-line no-duplicate-selectors
  &:active {
    .Wave--colorMask,
    .Wave--colorPurple,
    .Wave--colorRed,
    .Wave--colorOrange,
    .Hand {
      animation-duration: get-duration();
    }
  }
}


================================================
FILE: examples/src/components/Brand/Logo.html
================================================
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 78" class="Svg Svg--srcLogo">
  <path class="Wave Wave--colorMask" d="M19.738 61.097c-7.5-4.3-11.2-12.8-9.8-20.7L6.294 38.33l-2.756 4.667c-6.4 11.1-2.6 25.4 8.5 31.9 11.2 6.4 25.5 2.6 31.9-8.5.9-1.6 1.8-3.1 2.7-4.7l-4-2.5c-6.2 5.2-15.3 6.3-22.9 1.9z"/>
  <path class="Wave Wave--colorPurple" d="M19.738 61.097c-8.8-5.1-12.3-15.9-8.5-24.9l-2.783-1.6-2.717 4.7c-6.4 11.1-2.6 25.4 8.5 31.9 11.2 6.4 25.5 2.6 31.9-8.5.9-1.6 1.8-3.1 2.7-4.7l-3.3-1.9c-5.8 7.8-16.9 10.2-25.8 5z"/>
  <path class="Wave Wave--colorRed" d="M46.938 54.097c-5.4 9.4-17.6 12.5-27.1 7s-12.9-17.6-7.5-27l1-1.7-2.7-1.6-2.7 4.7c-6.5 11.2-2.7 25.5 8.5 32 11.2 6.4 25.5 2.6 31.9-8.5.9-1.6 1.784-3.11 2.684-4.71l-3.184-1.79-.9 1.6z"/>
  <path class="Wave Wave--colorOrange" d="M23.03 59.23c-10.797-6.323-14.684-20.024-8.998-30.983l-1.324-.87-2.77 4.62c-6.4 11.1-2.6 25.4 8.5 31.9 11.2 6.4 25.5 2.6 32-8.6.78-1.355 2.116-3.63 2.116-3.63l-1.524-.865c-6.54 10.625-17.063 14.677-28 8.427z"/>
  <path class="Hand" d="M59.305 36.397c-.7-2.4-2.7-4.3-5.2-4.6 1-3.8-1.5-7.5-5.2-8 .9-3.5-1.4-7.1-5-7.8 3.9-6.7 5.2-8.1 4.4-11.3-1.5-5.5-8.9-6.4-11.7-1.5l-6.9 12c-2.9-3.4-8.2-2.8-10.4 1l-7.2 12.2c-6.4 11.1-2.6 25.4 8.5 31.9 11.2 6.4 25.5 2.6 32-8.6 6.4-11.1 7.6-12 6.7-15.3zm-10.4 13.2c-5.3 9.1-17 12.2-26.1 7-9.1-5.3-12.2-17-7-26.1 7.5-13.1 7.1-12.9 8.4-13.3 1.9-.5 3.4 1.5 2.4 3.1l-5.1 8.8c-1.4 2.4 2.3 4.6 3.7 2.1 15.8-27.4 14.9-26.6 16.3-26.9 1.1-.3 2.3.4 2.6 1.5.4 1.4.2.9-10.7 19.8-1.4 2.4 2.3 4.6 3.7 2.1l3.7-6.5c1.4-2.4 5.1-.3 3.7 2.1l-3.7 6.5c-1.4 2.4 2.3 4.6 3.7 2.1 1.4-2.4 1.7-3.5 3-3.9 1.1-.3 2.3.4 2.6 1.5.4 1.3-.4 2-4 8.2-1.4 2.4 2.3 4.6 3.7 2.1 1.3-2.3 1.7-3.5 2.9-3.8 1.1-.3 2.3.4 2.6 1.5.2 1.4-.4 1.7-6.4 12.1z"/>
</svg>


================================================
FILE: examples/src/components/Brand/Wordmark.html
================================================
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 176 42" class="Svg Svg--srcWordmark">
  <path d="M20.014.052h-.869c-.955 0-1.042.087-1.129.998l-2.04 16.282c-2.084-2.648-3.864-3.604-6.686-3.604-5.297 0-9.291 4.211-9.291 9.768 0 4.993 3.604 8.639 8.552 8.639 2.388 0 3.821-.651 5.991-2.779l-.174 1.172c-.044.26-.044.478-.044.564 0 .478.26.607 1.085.607h.869c.911 0 .998-.087 1.129-.998l3.603-29.48c.044-.26.044-.347.044-.565.001-.431-.259-.604-1.04-.604zM8.899 29.357c-3.343 0-5.774-2.474-5.774-5.86 0-3.995 2.779-6.99 6.425-6.99 3.343 0 5.818 2.345 5.818 5.513 0 4.125-2.865 7.337-6.469 7.337zm23.922-15.629c-1.737 0-2.866.607-4.689 2.432l.131-.825c.044-.304.044-.521.044-.565 0-.478-.26-.607-1.085-.607h-.869c-.911 0-.998.087-1.129.998l-1.867 15.37c-.044.217-.044.391-.044.564.044.478.26.607 1.042.607h.868c.956 0 1.042-.087 1.129-.998l.998-8.032c.478-3.994 1.954-6.035 4.384-6.035.347 0 .651.044.825.087.912.347.912.347 1.042.347.26 0 .391-.087.782-.607l.564-.825c.304-.347.391-.565.391-.694.001-.696-1.128-1.217-2.517-1.217zm21.185.434h-.869c-.956 0-1.042.087-1.129.998l-.217 1.867c-1.954-2.432-3.69-3.299-6.512-3.299-5.384 0-9.248 4.124-9.248 9.899 0 4.993 3.343 8.51 8.163 8.51 2.388 0 3.908-.738 6.078-2.908l-.172 1.302c-.044.304-.044.478-.044.564 0 .434.26.607 1.085.607h.869c.912 0 .998-.087 1.129-.998l1.867-15.37c.044-.217.044-.434.044-.565-.046-.476-.262-.607-1.044-.607zm-9.248 15.195c-3.212 0-5.6-2.518-5.6-5.86 0-3.951 2.779-6.99 6.382-6.99 3.299 0 5.731 2.388 5.731 5.6 0 4.038-2.909 7.25-6.513 7.25zm32.085-15.195h-.869c-.956 0-1.042.087-1.129.998l-.217 1.91c-2.127-2.474-3.864-3.343-6.512-3.343-5.34 0-9.421 4.255-9.421 9.812 0 4.906 3.603 8.596 8.379 8.596 2.258 0 3.821-.651 5.991-2.561l-.391 3.039c-.26 2.474-.738 3.821-1.65 4.776-1.042 1.129-2.735 1.78-4.646 1.78-2.952 0-5.036-1.52-5.253-3.777-.131-1.259-.131-1.259-1.129-1.259h-.738c-.912 0-1.085.131-1.085.869 0 4.081 3.43 6.947 8.336 6.947 2.908 0 5.427-1.042 6.947-2.866 1.345-1.607 1.867-3.212 2.345-7.12l2.041-16.628c.044-.217.044-.391.044-.565-.045-.477-.263-.608-1.043-.608zm-9.161 15.195c-3.386 0-5.862-2.518-5.862-5.948 0-3.951 2.822-6.903 6.556-6.903 3.43 0 5.862 2.388 5.862 5.818-.001 3.951-2.866 7.033-6.556 7.033zm31.909-15.195h-.869c-.956 0-1.042.087-1.129.998l-.217 1.91c-2.127-2.474-3.864-3.343-6.512-3.343-5.34 0-9.421 4.255-9.421 9.812 0 4.906 3.603 8.596 8.379 8.596 2.258 0 3.821-.651 5.991-2.561l-.391 3.04c-.26 2.474-.738 3.821-1.65 4.776-1.042 1.129-2.735 1.78-4.646 1.78-2.952 0-5.036-1.52-5.253-3.777-.131-1.259-.131-1.259-1.129-1.259h-.738c-.912 0-1.085.131-1.085.869 0 4.081 3.43 6.947 8.336 6.947 2.908 0 5.427-1.042 6.947-2.866 1.345-1.607 1.867-3.212 2.345-7.12l2.041-16.628c.044-.217.044-.391.044-.565-.043-.478-.261-.609-1.043-.609zm-9.159 15.195c-3.386 0-5.862-2.518-5.862-5.948 0-3.951 2.822-6.903 6.556-6.903 3.43 0 5.862 2.388 5.862 5.818-.001 3.951-2.866 7.033-6.556 7.033zm31.736-15.195h-.869c-.956 0-1.042.087-1.129.998l-.217 1.867c-1.954-2.432-3.69-3.299-6.512-3.299-5.384 0-9.248 4.124-9.248 9.899 0 4.993 3.343 8.51 8.163 8.51 2.388 0 3.908-.738 6.078-2.908l-.173 1.303c-.044.304-.044.478-.044.564 0 .434.26.607 1.085.607h.869c.912 0 .998-.087 1.129-.998l1.867-15.37c.044-.217.044-.434.044-.565-.045-.477-.262-.608-1.043-.608zm-9.248 15.195c-3.212 0-5.6-2.518-5.6-5.86 0-3.951 2.779-6.99 6.382-6.99 3.299 0 5.731 2.388 5.731 5.6 0 4.038-2.909 7.25-6.513 7.25zm25.267-15.629c-2.432 0-3.951.694-6.165 2.692l1.867-15.195c.044-.304.044-.478.044-.565 0-.434-.26-.607-1.085-.607h-.869c-.912 0-.998.087-1.129.998l-3.603 29.48c-.044.217-.044.391-.044.564.044.478.26.607 1.042.607h.868c.956 0 1.042-.087 1.129-.998l.26-1.954c2.041 2.474 3.864 3.386 6.729 3.386 5.167 0 9.248-4.342 9.248-9.812.001-4.992-3.515-8.596-8.292-8.596zm-1.345 15.629c-3.343 0-5.774-2.474-5.774-5.904 0-3.951 2.822-6.947 6.512-6.947 3.343 0 5.774 2.474 5.774 5.862 0 3.863-2.909 6.989-6.512 6.989zM155.813.052h-.869c-.912 0-.998.087-1.129.998l-3.603 29.48c-.044.217-.044.391-.044.564.044.478.26.607 1.042.607h.869c.956 0 1.042-.087 1.129-.998l3.646-29.48c.044-.304.044-.478.044-.565.001-.433-.26-.606-1.085-.606zm12.07 13.545c-5.167 0-9.074 4.298-9.074 10.073 0 5.166 3.473 8.596 8.77 8.596 2.388 0 4.428-.738 5.904-2.127.651-.607 1.042-1.129 1.042-1.432 0-.304-.087-.434-.738-.782l-.478-.304c-.434-.26-.565-.304-.651-.304a.718.718 0 0 0-.521.217c-1.259 1.345-2.605 1.954-4.515 1.954-1.997 0-3.69-.825-4.733-2.258-.651-.955-.912-1.867-.956-3.56h12.981c.869 0 1.085-.131 1.085-.825.002-5.644-3.167-9.248-8.116-9.248zm-5.688 7.555c.347-1.432.651-2.084 1.259-2.822.998-1.259 2.605-1.954 4.298-1.954 2.952 0 4.906 1.78 5.124 4.775h-10.681v.001z"/>
</svg>


================================================
FILE: examples/src/components/Brand/keyframes.scss
================================================
////
/// Components
/// Brand keyframes
////

@import 'props';

@keyframes logo-outline-bounce {
  25% {
    transform: translate(-$logo-bounce-offset, $logo-bounce-offset);
  }

  75% {
    transform: translate($logo-bounce-offset, -$logo-bounce-offset);
  }
}

@keyframes logo-rainbow-mask {
  0% {
    fill: get-color(coal, dark);
  }

  25% {
    fill: get-color(brand, purple);
  }

  50% {
    fill: get-color(brand, red);
  }

  75% {
    fill: get-color(brand, orange);
  }
}

@keyframes logo-rainbow-purple {
  0% {
    fill: get-color(brand, purple);
  }

  25% {
    fill: get-color(brand, red);
  }

  50% {
    fill: get-color(brand, orange);
  }

  75% {
    fill: get-color(coal, dark);
  }
}

@keyframes logo-rainbow-red {
  0% {
    fill: get-color(brand, red);
  }

  25% {
    fill: get-color(brand, orange);
  }

  50% {
    fill: get-color(coal, dark);
  }

  75% {
    fill: get-color(brand, purple);
  }
}

@keyframes logo-rainbow-orange {
  0% {
    fill: get-color(brand, orange);
  }

  25% {
    fill: get-color(coal, dark);
  }

  50% {
    fill: get-color(brand, purple);
  }

  75% {
    fill: get-color(brand, red);
  }
}


================================================
FILE: examples/src/components/Brand/props.scss
================================================
////
/// Components
/// Brand props
////

$logo-width: 4.6rem;
$wordmark-width: 17.6rem;
$logo-bounce-offset: 0.1rem;

@mixin logo-animation {
  .Wave--colorMask {
    animation: logo-rainbow-mask get-duration(slow) get-easing() infinite;
  }

  .Wave--colorPurple {
    animation: logo-rainbow-purple get-duration(slow) get-easing() infinite;
  }

  .Wave--colorRed {
    animation: logo-rainbow-red get-duration(slow) get-easing() infinite;
  }

  .Wave--colorOrange {
    animation: logo-rainbow-orange get-duration(slow) get-easing() infinite;
  }

  .Hand {
    animation: logo-outline-bounce get-duration(slow) linear infinite;
  }
}


================================================
FILE: examples/src/components/Button/Button.scss
================================================
////
/// Components
/// Button
////

@import 'utils/shared/layout';

.Button {
  display: inline-block;
  padding: get-spacing(tightest);
  font-size: get-type-scale(button);
  font-weight: get-type-scale(button, weight);
  text-align: center;
  white-space: nowrap;
  color: get-color(coal, dark);
  background-color: white;
  border: 0.4rem solid get-color(coal, dark);
  transition: color get-duration() get-easing(), background-color get-duration() get-easing(),
    border-color get-duration() get-easing();

  @media screen and (min-width: get-breakpoint(tablet)) {
    padding-right: get-spacing(tighter);
    padding-left: get-spacing(tighter);
    font-size: get-type-scale(button, tablet);
  }

  &:focus,
  &:hover {
    color: get-color(brand, blue);
    border-color: get-color(brand, blue);
  }

  &:active {
    color: darken(get-color(brand, blue), 10%);
    border-color: get-color(brand, blue);
  }

  &:disabled {
    pointer-events: none;
    color: get-color(ash);
    border-color: get-color(ash);
  }
}

///
/// Button container
.ButtonContainer {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  margin-top: -(get-spacing(tightest));
  margin-left: -(get-spacing(tightest));

  .Button {
    @include flex-item-fix;
    display: block;
    flex: 0 0 auto;
    margin-top: get-spacing(tightest);
    margin-left: get-spacing(tightest);
  }
}

///
/// Variants
@import 'variants';


================================================
FILE: examples/src/components/Button/variants.scss
================================================
////
/// Components
/// Button variants
////

.Button--isActive {
  color: white;
  background-color: get-color(coal, dark);

  &:focus,
  &:hover {
    color: white;
    background-color: get-color(brand, blue);
    border-color: get-color(brand, blue);
  }

  &:active {
    color: white;
    background-color: darken(get-color(brand, blue), 10%);
    border-color: darken(get-color(brand, blue), 10%);
  }

  &:disabled {
    pointer-events: none;
    color: white;
    background-color: get-color(ash);
    border-color: get-color(ash);
  }
}

.Button--typePill {
  border-radius: get-type-scale(button) * 2;
}


================================================
FILE: examples/src/components/Document/Favicon.html
================================================
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Draggable">

<link rel="icon" type="image/png" sizes="16x16" href="https://shopify.github.io/draggable/assets/img/favicons/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://shopify.github.io/draggable/assets/img/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="https://shopify.github.io/draggable/assets/img/favicons/favicon-96x96.png">
<link rel="apple-touch-icon" sizes="180x180" href="https://shopify.github.io/draggable/assets/img/favicons/apple-touch-icon.png">


================================================
FILE: examples/src/components/Document/Head.html
================================================
{% import 'components/Document/SocialShare.html' as SocialShare %}

{% macro render(ViewAttr) %}
  {% set url = 'https://shopify.github.io/draggable' %}
  {% set siteName = 'Draggable JS Examples' %}
  {% set titleSep = ' | ' %}

  {% set parentFragment = ViewAttr.parent + titleSep if ViewAttr.parent %}
  {% set childFragment = ViewAttr.child + titleSep if ViewAttr.child %}
  {% set titleText = [parentFragment, childFragment, siteName] %}

  {% set HeadAttr = {
    siteName: siteName,
    title: ViewAttr.subheading,
    description: 'Draggable is a lightweight, responsive, modern drag and drop JavaScript library – the ideal choice for adding slick native-feeling drag and drop behaviour to your web apps.',
    siteUrl: url,
    socialImg: url + '/assets/img/social/draggable-social.png',
    twitterHandle: '@Shopify',
    twitterId: '17136315'
  } %}

  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <title>{{ titleText | join('') | trim }}</title>

    <meta name="description" content="{{ HeadAttr.description }}">
    <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
    <meta name="format-detection" content="telephone=no">
    <meta name="theme-color" content="#212529">

    {{ SocialShare.render(HeadAttr) }}
    {% include 'components/Document/Favicon.html' %}

    <link rel="manifest" href="{{ url }}/manifest.json">
    <link rel="stylesheet" href="assets/css/examples-app.css?beta=12">

    <script src="assets/js/examples-runtime.js?beta=12" defer></script>
    <!-- <script src="assets/js/examples-vendor.js?beta=12" defer></script> -->
    <script src="assets/js/examples-app.js?beta=12" defer></script>
  </head>
{% endmacro %}


================================================
FILE: examples/src/components/Document/SocialShare.html
================================================
{% macro render(HeadAttr) %}
  <meta property="og:type" content="website">
  <meta property="og:site_name" content="{{ HeadAttr.siteName }}">
  <meta property="og:title" content="{{ HeadAttr.title }}">
  <meta property="og:description" content="{{ HeadAttr.description }}">
  <meta property="og:image" content="{{ HeadAttr.socialImg }}">
  <meta property="og:url" content="{{ siteUrl }}">
  <meta property="twitter:card" content="summary_large_image">
  <meta property="twitter:site" content="{{ HeadAttr.twitterHandle }}">
  <meta property="twitter:account_id" content="{{ HeadAttr.twitterId }}">
  <meta property="twitter:title" content="{{ HeadAttr.title }}">
  <meta property="twitter:description" content="{{ HeadAttr.description }}">
  <meta property="twitter:image" content="{{ HeadAttr.socialImg }}">
{% endmacro %}


================================================
FILE: examples/src/components/GridOverlay/GridOverlay.scss
================================================
////
/// Components
/// Grid Overlay
////

@import 'utils/shared/functions';
@import 'utils/shared/layout';
@import 'components/Main/props';

$grid-overlay-baseline: 0.1rem;

.GridOverlay {
  --columns: 4;
  --repeating-width: calc(100% / var(--columns));
  --gutter-size: get-layout-length(gutter, mobile);
  --column-width: calc((100% / var(--columns)) - var(--gutter-size));
  --baseline-stop: calc(var(--gutter-size) - #{$grid-overlay-baseline});
  --row-height: calc(#{rows(1, true)} + var(--gutter-size));
  --bg-width: calc(100% + var(--gutter-size));
  --bg-baseline: repeating-linear-gradient(
    to bottom,
    get-color(purple),
    get-color(purple) $grid-overlay-baseline,
    transparent $grid-overlay-baseline,
    transparent var(--baseline-stop),
    get-color(purple) var(--baseline-stop),
    get-color(purple) var(--gutter-size),
    transparent var(--gutter-size),
    transparent var(--row-height)
  );
  --bg-columns: repeating-linear-gradient(
    to right,
    get-color(purple, light),
    get-color(purple, light) var(--column-width),
    transparent var(--column-width),
    transparent var(--repeating-width)
  );

  @media screen and (min-width: get-breakpoint(tablet)) {
    --columns: 6;
    --gutter-size: get-layout-length(gutter);
    --row-height: calc(#{rows()} + var(--gutter-size));
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    --columns: 8;
  }

  // positioned parent will be `body`
  @include centered-width(get-layout-length(main-interior));
  z-index: 1;
  position: fixed;
  top: 0;
  bottom: 0;
  left: get-spacing(tight);
  right: get-spacing(tight);
  min-height: 100vh;
  background-image: var(--bg-baseline), var(--bg-columns);
  background-size: var(--bg-width) 100%;
  background-position: 0 calc(-1 * var(--gutter-size));
  mix-blend-mode: multiply;
  opacity: 0.8;
  pointer-events: none;

  @media screen and (min-width: get-breakpoint()) {
    left: $main-padding-left-tablet;
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    right: get-spacing(fattest);
    left: $main-padding-left-desktop;
  }
}

.GridOverlay--isHidden {
  display: none;
}


================================================
FILE: examples/src/components/Hamburger/Hamburger.html
================================================
<button type="button" id="MobileNavActivator" class="Hamburger" aria-controls="Sidebar" aria-expanded="false">
  <div class="HamburgerBun">
    <div class="HamburgerPatty"></div>
  </div>
</button>


================================================
FILE: examples/src/components/Hamburger/Hamburger.scss
================================================
////
/// Components
/// Hamburger
////

@import 'utils/shared/layout';
@import 'keyframes';
@import 'props';

.Hamburger {
  z-index: get-z-index(hamburger);
  position: absolute;
  top: get-spacing();
  left: 50%;
  margin-left: -$hamburger-offset;
  padding: get-spacing(tightest);
  // prevent the 'X' on page load
  opacity: 0;
  animation: FadeActivator get-duration(slow) get-easing() forwards;

  @media only screen and (min-width: get-breakpoint()) {
    @include visually-hidden;
  }

  &[aria-expanded='true'] {
    .HamburgerBun::before,
    .HamburgerBun::after {
      background-color: white;
    }

    .HamburgerBun::before {
      animation-name: HamburgerBefore-In;
    }

    .HamburgerBun::after {
      animation-name: HamburgerAfter-In;
    }

    .HamburgerPatty {
      animation-name: HamburgerPatty-In;
    }
  }
}

///
/// HamburgerBun menu styles
.HamburgerBun {
  position: relative;
  width: $hamburger-width;
  height: $hamburger-height;

  &::before,
  &::after {
    content: '';
    top: 0;
    display: block;
    transition: background-color get-duration() get-easing();
  }

  &::before,
  &::after,
  .HamburgerPatty {
    position: absolute;
    left: 0;
    width: 100%;
    height: $hamburger-line-height;
    border-radius: $hamburger-line-height;
    background-color: get-color(coal, dark);
    animation-duration: get-duration();
    animation-timing-function: get-easing();
    animation-fill-mode: both;
  }

  &::before {
    transform: translateY(0) rotate(0);
    animation-name: HamburgerBefore-Out;
  }

  &::after {
    transform: translateY($hamburger-after-y) rotate(0);
    animation-name: HamburgerAfter-Out;
  }
}

.HamburgerPatty {
  top: $hamburger-vertical-center;
  animation-name: HamburgerPatty-Out;
}


================================================
FILE: examples/src/components/Hamburger/keyframes.scss
================================================
////
/// Components
/// Hamburger keyframes
////

@import 'props';

@keyframes FadeActivator {
  to {
    opacity: 1;
  }
}

@keyframes HamburgerBefore-In {
  0% {
    transform: translateY(0) rotate(0);
  }

  50% {
    transform: translateY($hamburger-vertical-center) rotate(0);
  }

  100% {
    transform: translateY($hamburger-vertical-center) rotate(45deg);
  }
}

@keyframes HamburgerBefore-Out {
  0% {
    transform: translateY($hamburger-vertical-center) rotate(45deg);
  }

  50% {
    transform: translateY($hamburger-vertical-center) rotate(0);
  }

  100% {
    transform: translateY(0) rotate(0);
  }
}

@keyframes HamburgerAfter-In {
  0% {
    transform: translateY($hamburger-after-y) rotate(0);
  }

  50% {
    transform: translateY($hamburger-vertical-center) rotate(0);
  }

  100% {
    transform: translateY($hamburger-vertical-center) rotate(-45deg);
  }
}

@keyframes HamburgerAfter-Out {
  0% {
    transform: translateY($hamburger-vertical-center) rotate(-45deg);
  }

  50% {
    transform: translateY($hamburger-vertical-center) rotate(0);
  }

  100% {
    transform: translateY($hamburger-after-y) rotate(0);
  }
}

@keyframes HamburgerPatty-In {
  0%,
  25% {
    opacity: 1;
  }

  50%,
  100% {
    opacity: 0;
  }
}

@keyframes HamburgerPatty-Out {
  0%,
  25% {
    opacity: 0;
  }

  50%,
  100% {
    opacity: 1;
  }
}


================================================
FILE: examples/src/components/Hamburger/props.scss
================================================
////
/// Components
/// Hamburger props
////

$hamburger-width: 2.4rem;
$hamburger-height: 2rem;
$hamburger-line-height: 0.3rem;
$hamburger-after-y: $hamburger-height - $hamburger-line-height;
$hamburger-vertical-center: ($hamburger-height / 2) - ($hamburger-line-height / 2);
$hamburger-offset: (get-spacing(tightest) * 2 + $hamburger-width) / 2;


================================================
FILE: examples/src/components/Handle/DragHandle.scss
================================================
////
/// Components
/// DragHandle
////

@import 'props';

.DragHandle {
  position: relative;
  width: $handle-size;
  height: $handle-size;
  background-color: currentColor;
  transition: background-color get-duration(fast) get-easing();

  &::before,
  &::after {
    content: '';
    position: absolute;
    right: 0;
    left: 0;
    display: block;
    height: $handle-stroke-width;
    background-color: white;
    transition: background-color get-duration(fast) get-easing();
  }

  &::before {
    top: $handle-stroke-width;
  }

  &::after {
    bottom: $handle-stroke-width;
  }
}


================================================
FILE: examples/src/components/Handle/NopeHandle.scss
================================================
////
/// Components
/// NopeHandle
////

@import 'props';

.NopeHandle {
  position: relative;
  width: $handle-size;
  height: $handle-size;
  border: $handle-stroke-width solid currentColor;
  border-radius: 50%;
  transition: border-color get-duration(fast) get-easing();

  &::before {
    content: '';
    position: absolute;
    top: $handle-center - $handle-stroke-width;
    left: -($handle-stroke-width / 2);
    display: block;
    width: $handle-size - $handle-stroke-width;
    height: $handle-stroke-width;
    background-color: currentColor;
    transform: rotate(45deg);
  }
}


================================================
FILE: examples/src/components/Handle/props.scss
================================================
////
/// Components
/// Handle props
////

$handle-size: 2rem;
$handle-stroke-width: 0.4rem;
$handle-center: ($handle-size / 2) - ($handle-stroke-width / 2);

@mixin drag-handle-dragging {
  background-color: white;

  &::before,
  &::after {
    background-color: get-color(brand, blue);
  }
}


================================================
FILE: examples/src/components/Heading/Heading.scss
================================================
////
/// Components
/// Heading
////

@import 'props';

.Heading {
  @include Heading;
}

.Subheading {
  @include Subheading;
}

@import 'variants';


================================================
FILE: examples/src/components/Heading/props.scss
================================================
////
/// Components
/// Heading props
////

@mixin Heading {
  letter-spacing: get-type-scale(base, tracking);
  line-height: get-type-scale(base, leading);
  color: currentColor;
}

@mixin Subheading {
  font-size: get-type-scale(subheading);
  font-weight: get-type-scale(subheading, weight);
  letter-spacing: get-type-scale(base, tracking);
  line-height: get-type-scale(base, leading);
  color: get-color(coal, light);

  @media screen and (min-width: get-breakpoint(tablet)) {
    font-size: get-type-scale(subheading, tablet);
  }
}

///
/// Heading sizes
@mixin HeadingSizeJumbo {
  font-size: get-type-scale(jumbo);
  font-weight: get-type-scale(jumbo, weight);
  line-height: get-type-scale(jumbo, leading);

  @media screen and (min-width: get-breakpoint(tablet)) {
    font-size: get-type-scale(jumbo, tablet);
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    font-size: get-type-scale(jumbo, desktop);
  }
}

@mixin HeadingSize1 {
  margin-bottom: get-spacing(tight);
  font-size: get-type-scale(h1);
  font-weight: get-type-scale(h1, weight);

  @media screen and (min-width: get-breakpoint(tablet)) {
    margin-bottom: get-spacing();
    font-size: get-type-scale(h1, tablet);
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    font-size: get-type-scale(h1, desktop);
  }
}

@mixin HeadingSize2 {
  font-size: get-type-scale(h2);
  font-weight: get-type-scale(h2, weight);

  @media screen and (min-width: get-breakpoint(tablet)) {
    font-size: get-type-scale(h2, tablet);
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    font-size: get-type-scale(h2, desktop);
  }
}

@mixin HeadingSize3 {
  font-size: get-type-scale(h3);
  font-weight: get-type-scale(h3, weight);

  @media screen and (min-width: get-breakpoint(tablet)) {
    font-size: get-type-scale(h3, tablet);
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    font-size: get-type-scale(h3, desktop);
  }
}

@mixin HeadingSize4 {
  font-size: get-type-scale(h4);
  font-weight: get-type-scale(h4, weight);

  @media screen and (min-width: get-breakpoint(tablet)) {
    font-size: get-type-scale(h4, tablet);
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    font-size: get-type-scale(h4, desktop);
  }
}


================================================
FILE: examples/src/components/Heading/variants.scss
================================================
////
/// Components
/// Heading variants
////

@import 'props';

///
/// Heading sizes
.Heading--sizeJumbo {
  @include HeadingSizeJumbo;
}

.Heading--size1 {
  @include HeadingSize1;
}

.Heading--size2 {
  @include HeadingSize2;
}

.Heading--size3 {
  @include HeadingSize3;
}

.Heading--size4 {
  @include HeadingSize4;
}

///
/// Heading colors
.Heading--colorWhite {
  color: white;
}


================================================
FILE: examples/src/components/Link/Link.scss
================================================
////
/// Components
/// Link
////

.Link {
  color: get-color(purple, light);
  transition: color get-duration() get-easing();

  &:focus,
  &:hover {
    color: get-color(purple);
  }

  &:active {
    color: get-color(purple, dark);
  }
}

///
/// Variants
.Link--typeDark {
  color: get-color(purple);

  &:focus,
  &:hover {
    color: get-color(brand, yellow);
  }

  &:active {
    color: get-color(brand, orange);
  }
}

.Link--typeUnderlined {
  display: inline-block;
  font-size: 1.6rem;
  font-weight: 700;
  color: get-color(coal, dark);
  text-decoration: underline;
  text-decoration-line: underline;
  text-decoration-skip: ink;

  &:focus,
  &:hover {
    color: get-color(brand, blue);
  }

  &:active {
    color: darken(get-color(brand, blue), 10%);
  }
}

.Link--noWrap {
  white-space: nowrap;
}


================================================
FILE: examples/src/components/Main/Main.scss
================================================
////
/// Components
/// Main
////

@import 'utils/shared/layout';
@import 'components/MobileNav/props';
@import 'props';

.Main {
  padding: $mobile-nav-padding-top get-spacing(tight) get-spacing(looser);
  min-height: 100vh;
  overflow: hidden;
  background-color: white;

  @media screen and (min-width: get-breakpoint()) {
    padding-top: get-spacing(looser);
    padding-left: $main-padding-left-tablet;
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    padding: get-spacing(fat) get-spacing(fattest) get-spacing(fat) $main-padding-left-desktop;
  }
}

.MainInterior {
  @include centered-width(get-layout-length(main-interior));
}


================================================
FILE: examples/src/components/Main/props.scss
================================================
////
/// Components
/// Main props
////

$main-padding-left-tablet: get-layout-length(sidebar) + get-spacing(tight);
$main-padding-left-desktop: get-layout-length(sidebar) + get-spacing(fattest);


================================================
FILE: examples/src/components/MobileNav/index.js
================================================
import debounce, {debounceDuration} from '../../scripts/utils/debounce';

// equal to `get-breakpoint()` base value
const MAX_WIDTH = 960;

const Attrs = {
  controls: 'aria-controls',
  expanded: 'aria-expanded',
  hidden: 'aria-hidden',
};

export default class MobileNav {
  constructor(activator) {
    this.activator = activator;
    this.target = document.getElementById(activator.getAttribute(Attrs.controls));
  }

  init() {
    if (!this.target) {
      console.error('The activator must have a valid `aria-controls` value. Target not found.');
      return;
    }

    this._setState();
    this.activator.addEventListener('click', this.toggle.bind(this));

    window.addEventListener(
      'resize',
      debounce(() => {
        this._setState();
      }, debounceDuration),
    );
  }

  expand(widthExceeded = false) {
    const lockScrolling = !widthExceeded;
    const willExpand = widthExceeded ? 'undefined' : 'false';

    this.expanded = true;
    this.activator.setAttribute(Attrs.expanded, 'true');
    this.target.setAttribute(Attrs.hidden, willExpand);
    document.documentElement.dataset.scrollLock = lockScrolling;
  }

  collapse() {
    if (this.expanded === false) {
      return;
    }

    this.expanded = false;
    this.activator.setAttribute(Attrs.expanded, 'false');
    this.target.setAttribute(Attrs.hidden, 'true');
    document.documentElement.dataset.scrollLock = false;
  }

  toggle() {
    return this.expanded ? this.collapse() : this.expand();
  }

  _setState() {
    const windowWidth = document.documentElement.clientWidth;

    // currently collapses when resizing within any mobile range...
    // I should update this to remain `expanded` when resizing within that range
    return windowWidth < MAX_WIDTH ? this.collapse() : this.expand(true);
  }
}


================================================
FILE: examples/src/components/MobileNav/props.scss
================================================
////
/// Components
/// MobileNav props
////

$mobile-nav-padding-top: get-spacing(looser) * 2;


================================================
FILE: examples/src/components/Navigation/NavList.html
================================================
{% macro render(ViewAttr, SubNav) %}
  {% for Section, Links in SubNav %}
    {% set listClasses = ['NavList'] %}
    {% set listClasses = (
      listClasses.push('NavList--isCurrent') if ViewAttr.parent == Section, listClasses
    ) %}

    <ul class="{{ listClasses | join(' ') | trim }}">
      <li class="NavItem">
        <span class="NavHeading">{{ Section }}</span>
      </li>

      {% for Link in Links %}
        {% set linkHref = Link | lower | replace(' ', '-') %}
        {% set linkClasses = ['NavLink'] %}
        {% set linkClasses = (
          linkClasses.push('NavLink--isCurrent') if ViewAttr.child == Link, linkClasses
        ) %}
        {% set linkClasses = linkClasses | join(' ') | trim %}

        {% if '~' in Link %}
          {% set openingTag = '<span class="' + linkClasses + '">' %}
          {% set closingTag = '</span>' %}
        {% else %}
          {% set openingTag = '<a href="' + linkHref + '.html" class="' + linkClasses + '" title="See example: ' + Link + '">' %}
          {% set closingTag = '</a>' %}
        {% endif %}

        <li class="NavItem">
          {{ openingTag | safe }}
            {{ Link | replace('~', '') }}
          {{ closingTag | safe }}
        </li>
      {% endfor %}
    </ul>
  {% endfor %}
{% endmacro %}


================================================
FILE: examples/src/components/Navigation/Navigation.html
================================================
{% import 'components/Navigation/NavList.html' as NavList %}

{% macro render(ViewAttr, DataPages) %}
  <nav class="Navigation">
    {% for SubNav in DataPages %}
      {{ NavList.render(ViewAttr, SubNav) }}
    {% endfor %}
  </nav>
{% endmacro %}


================================================
FILE: examples/src/components/Navigation/Navigation.scss
================================================
////
/// Components
/// Navigation
////

.Navigation {
  padding: get-spacing(tight);

  @media screen and (min-width: get-breakpoint()) {
    flex: 1; // for sticky footer
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    padding-right: get-spacing(loose);
    padding-left: get-spacing(loose);
  }
}

.NavList {
  & + & {
    margin-top: get-spacing();

    @media screen and (min-width: get-breakpoint()) {
      margin-top: get-spacing(looser);
    }
  }
}

.NavItem {
  & + & {
    margin-top: get-spacing(tightest) + $spacing-unit;

    @media screen and (min-width: get-breakpoint()) {
      margin-top: get-spacing(tighter);
    }
  }
}

.NavHeading,
.NavLink {
  font-size: get-type-scale(nav);
  letter-spacing: get-type-scale(nav, tracking);
  line-height: get-type-scale(nav, leading);

  @media screen and (min-width: get-breakpoint()) {
    font-size: get-type-scale(nav, '960');
  }
}

.NavHeading {
  font-weight: get-type-scale(h1, weight);
  color: white;

  .NavList--isCurrent & {
    color: get-color(brand, yellow);
  }
}

// Use .Link class?
.NavLink {
  font-weight: get-type-scale(subheading, weight);
  color: get-color(coal, light);

  &.NavLink--isCurrent {
    pointer-events: none;
    color: get-color(purple);
  }

  &.NavLink--isDisabled {
    pointer-events: none;
    color: get-color(coal, light);
  }
}

a.NavLink {
  color: get-color(ash, dark);
  transition: color get-duration() get-easing();

  &:focus,
  &:hover {
    color: get-color(purple);
  }

  &:active {
    color: get-color(purple, dark);
  }
}


================================================
FILE: examples/src/components/Page/Page.scss
================================================
////
/// Components
/// Page
////

@import 'utils/shared/layout';

html {
  @include scroll-lock;
  font-family: get-font-stack();

  ::selection {
    color: white;
    background-color: get-color(coal, dark);
  }
}

body {
  cursor: get-cursor();
  position: relative;
  background-color: white;

  // Better page overscroll... specifically adds color above and below the Sidebar
  @media screen and (min-width: get-breakpoint()) {
    &::before,
    &::after {
      content: '';
      position: sticky;
      left: 0;
      display: block;
      width: get-layout-length(sidebar) - get-spacing(fattest);
      height: 0;
    }

    &::before {
      top: 0;
      box-shadow: 0 -#{get-spacing(fattest)} 0 get-spacing(fattest) get-color(coal, dark);
    }

    &::after {
      bottom: 0;
      box-shadow: 0 get-spacing(fattest) 0 get-spacing(fattest) get-color(coal, dark);
    }
  }
}

///
/// Cursor styles
p,
li,
dd,
.Heading,
.Subheading {
  cursor: get-cursor(text);
}

a,
button {
  cursor: get-cursor(pointer);

  &:active {
    cursor: get-cursor(pointer, active);
  }
}

.draggable--is-dragging {
  &,
  * {
    cursor: get-cursor(drag, active);
  }
}

// Set `state` cursors to never used tags only so they can be fetched on page load,
// rather than the instance they are first requested...
.preload-cursors {
  @include visually-hidden;

  b {
    cursor: get-cursor(drag, active);
  }

  u {
    cursor: get-cursor(pointer, active);
  }

  a {
    cursor: get-cursor(rock, active);
  }
}


================================================
FILE: examples/src/components/PageHeader/PageHeader.html
================================================
{% macro render(ViewAttr) %}
  {% set contentPath = '' %}
  {% set contentPath = ViewAttr.parent + '/' if ViewAttr.child %}
  {% set contentPath = contentPath + ViewAttr.id %}

  <header class="PageHeader">
    <h1 class="Heading Heading--size1">{{ ViewAttr.parent }}</h1>
    <h2 class="Subheading">{{ ViewAttr.subheading }}</h2>
    <a href="https://github.com/Shopify/draggable/tree/main/examples/src/content/{{ contentPath }}" class="Link Link--typeUnderlined" title="See this code example">View code on GitHub</a>
  </header>
{% endmacro %}


================================================
FILE: examples/src/components/PageHeader/PageHeader.scss
================================================
////
/// Components
/// PageHeader
////

@import 'utils/shared/layout';

.PageHeader {
  @include centered-width(get-layout-length(page-header));
  margin-bottom: get-spacing(loose);
  text-align: center;
  color: get-color(coal, dark);

  @media screen and (min-width: get-breakpoint(tablet)) {
    margin-bottom: get-spacing(loosest);
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    margin-bottom: get-spacing(fattest);
  }

  .Link {
    margin-top: get-spacing(tight);

    @media screen and (min-width: get-breakpoint(desktop)) {
      margin-top: get-spacing();
    }
  }
}


================================================
FILE: examples/src/components/PaperStack/PaperStack.scss
================================================
////
/// Components
/// PaperStack
////

@import 'utils/shared/layout';
@import 'props';

.PaperStack {
  position: relative;
  margin-right: auto;
  margin-left: auto;
  width: paper-stack-item(width);
  height: paper-stack(height);

  @media screen and (min-width: get-breakpoint(tablet)) {
    width: paper-stack-item(width, tablet);
    height: paper-stack(height, tablet);
  }

  @media screen and (min-width: get-breakpoint('1080p', wide)) {
    width: paper-stack-item(width, desktop);
    height: paper-stack(height, desktop);
  }
}

.PaperStackItem {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
}

.PaperStackContent {
  @include flex-center;
  position: relative;
  width: 100%;
  height: paper-stack-item(height);
  color: white;
  background-color: get-color(coal, dark);
  border: get-border() solid get-color(coal, dark);
  border-top-width: get-border(thick);
  transform: paper-stack-item(transform);
  backface-visibility: hidden; // this might not be making any difference...

  @media screen and (min-width: get-breakpoint(tablet)) {
    height: paper-stack-item(height, tablet);
  }

  @media screen and (min-width: get-breakpoint('1080p', wide)) {
    height: paper-stack-item(height, desktop);
  }
}

.PaperStackHeading {
  margin-top: paper-stack-heading(margin);
  font-size: paper-stack-heading(size);
  font-weight: paper-stack-heading(weight);
  line-height: paper-stack-heading(leading);

  @media screen and (min-width: get-breakpoint(tablet)) {
    font-size: paper-stack-heading(size, tablet);
  }

  @media screen and (min-width: get-breakpoint('1080p', wide)) {
    font-size: paper-stack-heading(size, desktop);
  }
}

///
/// Layout
.PaperStackItem:nth-child(1n + 2) {
  .PaperStackContent::after {
    content: '';
    position: absolute;
    right: -(paper-stack-shadow(offset));
    bottom: paper-stack-shadow(bottom);
    left: -(paper-stack-shadow(offset));
    display: block;
    height: paper-stack-shadow(height);
    background-color: get-color(coal, dark);
    transition: transform get-duration() get-easing();

    @media screen and (min-width: get-breakpoint(tablet)) {
      bottom: paper-stack-shadow(bottom, tablet);
      height: paper-stack-shadow(height, tablet);
    }

    @media screen and (min-width: get-breakpoint('1080p', wide)) {
      bottom: paper-stack-shadow(bottom, desktop);
      height: paper-stack-shadow(height, desktop);
    }
  }
}

// stylelint-disable-next-line no-duplicate-selectors
.PaperStackItem {
  @for $i from 1 through $paper-stack-item-count {
    &:nth-child(#{$i}) {
      z-index: ($paper-stack-item-count + 1) - $i;
    }
  }

  @include paper-stack-item-offset;

  @media screen and (min-width: get-breakpoint(tablet)) {
    @include paper-stack-item-offset(tablet);
  }

  @media screen and (min-width: get-breakpoint('1080p', wide)) {
    @include paper-stack-item-offset(desktop);
  }
}

@import 'variants';


================================================
FILE: examples/src/components/PaperStack/PaperStackItem.html
================================================
{% macro render(heading, options = {}) %}
  {% set classes = ['PaperStackItem'] %}
  {% set classes = (classes.push('PaperStackItem--isDraggable') if options.draggable, classes) %}
  {% set classes = (classes.push('PaperStackItem--item' + options.index) if options.index, classes) %}
  {% set classes = (classes.push(options.classes | join(' ')) if options.classes, classes) %}
  {% set classes = classes | join(' ') | trim %}

  {% set tabIndex = 'tabindex="1"' if options.draggable %}

  <li class="{{ classes }}" {{ tabIndex | safe }}>
    <div class="PaperStackContent">
      <h4 class="Heading text-no-select PaperStackHeading">{{ heading }}</h4>

      {% if options.draggable %}
        <div class="Pattern Pattern--typeHalftone"></div>
        <div class="Pattern Pattern--typePlaced"></div>
      {% endif %}
    </div>
  </li>
{% endmacro %}


================================================
FILE: examples/src/components/PaperStack/props.scss
================================================
////
/// Components
/// PaperStack props
////

$paper-stack-block-name: unquote('PaperStackItem');
$paper-stack-item-count: 4;

///
/// Size calc functions
@function paper-stack-height($height, $spacing) {
  @return $height - (($spacing / 2) * ($paper-stack-item-count - 1));
}

///
/// Style prop maps
$paper-stack-item: (
  spacing: (
    base: get-spacing(),
    tablet: get-spacing(loose),
    desktop: get-spacing(looser),
  ),
  width: (
    base: 24rem,
    tablet: 42rem,
    desktop: 60rem,
  ),
  height: (
    base: 38rem,
    tablet: 58rem,
    desktop: 78rem,
  ),
  transform: (
    base: perspective(90rem) rotateX(60deg),
    mirror: perspective(90rem) rotateX(58deg) scale(1.025),
  ),
);

@function paper-stack-item($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($paper-stack-item, $group, $variant);
}

$paper-stack-heading: (
  size: (
    base: 7.2rem,
    tablet: 12rem,
    desktop: 16rem,
  ),
  weight: 700,
  leading: 1,
  margin: 0.5em,
);

@function paper-stack-heading($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($paper-stack-heading, $group, $variant);
}

$paper-stack-shadow: (
  bottom: (
    base: paper-stack-item(spacing) / 2,
    tablet: paper-stack-item(spacing, tablet) / 2,
    desktop: paper-stack-item(spacing, desktop) / 3,
  ),
  height: (
    base: paper-stack-item(spacing),
    tablet: paper-stack-item(spacing, tablet),
    desktop: paper-stack-item(spacing, desktop),
  ),
  offset: (
    base: 0.8rem,
  ),
);

@function paper-stack-shadow($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($paper-stack-shadow, $group, $variant);
}

$paper-stack: (
  height: (
    base: paper-stack-height(paper-stack-item(height), paper-stack-item(spacing)),
    tablet: paper-stack-height(paper-stack-item(height, tablet), paper-stack-item(spacing, tablet)),
    desktop:
      paper-stack-height(paper-stack-item(height, desktop), paper-stack-item(spacing, desktop)),
  ),
);

@function paper-stack($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($paper-stack, $group, $variant);
}

///
/// Mixins
@mixin paper-stack-item-offset($breakpoint: $threads-default-value) {
  $adjusted-top-offset: -((paper-stack-item(width, $breakpoint) / $paper-stack-item-count) +
        (paper-stack-item(spacing, $breakpoint) / 2));

  @for $i from 1 through $paper-stack-item-count {
    &:nth-child(#{$i}),
    &.draggable--original ~ .PaperStackItem:nth-child(#{$i + 1}) {
      top: $adjusted-top-offset;
    }

    $adjusted-top-offset: $adjusted-top-offset + paper-stack-item(spacing, $breakpoint);
  }
}


================================================
FILE: examples/src/components/PaperStack/variants.scss
================================================
////
/// Components
/// PaperStack variants
////

@import 'components/Patterns/props';
@import 'props';

///
/// Draggable layout
.draggable--original:first-child + .PaperStackItem {
  .PaperStackContent::after {
    content: none;
  }
}

///
/// Draggable Items
.PaperStackItem--isDraggable {
  cursor: get-cursor(drag);

  .PaperStackContent {
    color: get-color(coal, dark);
    background-color: white;
    border-color: currentColor;
    transition: color get-duration(fast) get-easing(),
      background-color get-duration(fast) get-easing(), transform get-duration() get-easing();
  }

  // interaction
  &:focus,
  &:hover {
    .PaperStackContent {
      color: get-color(brand, blue);
      transform: paper-stack-item(transform) translateY(get-spacing(tightest));

      &::after {
        transform: translateY(-(get-spacing(tightest)));
      }
    }
  }

  &.draggable-source--is-dragging {
    .PaperStackContent {
      color: get-color(brand, blue);

      .Pattern--typeHalftone {
        @include pattern-halftone-animated;
      }
    }
  }

  &.draggable-source--placed {
    .PaperStackContent {
      .Pattern--typePlaced {
        @include pattern-placed-animated;
      }
    }
  }

  &.draggable-mirror {
    z-index: get-z-index(overlay);

    .PaperStackContent {
      color: white;
      background-color: get-color(brand, blue);
      border-color: get-color(brand, blue);
      transform: paper-stack-item(transform, mirror);

      &::after {
        content: none;
      }
    }
  }
}


================================================
FILE: examples/src/components/Patterns/Patterns.scss
================================================
////
/// Components
/// Patterns
////

@import 'utils/shared/layout';
@import 'keyframes';
@import 'props';

:root {
  --pattern-bg-color: white;
}

.Pattern {
  @include visible(false);
  @include position-cover;
}

.Pattern--typeStripes {
  @include stripes-bg;
}

.Pattern--typeHalftone {
  background-image: radial-gradient(currentColor 24%, transparent 25%),
    radial-gradient(currentColor 24%, transparent 25%);
  background-position: $halftone-bg-position-start;
  background-size: $halftone-bg-size $halftone-bg-size;
  animation: halftone get-duration(slow) steps(3) infinite both paused;
  // transition seems to have no affect... maybe bring back the `fade-in` animation?
  // transition: opacity get-duration() get-easing(), visibility get-duration() get-easing();
}

.Pattern--typePlaced {
  background-color: get-color(brand, blue);
}


================================================
FILE: examples/src/components/Patterns/keyframes.scss
================================================
////
/// Components
/// Patterns keyframes
////

@import 'props';

@keyframes placed {
  to {
    transform: scale(0);
  }
}

@keyframes halftone {
  from {
    background-position: $halftone-bg-position-start;
  }

  to {
    background-position: $halftone-bg-position-end;
  }
}


================================================
FILE: examples/src/components/Patterns/props.scss
================================================
////
/// Components
/// Pattern props
////

@import 'utils/shared/layout';

$stripes-bg-size: 0.8rem;
$halftone-bg-size: 1.2rem;
$halftone-bg-position-start: 0 0, ($halftone-bg-size / 2) ($halftone-bg-size / 2);
$halftone-bg-position-end: ($halftone-bg-size / 2) ($halftone-bg-size / 2),
  $halftone-bg-size $halftone-bg-size;

@mixin stripes-bg {
  background-image: repeating-linear-gradient(
    -45deg,
    var(--pattern-bg-color) 0%,
    var(--pattern-bg-color) 40%,
    currentColor 40%,
    currentColor 50%,
    var(--pattern-bg-color) 50%
  );
  background-size: $stripes-bg-size $stripes-bg-size;
}

@mixin pattern-bg-reset {
  background-image: none;
  background-color: transparent;
  background-size: auto auto;
}

@mixin pattern-halftone-animated {
  @include visible;
  animation-play-state: running;
}

@mixin pattern-placed-animated {
  @include visible;
  animation: placed get-duration() get-easing() both;
}


================================================
FILE: examples/src/components/PillSwitch/PillSwitch.html
================================================
{% macro render() %}
  <article class="PillSwitch">
    <div class="PillSwitchTrack">
      <div class="Pattern Pattern--typeHalftone"></div>
    </div>

    <span class="PillSwitchControl">
      <p class="Heading Heading--sizeJumbo text-no-select" data-switch-off="off" data-switch-on="on">off</p>
    </span>
  </article>
{% endmacro %}


================================================
FILE: examples/src/components/PillSwitch/PillSwitch.scss
================================================
////
/// Components
/// PillSwitch
////

@import 'utils/shared/layout';
@import 'components/Patterns/props';
@import 'props';

.PillSwitch {
  position: relative;
  margin-right: auto;
  margin-left: auto;
  width: pill-switch(size);
  height: pill-switch(size);

  @media screen and (min-width: get-breakpoint(tablet)) {
    width: pill-switch(size, tablet);
    height: pill-switch(size, tablet);
  }
}

.PillSwitchTrack {
  @include pill-switch-track-layout;
  @include pill-switch-border(get-border());
  position: absolute;
  top: 50%;
  left: 50%;
  color: get-color(brand, blue);
  background-color: white;
  transform: rotate(-45deg);
  overflow: hidden;

  &::after {
    content: '';
    position: absolute;
    top: -(get-border());
    right: -(get-border());
    bottom: -(get-border());
    left: -(get-border());
    display: block;
    background-color: get-color(coal, dark);
    transition: opacity get-duration(fast) get-easing();
  }

  @media screen and (min-width: get-breakpoint(tablet)) {
    @include pill-switch-track-layout('tablet');
    @include pill-switch-border(get-border(thick));
  }

  // halftone is always animated and blue to mitigate slight transition inconsistency...
  // ::after overlays it so its fine
  .Pattern--typeHalftone {
    @include pattern-halftone-animated;
    height: pill-switch(size);
    transform: rotate(45deg);

    @media screen and (min-width: get-breakpoint(tablet)) {
      height: pill-switch(size, tablet);
    }
  }
}

.PillSwitchControl {
  @include flex-center;
  position: absolute;
  bottom: 0;
  left: 0;
  width: pill-switch(control-size);
  height: pill-switch(control-size);
  color: get-color(coal, dark);
  background-color: white;
  border: get-border() solid currentColor;
  border-radius: 50%;
  transition: color get-duration(fast) get-easing();

  @media screen and (min-width: get-breakpoint(tablet)) {
    width: pill-switch(control-size, tablet);
    height: pill-switch(control-size, tablet);
    border-width: get-border(thick);
  }

  // visually center
  .Heading {
    margin-top: -0.1em;
    margin-left: -0.05em;
  }

  &:focus,
  &:hover,
  &.draggable-mirror {
    color: get-color(brand, blue);
  }

  &:active {
    color: get-color(brand, blue-dark);
  }

  &.draggable-source--is-dragging {
    @include visible(false);
  }
}

@import 'variants';


================================================
FILE: examples/src/components/PillSwitch/props.scss
================================================
////
/// Components
/// PillSwitch props
////

$pill-switch-size: 27.2rem;
$pill-switch-size-tablet: 54.8rem;

$pill-switch-control-size: 13rem;
$pill-switch-control-size-tablet: 32rem;

$pill-switch-radius: $pill-switch-control-size / 2;
$pill-switch-radius-tablet: $pill-switch-control-size-tablet / 2;

$pill-switch-data: (
  size: (
    base: $pill-switch-size,
    tablet: $pill-switch-size-tablet,
  ),
  radius: (
    base: $pill-switch-radius,
    tablet: $pill-switch-radius-tablet,
  ),
  control-size: (
    base: $pill-switch-control-size,
    tablet: $pill-switch-control-size-tablet,
  ),
  track-width: (
    base: $pill-switch-control-size * 2 + $pill-switch-radius,
    tablet: $pill-switch-control-size-tablet * 2,
  ),
);

@function pill-switch($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($pill-switch-data, $group, $variant);
}

///
/// Mixins
@mixin pill-switch-track-layout($breakpoint: 'base') {
  margin-top: -(pill-switch(radius, $breakpoint));
  margin-left: -(pill-switch(track-width, $breakpoint) / 2);
  width: pill-switch(track-width, $breakpoint);
  height: pill-switch(control-size, $breakpoint);
  border-radius: pill-switch(radius, $breakpoint);
}

@mixin pill-switch-border($width) {
  // cannot use border as the psuedo elements will not overlap
  box-shadow: inset 0 0 0 $width get-color(brand, blue);
}


================================================
FILE: examples/src/components/PillSwitch/variants.scss
================================================
////
/// Components
/// PillSwitch variants
////

@import 'components/Patterns/props';

.PillSwitch--isOn {
  .PillSwitchTrack {
    &::after {
      opacity: 0;
    }
  }

  .PillSwitchControl {
    top: 0;
    right: 0;
    bottom: auto;
    left: auto;
    color: white;
    background-color: get-color(brand, blue);
    border-color: get-color(brand, blue);

    &:focus,
    &:hover,
    &.draggable-mirror {
      color: get-color(brand, blue);
      background-color: white;
    }

    &:active {
      color: get-color(brand, blue-dark);
    }
  }
}


================================================
FILE: examples/src/components/Plate/Plate.html
================================================
{% macro render(index, options = {}) %}
  {% set classes = ['Plate'] %}

  {% if options.level and (
    options.level === 'Top' or options.level === 'Middle' or options.level === 'Bottom'
  ) %}
    {% set classes = (classes.push('Plate--level' + options.level), classes) %}
  {% endif %}

  {% set classes = (classes.push('Plate--isDraggable') if options.draggable, classes) %}
  {% set classes = (classes.push(options.classes | join(' ')) if options.classes, classes) %}
  {% set classes = classes | join(' ') | trim %}

  {% if options.draggable %}
    {% set openingTag = '<span class="' + classes + '" title="Click to drag">' %}
    {% set closingTag = '</span>' %}
  {% else %}
    {% set openingTag = '<span class="' + classes + '">' %}
    {% set closingTag = '</span>' %}
  {% endif %}

  {{ openingTag | safe }}
    <div class="PlateShadowWrapper">
      <div class="PlateShadow"></div>
    </div>

    <div class="PlateContent">
      {% if options.heading %}
        <h2 class="Heading Heading--size1 text-no-select">{{ options.heading }}</h2>
      {% endif %}

      <h3 class="Heading visually-hidden">{{ index }}</h3>
    </div>
  {{ closingTag | safe }}
{% endmacro %}


================================================
FILE: examples/src/components/Plate/Plate.scss
================================================
////
/// Components
/// Plate
////

@import 'utils/shared/layout';
@import 'keyframes';
@import 'props';

.PlateWrapper {
  @include centered-width($plate-max-size);
  position: relative;
  padding-top: 100%;
  height: 0;

  @media screen and (min-width: get-breakpoint('720p', wide)) {
    padding-top: 0;
    height: $plate-max-size;
  }
}

.Plate {
  @include position-cover;
  height: 0;
  color: white;
  // required for more accurate :hover hitbox
  border-radius: 50%;
}

.PlateShadowWrapper {
  @include position-cover;
  pointer-events: none;
}

.PlateShadow {
  width: 100%;
  height: 100%;

  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    display: block;
    width: 100%;
    height: 100%;
    background-color: get-color(coal, dark);
    border-radius: 50%;
  }
}

.PlateContent {
  @include position-cover;
  @include flex-center;
  background-color: get-color(coal, dark);
  border-radius: 50%;

  .Heading {
    margin-bottom: 0;
  }
}

@import 'variants';


================================================
FILE: examples/src/components/Plate/index.js
================================================
import flipSign from '../../scripts/utils/flip-sign';

const scaleFactor = 0.725;
const translateFactors = {
  bottom: 0.075,
  middle: 0.5,
  top: 0.975,
};
const Classes = {
  bottom: 'Plate--levelBottom',
  middle: 'Plate--levelMiddle',
  top: 'Plate--levelTop',
};

function calculatePlateScale(value, max, factor) {
  const step1 = Math.abs(value) / max;
  const step2 = step1 - step1 * factor;

  return 1 - step2;
}

export default class Plate {
  constructor(wrapper) {
    this.wrapper = wrapper;
    this.plates = {
      bottom: wrapper.getElementsByClassName(Classes.bottom)[0],
      middle: wrapper.getElementsByClassName(Classes.middle)[0],
      top: wrapper.getElementsByClassName(Classes.top)[0],
    };
    this.threshold = {
      min: -27.2,
      max: 27.2,
    };
    this.initialMousePosition = {
      x: 0,
      y: 0,
    };
  }

  setThreshold() {
    const newThreshold = this.wrapper.offsetWidth / 10;

    this.threshold = {
      min: flipSign(newThreshold),
      max: newThreshold,
    };
  }

  setInitialMousePosition(sensorEvent) {
    this.initialMousePosition.x = sensorEvent.clientX;
    this.initialMousePosition.y = sensorEvent.clientY;
  }

  dragWarp(source, sensorEvent) {
    const adjustedX = this._offsetWithinThreshold(this.initialMousePosition.x, sensorEvent.clientX);
    const adjustedY = this._offsetWithinThreshold(this.initialMousePosition.y, sensorEvent.clientY);

    this._scalePlates(adjustedX, adjustedY);
    this._translateShadow(adjustedX, adjustedY);
    this._translateEachPlate(adjustedX, adjustedY);
  }

  resetWarp() {
    this._scalePlates(0, 0);
    this._translateShadow(0, 0);
    this._translateEachPlate(0, 0);
  }

  _offsetWithinThreshold(initialPosition, currentPosition) {
    const updatedPosition = initialPosition - currentPosition;
    let offset = updatedPosition;

    if (updatedPosition < this.threshold.min) {
      offset = this.threshold.min;
    } else if (updatedPosition > this.threshold.max) {
      offset = this.threshold.max;
    }

    return offset;
  }

  _scalePlates(x, y) {
    const scaleX = calculatePlateScale(x, this.threshold.max, scaleFactor);
    const scaleY = calculatePlateScale(y, this.threshold.max, scaleFactor);

    this.wrapper.style.setProperty('--plate-scale-x', `${scaleX}`);
    this.wrapper.style.setProperty('--plate-scale-y', `${scaleY}`);
  }

  _translateEachPlate(x, y) {
    for (const plateLevel in this.plates) {
      // eslint-disable-next-line no-prototype-builtins
      if (this.plates.hasOwnProperty(plateLevel)) {
        const translateX = flipSign(x * 2) * translateFactors[plateLevel];
        const translateY = flipSign(y * 2) * translateFactors[plateLevel];

        this.wrapper.style.setProperty(`--${plateLevel}-translate-x`, `${translateX}px`);
        this.wrapper.style.setProperty(`--${plateLevel}-translate-y`, `${translateY}px`);
      }
    }
  }

  _translateShadow(x, y) {
    this.wrapper.style.setProperty('--shadow-offset-x', `${x / 2}px`);
    this.wrapper.style.setProperty('--shadow-offset-y', `${y / 2}px`);
  }
}


================================================
FILE: examples/src/components/Plate/keyframes.scss
================================================
////
/// Components
/// Plate keyframes
////

@keyframes plate-small {
  0%,
  100% {
    transform: scale(1, 1);
  }

  10% {
    transform: scale(1.1, 0.96);
  }

  25% {
    transform: scale(0.925, 1.075);
  }

  50% {
    transform: scale(1.0125, 0.975);
  }

  75% {
    transform: scale(0.975, 1.0125);
  }

  95% {
    transform: scale(1.005, 0.995);
  }
}

@keyframes plate-medium {
  0%,
  100% {
    transform: scale(1, 1);
  }

  10% {
    transform: scale(1.15, 0.95);
  }

  25% {
    transform: scale(0.9, 1.1);
  }

  50% {
    transform: scale(1.025, 0.96);
  }

  75% {
    transform: scale(0.98, 1.025);
  }

  95% {
    transform: scale(1.01, 0.985);
  }
}

@keyframes plate-big {
  0%,
  100% {
    transform: scale(1, 1);
  }

  10% {
    transform: scale(1.2, 0.9);
  }

  25% {
    transform: scale(0.85, 1.15);
  }

  50% {
    transform: scale(1.075, 0.95);
  }

  75% {
    transform: scale(0.975, 1.05);
  }

  95% {
    transform: scale(1.0125, 0.98);
  }
}

@keyframes plate-placed {
  0%,
  100% {
    color: get-color(coal, dark);
  }

  50% {
    color: get-color(brand, blue);
  }
}


================================================
FILE: examples/src/components/Plate/props.scss
================================================
////
/// Components
/// Plate props
////

$plate-max-size: 80rem;


================================================
FILE: examples/src/components/Plate/variants.scss
================================================
////
/// Components
/// Plate variants
////

///
/// Level variant
.Plate--levelBottom {
  padding-top: 100%;
  width: 100%;

  .PlateShadow {
    transform: rotate(55deg);
  }
}

.Plate--levelMiddle {
  padding-top: 75%;
  width: 75%;

  .PlateShadow {
    transform: rotate(45deg);
  }
}

.Plate--levelTop {
  padding-top: 50%;
  width: 50%;

  .PlateShadow {
    transform: rotate(35deg);
  }
}

///
/// Draggable variant
.PlateWrapper {
  --shadow-offset-x: 0;
  --shadow-offset-y: 0;
  --plate-scale-x: 1;
  --plate-scale-y: 1;
  --bottom-translate-x: 0;
  --bottom-translate-y: 0;
  --middle-translate-x: 0;
  --middle-translate-y: 0;
  --top-translate-x: 0;
  --top-translate-y: 0;

  &.draggable-container--placed {
    .Plate--levelBottom,
    .Plate--levelMiddle,
    .Plate--levelTop {
      animation-name: plate-placed;
      animation-duration: get-duration();
      animation-timing-function: get-easing();
    }

    .Plate--levelBottom {
      animation-delay: get-duration() / 2;
    }

    .Plate--levelMiddle {
      animation-delay: get-duration() / 4;
    }
  }
}

.Plate--isDraggable {
  color: get-color(coal, dark);
  // helps smooth out on some devices: + transform get-duration(faster) linear
  transition: color get-duration(fast) get-easing();

  &:focus,
  &:hover {
    color: get-color(brand, blue);
  }

  .PlateShadowWrapper {
    transform: translate3d(var(--shadow-offset-x), var(--shadow-offset-y), 0);
  }

  .PlateShadow::before {
    background-color: currentColor;
    animation-duration: get-duration(slow);
    animation-timing-function: get-easing();
  }

  .PlateContent {
    background-color: white;
    border: get-border(flexible) solid currentColor;
    animation-duration: get-duration(slow);
    animation-timing-function: get-easing();

    @media screen and (min-width: get-breakpoint()) {
      border-width: get-border(thick);
    }
  }

  &.Plate--levelBottom {
    transform: translate3d(var(--bottom-translate-x), var(--bottom-translate-y), 0)
      scale(var(--plate-scale-x), var(--plate-scale-y));

    &:focus,
    &:hover {
      .PlateContent,
      .PlateShadow::before {
        animation-name: plate-small;
      }
    }
  }

  &.Plate--levelMiddle {
    transform: translate3d(var(--middle-translate-x), var(--middle-translate-y), 0)
      scale(var(--plate-scale-x), var(--plate-scale-y));

    &:focus,
    &:hover {
      .PlateContent,
      .PlateShadow::before {
        animation-name: plate-medium;
      }
    }
  }

  &.Plate--levelTop {
    transform: translate3d(var(--top-translate-x), var(--top-translate-y), 0)
      scale(var(--plate-scale-x), var(--plate-scale-y));

    &:focus,
    &:hover {
      .PlateContent,
      .PlateShadow::before {
        animation-name: plate-big;
      }
    }
  }

  // would be nice if there was a better way to suppress the creation of the mirror
  &.draggable-mirror {
    display: none;
  }
}

.draggable-container--placed {
  .Plate--levelBottom {
    .PlateContent,
    .PlateShadow::before {
      animation-name: plate-small;
    }
  }

  .Plate--levelMiddle {
    .PlateContent,
    .PlateShadow::before {
      animation-name: plate-medium;
    }
  }

  .Plate--levelTop {
    .PlateContent,
    .PlateShadow::before {
      animation-name: plate-big;
    }
  }
}


================================================
FILE: examples/src/components/Sidebar/Sidebar.html
================================================
{% import 'components/Navigation/Navigation.html' as Navigation %}

{% macro render(ViewAttr, DataPages) %}
  <aside id="Sidebar" class="Sidebar" aria-hidden="true">
    <header class="SidebarHeader">
      {% include 'components/Brand/Brand.html' %}
    </header>

    {{ Navigation.render(ViewAttr, DataPages) }}

    <footer class="SidebarFooter">
      <p class="LegalText"><a href="https://shopify.github.io/draggable/" class="Link Link--typeDark" title="Visit Draggable JS">draggable.js</a> was developed by <a href="https://github.com/tsov" class="Link Link--noWrap" title="Github: tsov">Max Hoffmann</a> and <a href="https://github.com/beefchimi" class="Link Link--noWrap" title="Github: beefchimi">Curtis Dulmage</a>.</p>

      <p class="LegalText">Draggable is released under the <a href="https://github.com/Shopify/shopify.github.com/blob/main/LICENSE.md" class="Link Link--noWrap" title="View MIT License" target="_blank" rel="noopener">MIT license</a>. You are free to use the code from this library for both personal and commercial use.</p>

      <p class="preload-cursors"><b>Special thanks</b> <u>to all of our</u> <a href="https://github.com/Shopify/draggable/graphs/contributors" title="We love our contributors!">amazing contributors</a>.</p>
    </footer>
  </aside>
{% endmacro %}


================================================
FILE: examples/src/components/Sidebar/Sidebar.scss
================================================
////
/// Components
/// Sidebar
////

@import 'utils/shared/layout';
@import 'components/MobileNav/props';

.Sidebar {
  @include position-cover;
  z-index: get-z-index(sidebar);
  background-color: get-color(coal, dark);
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;

  @media screen and (max-width: get-breakpoint() - 1px) {
    text-align: center;
    transition: opacity get-duration() get-easing(), visibility get-duration() get-easing();

    &::before {
      content: '';
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      display: block;
      height: $mobile-nav-padding-top;
      background: linear-gradient(
        rgba(get-color(coal, dark), 0.9) 40%,
        rgba(get-color(coal, dark), 0)
      );
    }

    // protect against resizing visibility
    &[aria-hidden='undefined'] {
      display: none;
    }

    &[aria-hidden='true'] {
      @include visible(false);
    }
  }

  @media screen and (min-width: get-breakpoint()) {
    position: fixed;
    right: auto;
    display: flex; // for sticky footer
    flex-direction: column; // for sticky footer
    width: get-layout-length(sidebar);
  }
}

.SidebarHeader {
  padding: $mobile-nav-padding-top get-spacing(tight) get-spacing(tight);

  @media screen and (min-width: get-breakpoint()) {
    padding-top: get-spacing(looser);
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    padding-top: get-spacing(fat);
    padding-right: get-spacing(loose);
    padding-left: get-spacing(loose);
  }
}

.SidebarFooter {
  padding: get-spacing(loose) get-spacing(tight);

  @media screen and (min-width: get-breakpoint(desktop)) {
    padding: get-spacing(fat) get-spacing(loose);
  }
}

.LegalText {
  font-size: get-type-scale(footer);
  font-weight: get-type-scale(footer, weight);
  line-height: get-type-scale(footer, leading);
  color: white;

  & + & {
    margin-top: get-spacing(tighter);
  }

  @media screen and (max-width: get-breakpoint() - 1px) {
    margin-left: auto;
    margin-right: auto;
    max-width: get-layout-length(sidebar);
  }
}


================================================
FILE: examples/src/components/StackedList/StackedList.scss
================================================
////
/// Components
/// StackedList
////

@import 'utils/shared/layout';
@import 'utils/shared/typography';
@import 'components/Handle/props';
@import 'components/Heading/props';
@import 'components/Patterns/props';
@import 'props';

.StackedListWrapper {
  @include stripes-bg;
  position: relative;
  color: get-color(coal, dark);
  box-shadow: inset 0 0 0 get-border(thin) currentColor;
  // `draggable-container-parent--capacity` changes the `color` on `StackedListWrapper`...
  // This is supposed to "trickle" down and cause all children to transition color as well...
  // Problem is, sometimes these transitions seem to collide and we don't get syncronised timing...
  // Sadly, there is no way to target `box-shadow`'s color without the use of currentColor.
  // transition: color get-duration(fast) get-easing();

  @media screen and (min-width: get-breakpoint(tablet)) {
    box-shadow: inset 0 0 0 get-border() currentColor;
  }
}

.StackedListHeader,
.StackedListContent {
  // cannot be `min-height`, as a child's `height: 100%` will not work
  // by using `height`, we will get visible scrollbars
  height: stacked-list-item();

  @media screen and (min-width: get-breakpoint(desktop)) {
    height: stacked-list-item(base, desktop);
  }
}

.StackedListHeader {
  padding: stacked-list-header(padding);
  background-color: currentColor;
  transition: color get-duration(fast) get-easing();

  @media screen and (min-width: get-breakpoint(tablet)) {
    padding: stacked-list-header(padding, tablet);
  }

  p {
    margin-top: 0.2em;
    font-size: get-type-scale(paragraph);
    color: white;

    @media screen and (min-width: get-breakpoint(tablet)) {
      font-size: get-type-scale(paragraph, tablet);
    }

    @media screen and (min-width: get-breakpoint(desktop)) {
      font-size: get-type-scale(paragraph, desktop);
    }
  }
}

.StackedList {
  position: relative;
  margin-top: -(get-border(thin));

  @media screen and (min-width: get-breakpoint(tablet)) {
    margin-top: -(get-border());
  }

  &::before {
    @include visible(false);
    @include position-cover;
    @include Heading;
    @include HeadingSize4;
    @include text-no-select;
    // stylelint-disable-next-line shopify/content-no-strings
    content: 'drop items here';
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    width: 80%;
    height: 80%;
    background-color: white;
    transition: opacity get-duration() get-easing(), visibility get-duration() get-easing();
  }

  &:empty {
    &::before {
      @include visible;
    }
  }
}

.StackedListItem {
  cursor: get-cursor();

  &:nth-child(1n + 2) {
    margin-top: -(get-border(thin));

    @media screen and (min-width: get-breakpoint(tablet)) {
      margin-top: -(get-border());
    }
  }

  .draggable--original:first-child + & {
    margin-top: 0;
  }
}

.StackedListContent {
  position: relative;
  display: flex;
  align-items: center;
  padding: get-spacing(tighter);
  color: currentColor;
  background-color: get-color(ash, light);
  border: get-border(thin) solid currentColor;
  transition: color get-duration(fast) get-easing(),
    background-color get-duration(fast) get-easing(), transform get-duration() get-easing(bungie);

  @media screen and (min-width: get-breakpoint(tablet)) {
    border-width: get-border();
  }

  .Heading {
    flex: 1 1 auto;
  }

  .DragHandle,
  .NopeHandle {
    flex: 0 0 $handle-size;
    margin-left: get-spacing(tight);
  }

  // top border psuedo element... solution to create a collapsed border
  // required to make the hover style highlight each side of the element
  &::before {
    content: '';
    position: absolute;
    top: -(get-border(thin));
    right: -(get-border(thin));
    left: -(get-border(thin));
    display: block;
    height: get-border(thin);
    background-color: currentColor;
    opacity: 0;
    transition: color get-duration(fast) get-easing(), opacity get-duration(fast) get-easing();

    @media screen and (min-width: get-breakpoint(tablet)) {
      top: -(get-border());
      right: -(get-border());
      left: -(get-border());
      height: get-border();
    }
  }
}

@import 'variants';


================================================
FILE: examples/src/components/StackedList/StackedListItem.html
================================================
{% macro render(heading, options = {}) %}
  {% set classes = ['StackedListItem'] %}
  {% set classes = (classes.push('StackedListItem--isDraggable') if options.draggable, classes) %}
  {% set classes = (classes.push('StackedListItem--item' + options.index) if options.index, classes) %}
  {% set classes = (classes.push(options.classes | join(' ')) if options.classes, classes) %}
  {% set classes = classes | join(' ') | trim %}

  {% set tabIndex = 'tabindex="1"' if options.draggable %}
  {% set iconClass = 'DragHandle' if options.draggable else 'NopeHandle' %}

  <li class="{{ classes }}" {{ tabIndex | safe }}>
    <div class="StackedListContent">
      <h4 class="Heading Heading--size4 text-no-select">{{ heading }}</h4>
      <div class="{{ iconClass }}"></div>

      {% if options.draggable %}
        <div class="Pattern Pattern--typeHalftone"></div>
        <div class="Pattern Pattern--typePlaced"></div>
      {% endif %}
    </div>
  </li>
{% endmacro %}


================================================
FILE: examples/src/components/StackedList/props.scss
================================================
////
/// Components
/// StackedList props
////

$stacked-list-header: (
  padding: (
    base: get-spacing(tighter) + get-border(thin),
    tablet: get-spacing(tighter) + get-border(),
  ),
);

@function stacked-list-header($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($stacked-list-header, $group, $variant);
}

// using static values instead of `rows()`
// will consider switching later when I have more time
$stacked-list-item: (
  base: (
    base: 7.2rem,
    desktop: 8.6rem,
  ),
  medium: (
    base: 10rem,
    desktop: 16.4rem,
  ),
  large: (
    base: 14.4rem,
    desktop: 20.6rem,
  ),
);

@function stacked-list-item($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($stacked-list-item, $group, $variant);
}

///
/// Mixins
@mixin stacked-list-scroll-height($size: stacked-list-item(), $rows: 6, $border-width: thin) {
  height: ($size * $rows) - (get-border($border-width) * ($rows - 1));
}

@mixin scroll-indicator($vertical: true) {
  content: '';
  position: absolute;
  display: block;
  background-color: currentColor;
  transition: color get-duration(fast) get-easing(), opacity get-duration() get-easing();

  @if $vertical {
    right: 0;
    bottom: 0;
    left: 0;
    height: get-border(thin);
  } @else {
    top: 0;
    right: 0;
    bottom: 0;
    width: get-border(thin);
  }

  @media screen and (min-width: get-breakpoint(tablet)) {
    @if $vertical {
      height: get-border();
    } @else {
      width: get-border();
    }
  }
}


================================================
FILE: examples/src/components/StackedList/variants.scss
================================================
////
/// Components
/// StackedList variants
////

@import 'components/Handle/props';
@import 'components/Patterns/props';
@import 'props';

///
/// Size variants
.StackedListWrapper--sizeMedium {
  .StackedListHeader,
  .StackedListContent {
    height: stacked-list-item(medium);

    @media screen and (min-width: get-breakpoint(desktop)) {
      height: stacked-list-item(medium, desktop);
    }
  }
}

.StackedListWrapper--sizeLarge {
  .StackedListHeader,
  .StackedListContent {
    height: stacked-list-item(large);

    @media screen and (min-width: get-breakpoint(desktop)) {
      height: stacked-list-item(large, desktop);
    }
  }
}

///
/// Vertical scroll variant
/// Not to be paired with --axisHorizontal
.StackedListWrapper--hasScrollIndicator {
  &::after {
    @include scroll-indicator;
  }

  // does not address :focus on child elements
  &:hover {
    &::after {
      opacity: 0.1;
    }
  }
}

.StackedList--hasScroll {
  @include stacked-list-scroll-height;
  overflow-y: scroll;

  @media screen and (min-width: get-breakpoint(desktop)) {
    @include stacked-list-scroll-height(stacked-list-item(base, desktop), 7, base);
  }

  // Size variants

  .StackedListWrapper--sizeMedium & {
    @include stacked-list-scroll-height(stacked-list-item(medium), 3);

    @media screen and (min-width: get-breakpoint(desktop)) {
      @include stacked-list-scroll-height(stacked-list-item(medium, desktop), 3, base);
    }
  }

  .StackedListWrapper--sizeLarge & {
    @include stacked-list-scroll-height(stacked-list-item(large), 3);

    @media screen and (min-width: get-breakpoint(desktop)) {
      @include stacked-list-scroll-height(stacked-list-item(large, desktop), 3, base);
    }
  }
}

///
/// Axis variant
/// Has horizontal scrolling built-in
.StackedListWrapper--axisHorizontal {
  display: flex;

  &::after {
    @include scroll-indicator(false);
  }

  // does not address :focus on child elements
  &:hover {
    &::after {
      opacity: 0.1;
    }
  }

  .StackedListHeader,
  .StackedListContent {
    height: stacked-list-item();

    @media screen and (min-width: get-breakpoint(tablet)) {
      height: stacked-list-item(base, desktop);
    }
  }

  .StackedListHeader {
    flex: 0 0 stacked-list-item(large);

    @media screen and (min-width: get-breakpoint(tablet)) {
      flex-basis: stacked-list-item(large, desktop);
    }
  }

  .StackedList {
    display: flex;
    flex: 1 1 auto;
    margin-top: 0;
    margin-left: -(get-border(thin));
    overflow-x: scroll;

    @media screen and (min-width: get-breakpoint(tablet)) {
      margin-left: -(get-border());
    }
  }

  .StackedListItem {
    flex: 1 0 stacked-list-item(large);
    max-width: stacked-list-item(large) * 2;

    &:nth-child(1n + 2) {
      margin-top: 0;
      margin-left: -(get-border(thin));

      @media screen and (min-width: get-breakpoint(tablet)) {
        margin-left: -(get-border());
      }
    }

    @media screen and (min-width: get-breakpoint(tablet)) {
      flex-basis: stacked-list-item(large, desktop);
      max-width: stacked-list-item(large, desktop) * 2;
    }
  }

  .draggable--original:first-child + .StackedListItem {
    margin-left: 0;
  }

  .StackedListContent {
    flex-direction: column;
    justify-content: center;
    text-align: center;

    &::before {
      top: -(get-border(thin));
      right: auto;
      bottom: -(get-border(thin));
      left: -(get-border(thin));
      width: get-border(thin);
      height: auto;

      @media screen and (min-width: get-breakpoint(tablet)) {
        top: -(get-border());
        bottom: -(get-border());
        left: -(get-border());
        width: get-border();
      }
    }
  }

  .DragHandle,
  .NopeHandle {
    margin-left: 0;
  }

  &.StackedListWrapper--sizeMedium {
    .StackedListHeader,
    .StackedListContent {
      height: stacked-list-item(medium);

      @media screen and (min-width: get-breakpoint(tablet)) {
        height: stacked-list-item(medium, desktop);
      }
    }
  }

  &.StackedListWrapper--sizeLarge {
    .StackedListHeader,
    .StackedListContent {
      height: stacked-list-item(large);

      @media screen and (min-width: get-breakpoint(tablet)) {
        height: stacked-list-item(large, desktop);
      }
    }
  }
}

///
/// Draggable variant
.StackedListItem--isDraggable {
  cursor: get-cursor(drag);

  .StackedListContent {
    background-color: white;
  }

  // interaction
  &:focus {
    outline: none;
  }

  &:focus,
  &:hover {
    .StackedListContent {
      color: get-color(brand, blue);
    }

    + .StackedListItem {
      .StackedListContent::before {
        background-color: get-color(brand, blue);
        opacity: 1;
      }
    }
  }

  &.draggable-source--is-dragging {
    .StackedListContent {
      color: get-color(brand, blue);

      .Pattern--typeHalftone {
        @include pattern-halftone-animated;
      }
    }

    + .StackedListItem,
    + .draggable--original + .StackedListItem {
      // stylelint-disable-next-line selector-max-class
      .StackedListContent::before {
        background-color: get-color(brand, blue);
        opacity: 1;
      }
    }
  }

  &.draggable-source--placed {
    .StackedListContent {
      .Pattern--typePlaced {
        @include pattern-placed-animated;
      }
    }
  }

  &.draggable-mirror {
    z-index: get-z-index(overlay);
    transition: width get-duration() get-easing(bungie), height get-duration() get-easing(bungie);

    .StackedListContent {
      height: 100%;
      color: white;
      background-color: get-color(brand, blue);
      border-color: get-color(brand, blue);
      transform: scale(1.025);

      &::before,
      &::after {
        display: none;
      }
    }

    .DragHandle {
      @include drag-handle-dragging;
    }
  }
}


================================================
FILE: examples/src/components/Svg/Svg.scss
================================================
////
/// Components
/// Svg
////

a.SvgContainer {
  display: block;
  color: black; // default to black
}

.SvgContainer {
  .Svg {
    width: 100%;
    height: 100%;
    overflow: visible;
  }

  .Svg--heightAuto {
    height: auto;
  }
}

.Svg {
  fill: currentColor;
}


================================================
FILE: examples/src/content/Draggable/DragEvents/DragEvents.html
================================================
{% import 'components/PillSwitch/PillSwitch.html' as PillSwitch %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    {{ PillSwitch.render() }}
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Draggable/DragEvents/DragEvents.scss
================================================
////
/// Content
/// DragEvents
////

.DragEvents {
  // styles
}


================================================
FILE: examples/src/content/Draggable/DragEvents/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Draggable} from '@shopify/draggable';

function translateMirror(mirror, mirrorCoords, containerRect) {
  if (mirrorCoords.top < containerRect.top || mirrorCoords.left < containerRect.left) {
    return;
  }

  requestAnimationFrame(() => {
    mirror.style.transform = `translate3d(${mirrorCoords.left}px, ${mirrorCoords.top}px, 0)`;
  });
}

function calcOffset(offset) {
  return offset * 2 * 0.5;
}

export default function DragEvents() {
  const toggleClass = 'PillSwitch--isOn';
  const containers = document.querySelectorAll('#DragEvents .PillSwitch');

  if (containers.length === 0) {
    return false;
  }

  const draggable = new Draggable(containers, {
    draggable: '.PillSwitchControl',
    delay: 0,
  });

  let isToggled = false;
  let initialMousePosition;
  let containerRect;
  let dragRect;
  let dragThreshold;
  let headings;
  let headingText;

  // --- Draggable events --- //
  draggable.on('drag:start', (evt) => {
    initialMousePosition = {
      x: evt.sensorEvent.clientX,
      y: evt.sensorEvent.clientY,
    };
  });

  draggable.on('mirror:created', (evt) => {
    containerRect = evt.sourceContainer.getBoundingClientRect();
    dragRect = evt.source.getBoundingClientRect();

    const containerRectQuarter = containerRect.width / 4;
    dragThreshold = isToggled ? containerRectQuarter * -1 : containerRectQuarter;
    headings = {
      source: evt.originalSource.querySelector('[data-switch-on]'),
      mirror: evt.mirror.querySelector('[data-switch-on]'),
    };
    headingText = {
      on: headings.source.dataset.switchOn,
      off: headings.source.dataset.switchOff,
    };
  });

  draggable.on('mirror:move', (evt) => {
    // Required to help restrict the draggable element to the container
    evt.cancel();

    // We do not want to use `getBoundingClientRect` while dragging,
    // as that would be very expensive.
    // Instead, we look at the mouse position, which we can ballpark as being
    // close to the center of the draggable element.
    // We need to look at both the X and Y offset and determine which is the higher number.
    // That way we can drag outside of the container and still have the
    // draggable element move appropriately.
    const offsetX = calcOffset(evt.sensorEvent.clientX - initialMousePosition.x);
    const offsetY = calcOffset(initialMousePosition.y - evt.sensorEvent.clientY);
    const offsetValue = offsetX > offsetY ? offsetX : offsetY;
    const mirrorCoords = {
      top: dragRect.top - offsetValue,
      left: dragRect.left + offsetValue,
    };

    translateMirror(evt.mirror, mirrorCoords, containerRect);

    if (isToggled && offsetValue < dragThreshold) {
      evt.sourceContainer.classList.remove(toggleClass);
      headings.source.textContent = headingText.off;
      headings.mirror.textContent = headingText.off;
      isToggled = false;
    } else if (!isToggled && offsetValue > dragThreshold) {
      evt.sourceContainer.classList.add(toggleClass);
      headings.source.textContent = headingText.on;
      headings.mirror.textContent = headingText.on;
      isToggled = true;
    }
  });

  const triggerMouseUpOnESC = (evt) => {
    if (evt.key === 'Escape') {
      draggable.cancel();
    }
  };

  draggable.on('drag:start', () => {
    document.addEventListener('keyup', triggerMouseUpOnESC);
  });

  return draggable;
}


================================================
FILE: examples/src/content/Droppable/UniqueDropzone/UniqueDropzone.html
================================================
{% import 'components/Block/Block.html' as Block %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="BlockLayout BlockLayout--typeFlex">
      <div class="BlockWrapper BlockWrapper--isDropzone draggable-dropzone--occupied" data-dropzone="1">
        {{ Block.render('one', {type: 'Hollow'}) }}
        {{ Block.render('one', {index: 1, draggable: true}) }}
      </div>
      <div class="BlockWrapper BlockWrapper--isDropzone draggable-dropzone--occupied" data-dropzone="2">
        {{ Block.render('two', {type: 'Hollow'}) }}
        {{ Block.render('two', {index: 2, draggable: true}) }}
      </div>
      <div class="BlockWrapper BlockWrapper--isDropzone draggable-dropzone--occupied" data-dropzone="4">
        {{ Block.render('four', {type: 'Hollow'}) }}
        {{ Block.render('four', {index: 4, draggable: true}) }}
      </div>
      <div class="BlockWrapper BlockWrapper--isDropzone draggable-dropzone--occupied" data-dropzone="8">
        {{ Block.render('eight', {type: 'Hollow'}) }}
        {{ Block.render('eight', {index: 8, draggable: true}) }}
      </div>
    </article>

    <article class="BlockLayout BlockLayout--typeGrid">
      <div class="BlockWrapper BlockWrapper--isDropzone" data-dropzone="1">
        {{ Block.render('', {type: 'Stripes'}) }}
      </div>
      <div class="BlockWrapper BlockWrapper--isDropzone" data-dropzone="2">
        {{ Block.render('', {type: 'Stripes'}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('three', {index: 3, type: 'Shell'}) }}
      </div>
      <div class="BlockWrapper BlockWrapper--isDropzone" data-dropzone="4">
        {{ Block.render('', {type: 'Stripes'}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('five', {index: 5, type: 'Shell'}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('six', {index: 6, type: 'Shell'}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('seven', {index: 7, type: 'Shell'}) }}
      </div>
      <div class="BlockWrapper BlockWrapper--isDropzone" data-dropzone="8">
        {{ Block.render('', {type: 'Stripes'}) }}
      </div>
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Droppable/UniqueDropzone/UniqueDropzone.scss
================================================
////
/// Content
/// UniqueDropzone
////

@import 'utils/shared/functions';

$grid-area-names: a, b, c, d, e, f, g, h;
$grid-rows: 6;
$grid-columns: 4;

.UniqueDropzone {
  .BlockLayout {
    .BlockWrapper {
      .Block:nth-child(1n + 3):not(.draggable-source--is-dragging) {
        min-height: 0;
        height: 0;
      }
    }
  }

  .BlockLayout--typeFlex {
    .BlockWrapper {
      flex: 1 1 calc(50% - #{get-layout-length(gutter)});

      @media screen and (min-width: get-breakpoint(mobile, wide)) {
        flex-basis: calc(25% - #{get-layout-length(gutter)});
      }
    }
  }

  .BlockLayout--typeGrid {
    grid-template-rows: repeat($grid-rows, 1fr);
    grid-template-columns: repeat($grid-columns, 1fr);
    grid-template-areas:
      'a a b b'
      'a a d d'
      'c c d d'
      'e e f f'
      'e e g g'
      'h h h h';
    margin-top: get-border(thin);
    border: get-border(thin) solid get-color(coal, dark);
    background-color: get-color(coal, dark);

    @media screen and (min-width: get-breakpoint(tablet)) {
      // special fractions to line up with the flexContainer
      grid-template-columns: 1fr 1.025fr 1.025fr 1fr;
      grid-template-areas:
        'a c c g'
        'a c c g'
        'a d f g'
        'b d f g'
        'b e f h'
        'b e f h';
      margin-top: get-border();
      border-width: get-border();
    }

    .BlockWrapper--isDropzone {
      &::before {
        content: '';
        position: absolute;
        top: -(get-border(thin));
        right: -(get-border(thin));
        bottom: -(get-border(thin));
        left: -(get-border(thin));
        display: block;
        pointer-events: none;
        background-color: get-color(brand, blue);
        opacity: 0;
        transition: opacity get-duration(fast) get-easing();

        // stylelint-disable-next-line max-nesting-depth
        @media screen and (min-width: get-breakpoint(tablet)) {
          top: -(get-border());
          right: -(get-border());
          bottom: -(get-border());
          left: -(get-border());
        }
      }

      // not focusable, but, whatever... this was hard to solve
      &.draggable-dropzone--occupied:hover {
        // stylelint-disable-next-line max-nesting-depth
        &::before {
          opacity: 1;
        }
      }
    }

    .BlockContent {
      border: 0;
    }

    @for $i from 1 through length($grid-area-names) {
      .BlockWrapper:nth-child(#{$i}) {
        grid-area: nth($grid-area-names, $i);
      }
    }
  }

  // stylelint-disable-next-line no-duplicate-selectors
  .BlockLayout--typeFlex {
    .BlockContent {
      @media screen and (min-width: get-breakpoint(tablet)) {
        min-height: rows(3);
      }

      @media screen and (min-width: get-breakpoint(desktop)) {
        min-height: rows(4);
      }
    }
  }

  // not quite lining up with the rows correctly...
  // will likely need to tweak `grid` values
  // stylelint-disable-next-line no-duplicate-selectors
  .BlockLayout--typeGrid {
    // stylelint-disable-next-line no-duplicate-selectors
    .BlockContent {
      @media screen and (min-width: get-breakpoint(tablet)) {
        min-height: rows(3, false, true);
      }

      @media screen and (min-width: get-breakpoint(desktop)) {
        min-height: rows(4, false, true);
      }
    }
  }
}


================================================
FILE: examples/src/content/Droppable/UniqueDropzone/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Droppable} from '@shopify/draggable';

export default function UniqueDropzone() {
  const containers = document.querySelectorAll('#UniqueDropzone .BlockLayout');

  if (containers.length === 0) {
    return false;
  }

  const droppable = new Droppable(containers, {
    draggable: '.Block--isDraggable',
    dropzone: '.BlockWrapper--isDropzone',
    mirror: {
      constrainDimensions: true,
    },
  });

  let droppableOrigin;

  // --- Draggable events --- //
  droppable.on('drag:start', (evt) => {
    droppableOrigin = evt.originalSource.parentNode.dataset.dropzone;
  });

  droppable.on('droppable:dropped', (evt) => {
    if (droppableOrigin !== evt.dropzone.dataset.dropzone) {
      evt.cancel();
    }
  });

  return droppable;
}


================================================
FILE: examples/src/content/Home/Home.html
================================================
{% import 'components/Plate/Plate.html' as Plate %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="PlateWrapper">
      {{ Plate.render('Three', {level: 'Bottom', draggable: true}) }}
      {{ Plate.render('Two',   {level: 'Middle', draggable: true}) }}
      {{ Plate.render('One',   {heading: 'hello', level: 'Top', draggable: true}) }}
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Home/Home.scss
================================================
////
/// Content
/// Home
////

.Home {
  // styles
}


================================================
FILE: examples/src/content/Home/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Draggable} from '@shopify/draggable';

// eslint-disable-next-line shopify/strict-component-boundaries
import Plate from '../../components/Plate';

export default function Home() {
  const containerSelector = '#Home .PlateWrapper';
  const container = document.querySelector(containerSelector);

  if (!container) {
    return false;
  }

  const draggable = new Draggable(container, {
    draggable: '.Plate',
  });
  const plates = new Plate(container);

  // --- Draggable events --- //
  draggable.on('drag:start', (evt) => {
    plates.setThreshold();
    plates.setInitialMousePosition(evt.sensorEvent);
  });

  draggable.on('drag:move', (evt) => {
    // rAF seems to cause the animation to get stuck?
    // requestAnimationFrame(() => {});
    plates.dragWarp(evt.source, evt.sensorEvent);
  });

  draggable.on('drag:stop', () => {
    plates.resetWarp();
  });

  return draggable;
}


================================================
FILE: examples/src/content/Plugins/Collidable/Collidable.html
================================================
{% import 'components/Block/Block.html' as Block %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="BlockLayout BlockLayout--typePositioned">
      <div class="BlockWrapper BlockWrapper--isDropzone draggable-dropzone--occupied">
        {{ Block.render('drop', {type: 'Hollow'}) }}
        {{ Block.render('drag', {index: 1, draggable: true}) }}
      </div>

      {{ Block.render('', {index: 2, type: 'Stripes', classes: ['CollidableObstacle']}) }}
      {{ Block.render('', {index: 3, type: 'Stripes', classes: ['CollidableObstacle']}) }}

      <div class="BlockWrapper BlockWrapper--isDropzone">
        {{ Block.render('drop', {index: 4, type: 'Hollow'}) }}
      </div>

      {# If we ever implement a "constrain to container" feature, these can be removed #}
      <div class="CollidableWall CollidableWall--itemTop CollidableObstacle"></div>
      <div class="CollidableWall CollidableWall--itemRight CollidableObstacle"></div>
      <div class="CollidableWall CollidableWall--itemBottom CollidableObstacle"></div>
      <div class="CollidableWall CollidableWall--itemLeft CollidableObstacle"></div>
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Plugins/Collidable/Collidable.scss
================================================
////
/// Content
/// Collidable
////

@import 'props';

.Collidable {
  .BlockLayout--typePositioned {
    width: 100%;
    height: collidable(container-height);

    @media screen and (min-width: get-breakpoint(tablet)) {
      height: collidable(container-height, tablet);
    }

    @media screen and (min-width: get-breakpoint(desktop)) {
      height: collidable(container-height, desktop);
    }
  }

  .Block--item2,
  .Block--item3,
  .BlockWrapper:nth-child(1),
  .BlockWrapper:nth-child(4) {
    position: absolute;
    width: calc(50% - #{get-border(thin) * 2.5});

    @media screen and (min-width: get-breakpoint(tablet)) {
      width: calc(25% - #{get-border()});
    }
  }

  ///
  /// Obstacles
  .Block--item2,
  .Block--item3 {
    height: collidable(obstacle-height);

    @media screen and (min-width: get-breakpoint(tablet)) {
      height: collidable(obstacle-height, tablet);
    }

    @media screen and (min-width: get-breakpoint(desktop)) {
      height: collidable(obstacle-height, desktop);
    }
  }

  .Block--item2 {
    top: collidable(container-padding);
    right: collidable(container-padding);

    @media screen and (min-width: get-breakpoint(tablet)) {
      top: collidable(container-padding, tablet);
      right: auto;
      left: calc(25% + #{collidable(container-padding, tablet)});
    }
  }

  .Block--item3 {
    bottom: collidable(container-padding);
    left: collidable(container-padding);

    @media screen and (min-width: get-breakpoint(tablet)) {
      bottom: collidable(container-padding, tablet);
      right: collidable(container-padding, tablet);
      left: auto;
    }
  }

  ///
  /// Droppables
  .BlockWrapper:nth-child(1),
  .BlockWrapper:nth-child(4) {
    height: collidable(block-height);

    @media screen and (min-width: get-breakpoint(tablet)) {
      height: collidable(block-height, tablet);
    }

    @media screen and (min-width: get-breakpoint(desktop)) {
      height: collidable(block-height, desktop);
    }
  }

  .BlockWrapper:nth-child(1) {
    top: collidable(container-padding);
    left: collidable(container-padding);

    @media screen and (min-width: get-breakpoint(tablet)) {
      top: collidable(container-padding, tablet);
      left: collidable(container-padding, tablet);
    }
  }

  .BlockWrapper:nth-child(4) {
    bottom: collidable(container-padding);
    right: collidable(container-padding);

    @media screen and (min-width: get-breakpoint(tablet)) {
      top: collidable(container-padding, tablet);
      right: collidable(container-padding, tablet);
      bottom: auto;
    }
  }

  ///
  /// Walls
  .CollidableWall {
    position: absolute;
    background-color: get-color(coal, dark);
    transition: background-color get-duration() get-easing();
  }

  .CollidableWall--itemTop {
    top: 0;
    right: 0;
    left: 0;
    height: get-border(thin);

    @media screen and (min-width: get-breakpoint(tablet)) {
      height: get-border();
    }
  }

  .CollidableWall--itemRight {
    top: 0;
    right: 0;
    bottom: 0;
    width: get-border(thin);

    @media screen and (min-width: get-breakpoint(tablet)) {
      width: get-border();
    }
  }

  .CollidableWall--itemBottom {
    right: 0;
    bottom: 0;
    left: 0;
    height: get-border(thin);

    @media screen and (min-width: get-breakpoint(tablet)) {
      height: get-border();
    }
  }

  .CollidableWall--itemLeft {
    top: 0;
    bottom: 0;
    left: 0;
    width: get-border(thin);

    @media screen and (min-width: get-breakpoint(tablet)) {
      width: get-border();
    }
  }

  // Draggable
  .draggable-mirror {
    .BlockContent {
      transform: scale(0.9);
    }
  }

  .draggable-container--is-dragging:not(.draggable-container--over) {
    .Block--typeStripes {
      .BlockContent {
        color: get-color(brand, red);
      }
    }

    .CollidableWall {
      background-color: get-color(brand, red);
    }
  }

  // stylelint-disable-next-line no-duplicate-selectors
  .CollidableWall {
    &.isColliding {
      background-color: get-color(brand, red);
    }
  }
}


================================================
FILE: examples/src/content/Plugins/Collidable/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Droppable, Plugins} from '@shopify/draggable';

export default function PluginsCollidable() {
  const containerSelector = '#Collidable .BlockLayout';
  const containers = document.querySelectorAll(containerSelector);
  const wallClass = 'CollidableWall';
  const walls = document.querySelectorAll(`.${wallClass}`);

  if (containers.length === 0) {
    return false;
  }

  const droppable = new Droppable(containers, {
    draggable: '.Block--isDraggable',
    dropzone: '.BlockWrapper--isDropzone',
    collidables: '.CollidableObstacle',
    mirror: {
      appendTo: containerSelector,
      constrainDimensions: true,
    },
    plugins: [Plugins.Collidable],
  });

  // --- Draggable events --- //
  droppable.on('collidable:in', ({collidingElement}) => {
    if (collidingElement.classList.contains(wallClass)) {
      walls.forEach((wall) => wall.classList.add('isColliding'));
    } else {
      collidingElement.classList.add('isColliding');
    }
  });

  droppable.on('collidable:out', ({collidingElement}) => {
    if (collidingElement.classList.contains(wallClass)) {
      walls.forEach((wall) => wall.classList.remove('isColliding'));
    } else {
      collidingElement.classList.remove('isColliding');
    }
  });

  return droppable;
}


================================================
FILE: examples/src/content/Plugins/Collidable/props.scss
================================================
////
/// Content
/// Collidable props
////

@import 'utils/shared/functions';

$collidable-container-height: 60rem;
$collidable-container-height-tablet: 64rem;
$collidable-container-height-desktop: 80rem;

$collidable-block-height: rows(3, true);
$collidable-block-height-tablet: rows(4);
$collidable-block-height-desktop: rows(5);

$collidable: (
  container-height: (
    base: $collidable-container-height,
    tablet: $collidable-container-height-tablet,
    desktop: $collidable-container-height-desktop,
  ),
  container-padding: (
    base: get-border(thin) * 2,
    tablet: get-border() * 2,
  ),
  block-height: (
    base: $collidable-block-height,
    tablet: $collidable-block-height-tablet,
    desktop: $collidable-block-height-desktop,
  ),
  obstacle-height: (
    base: $collidable-container-height / 3,
    tablet: $collidable-container-height-tablet - $collidable-block-height-tablet -
      (
        get-border() * 5,
      ),
    desktop: $collidable-container-height-desktop - $collidable-block-height-desktop -
      (
        get-border() * 5,
      ),
  ),
);

@function collidable($group: $threads-default-value, $variant: $threads-default-value) {
  @return threads-value-get($collidable, $group, $variant);
}


================================================
FILE: examples/src/content/Plugins/Snappable/Snappable.html
================================================
{% import 'components/Block/Block.html' as Block %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="BlockLayout BlockLayout--typeGrid">
      <div class="BlockWrapper">
        {{ Block.render('snap', {index: 1, draggable: true, classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('two', {index: 2}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('', {index: 3, type: 'Stripes', classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('', {index: 4, type: 'Stripes', classes: ['draggable-source']}) }}
      </div>

      <div class="BlockWrapper">
        {{ Block.render('five', {index: 5}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('', {index: 6, type: 'Stripes', classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('crack', {index: 7, draggable: true, classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('eight', {index: 8}) }}
      </div>

      <div class="BlockWrapper">
        {{ Block.render('', {index: 9, type: 'Stripes', classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('ten', {index: 10}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('', {index: 11, type: 'Stripes', classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('pop', {index: 12, draggable: true, classes: ['draggable-source']}) }}
      </div>

      <div class="BlockWrapper">
        {{ Block.render('pow', {index: 13, draggable: true, classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('', {index: 14, type: 'Stripes', classes: ['draggable-source']}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('fifteen', {index: 15}) }}
      </div>
      <div class="BlockWrapper">
        {{ Block.render('', {index: 16, type: 'Stripes', classes: ['draggable-source']}) }}
      </div>
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Plugins/Snappable/Snappable.scss
================================================
////
/// Content
/// Snappable
////

@import 'utils/shared/functions';

.Snappable {
  .BlockLayout--typeGrid {
    grid-template-columns: repeat(2, 1fr);

    @media screen and (min-width: get-breakpoint(tablet)) {
      grid-template-rows: repeat(4, rows(3));
      grid-template-columns: repeat(4, 1fr);
    }

    @media screen and (min-width: get-breakpoint(desktop)) {
      grid-template-rows: repeat(4, rows(4));
    }
  }
}


================================================
FILE: examples/src/content/Plugins/Snappable/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Swappable, Plugins} from '@shopify/draggable';

export default function PluginsSnappable() {
  const containerSelector = '#Snappable .BlockLayout';
  const containers = document.querySelectorAll(containerSelector);

  if (containers.length === 0) {
    return false;
  }

  const swappable = new Swappable(containers, {
    mirror: {
      appendTo: containerSelector,
      constrainDimensions: true,
    },
    plugins: [Plugins.Snappable],
  });

  // --- Draggable events --- //
  swappable.on('drag:start', (evt) => {
    if (evt.originalSource.classList.contains('Block--typeStripes')) {
      evt.cancel();
    }
  });

  return swappable;
}


================================================
FILE: examples/src/content/Plugins/SortAnimation/SortAnimation.html
================================================
{% import 'components/Block/Block.html' as Block %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="BlockLayout BlockLayout--typeFlex">
      {{ Block.render('one',   {index: 1, draggable: true}) }}
      {{ Block.render('two',   {index: 2, draggable: true}) }}
      {{ Block.render('three', {index: 3, draggable: true}) }}
      {{ Block.render('four',  {index: 4, draggable: true}) }}
      {{ Block.render('five',  {index: 5, draggable: true}) }}
      {{ Block.render('six',   {index: 6, draggable: true}) }}
      {{ Block.render('seven', {index: 7, draggable: true}) }}
      {{ Block.render('eight', {index: 8, draggable: true}) }}
      {{ Block.render('nine',  {index: 9, draggable: true}) }}
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Plugins/SortAnimation/SortAnimation.scss
================================================
////
/// Content
/// SortAnimation
////

@import 'utils/shared/functions';
@import 'utils/shared/layout';

$sort-anim-block-name: unquote('Block');

.SortAnimation {
  @include draggable-source-layout($sort-anim-block-name, 1, 2, 4, 5, 7, 8) {
    flex-basis: 50%;
  }

  @include draggable-source-layout($sort-anim-block-name, 3, 6, 9) {
    flex-basis: 100%;
  }

  @media screen and (min-width: get-breakpoint(tablet)) {
    @include draggable-source-layout($sort-anim-block-name, 1, 2, 3, 4, 5, 6, 7, 8, 9) {
      flex-basis: 33.333%;
    }
  }

  .BlockContent {
    @media screen and (min-width: get-breakpoint(tablet)) {
      height: rows(3);
    }

    @media screen and (min-width: get-breakpoint(desktop)) {
      height: rows(4);
    }

    @media screen and (min-width: get-breakpoint('1080p', wide)) {
      height: rows(5);
    }
  }
}


================================================
FILE: examples/src/content/Plugins/SortAnimation/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Sortable, Plugins} from '@shopify/draggable';

export default function SortAnimation() {
  const containers = document.querySelectorAll('#SortAnimation .BlockLayout');

  if (containers.length === 0) {
    return false;
  }

  const sortable = new Sortable(containers, {
    draggable: '.Block--isDraggable',
    mirror: {
      constrainDimensions: true,
    },
    plugins: [Plugins.SortAnimation],
    swapAnimation: {
      duration: 200,
      easingFunction: 'ease-in-out',
    },
  });

  return sortable;
}


================================================
FILE: examples/src/content/Plugins/SwapAnimation/SwapAnimation.html
================================================
{% import 'components/Block/Block.html' as Block %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="BlockLayout BlockLayout--typeFlex">
      {{ Block.render('one',   {index: 1}) }}
      {{ Block.render('two',   {index: 2, draggable: true}) }}
      {{ Block.render('three', {index: 3, draggable: true}) }}
      {{ Block.render('four',  {index: 4, draggable: true}) }}
      {{ Block.render('five',  {index: 5}) }}
      {{ Block.render('six',   {index: 6, draggable: true}) }}
      {{ Block.render('seven', {index: 7, draggable: true}) }}
      {{ Block.render('eight', {index: 8, draggable: true}) }}
      {{ Block.render('nine',  {index: 9}) }}
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Plugins/SwapAnimation/SwapAnimation.scss
================================================
////
/// Content
/// SwapAnimation
////

@import 'utils/shared/functions';
@import 'utils/shared/layout';

$swap-anim-block-name: unquote('Block');

.SwapAnimation {
  @include draggable-source-layout($swap-anim-block-name, 1, 2, 4, 5, 7, 8) {
    flex-basis: 50%;
  }

  @include draggable-source-layout($swap-anim-block-name, 3, 6, 9) {
    flex-basis: 100%;
  }

  @media screen and (min-width: get-breakpoint(tablet)) {
    @include draggable-source-layout($swap-anim-block-name, 1, 2, 3, 4, 5, 6, 7, 8, 9) {
      flex-basis: 33.333%;
    }
  }

  .BlockContent {
    @media screen and (min-width: get-breakpoint(tablet)) {
      height: rows(3);
    }

    @media screen and (min-width: get-breakpoint(desktop)) {
      height: rows(4);
    }

    @media screen and (min-width: get-breakpoint('1080p', wide)) {
      height: rows(5);
    }
  }
}


================================================
FILE: examples/src/content/Plugins/SwapAnimation/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Sortable, Plugins} from '@shopify/draggable';

export default function PluginsSwapAnimation() {
  const containers = document.querySelectorAll('#SwapAnimation .BlockLayout');

  if (containers.length === 0) {
    return false;
  }

  const sortable = new Sortable(containers, {
    draggable: '.Block--isDraggable',
    mirror: {
      constrainDimensions: true,
    },
    plugins: [Plugins.SwapAnimation],
    swapAnimation: {
      duration: 200,
      easingFunction: 'ease-in-out',
    },
  });

  return sortable;
}


================================================
FILE: examples/src/content/Sortable/MultipleContainers/MultipleContainers.html
================================================
{% import 'components/StackedList/StackedListItem.html' as StackedListItem %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article id="ContainerOne" class="StackedListWrapper StackedListWrapper--sizeLarge StackedListWrapper--axisHorizontal Container">
      <header class="StackedListHeader">
        <h3 class="Heading Heading--size3 Heading--colorWhite">Container one</h3>
      </header>

      <ul class="StackedList">
        {{ StackedListItem.render('zebra',    {index: 1, draggable: true}) }}
        {{ StackedListItem.render('giraffe',  {index: 2, draggable: true}) }}
        {{ StackedListItem.render('baboon',   {index: 3                 }) }}
        {{ StackedListItem.render('elephant', {index: 4, draggable: true}) }}
        {{ StackedListItem.render('leopard',  {index: 5, draggable: true}) }}
      </ul>
    </article>

    <article id="ContainerTwo" class="StackedListWrapper StackedListWrapper--sizeMedium StackedListWrapper--hasScrollIndicator Container">
      <header class="StackedListHeader">
        <h3 class="Heading Heading--size3 Heading--colorWhite">Container two</h3>
        <p><em>3 item capacity</em></p>
      </header>

      <ul class="StackedList StackedList--hasScroll">
        {{ StackedListItem.render('fluorescent grey', {index: 6, draggable: true}) }}
        {{ StackedListItem.render('rebecca purple',   {index: 7, draggable: true}) }}
      </ul>
    </article>

    <article id="ContainerThree" class="StackedListWrapper StackedListWrapper--hasScrollIndicator Container">
      <header class="StackedListHeader">
        <h3 class="Heading Heading--size3 Heading--colorWhite">Container three</h3>
      </header>

      <ul class="StackedList StackedList--hasScroll">
        {{ StackedListItem.render('apple',         {index: 8,  draggable: true}) }}
        {{ StackedListItem.render('banana',        {index: 9,  draggable: true}) }}
        {{ StackedListItem.render('cucumber',      {index: 10, draggable: true}) }}
        {{ StackedListItem.render('daikon radish', {index: 11                 }) }}
        {{ StackedListItem.render('elderberry',    {index: 12, draggable: true}) }}
        {{ StackedListItem.render('fresh thyme',   {index: 13, draggable: true}) }}
        {{ StackedListItem.render('guava',         {index: 14, draggable: true}) }}
      </ul>
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Sortable/MultipleContainers/MultipleContainers.scss
================================================
////
/// Content
/// MultipleContainers
////

@import 'utils/shared/layout';
@import 'components/StackedList/props';

$grid-columns: 8;

.MultipleContainers {
  display: grid;
  gap: get-layout-length(gutter);
  grid-template-columns: 100%;
  grid-template-areas: 'a' 'b' 'c';

  @media screen and (min-width: get-breakpoint(desktop)) {
    grid-template-columns: repeat($grid-columns, 1fr);
    grid-template-areas:
      'a a a a a a a a'
      'b b b b b c c c';
  }

  @media screen and (min-width: get-breakpoint('1080p', wide)) {
    @include centered-width(columns(6));
  }

  .Container {
    &:nth-child(1) {
      grid-area: a;
    }

    &:nth-child(2) {
      grid-area: b;
    }

    &:nth-child(3) {
      grid-area: c;
    }
  }

  // resolve slim padding-bottom when single column
  .StackedListHeader {
    @media screen and (min-width: get-breakpoint(tablet)) and (max-width: get-breakpoint(desktop) - 1px) {
      height: auto;
    }
  }

  .draggable--is-dragging & .draggable-container-parent--capacity {
    color: get-color(brand, blue);
  }
}


================================================
FILE: examples/src/content/Sortable/MultipleContainers/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Sortable, Plugins} from '@shopify/draggable';

const Classes = {
  draggable: 'StackedListItem--isDraggable',
  capacity: 'draggable-container-parent--capacity',
};

export default function MultipleContainers() {
  const containers = document.querySelectorAll('#MultipleContainers .StackedList');

  if (containers.length === 0) {
    return false;
  }

  const sortable = new Sortable(containers, {
    draggable: `.${Classes.draggable}`,
    mirror: {
      constrainDimensions: true,
    },
    plugins: [Plugins.ResizeMirror],
  });

  const containerTwoCapacity = 3;
  const containerTwoParent = sortable.containers[1].parentNode;
  let currentMediumChildren;
  let capacityReached;
  let lastOverContainer;

  // --- Draggable events --- //
  sortable.on('drag:start', (evt) => {
    currentMediumChildren = sortable.getDraggableElementsForContainer(sortable.containers[1])
      .length;
    capacityReached = currentMediumChildren === containerTwoCapacity;
    lastOverContainer = evt.sourceContainer;
    containerTwoParent.classList.toggle(Classes.capacity, capacityReached);
  });

  sortable.on('sortable:sort', (evt) => {
    if (!capacityReached) {
      return;
    }

    const sourceIsCapacityContainer = evt.dragEvent.sourceContainer === sortable.containers[1];

    if (!sourceIsCapacityContainer && evt.dragEvent.overContainer === sortable.containers[1]) {
      evt.cancel();
    }
  });

  sortable.on('sortable:sorted', (evt) => {
    if (lastOverContainer === evt.dragEvent.overContainer) {
      return;
    }

    lastOverContainer = evt.dragEvent.overContainer;
  });

  return sortable;
}


================================================
FILE: examples/src/content/Sortable/SimpleList/SimpleList.html
================================================
{% import 'components/StackedList/StackedListItem.html' as StackedListItem %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="StackedListWrapper StackedListWrapper--hasScrollIndicator">
      <header class="StackedListHeader">
        <h3 class="Heading Heading--size3 Heading--colorWhite">Simple list</h3>
      </header>

      <ul class="StackedList StackedList--hasScroll">
        {{ StackedListItem.render('item one',    {index: 1, draggable: true}) }}
        {{ StackedListItem.render('item two',    {index: 2, draggable: true}) }}
        {{ StackedListItem.render('item three',  {index: 3, draggable: true}) }}
        {{ StackedListItem.render('item four',   {index: 4, draggable: true}) }}
        {{ StackedListItem.render('item five',   {index: 5}) }}
        {{ StackedListItem.render('item six',    {index: 6, draggable: true}) }}
        {{ StackedListItem.render('item seven',  {index: 7, draggable: true}) }}
        {{ StackedListItem.render('item eight',  {index: 8}) }}
        {{ StackedListItem.render('item nine',   {index: 9}) }}
        {{ StackedListItem.render('item ten',    {index: 10, draggable: true}) }}
        {{ StackedListItem.render('item eleven', {index: 11}) }}
        {{ StackedListItem.render('item twelve', {index: 12, draggable: true}) }}
      </ul>
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Sortable/SimpleList/SimpleList.scss
================================================
////
/// Content
/// Simple list
////

@import 'utils/shared/layout';
@import 'components/StackedList/props';

// using an arbitrary width until I have time to fix the `columns` function
$simple-list-width: 42rem;

.SimpleList {
  @include centered-width(columns(5));
}


================================================
FILE: examples/src/content/Sortable/SimpleList/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Sortable} from '@shopify/draggable';

export default function SimpleList() {
  const containerSelector = '#SimpleList .StackedList';
  const containers = document.querySelectorAll(containerSelector);

  if (containers.length === 0) {
    return false;
  }

  const sortable = new Sortable(containers, {
    draggable: '.StackedListItem--isDraggable',
    mirror: {
      appendTo: containerSelector,
      constrainDimensions: true,
    },
  });

  return sortable;
}


================================================
FILE: examples/src/content/Sortable/Transformed/Transformed.html
================================================
{% import 'components/PaperStack/PaperStackItem.html' as PaperStackItem %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="PaperStackWrapper">
      <ul class="PaperStack">
        {{ PaperStackItem.render('one',   {index: 1, draggable: true}) }}
        {{ PaperStackItem.render('two',   {index: 2, draggable: true}) }}
        {{ PaperStackItem.render('three', {index: 3, draggable: true}) }}
        {{ PaperStackItem.render('four',  {index: 4, draggable: true}) }}
      </ul>
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Sortable/Transformed/Transformed.scss
================================================
////
/// Content
/// Transformed
////

.Transformed {
  // styles
}


================================================
FILE: examples/src/content/Sortable/Transformed/index.js
================================================
// eslint-disable-next-line import/no-unresolved
import {Sortable} from '@shopify/draggable';

export default function Transformed() {
  const containerSelector = '#Transformed .PaperStack';
  const containers = document.querySelectorAll(containerSelector);

  if (containers.length === 0) {
    return false;
  }

  const sortable = new Sortable(containers, {
    draggable: '.PaperStackItem--isDraggable',
    mirror: {
      appendTo: containerSelector,
      constrainDimensions: true,
    },
  });

  return sortable;
}


================================================
FILE: examples/src/content/Swappable/Flexbox/Flexbox.html
================================================
{% import 'components/Block/Block.html' as Block %}

{% macro render(id) %}
  <section id="{{ id }}" class="{{ id }}">
    <article class="BlockLayout BlockLayout--typeFlex">
      {{ Block.render('one',   {index: 1, draggable: true}) }}
      {{ Block.render('two',   {index: 2}) }}
      {{ Block.render('three', {index: 3, draggable: true}) }}
      {{ Block.render('four',  {index: 4, draggable: true}) }}
      {{ Block.render('five',  {index: 5, draggable: true}) }}
      {{ Block.render('six',   {index: 6}) }}
      {{ Block.render('seven', {index: 7, draggable: true}) }}
    </article>
  </section>
{% endmacro %}


================================================
FILE: examples/src/content/Swappable/Flexbox/Flexbox.scss
================================================
////
/// Content
/// Flexbox
////

@import 'utils/shared/functions';
@import 'utils/shared/layout';

$flexbox-block-name: unquote('Block');

.Flexbox {
  @include draggable-source-layout($flexbox-block-name, 1, 2, 4, 5) {
    flex-basis: 50%;
  }

  @include draggable-source-layout($flexbox-block-name, 3, 6, 7) {
    flex-basis: 100%;
  }

  @include draggable-source-layout($flexbox-block-name, 1, 2, 4, 5, 7) {
    .BlockContent {
      height: rows(2);
    }
  }

  @include draggable-source-layout($flexbox-block-name, 3, 6) {
    .BlockContent {
      height: rows(3);
    }
  }

  @media screen and (min-width: get-breakpoint(tablet)) {
    @include draggable-source-layout($flexbox-block-name, 1, 2, 4, 5, 7) {
      .BlockContent {
        height: rows(3);
      }
    }

    @include draggable-source-layout($flexbox-block-name, 3, 6) {
      .BlockContent {
        height: rows(4);
      }
    }
  }

  @media screen and (min-width: get-breakpoint(desktop)) {
    @include draggable-source-layout($flexbox-block-name, 1, 2, 3) {
      flex-basis: 33.333%;
    }

    @include draggable-source-layout($flexbox-block-name, 4) {
      flex-basis: 25%;
    }

    @include draggable-source-layout($flexbox-block-name, 5) {
      flex-basis: 75%;
    }

    @include draggable-source-layout($flexbox-block-name, 6, 7) {
      flex-basis: 50%;
    }

    @include draggable-source-layout($flexbox-block-name, 1, 2, 3, 4, 6, 7) {
      .BlockContent {
        height: rows(4);
      }
    }

    @include draggable-source-layout($flexbox-block-name, 4, 5) {
      .BlockContent {
        height: rows(5);
      }
    }
  }

  @media screen and (min-width: get-breakpoint('1080p
Download .txt
gitextract_gnoywtw_/

├── .changeset/
│   ├── README.md
│   └── config.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github/
│   ├── .probots.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yaml
│   └── workflows/
│       ├── changelog.yml
│       ├── ci.yml
│       ├── cla.yml
│       ├── release.yml
│       └── snapit.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── .vscode/
│   ├── extensions.json
│   ├── launch.json
│   └── settings.json
├── AUTHORS
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── babel.config.js
├── config/
│   └── typescript/
│       └── rollup-plugin-includepaths.d.ts
├── doc/
│   └── typescript.md
├── esdoc.json
├── examples/
│   ├── .babelrc
│   ├── .browserslistrc
│   ├── .editorconfig
│   ├── .eslintignore
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .nvmrc
│   ├── .prettierignore
│   ├── .prettierrc
│   ├── .stylelintignore
│   ├── .stylelintrc
│   ├── .vscode/
│   │   ├── extensions.json
│   │   └── settings.json
│   ├── README.md
│   ├── package.json
│   ├── postcss.config.js
│   ├── src/
│   │   ├── components/
│   │   │   ├── Analytics/
│   │   │   │   └── index.js
│   │   │   ├── Block/
│   │   │   │   ├── Block.html
│   │   │   │   ├── Block.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Brand/
│   │   │   │   ├── Brand.html
│   │   │   │   ├── Brand.scss
│   │   │   │   ├── Logo.html
│   │   │   │   ├── Wordmark.html
│   │   │   │   ├── keyframes.scss
│   │   │   │   └── props.scss
│   │   │   ├── Button/
│   │   │   │   ├── Button.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Document/
│   │   │   │   ├── Favicon.html
│   │   │   │   ├── Head.html
│   │   │   │   └── SocialShare.html
│   │   │   ├── GridOverlay/
│   │   │   │   └── GridOverlay.scss
│   │   │   ├── Hamburger/
│   │   │   │   ├── Hamburger.html
│   │   │   │   ├── Hamburger.scss
│   │   │   │   ├── keyframes.scss
│   │   │   │   └── props.scss
│   │   │   ├── Handle/
│   │   │   │   ├── DragHandle.scss
│   │   │   │   ├── NopeHandle.scss
│   │   │   │   └── props.scss
│   │   │   ├── Heading/
│   │   │   │   ├── Heading.scss
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Link/
│   │   │   │   └── Link.scss
│   │   │   ├── Main/
│   │   │   │   ├── Main.scss
│   │   │   │   └── props.scss
│   │   │   ├── MobileNav/
│   │   │   │   ├── index.js
│   │   │   │   └── props.scss
│   │   │   ├── Navigation/
│   │   │   │   ├── NavList.html
│   │   │   │   ├── Navigation.html
│   │   │   │   └── Navigation.scss
│   │   │   ├── Page/
│   │   │   │   └── Page.scss
│   │   │   ├── PageHeader/
│   │   │   │   ├── PageHeader.html
│   │   │   │   └── PageHeader.scss
│   │   │   ├── PaperStack/
│   │   │   │   ├── PaperStack.scss
│   │   │   │   ├── PaperStackItem.html
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Patterns/
│   │   │   │   ├── Patterns.scss
│   │   │   │   ├── keyframes.scss
│   │   │   │   └── props.scss
│   │   │   ├── PillSwitch/
│   │   │   │   ├── PillSwitch.html
│   │   │   │   ├── PillSwitch.scss
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Plate/
│   │   │   │   ├── Plate.html
│   │   │   │   ├── Plate.scss
│   │   │   │   ├── index.js
│   │   │   │   ├── keyframes.scss
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   ├── Sidebar/
│   │   │   │   ├── Sidebar.html
│   │   │   │   └── Sidebar.scss
│   │   │   ├── StackedList/
│   │   │   │   ├── StackedList.scss
│   │   │   │   ├── StackedListItem.html
│   │   │   │   ├── props.scss
│   │   │   │   └── variants.scss
│   │   │   └── Svg/
│   │   │       └── Svg.scss
│   │   ├── content/
│   │   │   ├── Draggable/
│   │   │   │   └── DragEvents/
│   │   │   │       ├── DragEvents.html
│   │   │   │       ├── DragEvents.scss
│   │   │   │       └── index.js
│   │   │   ├── Droppable/
│   │   │   │   └── UniqueDropzone/
│   │   │   │       ├── UniqueDropzone.html
│   │   │   │       ├── UniqueDropzone.scss
│   │   │   │       └── index.js
│   │   │   ├── Home/
│   │   │   │   ├── Home.html
│   │   │   │   ├── Home.scss
│   │   │   │   └── index.js
│   │   │   ├── Plugins/
│   │   │   │   ├── Collidable/
│   │   │   │   │   ├── Collidable.html
│   │   │   │   │   ├── Collidable.scss
│   │   │   │   │   ├── index.js
│   │   │   │   │   └── props.scss
│   │   │   │   ├── Snappable/
│   │   │   │   │   ├── Snappable.html
│   │   │   │   │   ├── Snappable.scss
│   │   │   │   │   └── index.js
│   │   │   │   ├── SortAnimation/
│   │   │   │   │   ├── SortAnimation.html
│   │   │   │   │   ├── SortAnimation.scss
│   │   │   │   │   └── index.js
│   │   │   │   └── SwapAnimation/
│   │   │   │       ├── SwapAnimation.html
│   │   │   │       ├── SwapAnimation.scss
│   │   │   │       └── index.js
│   │   │   ├── Sortable/
│   │   │   │   ├── MultipleContainers/
│   │   │   │   │   ├── MultipleContainers.html
│   │   │   │   │   ├── MultipleContainers.scss
│   │   │   │   │   └── index.js
│   │   │   │   ├── SimpleList/
│   │   │   │   │   ├── SimpleList.html
│   │   │   │   │   ├── SimpleList.scss
│   │   │   │   │   └── index.js
│   │   │   │   └── Transformed/
│   │   │   │       ├── Transformed.html
│   │   │   │       ├── Transformed.scss
│   │   │   │       └── index.js
│   │   │   ├── Swappable/
│   │   │   │   ├── Flexbox/
│   │   │   │   │   ├── Flexbox.html
│   │   │   │   │   ├── Flexbox.scss
│   │   │   │   │   └── index.js
│   │   │   │   ├── Floated/
│   │   │   │   │   ├── Floated.html
│   │   │   │   │   ├── Floated.scss
│   │   │   │   │   └── index.js
│   │   │   │   └── GridLayout/
│   │   │   │       ├── GridLayout.html
│   │   │   │       ├── GridLayout.scss
│   │   │   │       └── index.js
│   │   │   └── index.js
│   │   ├── scripts/
│   │   │   ├── examples-app.js
│   │   │   └── utils/
│   │   │       ├── debounce.js
│   │   │       └── flip-sign.js
│   │   ├── styles/
│   │   │   ├── examples-app.scss
│   │   │   ├── examples-theme/
│   │   │   │   ├── _border.scss
│   │   │   │   ├── _breakpoint.scss
│   │   │   │   ├── _color.scss
│   │   │   │   ├── _cursor.scss
│   │   │   │   ├── _duration.scss
│   │   │   │   ├── _easing.scss
│   │   │   │   ├── _font-stack.scss
│   │   │   │   ├── _layout-length.scss
│   │   │   │   ├── _spacing.scss
│   │   │   │   ├── _type-scale.scss
│   │   │   │   ├── _z-index.scss
│   │   │   │   └── examples-theme.scss
│   │   │   ├── reset.scss
│   │   │   └── utils/
│   │   │       ├── global/
│   │   │       │   ├── _animation.scss
│   │   │       │   ├── _layout.scss
│   │   │       │   ├── _typography.scss
│   │   │       │   └── global-utils.scss
│   │   │       └── shared/
│   │   │           ├── animation.scss
│   │   │           ├── functions.scss
│   │   │           ├── layout.scss
│   │   │           └── typography.scss
│   │   └── views/
│   │       ├── collidable.html
│   │       ├── data-pages.json
│   │       ├── drag-events.html
│   │       ├── flexbox.html
│   │       ├── floated.html
│   │       ├── grid-layout.html
│   │       ├── index.html
│   │       ├── multiple-containers.html
│   │       ├── simple-list.html
│   │       ├── snappable.html
│   │       ├── sort-animation.html
│   │       ├── swap-animation.html
│   │       ├── templates/
│   │       │   └── document.html
│   │       ├── transformed.html
│   │       └── unique-dropzone.html
│   └── tools/
│       ├── index.js
│       ├── server.js
│       ├── tasks/
│       │   ├── index.js
│       │   ├── scripts.js
│       │   ├── styles.js
│       │   └── views.js
│       ├── watch.js
│       ├── webpack.config.js
│       └── webpack.plugins.js
├── index.d.ts
├── jest.config.js
├── package.json
├── rollup.config.ts
├── rollup.development.config.ts
├── src/
│   ├── Draggable/
│   │   ├── DragEvent/
│   │   │   ├── DragEvent.ts
│   │   │   ├── README.md
│   │   │   ├── index.ts
│   │   │   └── tests/
│   │   │       └── DragEvent.test.ts
│   │   ├── Draggable.js
│   │   ├── DraggableEvent/
│   │   │   ├── DraggableEvent.ts
│   │   │   ├── README.md
│   │   │   └── index.ts
│   │   ├── Emitter/
│   │   │   ├── Emitter.ts
│   │   │   ├── index.ts
│   │   │   └── tests/
│   │   │       └── Emitter.test.ts
│   │   ├── Plugins/
│   │   │   ├── Announcement/
│   │   │   │   ├── Announcement.js
│   │   │   │   ├── README.md
│   │   │   │   └── index.js
│   │   │   ├── Focusable/
│   │   │   │   ├── Focusable.js
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── Focusable.test.js
│   │   │   ├── Mirror/
│   │   │   │   ├── Mirror.js
│   │   │   │   ├── MirrorEvent/
│   │   │   │   │   ├── MirrorEvent.ts
│   │   │   │   │   ├── README.md
│   │   │   │   │   └── index.ts
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── Mirror.test.js
│   │   │   ├── README.md
│   │   │   ├── Scrollable/
│   │   │   │   ├── README.md
│   │   │   │   ├── Scrollable.js
│   │   │   │   └── index.js
│   │   │   └── index.js
│   │   ├── README.md
│   │   ├── Sensors/
│   │   │   ├── DragSensor/
│   │   │   │   ├── DragSensor.js
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── DragSensor.test.js
│   │   │   ├── ForceTouchSensor/
│   │   │   │   ├── ForceTouchSensor.js
│   │   │   │   ├── README.md
│   │   │   │   └── index.js
│   │   │   ├── MouseSensor/
│   │   │   │   ├── MouseSensor.js
│   │   │   │   ├── README.md
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── MouseSensor.test.js
│   │   │   ├── README.md
│   │   │   ├── Sensor/
│   │   │   │   ├── README.md
│   │   │   │   ├── Sensor.js
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── Sensor.test.js
│   │   │   ├── SensorEvent/
│   │   │   │   ├── README.md
│   │   │   │   ├── SensorEvent.ts
│   │   │   │   └── index.ts
│   │   │   ├── TouchSensor/
│   │   │   │   ├── README.md
│   │   │   │   ├── TouchSensor.js
│   │   │   │   ├── index.js
│   │   │   │   └── tests/
│   │   │   │       └── TouchSensor.test.js
│   │   │   └── index.js
│   │   ├── index.js
│   │   └── tests/
│   │       └── Draggable.test.js
│   ├── Droppable/
│   │   ├── Droppable.js
│   │   ├── DroppableEvent/
│   │   │   ├── DroppableEvent.ts
│   │   │   ├── README.md
│   │   │   └── index.ts
│   │   ├── README.md
│   │   ├── index.js
│   │   └── tests/
│   │       └── Droppable.test.js
│   ├── Plugins/
│   │   ├── Collidable/
│   │   │   ├── Collidable.js
│   │   │   ├── CollidableEvent/
│   │   │   │   ├── CollidableEvent.ts
│   │   │   │   ├── README.md
│   │   │   │   └── index.ts
│   │   │   ├── README.md
│   │   │   └── index.js
│   │   ├── README.md
│   │   ├── ResizeMirror/
│   │   │   ├── README.md
│   │   │   ├── ResizeMirror.ts
│   │   │   ├── index.ts
│   │   │   └── tests/
│   │   │       └── ResizeMirror.test.ts
│   │   ├── Snappable/
│   │   │   ├── README.md
│   │   │   ├── Snappable.js
│   │   │   ├── SnappableEvent/
│   │   │   │   ├── README.md
│   │   │   │   ├── SnappableEvent.ts
│   │   │   │   └── index.ts
│   │   │   └── index.js
│   │   ├── SortAnimation/
│   │   │   ├── README.md
│   │   │   ├── SortAnimation.js
│   │   │   └── index.js
│   │   ├── SwapAnimation/
│   │   │   ├── README.md
│   │   │   ├── SwapAnimation.ts
│   │   │   └── index.ts
│   │   └── index.js
│   ├── Sortable/
│   │   ├── README.md
│   │   ├── Sortable.js
│   │   ├── SortableEvent/
│   │   │   ├── README.md
│   │   │   ├── SortableEvent.ts
│   │   │   └── index.ts
│   │   ├── index.js
│   │   └── tests/
│   │       └── Sortable.test.js
│   ├── Swappable/
│   │   ├── README.md
│   │   ├── Swappable.js
│   │   ├── SwappableEvent/
│   │   │   ├── README.md
│   │   │   ├── SwappableEvent.ts
│   │   │   └── index.ts
│   │   ├── index.js
│   │   └── tests/
│   │       └── Swappable.test.js
│   ├── index.js
│   └── shared/
│       ├── AbstractEvent/
│       │   ├── AbstractEvent.ts
│       │   ├── README.md
│       │   ├── index.ts
│       │   └── tests/
│       │       └── AbstractEvent.test.ts
│       ├── AbstractPlugin/
│       │   ├── AbstractPlugin.ts
│       │   ├── README.md
│       │   └── index.ts
│       ├── README.md
│       ├── types.ts
│       └── utils/
│           ├── README.md
│           ├── closest/
│           │   ├── README.md
│           │   ├── closest.ts
│           │   ├── index.ts
│           │   └── tests/
│           │       └── closest.test.ts
│           ├── decorators/
│           │   ├── AutoBind.ts
│           │   └── index.ts
│           ├── distance/
│           │   ├── distance.ts
│           │   └── index.ts
│           ├── index.ts
│           ├── requestNextAnimationFrame/
│           │   ├── README.md
│           │   ├── index.ts
│           │   └── requestNextAnimationFrame.ts
│           └── touchCoords/
│               ├── index.ts
│               └── touchCoords.ts
├── test/
│   ├── environment.ts
│   ├── helper.ts
│   ├── helpers/
│   │   ├── constants.ts
│   │   ├── environment.ts
│   │   ├── event.ts
│   │   ├── index.ts
│   │   ├── module.ts
│   │   ├── plugin.ts
│   │   └── sensor.ts
│   ├── matchers/
│   │   ├── dom-event.ts
│   │   ├── event.ts
│   │   ├── index.ts
│   │   ├── order.ts
│   │   ├── sensor.ts
│   │   └── utils.ts
│   └── setup.ts
└── tsconfig.json
Download .txt
SYMBOL INDEX (631 symbols across 83 files)

FILE: config/typescript/rollup-plugin-includepaths.d.ts
  type Options (line 2) | interface Options {

FILE: examples/src/components/Analytics/index.js
  function gtag (line 1) | function gtag() {
  class Analytics (line 5) | class Analytics {
    method constructor (line 6) | constructor(ua) {
    method init (line 10) | init() {
    method _appendScript (line 28) | _appendScript() {

FILE: examples/src/components/MobileNav/index.js
  constant MAX_WIDTH (line 4) | const MAX_WIDTH = 960;
  class MobileNav (line 12) | class MobileNav {
    method constructor (line 13) | constructor(activator) {
    method init (line 18) | init() {
    method expand (line 35) | expand(widthExceeded = false) {
    method collapse (line 45) | collapse() {
    method toggle (line 56) | toggle() {
    method _setState (line 60) | _setState() {

FILE: examples/src/components/Plate/index.js
  function calculatePlateScale (line 15) | function calculatePlateScale(value, max, factor) {
  class Plate (line 22) | class Plate {
    method constructor (line 23) | constructor(wrapper) {
    method setThreshold (line 40) | setThreshold() {
    method setInitialMousePosition (line 49) | setInitialMousePosition(sensorEvent) {
    method dragWarp (line 54) | dragWarp(source, sensorEvent) {
    method resetWarp (line 63) | resetWarp() {
    method _offsetWithinThreshold (line 69) | _offsetWithinThreshold(initialPosition, currentPosition) {
    method _scalePlates (line 82) | _scalePlates(x, y) {
    method _translateEachPlate (line 90) | _translateEachPlate(x, y) {
    method _translateShadow (line 103) | _translateShadow(x, y) {

FILE: examples/src/content/Draggable/DragEvents/index.js
  function translateMirror (line 4) | function translateMirror(mirror, mirrorCoords, containerRect) {
  function calcOffset (line 14) | function calcOffset(offset) {
  function DragEvents (line 18) | function DragEvents() {

FILE: examples/src/content/Droppable/UniqueDropzone/index.js
  function UniqueDropzone (line 4) | function UniqueDropzone() {

FILE: examples/src/content/Home/index.js
  function Home (line 7) | function Home() {

FILE: examples/src/content/Plugins/Collidable/index.js
  function PluginsCollidable (line 4) | function PluginsCollidable() {

FILE: examples/src/content/Plugins/Snappable/index.js
  function PluginsSnappable (line 4) | function PluginsSnappable() {

FILE: examples/src/content/Plugins/SortAnimation/index.js
  function SortAnimation (line 4) | function SortAnimation() {

FILE: examples/src/content/Plugins/SwapAnimation/index.js
  function PluginsSwapAnimation (line 4) | function PluginsSwapAnimation() {

FILE: examples/src/content/Sortable/MultipleContainers/index.js
  function MultipleContainers (line 9) | function MultipleContainers() {

FILE: examples/src/content/Sortable/SimpleList/index.js
  function SimpleList (line 4) | function SimpleList() {

FILE: examples/src/content/Sortable/Transformed/index.js
  function Transformed (line 4) | function Transformed() {

FILE: examples/src/content/Swappable/Flexbox/index.js
  function Flexbox (line 4) | function Flexbox() {

FILE: examples/src/content/Swappable/Floated/index.js
  function Floated (line 4) | function Floated() {

FILE: examples/src/content/Swappable/GridLayout/index.js
  function GridLayout (line 4) | function GridLayout() {

FILE: examples/src/scripts/utils/debounce.js
  function debounce (line 1) | function debounce(callback, wait) {

FILE: examples/src/scripts/utils/flip-sign.js
  function flipSign (line 1) | function flipSign(number) {

FILE: examples/tools/server.js
  function reloadServer (line 6) | function reloadServer(done) {
  function startServer (line 11) | function startServer() {

FILE: examples/tools/tasks/scripts.js
  function scripts (line 5) | function scripts() {

FILE: examples/tools/tasks/styles.js
  function styles (line 15) | function styles() {

FILE: examples/tools/tasks/views.js
  function views (line 14) | function views() {

FILE: examples/tools/watch.js
  function reportWatchStats (line 8) | function reportWatchStats(path) {
  function watch (line 12) | function watch() {

FILE: examples/tools/webpack.plugins.js
  function initPlugins (line 3) | function initPlugins(isProd = false) {

FILE: index.d.ts
  type GetEventByEventName (line 29) | type GetEventByEventName<TEventName> =
  type DelayOptions (line 98) | interface DelayOptions {
  class DragEvent (line 107) | class DragEvent extends AbstractEvent {
  class DragStartEvent (line 116) | class DragStartEvent extends DragEvent {}
  class DragMoveEvent (line 118) | class DragMoveEvent extends DragEvent {}
  class DragOverEvent (line 120) | class DragOverEvent extends DragEvent {
  class DragOutEvent (line 125) | class DragOutEvent extends DragEvent {
  class DragOverContainerEvent (line 130) | class DragOverContainerEvent extends DragEvent {
  class DragOutContainerEvent (line 134) | class DragOutContainerEvent extends DragEvent {
  class DragPressureEvent (line 138) | class DragPressureEvent extends DragEvent {
  class DragStopEvent (line 142) | class DragStopEvent extends DragEvent {}
  class DragStoppedEvent (line 144) | class DragStoppedEvent extends DragEvent {}
  type DraggableEventNames (line 149) | type DraggableEventNames =
  class DraggableEvent (line 162) | class DraggableEvent extends AbstractEvent {
  class DraggableInitializedEvent (line 165) | class DraggableInitializedEvent extends DraggableEvent {}
  class DraggableDestroyEvent (line 166) | class DraggableDestroyEvent extends DraggableEvent {}
  type DraggableClassNames (line 168) | type DraggableClassNames =
  type DraggableContainer (line 179) | type DraggableContainer = HTMLElement | HTMLElement[] | NodeList;
  type DraggableOptions (line 181) | interface DraggableOptions {
  class Draggable (line 202) | class Draggable<TEventListType = DraggableEventNames> {
  type AnnouncementOptions (line 247) | interface AnnouncementOptions {
  class Announcement (line 252) | class Announcement extends AbstractPlugin {
  class Focusable (line 261) | class Focusable extends AbstractPlugin {
  type MirrorEventNames (line 270) | type MirrorEventNames =
  class MirrorEvent (line 277) | class MirrorEvent extends AbstractEvent {
  class MirrorCreateEvent (line 284) | class MirrorCreateEvent extends MirrorEvent {}
  class MirrorCreatedEvent (line 285) | class MirrorCreatedEvent extends MirrorEvent {
  class MirrorAttachedEvent (line 288) | class MirrorAttachedEvent extends MirrorEvent {
  class MirrorMoveEvent (line 291) | class MirrorMoveEvent extends MirrorEvent {
  class MirrorMovedEvent (line 296) | class MirrorMovedEvent extends MirrorEvent {
  class MirrorDestroyEvent (line 301) | class MirrorDestroyEvent extends MirrorEvent {
  type MirrorOptions (line 305) | interface MirrorOptions {
  class Mirror (line 314) | class Mirror extends AbstractPlugin {
  type ScrollableOptions (line 323) | interface ScrollableOptions {
  class Scrollable (line 329) | class Scrollable extends AbstractPlugin {
  class SensorEvent (line 337) | class SensorEvent extends AbstractEvent {
  class DragStartSensorEvent (line 346) | class DragStartSensorEvent extends SensorEvent {}
  class DragMoveSensorEvent (line 348) | class DragMoveSensorEvent extends SensorEvent {}
  class DragStopSensorEvent (line 350) | class DragStopSensorEvent extends SensorEvent {}
  class DragPressureSensorEvent (line 352) | class DragPressureSensorEvent extends SensorEvent {}
  type SensorOptions (line 354) | interface SensorOptions {
  class Sensor (line 358) | class Sensor {
  type Sensors (line 371) | interface Sensors {
  class DragSensor (line 375) | class DragSensor extends Sensor {}
  class ForceTouchSensor (line 377) | class ForceTouchSensor extends Sensor {}
  class MouseSensor (line 379) | class MouseSensor extends Sensor {}
  class TouchSensor (line 381) | class TouchSensor extends Sensor {}
  type DroppableEventNames (line 386) | type DroppableEventNames =
  class DroppableEvent (line 393) | class DroppableEvent extends AbstractEvent {
  class DroppableStartEvent (line 397) | class DroppableStartEvent extends DroppableEvent {
  class DroppableDroppedEvent (line 401) | class DroppableDroppedEvent extends DroppableEvent {
  class DroppableReturnedEvent (line 405) | class DroppableReturnedEvent extends DroppableEvent {
  class DroppableStopEvent (line 409) | class DroppableStopEvent extends DroppableEvent {
  type DroppableClassNames (line 413) | type DroppableClassNames =
  type DroppableOptions (line 418) | interface DroppableOptions extends DraggableOptions {
  class Droppable (line 427) | class Droppable<T = DroppableEventNames> extends Draggable<T> {
  type SortableEventNames (line 435) | type SortableEventNames =
  class SortableEvent (line 442) | class SortableEvent extends AbstractEvent {
  class SortableStartEvent (line 446) | class SortableStartEvent extends SortableEvent {
  class SortableSortEvent (line 451) | class SortableSortEvent extends SortableEvent {
  class SortableSortedEvent (line 458) | class SortableSortedEvent extends SortableEvent {
  class SortableStopEvent (line 465) | class SortableStopEvent extends SortableEvent {
  class Sortable (line 472) | class Sortable<T = SortableEventNames> extends Draggable<T> {}
  type SwappableEventNames (line 477) | type SwappableEventNames =
  class SwappableEvent (line 484) | class SwappableEvent extends AbstractEvent {
  class SwappableStartEvent (line 488) | class SwappableStartEvent extends SwappableEvent {}
  class SwappableSwapEvent (line 490) | class SwappableSwapEvent extends SwappableEvent {
  class SwappableSwappedEvent (line 495) | class SwappableSwappedEvent extends SwappableEvent {
  class SwappableStopEvent (line 499) | class SwappableStopEvent extends SwappableEvent {}
  class Swappable (line 501) | class Swappable<T = SwappableEventNames> extends Draggable<T> {}
  type CollidableEventNames (line 506) | type CollidableEventNames = 'collidable:in' | 'collidable:out';
  class CollidableEvent (line 508) | class CollidableEvent extends AbstractEvent {
  class CollidableInEvent (line 512) | class CollidableInEvent extends CollidableEvent {}
  class CollidableOutEvent (line 513) | class CollidableOutEvent extends CollidableEvent {}
  type Collidables (line 515) | type Collidables =
  class Collidable (line 521) | class Collidable extends AbstractPlugin {
  class ResizeMirror (line 529) | class ResizeMirror extends AbstractPlugin {
  type SnappableEventNames (line 537) | type SnappableEventNames = 'snap:in' | 'snap:out';
  class SnapEvent (line 539) | class SnapEvent extends AbstractEvent {
  class SnapInEvent (line 543) | class SnapInEvent extends SnapEvent {}
  class SnapOutEvent (line 544) | class SnapOutEvent extends SnapEvent {}
  class Snappable (line 546) | class Snappable extends AbstractPlugin {
  type SwapAnimationOptions (line 554) | interface SwapAnimationOptions {
  class SwapAnimation (line 560) | class SwapAnimation extends AbstractPlugin {
  type SortAnimationOptions (line 568) | interface SortAnimationOptions {
  class SortAnimation (line 573) | class SortAnimation extends AbstractPlugin {

FILE: rollup.config.ts
  function generateConfig (line 18) | function generateConfig({

FILE: src/Draggable/DragEvent/DragEvent.ts
  type DragEventData (line 9) | interface DragEventData {
  class DragEvent (line 23) | class DragEvent<
    method constructor (line 33) | constructor(public data: T) {
    method source (line 43) | get source() {
    method originalSource (line 53) | get originalSource() {
    method mirror (line 63) | get mirror() {
    method sourceContainer (line 73) | get sourceContainer() {
    method sensorEvent (line 83) | get sensorEvent() {
    method originalEvent (line 93) | get originalEvent() {
  class DragStartEvent (line 108) | class DragStartEvent extends DragEvent<DragEventData> {
  class DragMoveEvent (line 119) | class DragMoveEvent extends DragEvent<DragEventData> {
  type DragOverEventData (line 127) | interface DragOverEventData extends DragEventData {
  class DragOverEvent (line 138) | class DragOverEvent extends DragEvent<DragOverEventData> {
    method overContainer (line 148) | get overContainer() {
    method over (line 158) | get over() {
  function isDragOverEvent (line 163) | function isDragOverEvent(
  type DragOutEventData (line 173) | interface DragOutEventData extends DragEventData {
  class DragOutEvent (line 184) | class DragOutEvent extends DragEvent<DragOutEventData> {
    method overContainer (line 193) | get overContainer() {
    method over (line 203) | get over() {
  type DragOverContainerEventData (line 212) | interface DragOverContainerEventData extends DragEventData {
  class DragOverContainerEvent (line 222) | class DragOverContainerEvent extends DragEvent<DragOverContainerEventDat...
    method overContainer (line 231) | get overContainer() {
  type DragOutContainerEventData (line 240) | interface DragOutContainerEventData extends DragEventData {
  class DragOutContainerEvent (line 250) | class DragOutContainerEvent extends DragEvent<DragOutContainerEventData> {
    method overContainer (line 259) | get overContainer() {
  type DragPressureEventData (line 268) | interface DragPressureEventData extends DragEventData {
  class DragPressureEvent (line 278) | class DragPressureEvent extends DragEvent<DragPressureEventData> {
    method pressure (line 287) | get pressure() {
  class DragStopEvent (line 298) | class DragStopEvent extends DragEvent<DragEventData> {
  class DragStoppedEvent (line 309) | class DragStoppedEvent extends DragEvent<DragEventData> {

FILE: src/Draggable/Draggable.js
  class Draggable (line 75) | class Draggable {
    method constructor (line 104) | constructor(containers = [document.body], options = {}) {
    method destroy (line 200) | destroy() {
    method addPlugin (line 222) | addPlugin(...plugins) {
    method removePlugin (line 238) | removePlugin(...plugins) {
    method addSensor (line 257) | addSensor(...sensors) {
    method removeSensor (line 275) | removeSensor(...sensors) {
    method addContainer (line 294) | addContainer(...containers) {
    method removeContainer (line 306) | removeContainer(...containers) {
    method on (line 321) | on(type, ...callbacks) {
    method off (line 333) | off(type, callback) {
    method trigger (line 344) | trigger(event) {
    method getClassNameFor (line 354) | getClassNameFor(name) {
    method getClassNamesFor (line 362) | getClassNamesFor(name) {
    method isDragging (line 378) | isDragging() {
    method getDraggableElements (line 386) | getDraggableElements() {
    method getDraggableElementsForContainer (line 398) | getDraggableElementsForContainer(container) {
    method cancel (line 413) | cancel() {
    method [onDragStart] (line 422) | [onDragStart](event) {
    method [onDragMove] (line 502) | [onDragMove](event) {
    method [dragStop] (line 609) | [dragStop](event) {
    method [onDragStop] (line 697) | [onDragStop](event) {
    method [onDragPressure] (line 706) | [onDragPressure](event) {
  function getSensorEvent (line 726) | function getSensorEvent(event) {
  function applyUserSelect (line 730) | function applyUserSelect(element, value) {

FILE: src/Draggable/DraggableEvent/DraggableEvent.ts
  type DraggableEventData (line 8) | interface DraggableEventData {
  class DraggableEvent (line 18) | class DraggableEvent extends AbstractEvent<DraggableEventData> {
    method draggable (line 27) | get draggable() {
  class DraggableInitializedEvent (line 38) | class DraggableInitializedEvent extends DraggableEvent {
  class DraggableDestroyEvent (line 48) | class DraggableDestroyEvent extends DraggableEvent {

FILE: src/Draggable/Emitter/Emitter.ts
  type CallbackFunction (line 3) | type CallbackFunction = (event: AbstractEvent<unknown>) => void;
  type Callback (line 5) | interface Callback {
  class Emitter (line 14) | class Emitter {
    method on (line 22) | on(type: string, ...callbacks: CallbackFunction[]) {
    method off (line 37) | off(type: string, callback: CallbackFunction) {
    method trigger (line 57) | trigger(event: AbstractEvent<unknown>) {

FILE: src/Draggable/Emitter/tests/Emitter.test.ts
  class TestEvent (line 5) | class TestEvent extends AbstractEvent<unknown> {}

FILE: src/Draggable/Plugins/Announcement/Announcement.js
  constant ARIA_RELEVANT (line 8) | const ARIA_RELEVANT = 'aria-relevant';
  constant ARIA_ATOMIC (line 9) | const ARIA_ATOMIC = 'aria-atomic';
  constant ARIA_LIVE (line 10) | const ARIA_LIVE = 'aria-live';
  constant ROLE (line 11) | const ROLE = 'role';
  class Announcement (line 29) | class Announcement extends AbstractPlugin {
    method constructor (line 35) | constructor(draggable) {
    method attach (line 62) | attach() {
    method detach (line 69) | detach() {
    method getOptions (line 76) | getOptions() {
    method [announceEvent] (line 85) | [announceEvent](event) {
    method [announceMessage] (line 102) | [announceMessage](message) {
    method [onInitialize] (line 110) | [onInitialize]() {
    method [onDestroy] (line 126) | [onDestroy]() {
  function announce (line 142) | function announce(message, {expire}) {
  function createRegion (line 157) | function createRegion() {

FILE: src/Draggable/Plugins/Focusable/Focusable.js
  class Focusable (line 19) | class Focusable extends AbstractPlugin {
    method constructor (line 25) | constructor(draggable) {
    method attach (line 45) | attach() {
    method detach (line 54) | detach() {
    method getOptions (line 67) | getOptions() {
    method getElements (line 75) | getElements() {
    method [onInitialize] (line 86) | [onInitialize]() {
    method [onDestroy] (line 97) | [onDestroy]() {
  function decorateElement (line 118) | function decorateElement(element) {
  function stripElement (line 134) | function stripElement(element) {

FILE: src/Draggable/Plugins/Mirror/Mirror.js
  class Mirror (line 46) | class Mirror extends AbstractPlugin {
    method constructor (line 52) | constructor(draggable) {
    method attach (line 101) | attach() {
    method detach (line 113) | detach() {
    method getOptions (line 126) | getOptions() {
    method [onDragStart] (line 130) | [onDragStart](dragEvent) {
    method [onDragMove] (line 193) | [onDragMove](dragEvent) {
    method [onDragStop] (line 237) | [onDragStop](dragEvent) {
    method [onScroll] (line 266) | [onScroll]() {
    method [onMirrorCreated] (line 279) | [onMirrorCreated]({mirror, source, sensorEvent}) {
    method [onMirrorMove] (line 323) | [onMirrorMove](mirrorEvent) {
    method [getAppendableContainer] (line 378) | [getAppendableContainer](source) {
  function computeMirrorDimensions (line 401) | function computeMirrorDimensions({source, ...args}) {
  function calculateMirrorOffset (line 417) | function calculateMirrorOffset({sensorEvent, sourceRect, options, ...arg...
  function resetMirror (line 443) | function resetMirror({mirror, source, options, ...args}) {
  function addMirrorClasses (line 478) | function addMirrorClasses({mirror, mirrorClasses, ...args}) {
  function removeMirrorID (line 492) | function removeMirrorID({mirror, ...args}) {
  function positionMirror (line 512) | function positionMirror({withFrame = false, initial = false} = {}) {
  function withPromise (line 583) | function withPromise(callback, {raf = false} = {}) {
  function isNativeDragEvent (line 599) | function isNativeDragEvent(sensorEvent) {

FILE: src/Draggable/Plugins/Mirror/MirrorEvent/MirrorEvent.ts
  type MirrorEventData (line 6) | interface MirrorEventData {
  class MirrorEvent (line 20) | class MirrorEvent<
    method constructor (line 28) | constructor(public data: T) {
    method source (line 38) | get source() {
    method originalSource (line 48) | get originalSource() {
    method sourceContainer (line 58) | get sourceContainer() {
    method sensorEvent (line 68) | get sensorEvent() {
    method dragEvent (line 78) | get dragEvent() {
    method originalEvent (line 88) | get originalEvent() {
  class MirrorCreateEvent (line 103) | class MirrorCreateEvent extends MirrorEvent<MirrorEventData> {
  type MirrorCreatedEventData (line 107) | interface MirrorCreatedEventData extends MirrorEventData {
  class MirrorCreatedEvent (line 117) | class MirrorCreatedEvent extends MirrorEvent<MirrorCreatedEventData> {
    method mirror (line 126) | get mirror() {
  type MirrorAttachedEventData (line 131) | interface MirrorAttachedEventData extends MirrorEventData {
  class MirrorAttachedEvent (line 141) | class MirrorAttachedEvent extends MirrorEvent<MirrorAttachedEventData> {
    method mirror (line 150) | get mirror() {
  type MirrorMoveEventData (line 155) | interface MirrorMoveEventData extends MirrorEventData {
  class MirrorMoveEvent (line 167) | class MirrorMoveEvent extends MirrorEvent<MirrorMoveEventData> {
    method mirror (line 177) | get mirror() {
    method passedThreshX (line 186) | get passedThreshX() {
    method passedThreshY (line 195) | get passedThreshY() {
  type MirrorMovedEventData (line 200) | interface MirrorMovedEventData extends MirrorEventData {
  class MirrorMovedEvent (line 212) | class MirrorMovedEvent extends MirrorEvent<MirrorMovedEventData> {
    method mirror (line 221) | get mirror() {
    method passedThreshX (line 230) | get passedThreshX() {
    method passedThreshY (line 239) | get passedThreshY() {
  type MirrorDestroyEventData (line 244) | interface MirrorDestroyEventData extends MirrorEventData {
  class MirrorDestroyEvent (line 254) | class MirrorDestroyEvent extends MirrorEvent<MirrorDestroyEventData> {
    method mirror (line 264) | get mirror() {

FILE: src/Draggable/Plugins/Scrollable/Scrollable.js
  class Scrollable (line 29) | class Scrollable extends AbstractPlugin {
    method constructor (line 35) | constructor(draggable) {
    method attach (line 90) | attach() {
    method detach (line 100) | detach() {
    method getOptions (line 111) | getOptions() {
    method getScrollableElement (line 120) | getScrollableElement(target) {
    method hasDefinedScrollableElements (line 136) | hasDefinedScrollableElements() {
    method [onDragStart] (line 145) | [onDragStart](dragEvent) {
    method [onDragMove] (line 156) | [onDragMove](dragEvent) {
    method [onDragStop] (line 195) | [onDragStop]() {
    method [scroll] (line 209) | [scroll]() {
  function hasOverflow (line 272) | function hasOverflow(element) {
  function isStaticallyPositioned (line 290) | function isStaticallyPositioned(element) {
  function closestScrollableElement (line 301) | function closestScrollableElement(element) {
  function getDocumentScrollingElement (line 328) | function getDocumentScrollingElement() {

FILE: src/Draggable/Sensors/DragSensor/DragSensor.js
  class DragSensor (line 24) | class DragSensor extends Sensor {
    method constructor (line 31) | constructor(containers = [], options = {}) {
    method attach (line 66) | attach() {
    method detach (line 73) | detach() {
    method [onDragStart] (line 82) | [onDragStart](event) {
    method [onDragOver] (line 120) | [onDragOver](event) {
    method [onDragEnd] (line 149) | [onDragEnd](event) {
    method [onDrop] (line 180) | [onDrop](event) {
    method [onMouseDown] (line 189) | [onMouseDown](event) {
    method [onMouseUp] (line 245) | [onMouseUp]() {
    method [reset] (line 254) | [reset]() {

FILE: src/Draggable/Sensors/DragSensor/tests/DragSensor.test.js
  function setup (line 28) | function setup(optionsParam = {}) {
  function teardown (line 44) | function teardown() {
  function dragFlow (line 72) | function dragFlow() {
  function dragFlow (line 89) | function dragFlow() {
  function dragFlow (line 102) | function dragFlow() {
  function hastyDragFlow (line 111) | function hastyDragFlow() {
  function dragFlow (line 127) | function dragFlow() {
  function dragFlow (line 141) | function dragFlow() {
  function dragFlow (line 155) | function dragFlow() {
  function dragFlow (line 183) | function dragFlow() {
  function dragFlow (line 196) | function dragFlow() {
  function hastyDragFlow (line 205) | function hastyDragFlow() {
  function dragFlow (line 222) | function dragFlow() {

FILE: src/Draggable/Sensors/ForceTouchSensor/ForceTouchSensor.js
  class ForceTouchSensor (line 25) | class ForceTouchSensor extends Sensor {
    method constructor (line 32) | constructor(containers = [], options = {}) {
    method attach (line 53) | attach() {
    method detach (line 80) | detach() {
    method [onMouseForceWillBegin] (line 109) | [onMouseForceWillBegin](event) {
    method [onMouseForceDown] (line 119) | [onMouseForceDown](event) {
    method [onMouseUp] (line 162) | [onMouseUp](event) {
    method [onMouseDown] (line 187) | [onMouseDown](event) {
    method [onMouseMove] (line 204) | [onMouseMove](event) {
    method [onMouseForceChange] (line 227) | [onMouseForceChange](event) {
    method [onMouseForceGlobalChange] (line 252) | [onMouseForceGlobalChange](event) {

FILE: src/Draggable/Sensors/MouseSensor/MouseSensor.js
  class MouseSensor (line 23) | class MouseSensor extends Sensor {
    method constructor (line 30) | constructor(containers = [], options = {}) {
    method attach (line 66) | attach() {
    method detach (line 73) | detach() {
    method [onMouseDown] (line 82) | [onMouseDown](event) {
    method [startDrag] (line 128) | [startDrag]() {
    method [onDistanceChange] (line 162) | [onDistanceChange](event) {
    method [onMouseMove] (line 193) | [onMouseMove](event) {
    method [onMouseUp] (line 216) | [onMouseUp](event) {
    method [onContextMenuWhileDragging] (line 260) | [onContextMenuWhileDragging](event) {
  function preventNativeDragStart (line 265) | function preventNativeDragStart(event) {

FILE: src/Draggable/Sensors/MouseSensor/tests/MouseSensor.test.js
  function setup (line 36) | function setup(optionsParam = {}) {
  function teardown (line 52) | function teardown() {
  function dragFlow (line 65) | function dragFlow() {
  function dragFlow (line 123) | function dragFlow() {
  function dragFlowWithRightClick (line 133) | function dragFlowWithRightClick() {
  function dragFlowWithCtrlKey (line 139) | function dragFlowWithCtrlKey() {
  function dragFlowWithMetaKey (line 145) | function dragFlowWithMetaKey() {
  function dragFlow (line 165) | function dragFlow() {
  function dragFlow (line 234) | function dragFlow() {
  function dragFlow (line 244) | function dragFlow() {
  function hastyDragFlow (line 250) | function hastyDragFlow() {
  function dragFlow (line 265) | function dragFlow() {
  function dragFlow (line 284) | function dragFlow() {
  function dragFlow (line 294) | function dragFlow() {
  function hastyDragFlow (line 300) | function hastyDragFlow() {
  function dragFlow (line 315) | function dragFlow() {
  function dragFlow (line 334) | function dragFlow() {
  function dragFlow (line 343) | function dragFlow() {
  function dragFlow (line 352) | function dragFlow() {
  function dragFlow (line 365) | function dragFlow() {
  function dragFlow (line 380) | function dragFlow() {

FILE: src/Draggable/Sensors/Sensor/Sensor.js
  class Sensor (line 12) | class Sensor {
    method constructor (line 19) | constructor(containers = [], options = {}) {
    method attach (line 74) | attach() {
    method detach (line 82) | detach() {
    method addContainer (line 91) | addContainer(...containers) {
    method removeContainer (line 100) | removeContainer(...containers) {
    method trigger (line 111) | trigger(element, sensorEvent) {
  function calcDelay (line 127) | function calcDelay(optionsDelay) {

FILE: src/Draggable/Sensors/SensorEvent/SensorEvent.ts
  type SensorEventData (line 3) | interface SensorEventData {
  class SensorEvent (line 19) | class SensorEvent extends AbstractEvent<SensorEventData> {
    method originalEvent (line 26) | get originalEvent() {
    method clientX (line 36) | get clientX() {
    method clientY (line 46) | get clientY() {
    method target (line 57) | get target() {
    method container (line 67) | get container() {
    method originalSource (line 77) | get originalSource() {
    method pressure (line 87) | get pressure() {
  class DragStartSensorEvent (line 98) | class DragStartSensorEvent extends SensorEvent {
  class DragMoveSensorEvent (line 108) | class DragMoveSensorEvent extends SensorEvent {
  class DragStopSensorEvent (line 118) | class DragStopSensorEvent extends SensorEvent {
  class DragPressureSensorEvent (line 128) | class DragPressureSensorEvent extends SensorEvent {

FILE: src/Draggable/Sensors/TouchSensor/TouchSensor.js
  class TouchSensor (line 46) | class TouchSensor extends Sensor {
    method constructor (line 53) | constructor(containers = [], options = {}) {
    method attach (line 101) | attach() {
    method detach (line 108) | detach() {
    method [onTouchStart] (line 117) | [onTouchStart](event) {
    method [startDrag] (line 168) | [startDrag]() {
    method [onDistanceChange] (line 198) | [onDistanceChange](event) {
    method [onTouchMove] (line 229) | [onTouchMove](event) {
    method [onTouchEnd] (line 255) | [onTouchEnd](event) {
  function onContextMenu (line 297) | function onContextMenu(event) {

FILE: src/Draggable/Sensors/TouchSensor/tests/TouchSensor.test.js
  function setup (line 27) | function setup(optionsParam = {}) {
  function teardown (line 43) | function teardown() {
  function dragFlow (line 60) | function dragFlow() {
  function dragFlow (line 70) | function dragFlow() {
  function dragFlow (line 132) | function dragFlow() {
  function dragFlow (line 141) | function dragFlow() {
  function dragFlow (line 150) | function dragFlow() {
  function dragFlow (line 161) | function dragFlow() {
  function dragFlow (line 171) | function dragFlow() {
  function dragFlow (line 188) | function dragFlow() {
  function dragFlow (line 197) | function dragFlow() {
  function dragFlow (line 206) | function dragFlow() {
  function dragFlow (line 217) | function dragFlow() {
  function dragFlow (line 228) | function dragFlow() {
  function dragFlow (line 246) | function dragFlow() {
  function dragFlow (line 256) | function dragFlow() {
  function dragFlow (line 266) | function dragFlow() {
  function dragFlow (line 279) | function dragFlow() {
  function dragFlow (line 295) | function dragFlow() {

FILE: src/Draggable/tests/Draggable.test.js
  function stubHandler (line 255) | function stubHandler() {
  function stubHandler (line 272) | function stubHandler() {
  function stubHandler (line 287) | function stubHandler() {
  function stubHandler (line 304) | function stubHandler() {

FILE: src/Droppable/Droppable.js
  function onDroppableDroppedDefaultAnnouncement (line 25) | function onDroppableDroppedDefaultAnnouncement({dragEvent, dropzone}) {
  function onDroppableReturnedDefaultAnnouncement (line 41) | function onDroppableReturnedDefaultAnnouncement({dragEvent, dropzone}) {
  class Droppable (line 78) | class Droppable extends Draggable {
    method constructor (line 85) | constructor(containers = [], options = {}) {
    method destroy (line 132) | destroy() {
    method [onDragStart] (line 145) | [onDragStart](event) {
    method [onDragMove] (line 192) | [onDragMove](event) {
    method [onDragStop] (line 218) | [onDragStop](event) {
    method [dropInDropzone] (line 247) | [dropInDropzone](event, dropzone) {
    method [returnToOriginalDropzone] (line 276) | [returnToOriginalDropzone](event) {
    method [closestDropzone] (line 300) | [closestDropzone](target) {
    method [getDropzones] (line 313) | [getDropzones]() {

FILE: src/Droppable/DroppableEvent/DroppableEvent.ts
  type DroppableEventData (line 5) | interface DroppableEventData {
  class DroppableEvent (line 15) | class DroppableEvent<
    method constructor (line 25) | constructor(public data: T) {
    method dragEvent (line 35) | get dragEvent() {
  type DroppableStartEventData (line 40) | interface DroppableStartEventData extends DroppableEventData {
  class DroppableStartEvent (line 50) | class DroppableStartEvent extends DroppableEvent<DroppableStartEventData> {
    method dropzone (line 60) | get dropzone() {
  type DroppableDroppedEventData (line 65) | interface DroppableDroppedEventData extends DroppableEventData {
  class DroppableDroppedEvent (line 75) | class DroppableDroppedEvent extends DroppableEvent<DroppableDroppedEvent...
    method dropzone (line 85) | get dropzone() {
  type DroppableReturnedEventData (line 90) | interface DroppableReturnedEventData extends DroppableEventData {
  class DroppableReturnedEvent (line 100) | class DroppableReturnedEvent extends DroppableEvent<DroppableReturnedEve...
    method dropzone (line 110) | get dropzone() {
  type DroppableStopEventData (line 115) | interface DroppableStopEventData extends DroppableEventData {
  class DroppableStopEvent (line 125) | class DroppableStopEvent extends DroppableEvent<DroppableStopEventData> {
    method dropzone (line 135) | get dropzone() {

FILE: src/Droppable/tests/Droppable.test.js
  function move (line 244) | function move(

FILE: src/Plugins/Collidable/Collidable.js
  class Collidable (line 16) | class Collidable extends AbstractPlugin {
    method constructor (line 22) | constructor(draggable) {
    method attach (line 54) | attach() {
    method detach (line 63) | detach() {
    method getCollidables (line 73) | getCollidables() {
    method [onDragMove] (line 97) | [onDragMove](event) {
    method [onDragStop] (line 144) | [onDragStop](event) {
    method [onRequestAnimationFrame] (line 166) | [onRequestAnimationFrame](target) {

FILE: src/Plugins/Collidable/CollidableEvent/CollidableEvent.ts
  type CollidableEventData (line 5) | interface CollidableEventData {
  class CollidableEvent (line 15) | class CollidableEvent<
    method constructor (line 25) | constructor(public data: T) {
    method dragEvent (line 35) | get dragEvent() {
  type CollidableInEventData (line 40) | interface CollidableInEventData extends CollidableEventData {
  class CollidableInEvent (line 50) | class CollidableInEvent extends CollidableEvent<CollidableInEventData> {
    method collidingElement (line 59) | get collidingElement() {
  type CollidableOutEventData (line 64) | interface CollidableOutEventData extends CollidableEventData {
  class CollidableOutEvent (line 74) | class CollidableOutEvent extends CollidableEvent<CollidableOutEventData> {
    method collidingElement (line 83) | get collidingElement() {

FILE: src/Plugins/ResizeMirror/ResizeMirror.ts
  class ResizeMirror (line 25) | class ResizeMirror extends AbstractPlugin {
    method constructor (line 34) | constructor(draggable: FixMeAny) {
    method attach (line 61) | attach() {
    method detach (line 71) | detach() {
    method getOptions (line 83) | getOptions() {
    method onMirrorCreated (line 93) | private onMirrorCreated({mirror}: MirrorCreatedEvent) {
    method onMirrorDestroy (line 103) | private onMirrorDestroy() {
    method onDragOver (line 113) | private onDragOver(dragEvent: DragOverEvent | DragOverContainerEvent) {
    method resize (line 122) | private resize(dragEvent: DragOverEvent | DragOverContainerEvent) {

FILE: src/Plugins/ResizeMirror/tests/ResizeMirror.test.ts
  function mockDimensions (line 152) | function mockDimensions(element: HTMLElement, {width = 0, height = 0}) {
  function waitForNextRequestAnimationFrame (line 179) | function waitForNextRequestAnimationFrame() {
  function withMockedAppendChild (line 184) | function withMockedAppendChild(callback: () => void) {

FILE: src/Plugins/Snappable/Snappable.js
  class Snappable (line 18) | class Snappable extends AbstractPlugin {
    method constructor (line 24) | constructor(draggable) {
    method attach (line 50) | attach() {
    method detach (line 65) | detach() {
    method [onDragStart] (line 82) | [onDragStart](event) {
    method [onDragStop] (line 95) | [onDragStop]() {
    method [onDragOver] (line 104) | [onDragOver](event) {
    method [onDragOut] (line 149) | [onDragOut](event) {
    method [onMirrorCreated] (line 179) | [onMirrorCreated]({mirror}) {
    method [onMirrorDestroy] (line 188) | [onMirrorDestroy]() {

FILE: src/Plugins/Snappable/SnappableEvent/SnappableEvent.ts
  type SnapEventData (line 5) | interface SnapEventData {
  class SnapEvent (line 16) | class SnapEvent extends AbstractEvent<SnapEventData> {
    method dragEvent (line 25) | get dragEvent() {
    method snappable (line 35) | get snappable() {
  class SnapInEvent (line 46) | class SnapInEvent extends SnapEvent {
  class SnapOutEvent (line 57) | class SnapOutEvent extends SnapEvent {

FILE: src/Plugins/SortAnimation/SortAnimation.js
  class SortAnimation (line 24) | class SortAnimation extends AbstractPlugin {
    method constructor (line 30) | constructor(draggable) {
    method attach (line 60) | attach() {
    method detach (line 68) | detach() {
    method getOptions (line 77) | getOptions() {
    method [onSortableSort] (line 86) | [onSortableSort]({dragEvent}) {
    method [onSortableSorted] (line 104) | [onSortableSorted]({oldIndex, newIndex}) {
  function animate (line 147) | function animate({from, to}, {duration, easingFunction}) {
  function resetElementOnTransitionEnd (line 167) | function resetElementOnTransitionEnd(event) {

FILE: src/Plugins/SwapAnimation/SwapAnimation.ts
  type Options (line 5) | interface Options {
  class SwapAnimation (line 31) | class SwapAnimation extends AbstractPlugin {
    method constructor (line 39) | constructor(draggable: FixMeAny) {
    method attach (line 65) | attach() {
    method detach (line 72) | detach() {
    method getOptions (line 80) | getOptions() {
    method onSortableSorted (line 90) | onSortableSorted({oldIndex, newIndex, dragEvent}: FixMeAny) {
  function animate (line 118) | function animate(
  function resetElementOnTransitionEnd (line 151) | function resetElementOnTransitionEnd(event: Event) {
  function isHTMLElement (line 164) | function isHTMLElement(eventTarget: EventTarget): eventTarget is HTMLEle...

FILE: src/Sortable/Sortable.js
  function onSortableSortedDefaultAnnouncement (line 21) | function onSortableSortedDefaultAnnouncement({dragEvent}) {
  class Sortable (line 62) | class Sortable extends Draggable {
    method constructor (line 69) | constructor(containers = [], options = {}) {
    method destroy (line 107) | destroy() {
    method index (line 121) | index(element) {
    method getSortableElementsForContainer (line 133) | getSortableElementsForContainer(container) {
    method [onDragStart] (line 152) | [onDragStart](event) {
    method [onDragOverContainer] (line 174) | [onDragOverContainer](event) {
    method [onDragOver] (line 221) | [onDragOver](event) {
    method [onDragStop] (line 268) | [onDragStop](event) {
  function index (line 284) | function index(element) {
  function move (line 288) | function move({source, over, overContainer, children}) {
  function moveInsideEmptyContainer (line 304) | function moveInsideEmptyContainer(source, overContainer) {
  function moveWithinContainer (line 312) | function moveWithinContainer(source, over) {
  function moveOutsideContainer (line 325) | function moveOutsideContainer(source, over, overContainer) {

FILE: src/Sortable/SortableEvent/SortableEvent.ts
  type SortableEventData (line 12) | interface SortableEventData {
  class SortableEvent (line 22) | class SortableEvent<
    method constructor (line 32) | constructor(public data: T) {
    method dragEvent (line 42) | get dragEvent() {
  type SortableStartEventData (line 47) | interface SortableStartEventData extends SortableEventData {
  class SortableStartEvent (line 58) | class SortableStartEvent extends SortableEvent<SortableStartEventData> {
    method startIndex (line 68) | get startIndex() {
    method startContainer (line 78) | get startContainer() {
  type SortableSortEventData (line 83) | interface SortableSortEventData extends SortableEventData {
  class SortableSortEvent (line 99) | class SortableSortEvent extends SortableEvent<SortableSortEventData> {
    method currentIndex (line 109) | get currentIndex() {
    method over (line 119) | get over() {
    method overContainer (line 129) | get overContainer() {
  type SortableSortedEventData (line 134) | interface SortableSortedEventData extends SortableEventData {
  class SortableSortedEvent (line 147) | class SortableSortedEvent extends SortableEvent<SortableSortedEventData> {
    method oldIndex (line 156) | get oldIndex() {
    method newIndex (line 166) | get newIndex() {
    method oldContainer (line 176) | get oldContainer() {
    method newContainer (line 186) | get newContainer() {
  type SortableStopEventData (line 191) | interface SortableStopEventData extends SortableEventData {
  class SortableStopEvent (line 204) | class SortableStopEvent extends SortableEvent<SortableStopEventData> {
    method oldIndex (line 213) | get oldIndex() {
    method newIndex (line 223) | get newIndex() {
    method oldContainer (line 233) | get oldContainer() {
    method newContainer (line 243) | get newContainer() {

FILE: src/Swappable/Swappable.js
  function onSwappableSwappedDefaultAnnouncement (line 19) | function onSwappableSwappedDefaultAnnouncement({dragEvent, swappedElemen...
  class Swappable (line 47) | class Swappable extends Draggable {
    method constructor (line 54) | constructor(containers = [], options = {}) {
    method destroy (line 82) | destroy() {
    method [onDragStart] (line 95) | [onDragStart](event) {
    method [onDragOver] (line 112) | [onDragOver](event) {
    method [onDragStop] (line 159) | [onDragStop](event) {
  function withTempElement (line 169) | function withTempElement(callback) {
  function swap (line 175) | function swap(source, over) {

FILE: src/Swappable/SwappableEvent/SwappableEvent.ts
  type SwappableEventData (line 5) | interface SwappableEventData {
  class SwappableEvent (line 15) | class SwappableEvent<
    method constructor (line 25) | constructor(public data: T) {
    method dragEvent (line 35) | get dragEvent() {
  class SwappableStartEvent (line 46) | class SwappableStartEvent extends SwappableEvent<SwappableEventData> {
  type SwappableSwapEventData (line 51) | interface SwappableSwapEventData extends SwappableEventData {
  class SwappableSwapEvent (line 62) | class SwappableSwapEvent extends SwappableEvent<SwappableSwapEventData> {
    method over (line 72) | get over() {
    method overContainer (line 82) | get overContainer() {
  type SwappableSwappedEventData (line 87) | interface SwappableSwappedEventData extends SwappableEventData {
  class SwappableSwappedEvent (line 97) | class SwappableSwappedEvent extends SwappableEvent<SwappableSwappedEvent...
    method swappedElement (line 106) | get swappedElement() {
  class SwappableStopEvent (line 117) | class SwappableStopEvent extends SwappableEvent<SwappableEventData> {

FILE: src/shared/AbstractEvent/AbstractEvent.ts
  class AbstractEvent (line 9) | class AbstractEvent<T> {
    method constructor (line 39) | constructor(public data: T) {}
    method type (line 46) | get type() {
    method cancelable (line 55) | get cancelable() {
    method cancel (line 63) | cancel() {
    method canceled (line 72) | canceled() {
    method clone (line 82) | clone(data: Partial<T>): AbstractEvent<T> {

FILE: src/shared/AbstractPlugin/AbstractPlugin.ts
  method constructor (line 15) | constructor(protected draggable: FixMeAny) {}
  method attach (line 21) | attach() {
  method detach (line 29) | detach() {

FILE: src/shared/types.ts
  type FixMeAny (line 1) | type FixMeAny = any;
  type FixMeUnknown (line 2) | type FixMeUnknown = unknown;

FILE: src/shared/utils/closest/closest.ts
  type Node (line 2) | interface Node {
  type CallbackFunction (line 8) | type CallbackFunction = (element: Node) => boolean;
  type Value (line 9) | type Value = string | CallbackFunction | NodeList | Node | Node[];
  function closest (line 20) | function closest(node?: Node, value?: Value) {
  function isSelector (line 63) | function isSelector(value: Value): value is string {
  function isNodeList (line 67) | function isNodeList(value: Value): value is NodeList | Node[] {
  function isElement (line 71) | function isElement(value: Value): value is Node {
  function isFunction (line 75) | function isFunction(value: Value): value is (element: Node) => boolean {

FILE: src/shared/utils/closest/tests/closest.test.ts
  function selector (line 38) | function selector() {
  function callback (line 54) | function callback(currentElement: Node) {

FILE: src/shared/utils/decorators/AutoBind.ts
  function AutoBind (line 1) | function AutoBind<T extends (...args: any[]) => any>(

FILE: src/shared/utils/distance/distance.ts
  function distance (line 9) | function distance(

FILE: src/shared/utils/requestNextAnimationFrame/requestNextAnimationFrame.ts
  function requestNextAnimationFrame (line 1) | function requestNextAnimationFrame(callback: () => void) {

FILE: src/shared/utils/touchCoords/touchCoords.ts
  function touchCoords (line 6) | function touchCoords(event: TouchEvent) {

FILE: test/environment.ts
  type Event (line 4) | interface Event {

FILE: test/helpers/constants.ts
  constant DRAG_DELAY (line 18) | const DRAG_DELAY = 100;

FILE: test/helpers/environment.ts
  function createSandbox (line 3) | function createSandbox(content: string) {
  function withElementFromPoint (line 11) | function withElementFromPoint(
  constant REQUEST_ANIMATION_FRAME_TIMEOUT (line 21) | const REQUEST_ANIMATION_FRAME_TIMEOUT = 15;
  function waitForRequestAnimationFrame (line 23) | function waitForRequestAnimationFrame(
  function waitForPromisesToResolve (line 29) | function waitForPromisesToResolve() {

FILE: test/helpers/event.ts
  function triggerEvent (line 3) | function triggerEvent(

FILE: test/helpers/module.ts
  type Options (line 15) | interface Options {
  function drag (line 21) | function drag({from, to, sensor = 'mouse'}: Options) {

FILE: test/helpers/plugin.ts
  class TestPlugin (line 3) | class TestPlugin extends AbstractPlugin {
    method constructor (line 4) | constructor(draggable: any) {
    method attach (line 13) | attach() {
    method detach (line 17) | detach() {

FILE: test/helpers/sensor.ts
  function waitForDragDelay (line 8) | function waitForDragDelay({
  function clickMouse (line 23) | function clickMouse(element: HTMLElement, options = {}) {
  function moveMouse (line 30) | function moveMouse(element: HTMLElement, options = {}) {
  function releaseMouse (line 37) | function releaseMouse(element: HTMLElement, options = {}) {
  function touchStart (line 44) | function touchStart(element: HTMLElement, options = {}) {
  function touchMove (line 51) | function touchMove(element: HTMLElement, options = {}) {
  function touchRelease (line 58) | function touchRelease(element: HTMLElement, options = {}) {
  function dragStart (line 65) | function dragStart(element: HTMLElement, options = {}) {
  function dragOver (line 72) | function dragOver(element: HTMLElement, options = {}) {
  function dragDrop (line 79) | function dragDrop(element: HTMLElement, options = {}) {
  function dragStop (line 86) | function dragStop(element: HTMLElement, options = {}) {
  function getDataTransferStub (line 93) | function getDataTransferStub() {

FILE: test/matchers/dom-event.ts
  function toHaveDefaultPrevented (line 1) | function toHaveDefaultPrevented(event: Event) {
  function toHaveStoppedPropagation (line 14) | function toHaveStoppedPropagation(event: Event) {

FILE: test/matchers/event.ts
  function toHaveBeenCalledWithEvent (line 5) | function toHaveBeenCalledWithEvent(
  function toHaveBeenCalledWithEventProperties (line 55) | function toHaveBeenCalledWithEventProperties(

FILE: test/matchers/order.ts
  function toHaveOrder (line 1) | function toHaveOrder(actualOrder: HTMLElement[], expectedOrder: HTMLElem...

FILE: test/matchers/sensor.ts
  function toHaveTriggeredSensorEvent (line 1) | function toHaveTriggeredSensorEvent(
  function toHaveCanceledSensorEvent (line 33) | function toHaveCanceledSensorEvent(

FILE: test/matchers/utils.ts
  function expectation (line 1) | function expectation(passed: boolean) {
Condensed preview — 347 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (680K chars).
[
  {
    "path": ".changeset/README.md",
    "chars": 510,
    "preview": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that wo"
  },
  {
    "path": ".changeset/config.json",
    "chars": 307,
    "preview": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@2.3.1/schema.json\",\n  \"changelog\": [\"@changesets/changelog-github\","
  },
  {
    "path": ".editorconfig",
    "chars": 394,
    "preview": "# editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntri"
  },
  {
    "path": ".eslintignore",
    "chars": 7,
    "preview": "build/\n"
  },
  {
    "path": ".eslintrc.js",
    "chars": 487,
    "preview": "const path = require('path');\n\nmodule.exports = {\n  extends: [\n    'plugin:@shopify/typescript',\n    'plugin:@shopify/je"
  },
  {
    "path": ".github/.probots.yml",
    "chars": 17,
    "preview": "enabled:\n  - cla\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 1071,
    "preview": "> Please use this template to help contributors get a detailed description of the issue or feature.\n\n**For support quest"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 670,
    "preview": "<!-- Thank you for submitting a pull request! Please make sure you have read the [contribution guidelines](https://githu"
  },
  {
    "path": ".github/dependabot.yaml",
    "chars": 114,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: \"/\"\n    schedule:\n      interval: weekly\n"
  },
  {
    "path": ".github/workflows/changelog.yml",
    "chars": 755,
    "preview": "name: Changelog\n\non:\n  pull_request:\n    types:\n      - labeled\n      - unlabeled\n      - opened\n      - synchronize\n   "
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 935,
    "preview": "name: CI\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n "
  },
  {
    "path": ".github/workflows/cla.yml",
    "chars": 618,
    "preview": "# .github/workflows/cla.yml\nname: Contributor License Agreement (CLA)\n\non:\n  pull_request_target:\n    types: [opened, sy"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 1090,
    "preview": "name: Release\n\non:\n  push:\n    branches:\n      - main\n\nconcurrency: ${{ github.workflow }}-${{ github.ref }}\n\njobs:\n  re"
  },
  {
    "path": ".github/workflows/snapit.yml",
    "chars": 6931,
    "preview": "name: Snapshot\n\non:\n  issue_comment:\n    types:\n      - created\n\nconcurrency: ${{ github.workflow }}-${{ github.ref }}\n\n"
  },
  {
    "path": ".gitignore",
    "chars": 405,
    "preview": "# Ignore OS Specific files\n.DS_Store\n\n# Ignore the SASS cache\n.sass-cache\n\n# Logs\nlogs\n*.log\n\n# Dependency directory\n# D"
  },
  {
    "path": ".nvmrc",
    "chars": 9,
    "preview": "v20.17.0\n"
  },
  {
    "path": ".prettierignore",
    "chars": 7,
    "preview": "build/\n"
  },
  {
    "path": ".prettierrc",
    "chars": 27,
    "preview": "\"@shopify/prettier-config\"\n"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 123,
    "preview": "{\n  \"recommendations\": [\n    \"dbaeumer.vscode-eslint\",\n    \"editorconfig.editorconfig\",\n    \"esbenp.prettier-vscode\"\n  ]"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 304,
    "preview": "{\n  \"version\": \"1.0.0\",\n  \"configurations\": [\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"Jest"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 551,
    "preview": "{\n  \"files.exclude\": {\n    \"**/.git\": true,\n    \"**/.DS_Store\": true,\n    \"**/node_modules\": true,\n    \".rollup.cache\": "
  },
  {
    "path": "AUTHORS",
    "chars": 197,
    "preview": "Maintainer\n----------\nShopify\nhttps://github.com/Shopify\n\nOriginal Authors\n----------------\nMax Hoffmann / max.hoffmann@"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 12138,
    "preview": "# Changelog\n\n## 1.2.1\n\n### Patch Changes\n\n- [#661](https://github.com/Shopify/draggable/pull/661) [`f0194c4`](https://gi"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3228,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3143,
    "preview": "# Contributing to Draggable\n\nThank you for contributing to draggable :tada: Any contributions to draggable are\nappreciat"
  },
  {
    "path": "LICENSE.md",
    "chars": 1072,
    "preview": "MIT License\n\nCopyright (c) 2018-present Shopify\n\nPermission is hereby granted, free of charge, to any person obtaining a"
  },
  {
    "path": "README.md",
    "chars": 7611,
    "preview": "[![npm version](https://img.shields.io/npm/v/@shopify/draggable.svg?label=@shopify/draggable)](https://www.npmjs.com/pac"
  },
  {
    "path": "babel.config.js",
    "chars": 1858,
    "preview": "module.exports = function (api) {\n  api.cache(true);\n\n  return {\n    presets: [\n      [\n        '@babel/preset-env',\n   "
  },
  {
    "path": "config/typescript/rollup-plugin-includepaths.d.ts",
    "chars": 226,
    "preview": "declare module 'rollup-plugin-includepaths' {\n  interface Options {\n    include: {[key: string]: string};\n    paths: str"
  },
  {
    "path": "doc/typescript.md",
    "chars": 1426,
    "preview": "# Default usage\n\n```typescript\nimport {Sortable} from '@shopify/draggable';\n\nconst sortable = new Sortable(document.quer"
  },
  {
    "path": "esdoc.json",
    "chars": 184,
    "preview": "{\n  \"source\": \"./src\",\n  \"destination\": \"./docs\",\n  \"plugins\": [\n    {\"name\": \"esdoc-standard-plugin\"},\n    {\"name\": \"es"
  },
  {
    "path": "examples/.babelrc",
    "chars": 194,
    "preview": "{\n  \"presets\": [\n    [\n      \"babel-preset-shopify/web\",\n      {\n        \"babel-preset-shopify/web\": {\n          \"module"
  },
  {
    "path": "examples/.browserslistrc",
    "chars": 20,
    "preview": "> 1%\nLast 1 version\n"
  },
  {
    "path": "examples/.editorconfig",
    "chars": 523,
    "preview": "# editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntri"
  },
  {
    "path": "examples/.eslintignore",
    "chars": 52,
    "preview": "node_modules\npackages\ndist\nscrap\nsrc/scripts/vendor\n"
  },
  {
    "path": "examples/.eslintrc.js",
    "chars": 860,
    "preview": "/* eslint-env node */\nmodule.exports = {\n  extends: ['plugin:shopify/esnext', 'plugin:shopify/webpack', 'plugin:shopify/"
  },
  {
    "path": "examples/.gitignore",
    "chars": 417,
    "preview": "# OS files\n.DS_Store\n\n# Caches\n.cache\n.eslintcache\n.sass-cache\n.npm\n*.tsbuildinfo\n\n# Dev\n.dev\n\n# Environment\n.env\n.env.t"
  },
  {
    "path": "examples/.nvmrc",
    "chars": 9,
    "preview": "v20.17.0\n"
  },
  {
    "path": "examples/.prettierignore",
    "chars": 93,
    "preview": "node_modules\npackages\n/.github\n/assets-manifest.json\n/bundle-report.html\n/dist\n/package.json\n"
  },
  {
    "path": "examples/.prettierrc",
    "chars": 127,
    "preview": "{\n  \"arrowParens\": \"always\",\n  \"bracketSpacing\": false,\n  \"printWidth\": 100,\n  \"singleQuote\": true,\n  \"trailingComma\": \""
  },
  {
    "path": "examples/.stylelintignore",
    "chars": 93,
    "preview": "node_modules\npackages\n/.github\n/assets-manifest.json\n/bundle-report.html\n/dist\n/package.json\n"
  },
  {
    "path": "examples/.stylelintrc",
    "chars": 920,
    "preview": "{\n  \"extends\": [\n    \"stylelint-config-shopify/prettier\"\n  ],\n  \"rules\": {\n    \"shopify/content-no-strings\": true,\n    \""
  },
  {
    "path": "examples/.vscode/extensions.json",
    "chars": 381,
    "preview": "{\n  \"recommendations\": [\n    \"christian-kohler.npm-intellisense\",\n    \"christian-kohler.path-intellisense\",\n    \"codezom"
  },
  {
    "path": "examples/.vscode/settings.json",
    "chars": 564,
    "preview": "{\n  \"css.validate\": false,\n  \"scss.validate\": false,\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll\": true\n  },\n  \"e"
  },
  {
    "path": "examples/README.md",
    "chars": 7022,
    "preview": "![banner-examples](https://user-images.githubusercontent.com/643944/34655498-c9701942-f3d8-11e7-9dd5-6d225e7c5f6f.png)\n\n"
  },
  {
    "path": "examples/package.json",
    "chars": 2577,
    "preview": "{\n  \"name\": \"draggable-examples\",\n  \"version\": \"1.1.0\",\n  \"description\": \"Examples for draggable.js\",\n  \"author\": \"Max H"
  },
  {
    "path": "examples/postcss.config.js",
    "chars": 257,
    "preview": "/* eslint-env node */\nmodule.exports = () => ({\n  plugins: {\n    autoprefixer: {},\n    cssnano: {\n      // reduceIdents "
  },
  {
    "path": "examples/src/components/Analytics/index.js",
    "chars": 952,
    "preview": "function gtag() {\n  window.dataLayer.push(arguments); // eslint-disable-line prefer-rest-params\n}\n\nexport default class "
  },
  {
    "path": "examples/src/components/Block/Block.html",
    "chars": 1378,
    "preview": "{% macro render(heading, options = {}) %}\n  {% set classes = ['Block'] %}\n\n  {% set classes = (classes.push('Block--type"
  },
  {
    "path": "examples/src/components/Block/Block.scss",
    "chars": 661,
    "preview": "////\n/// Components\n/// Block\n////\n\n@import 'utils/shared/functions';\n@import 'utils/shared/layout';\n\n.BlockWrapper {\n  "
  },
  {
    "path": "examples/src/components/Block/variants.scss",
    "chars": 3174,
    "preview": "////\n/// Components\n/// Block variants\n////\n\n@import 'utils/shared/layout';\n@import 'components/Patterns/props';\n\n///\n//"
  },
  {
    "path": "examples/src/components/Brand/Brand.html",
    "chars": 265,
    "preview": "<a href=\"./\" class=\"Brand\" title=\"Return to Examples index\">\n  <div class=\"SvgContainer BrandLogo\">\n    {% include 'comp"
  },
  {
    "path": "examples/src/components/Brand/Brand.scss",
    "chars": 1204,
    "preview": "////\n/// Components\n/// Brand\n////\n\n@import 'keyframes';\n@import 'props';\n\n.Brand {\n  cursor: get-cursor(rock);\n  displa"
  },
  {
    "path": "examples/src/components/Brand/Logo.html",
    "chars": 1747,
    "preview": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 60 78\" class=\"Svg Svg--srcLogo\">\n  <path class=\"Wave Wave--colorMas"
  },
  {
    "path": "examples/src/components/Brand/Wordmark.html",
    "chars": 4636,
    "preview": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 176 42\" class=\"Svg Svg--srcWordmark\">\n  <path d=\"M20.014.052h-.869c"
  },
  {
    "path": "examples/src/components/Brand/keyframes.scss",
    "chars": 1153,
    "preview": "////\n/// Components\n/// Brand keyframes\n////\n\n@import 'props';\n\n@keyframes logo-outline-bounce {\n  25% {\n    transform: "
  },
  {
    "path": "examples/src/components/Brand/props.scss",
    "chars": 640,
    "preview": "////\n/// Components\n/// Brand props\n////\n\n$logo-width: 4.6rem;\n$wordmark-width: 17.6rem;\n$logo-bounce-offset: 0.1rem;\n\n@"
  },
  {
    "path": "examples/src/components/Button/Button.scss",
    "chars": 1442,
    "preview": "////\n/// Components\n/// Button\n////\n\n@import 'utils/shared/layout';\n\n.Button {\n  display: inline-block;\n  padding: get-s"
  },
  {
    "path": "examples/src/components/Button/variants.scss",
    "chars": 615,
    "preview": "////\n/// Components\n/// Button variants\n////\n\n.Button--isActive {\n  color: white;\n  background-color: get-color(coal, da"
  },
  {
    "path": "examples/src/components/Document/Favicon.html",
    "chars": 719,
    "preview": "<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n<meta name=\"apple-mobile-web-app-status-bar-style\" content=\"bla"
  },
  {
    "path": "examples/src/components/Document/Head.html",
    "chars": 1745,
    "preview": "{% import 'components/Document/SocialShare.html' as SocialShare %}\n\n{% macro render(ViewAttr) %}\n  {% set url = 'https:/"
  },
  {
    "path": "examples/src/components/Document/SocialShare.html",
    "chars": 824,
    "preview": "{% macro render(HeadAttr) %}\n  <meta property=\"og:type\" content=\"website\">\n  <meta property=\"og:site_name\" content=\"{{ H"
  },
  {
    "path": "examples/src/components/GridOverlay/GridOverlay.scss",
    "chars": 2143,
    "preview": "////\n/// Components\n/// Grid Overlay\n////\n\n@import 'utils/shared/functions';\n@import 'utils/shared/layout';\n@import 'com"
  },
  {
    "path": "examples/src/components/Hamburger/Hamburger.html",
    "chars": 198,
    "preview": "<button type=\"button\" id=\"MobileNavActivator\" class=\"Hamburger\" aria-controls=\"Sidebar\" aria-expanded=\"false\">\n  <div cl"
  },
  {
    "path": "examples/src/components/Hamburger/Hamburger.scss",
    "chars": 1766,
    "preview": "////\n/// Components\n/// Hamburger\n////\n\n@import 'utils/shared/layout';\n@import 'keyframes';\n@import 'props';\n\n.Hamburger"
  },
  {
    "path": "examples/src/components/Hamburger/keyframes.scss",
    "chars": 1359,
    "preview": "////\n/// Components\n/// Hamburger keyframes\n////\n\n@import 'props';\n\n@keyframes FadeActivator {\n  to {\n    opacity: 1;\n  "
  },
  {
    "path": "examples/src/components/Hamburger/props.scss",
    "chars": 348,
    "preview": "////\n/// Components\n/// Hamburger props\n////\n\n$hamburger-width: 2.4rem;\n$hamburger-height: 2rem;\n$hamburger-line-height:"
  },
  {
    "path": "examples/src/components/Handle/DragHandle.scss",
    "chars": 592,
    "preview": "////\n/// Components\n/// DragHandle\n////\n\n@import 'props';\n\n.DragHandle {\n  position: relative;\n  width: $handle-size;\n  "
  },
  {
    "path": "examples/src/components/Handle/NopeHandle.scss",
    "chars": 592,
    "preview": "////\n/// Components\n/// NopeHandle\n////\n\n@import 'props';\n\n.NopeHandle {\n  position: relative;\n  width: $handle-size;\n  "
  },
  {
    "path": "examples/src/components/Handle/props.scss",
    "chars": 295,
    "preview": "////\n/// Components\n/// Handle props\n////\n\n$handle-size: 2rem;\n$handle-stroke-width: 0.4rem;\n$handle-center: ($handle-si"
  },
  {
    "path": "examples/src/components/Heading/Heading.scss",
    "chars": 150,
    "preview": "////\n/// Components\n/// Heading\n////\n\n@import 'props';\n\n.Heading {\n  @include Heading;\n}\n\n.Subheading {\n  @include Subhe"
  },
  {
    "path": "examples/src/components/Heading/props.scss",
    "chars": 2271,
    "preview": "////\n/// Components\n/// Heading props\n////\n\n@mixin Heading {\n  letter-spacing: get-type-scale(base, tracking);\n  line-he"
  },
  {
    "path": "examples/src/components/Heading/variants.scss",
    "chars": 389,
    "preview": "////\n/// Components\n/// Heading variants\n////\n\n@import 'props';\n\n///\n/// Heading sizes\n.Heading--sizeJumbo {\n  @include "
  },
  {
    "path": "examples/src/components/Link/Link.scss",
    "chars": 817,
    "preview": "////\n/// Components\n/// Link\n////\n\n.Link {\n  color: get-color(purple, light);\n  transition: color get-duration() get-eas"
  },
  {
    "path": "examples/src/components/Main/Main.scss",
    "chars": 655,
    "preview": "////\n/// Components\n/// Main\n////\n\n@import 'utils/shared/layout';\n@import 'components/MobileNav/props';\n@import 'props';"
  },
  {
    "path": "examples/src/components/Main/props.scss",
    "chars": 196,
    "preview": "////\n/// Components\n/// Main props\n////\n\n$main-padding-left-tablet: get-layout-length(sidebar) + get-spacing(tight);\n$ma"
  },
  {
    "path": "examples/src/components/MobileNav/index.js",
    "chars": 1807,
    "preview": "import debounce, {debounceDuration} from '../../scripts/utils/debounce';\n\n// equal to `get-breakpoint()` base value\ncons"
  },
  {
    "path": "examples/src/components/MobileNav/props.scss",
    "chars": 96,
    "preview": "////\n/// Components\n/// MobileNav props\n////\n\n$mobile-nav-padding-top: get-spacing(looser) * 2;\n"
  },
  {
    "path": "examples/src/components/Navigation/NavList.html",
    "chars": 1283,
    "preview": "{% macro render(ViewAttr, SubNav) %}\n  {% for Section, Links in SubNav %}\n    {% set listClasses = ['NavList'] %}\n    {%"
  },
  {
    "path": "examples/src/components/Navigation/Navigation.html",
    "chars": 249,
    "preview": "{% import 'components/Navigation/NavList.html' as NavList %}\n\n{% macro render(ViewAttr, DataPages) %}\n  <nav class=\"Navi"
  },
  {
    "path": "examples/src/components/Navigation/Navigation.scss",
    "chars": 1565,
    "preview": "////\n/// Components\n/// Navigation\n////\n\n.Navigation {\n  padding: get-spacing(tight);\n\n  @media screen and (min-width: g"
  },
  {
    "path": "examples/src/components/Page/Page.scss",
    "chars": 1506,
    "preview": "////\n/// Components\n/// Page\n////\n\n@import 'utils/shared/layout';\n\nhtml {\n  @include scroll-lock;\n  font-family: get-fon"
  },
  {
    "path": "examples/src/components/PageHeader/PageHeader.html",
    "chars": 546,
    "preview": "{% macro render(ViewAttr) %}\n  {% set contentPath = '' %}\n  {% set contentPath = ViewAttr.parent + '/' if ViewAttr.child"
  },
  {
    "path": "examples/src/components/PageHeader/PageHeader.scss",
    "chars": 600,
    "preview": "////\n/// Components\n/// PageHeader\n////\n\n@import 'utils/shared/layout';\n\n.PageHeader {\n  @include centered-width(get-lay"
  },
  {
    "path": "examples/src/components/PaperStack/PaperStack.scss",
    "chars": 2917,
    "preview": "////\n/// Components\n/// PaperStack\n////\n\n@import 'utils/shared/layout';\n@import 'props';\n\n.PaperStack {\n  position: rela"
  },
  {
    "path": "examples/src/components/PaperStack/PaperStackItem.html",
    "chars": 853,
    "preview": "{% macro render(heading, options = {}) %}\n  {% set classes = ['PaperStackItem'] %}\n  {% set classes = (classes.push('Pap"
  },
  {
    "path": "examples/src/components/PaperStack/props.scss",
    "chars": 2725,
    "preview": "////\n/// Components\n/// PaperStack props\n////\n\n$paper-stack-block-name: unquote('PaperStackItem');\n$paper-stack-item-cou"
  },
  {
    "path": "examples/src/components/PaperStack/variants.scss",
    "chars": 1522,
    "preview": "////\n/// Components\n/// PaperStack variants\n////\n\n@import 'components/Patterns/props';\n@import 'props';\n\n///\n/// Draggab"
  },
  {
    "path": "examples/src/components/Patterns/Patterns.scss",
    "chars": 851,
    "preview": "////\n/// Components\n/// Patterns\n////\n\n@import 'utils/shared/layout';\n@import 'keyframes';\n@import 'props';\n\n:root {\n  -"
  },
  {
    "path": "examples/src/components/Patterns/keyframes.scss",
    "chars": 281,
    "preview": "////\n/// Components\n/// Patterns keyframes\n////\n\n@import 'props';\n\n@keyframes placed {\n  to {\n    transform: scale(0);\n "
  },
  {
    "path": "examples/src/components/Patterns/props.scss",
    "chars": 928,
    "preview": "////\n/// Components\n/// Pattern props\n////\n\n@import 'utils/shared/layout';\n\n$stripes-bg-size: 0.8rem;\n$halftone-bg-size:"
  },
  {
    "path": "examples/src/components/PillSwitch/PillSwitch.html",
    "chars": 340,
    "preview": "{% macro render() %}\n  <article class=\"PillSwitch\">\n    <div class=\"PillSwitchTrack\">\n      <div class=\"Pattern Pattern-"
  },
  {
    "path": "examples/src/components/PillSwitch/PillSwitch.scss",
    "chars": 2347,
    "preview": "////\n/// Components\n/// PillSwitch\n////\n\n@import 'utils/shared/layout';\n@import 'components/Patterns/props';\n@import 'pr"
  },
  {
    "path": "examples/src/components/PillSwitch/props.scss",
    "chars": 1393,
    "preview": "////\n/// Components\n/// PillSwitch props\n////\n\n$pill-switch-size: 27.2rem;\n$pill-switch-size-tablet: 54.8rem;\n\n$pill-swi"
  },
  {
    "path": "examples/src/components/PillSwitch/variants.scss",
    "chars": 558,
    "preview": "////\n/// Components\n/// PillSwitch variants\n////\n\n@import 'components/Patterns/props';\n\n.PillSwitch--isOn {\n  .PillSwitc"
  },
  {
    "path": "examples/src/components/Plate/Plate.html",
    "chars": 1187,
    "preview": "{% macro render(index, options = {}) %}\n  {% set classes = ['Plate'] %}\n\n  {% if options.level and (\n    options.level ="
  },
  {
    "path": "examples/src/components/Plate/Plate.scss",
    "chars": 1008,
    "preview": "////\n/// Components\n/// Plate\n////\n\n@import 'utils/shared/layout';\n@import 'keyframes';\n@import 'props';\n\n.PlateWrapper "
  },
  {
    "path": "examples/src/components/Plate/index.js",
    "chars": 3078,
    "preview": "import flipSign from '../../scripts/utils/flip-sign';\n\nconst scaleFactor = 0.725;\nconst translateFactors = {\n  bottom: 0"
  },
  {
    "path": "examples/src/components/Plate/keyframes.scss",
    "chars": 1116,
    "preview": "////\n/// Components\n/// Plate keyframes\n////\n\n@keyframes plate-small {\n  0%,\n  100% {\n    transform: scale(1, 1);\n  }\n\n "
  },
  {
    "path": "examples/src/components/Plate/props.scss",
    "chars": 66,
    "preview": "////\n/// Components\n/// Plate props\n////\n\n$plate-max-size: 80rem;\n"
  },
  {
    "path": "examples/src/components/Plate/variants.scss",
    "chars": 3293,
    "preview": "////\n/// Components\n/// Plate variants\n////\n\n///\n/// Level variant\n.Plate--levelBottom {\n  padding-top: 100%;\n  width: 1"
  },
  {
    "path": "examples/src/components/Sidebar/Sidebar.html",
    "chars": 1304,
    "preview": "{% import 'components/Navigation/Navigation.html' as Navigation %}\n\n{% macro render(ViewAttr, DataPages) %}\n  <aside id="
  },
  {
    "path": "examples/src/components/Sidebar/Sidebar.scss",
    "chars": 2075,
    "preview": "////\n/// Components\n/// Sidebar\n////\n\n@import 'utils/shared/layout';\n@import 'components/MobileNav/props';\n\n.Sidebar {\n "
  },
  {
    "path": "examples/src/components/StackedList/StackedList.scss",
    "chars": 4187,
    "preview": "////\n/// Components\n/// StackedList\n////\n\n@import 'utils/shared/layout';\n@import 'utils/shared/typography';\n@import 'com"
  },
  {
    "path": "examples/src/components/StackedList/StackedListItem.html",
    "chars": 972,
    "preview": "{% macro render(heading, options = {}) %}\n  {% set classes = ['StackedListItem'] %}\n  {% set classes = (classes.push('St"
  },
  {
    "path": "examples/src/components/StackedList/props.scss",
    "chars": 1564,
    "preview": "////\n/// Components\n/// StackedList props\n////\n\n$stacked-list-header: (\n  padding: (\n    base: get-spacing(tighter) + ge"
  },
  {
    "path": "examples/src/components/StackedList/variants.scss",
    "chars": 5789,
    "preview": "////\n/// Components\n/// StackedList variants\n////\n\n@import 'components/Handle/props';\n@import 'components/Patterns/props"
  },
  {
    "path": "examples/src/components/Svg/Svg.scss",
    "chars": 273,
    "preview": "////\n/// Components\n/// Svg\n////\n\na.SvgContainer {\n  display: block;\n  color: black; // default to black\n}\n\n.SvgContaine"
  },
  {
    "path": "examples/src/content/Draggable/DragEvents/DragEvents.html",
    "chars": 192,
    "preview": "{% import 'components/PillSwitch/PillSwitch.html' as PillSwitch %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" clas"
  },
  {
    "path": "examples/src/content/Draggable/DragEvents/DragEvents.scss",
    "chars": 66,
    "preview": "////\n/// Content\n/// DragEvents\n////\n\n.DragEvents {\n  // styles\n}\n"
  },
  {
    "path": "examples/src/content/Draggable/DragEvents/index.js",
    "chars": 3406,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Draggable} from '@shopify/draggable';\n\nfunction translateMirror"
  },
  {
    "path": "examples/src/content/Droppable/UniqueDropzone/UniqueDropzone.html",
    "chars": 2217,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Droppable/UniqueDropzone/UniqueDropzone.scss",
    "chars": 3314,
    "preview": "////\n/// Content\n/// UniqueDropzone\n////\n\n@import 'utils/shared/functions';\n\n$grid-area-names: a, b, c, d, e, f, g, h;\n$"
  },
  {
    "path": "examples/src/content/Droppable/UniqueDropzone/index.js",
    "chars": 803,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Droppable} from '@shopify/draggable';\n\nexport default function "
  },
  {
    "path": "examples/src/content/Home/Home.html",
    "chars": 422,
    "preview": "{% import 'components/Plate/Plate.html' as Plate %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Home/Home.scss",
    "chars": 54,
    "preview": "////\n/// Content\n/// Home\n////\n\n.Home {\n  // styles\n}\n"
  },
  {
    "path": "examples/src/content/Home/index.js",
    "chars": 953,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Draggable} from '@shopify/draggable';\n\n// eslint-disable-next-l"
  },
  {
    "path": "examples/src/content/Plugins/Collidable/Collidable.html",
    "chars": 1192,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Plugins/Collidable/Collidable.scss",
    "chars": 4066,
    "preview": "////\n/// Content\n/// Collidable\n////\n\n@import 'props';\n\n.Collidable {\n  .BlockLayout--typePositioned {\n    width: 100%;\n"
  },
  {
    "path": "examples/src/content/Plugins/Collidable/index.js",
    "chars": 1313,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Droppable, Plugins} from '@shopify/draggable';\n\nexport default "
  },
  {
    "path": "examples/src/content/Plugins/Collidable/props.scss",
    "chars": 1238,
    "preview": "////\n/// Content\n/// Collidable props\n////\n\n@import 'utils/shared/functions';\n\n$collidable-container-height: 60rem;\n$col"
  },
  {
    "path": "examples/src/content/Plugins/Snappable/Snappable.html",
    "chars": 2217,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Plugins/Snappable/Snappable.scss",
    "chars": 433,
    "preview": "////\n/// Content\n/// Snappable\n////\n\n@import 'utils/shared/functions';\n\n.Snappable {\n  .BlockLayout--typeGrid {\n    grid"
  },
  {
    "path": "examples/src/content/Plugins/Snappable/index.js",
    "chars": 706,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Swappable, Plugins} from '@shopify/draggable';\n\nexport default "
  },
  {
    "path": "examples/src/content/Plugins/SortAnimation/SortAnimation.html",
    "chars": 785,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Plugins/SortAnimation/SortAnimation.scss",
    "chars": 852,
    "preview": "////\n/// Content\n/// SortAnimation\n////\n\n@import 'utils/shared/functions';\n@import 'utils/shared/layout';\n\n$sort-anim-bl"
  },
  {
    "path": "examples/src/content/Plugins/SortAnimation/index.js",
    "chars": 572,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Sortable, Plugins} from '@shopify/draggable';\n\nexport default f"
  },
  {
    "path": "examples/src/content/Plugins/SwapAnimation/SwapAnimation.html",
    "chars": 734,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Plugins/SwapAnimation/SwapAnimation.scss",
    "chars": 852,
    "preview": "////\n/// Content\n/// SwapAnimation\n////\n\n@import 'utils/shared/functions';\n@import 'utils/shared/layout';\n\n$swap-anim-bl"
  },
  {
    "path": "examples/src/content/Plugins/SwapAnimation/index.js",
    "chars": 579,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Sortable, Plugins} from '@shopify/draggable';\n\nexport default f"
  },
  {
    "path": "examples/src/content/Sortable/MultipleContainers/MultipleContainers.html",
    "chars": 2390,
    "preview": "{% import 'components/StackedList/StackedListItem.html' as StackedListItem %}\n\n{% macro render(id) %}\n  <section id=\"{{ "
  },
  {
    "path": "examples/src/content/Sortable/MultipleContainers/MultipleContainers.scss",
    "chars": 1067,
    "preview": "////\n/// Content\n/// MultipleContainers\n////\n\n@import 'utils/shared/layout';\n@import 'components/StackedList/props';\n\n$g"
  },
  {
    "path": "examples/src/content/Sortable/MultipleContainers/index.js",
    "chars": 1674,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Sortable, Plugins} from '@shopify/draggable';\n\nconst Classes = "
  },
  {
    "path": "examples/src/content/Sortable/SimpleList/SimpleList.html",
    "chars": 1379,
    "preview": "{% import 'components/StackedList/StackedListItem.html' as StackedListItem %}\n\n{% macro render(id) %}\n  <section id=\"{{ "
  },
  {
    "path": "examples/src/content/Sortable/SimpleList/SimpleList.scss",
    "chars": 270,
    "preview": "////\n/// Content\n/// Simple list\n////\n\n@import 'utils/shared/layout';\n@import 'components/StackedList/props';\n\n// using "
  },
  {
    "path": "examples/src/content/Sortable/SimpleList/index.js",
    "chars": 525,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Sortable} from '@shopify/draggable';\n\nexport default function S"
  },
  {
    "path": "examples/src/content/Sortable/Transformed/Transformed.html",
    "chars": 563,
    "preview": "{% import 'components/PaperStack/PaperStackItem.html' as PaperStackItem %}\n\n{% macro render(id) %}\n  <section id=\"{{ id "
  },
  {
    "path": "examples/src/content/Sortable/Transformed/Transformed.scss",
    "chars": 68,
    "preview": "////\n/// Content\n/// Transformed\n////\n\n.Transformed {\n  // styles\n}\n"
  },
  {
    "path": "examples/src/content/Sortable/Transformed/index.js",
    "chars": 525,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Sortable} from '@shopify/draggable';\n\nexport default function T"
  },
  {
    "path": "examples/src/content/Swappable/Flexbox/Flexbox.html",
    "chars": 625,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Swappable/Flexbox/Flexbox.scss",
    "chars": 1968,
    "preview": "////\n/// Content\n/// Flexbox\n////\n\n@import 'utils/shared/functions';\n@import 'utils/shared/layout';\n\n$flexbox-block-name"
  },
  {
    "path": "examples/src/content/Swappable/Flexbox/index.js",
    "chars": 477,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Swappable, Plugins} from '@shopify/draggable';\n\nexport default "
  },
  {
    "path": "examples/src/content/Swappable/Floated/Floated.html",
    "chars": 706,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Swappable/Floated/Floated.scss",
    "chars": 1964,
    "preview": "////\n/// Content\n/// Floated\n////\n\n@import 'utils/shared/functions';\n@import 'utils/shared/layout';\n\n$floated-block-name"
  },
  {
    "path": "examples/src/content/Swappable/Floated/index.js",
    "chars": 477,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Swappable, Plugins} from '@shopify/draggable';\n\nexport default "
  },
  {
    "path": "examples/src/content/Swappable/GridLayout/GridLayout.html",
    "chars": 961,
    "preview": "{% import 'components/Block/Block.html' as Block %}\n\n{% macro render(id) %}\n  <section id=\"{{ id }}\" class=\"{{ id }}\">\n "
  },
  {
    "path": "examples/src/content/Swappable/GridLayout/GridLayout.scss",
    "chars": 1082,
    "preview": "////\n/// Content\n/// Grid Layout\n////\n\n@import 'utils/shared/functions';\n\n$grid-area-names: a, b, c, d, e, f, g;\n$grid-r"
  },
  {
    "path": "examples/src/content/Swappable/GridLayout/index.js",
    "chars": 565,
    "preview": "// eslint-disable-next-line import/no-unresolved\nimport {Swappable, Plugins} from '@shopify/draggable';\n\nexport default "
  },
  {
    "path": "examples/src/content/index.js",
    "chars": 994,
    "preview": "// Home page\nimport Home from './Home';\n// Draggable\nimport DragEvents from './Draggable/DragEvents';\n// Droppable\nimpor"
  },
  {
    "path": "examples/src/scripts/examples-app.js",
    "chars": 675,
    "preview": "// eslint-disable-next-line shopify/strict-component-boundaries\nimport Analytics from '../components/Analytics';\n// esli"
  },
  {
    "path": "examples/src/scripts/utils/debounce.js",
    "chars": 337,
    "preview": "export default function debounce(callback, wait) {\n  let timeout = null;\n\n  return function (...args) {\n    const contex"
  },
  {
    "path": "examples/src/scripts/utils/flip-sign.js",
    "chars": 207,
    "preview": "export default function flipSign(number) {\n  if (Math.sign(number) === 1) {\n    return -Math.abs(number);\n  } else if (M"
  },
  {
    "path": "examples/src/styles/examples-app.scss",
    "chars": 1787,
    "preview": "////\n/// App Manifest\n////\n\n///\n/// Reset\n@import 'reset';\n\n///\n/// Threads + Examples themes\n@import 'threads/threads';"
  },
  {
    "path": "examples/src/styles/examples-theme/_border.scss",
    "chars": 137,
    "preview": "////\n/// Examples Theme\n/// Border\n////\n\n$examples-border-data: (\n  thin: 0.6rem,\n  base: 0.8rem,\n  thick: 1.6rem,\n  fle"
  },
  {
    "path": "examples/src/styles/examples-theme/_breakpoint.scss",
    "chars": 407,
    "preview": "////\n/// Examples Theme\n/// Breakpoint\n////\n\n$examples-breakpoint-data: (\n  base: 960px,\n  mobile: (\n    base: 320px,\n  "
  },
  {
    "path": "examples/src/styles/examples-theme/_color.scss",
    "chars": 449,
    "preview": "/////\n/// Examples Theme\n/// Color\n////\n\n$examples-color-data: (\n  base: transparent,\n  ash: (\n    light: #fafbfc,\n    b"
  },
  {
    "path": "examples/src/styles/examples-theme/_cursor.scss",
    "chars": 909,
    "preview": "////\n/// Examples Theme\n/// Cursor\n////\n\n$examples-cursor-data: (\n  base: #{url('https://shopify.github.io/draggable/ass"
  },
  {
    "path": "examples/src/styles/examples-theme/_duration.scss",
    "chars": 151,
    "preview": "////\n/// Examples Theme\n/// Duration\n////\n\n$examples-duration-data: (\n  faster: 60ms,\n  fast: 120ms,\n  base: 240ms,\n  sl"
  },
  {
    "path": "examples/src/styles/examples-theme/_easing.scss",
    "chars": 228,
    "preview": "////\n/// Examples Theme\n/// Easing\n////\n\n$examples-easing-data: (\n  base: cubic-bezier(0.64, 0, 0.35, 1),\n  in: cubic-be"
  },
  {
    "path": "examples/src/styles/examples-theme/_font-stack.scss",
    "chars": 415,
    "preview": "////\n/// Examples Theme\n/// Font Stack\n////\n\n$examples-font-stack-data: (\n  base: #{-apple-system,\n  BlinkMacSystemFont,"
  },
  {
    "path": "examples/src/styles/examples-theme/_layout-length.scss",
    "chars": 250,
    "preview": "////\n/// Examples Theme\n/// Layout Length\n////\n\n$examples-layout-length-data: (\n  base: 1rem,\n  gutter: (\n    mobile: 0."
  },
  {
    "path": "examples/src/styles/examples-theme/_spacing.scss",
    "chars": 389,
    "preview": "////\n/// Examples Theme\n/// Spacing\n////\n\n$spacing-unit: 0.4rem;\n\n$examples-spacing-data: (\n  tightest: $spacing-unit * "
  },
  {
    "path": "examples/src/styles/examples-theme/_type-scale.scss",
    "chars": 995,
    "preview": "////\n/// Examples Theme\n/// Type Scale\n////\n\n$examples-type-scale-data: (\n  base: (\n    base: 1rem,\n    leading: 1.2,\n  "
  },
  {
    "path": "examples/src/styles/examples-theme/_z-index.scss",
    "chars": 167,
    "preview": "////\n/// Examples Theme\n/// Z-Index\n////\n\n$examples-z-index-data: (\n  background: 1,\n  base: 10,\n  foreground: 20,\n  sid"
  },
  {
    "path": "examples/src/styles/examples-theme/examples-theme.scss",
    "chars": 1085,
    "preview": "////\n/// Themes\n/// Examples\n////\n\n@import 'border';\n@import 'breakpoint';\n@import 'color';\n@import 'cursor';\n@import 'l"
  },
  {
    "path": "examples/src/styles/reset.scss",
    "chars": 4676,
    "preview": "////\n/// Global reset\n/// Based on normalize.css\n////\n\n///\n/// Document\nhtml {\n  font-family: sans-serif;\n  font-size: 6"
  },
  {
    "path": "examples/src/styles/utils/global/_animation.scss",
    "chars": 1149,
    "preview": "////\n/// Global Utilities\n/// Animation\n////\n\n@keyframes jelly {\n  0% {\n    transform: scale(1, 1);\n  }\n  4% {\n    trans"
  },
  {
    "path": "examples/src/styles/utils/global/_layout.scss",
    "chars": 301,
    "preview": "////\n/// Global Utilities\n/// Layout\n////\n\n@import 'utils/shared/layout';\n\n.flex-item-fix {\n  @include flex-item-fix;\n}\n"
  },
  {
    "path": "examples/src/styles/utils/global/_typography.scss",
    "chars": 608,
    "preview": "////\n/// Global Utilities\n/// Typography\n////\n\n@import 'utils/shared/typography';\n\n.text-truncate {\n  @include text-trun"
  },
  {
    "path": "examples/src/styles/utils/global/global-utils.scss",
    "chars": 102,
    "preview": "////\n/// Global Utilities manifest\n////\n\n@import 'animation';\n@import 'layout';\n@import 'typography';\n"
  },
  {
    "path": "examples/src/styles/utils/shared/animation.scss",
    "chars": 126,
    "preview": "////\n/// Shared Utilities\n/// Animation\n////\n\n@mixin jelly-animation {\n  animation: jelly get-duration(slower) linear bo"
  },
  {
    "path": "examples/src/styles/utils/shared/functions.scss",
    "chars": 1196,
    "preview": "////\n/// Shared Utilities\n/// Functions\n////\n\n// Column based max-width layout\n// @param {Number} $count - Number of col"
  },
  {
    "path": "examples/src/styles/utils/shared/layout.scss",
    "chars": 4731,
    "preview": "////\n/// Shared Utilities\n/// Layout\n////\n\n/// Generate a selector chain to resolve draggable source layouts\n/// @param "
  },
  {
    "path": "examples/src/styles/utils/shared/typography.scss",
    "chars": 626,
    "preview": "////\n/// Shared Utilities\n/// Typography\n////\n\n// For truncating single line text.\n// @param {String} $display (optional"
  },
  {
    "path": "examples/src/views/collidable.html",
    "chars": 843,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/data-pages.json",
    "chars": 576,
    "preview": "{\n  \"DataPages\": [\n    {\n      \"Draggable\": [\n        \"Drag events\",\n        \"~Restrict axis\"\n      ]\n    },\n    {\n     "
  },
  {
    "path": "examples/src/views/drag-events.html",
    "chars": 822,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/flexbox.html",
    "chars": 836,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/floated.html",
    "chars": 813,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/grid-layout.html",
    "chars": 851,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/index.html",
    "chars": 733,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/multiple-containers.html",
    "chars": 843,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/simple-list.html",
    "chars": 798,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/snappable.html",
    "chars": 824,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/sort-animation.html",
    "chars": 815,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/swap-animation.html",
    "chars": 820,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/templates/document.html",
    "chars": 449,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\" data-scroll-lock=\"false\">\n  {% block head %}{% endblock %}\n\n  <body id=\"Page{% block Pag"
  },
  {
    "path": "examples/src/views/transformed.html",
    "chars": 861,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/src/views/unique-dropzone.html",
    "chars": 864,
    "preview": "{% extends 'templates/document.html' %}\n\n{% import 'components/Document/Head.html' as Head %}\n{% import 'components/Side"
  },
  {
    "path": "examples/tools/index.js",
    "chars": 325,
    "preview": "import gulp from 'gulp';\n\nimport tasks from './tasks';\nimport {watch} from './watch';\n\nexport const scripts = tasks.scri"
  },
  {
    "path": "examples/tools/server.js",
    "chars": 377,
    "preview": "import browsersync from 'browser-sync';\n\nexport const server = browsersync.create();\n\n// reload function requires a call"
  },
  {
    "path": "examples/tools/tasks/index.js",
    "chars": 227,
    "preview": "import {startServer} from '../server';\n\nimport {scripts} from './scripts';\nimport {styles} from './styles';\nimport {view"
  },
  {
    "path": "examples/tools/tasks/scripts.js",
    "chars": 342,
    "preview": "import webpack from 'webpack';\n\nimport {webpackConfig} from '../webpack.config';\n\nexport function scripts() {\n  return n"
  },
  {
    "path": "examples/tools/tasks/styles.js",
    "chars": 665,
    "preview": "import gulp from 'gulp';\nimport sass from 'gulp-sass';\nimport postcss from 'gulp-postcss';\nimport sourcemaps from 'gulp-"
  },
  {
    "path": "examples/tools/tasks/views.js",
    "chars": 941,
    "preview": "import fs from 'fs';\n\nimport gulp from 'gulp';\nimport data from 'gulp-data';\nimport htmlmin from 'gulp-htmlmin';\nimport "
  },
  {
    "path": "examples/tools/watch.js",
    "chars": 747,
    "preview": "import gulp from 'gulp';\n\nimport {reloadServer, startServer} from './server';\nimport {scripts} from './tasks/scripts';\ni"
  },
  {
    "path": "examples/tools/webpack.config.js",
    "chars": 1250,
    "preview": "/* eslint-env node */\n\nimport path from 'path';\n\nimport initPlugins from './webpack.plugins';\n\nconst distPath = path.res"
  },
  {
    "path": "examples/tools/webpack.plugins.js",
    "chars": 408,
    "preview": "import * as bundleAnalyzer from 'webpack-bundle-analyzer';\n\nexport default function initPlugins(isProd = false) {\n  cons"
  },
  {
    "path": "index.d.ts",
    "chars": 15715,
    "preview": "declare module '@shopify/draggable/lib/draggable.bundle.legacy' {\n  export * from '@shopify/draggable';\n}\n\ndeclare modul"
  },
  {
    "path": "jest.config.js",
    "chars": 591,
    "preview": "module.exports = {\n  testEnvironment: 'jsdom',\n  testMatch: ['<rootDir>/src/**/*.test.(js|ts)'],\n  setupFiles: ['<rootDi"
  }
]

// ... and 147 more files (download for full content)

About this extraction

This page contains the full source code of the Shopify/draggable GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 347 files (616.7 KB), approximately 167.5k tokens, and a symbol index with 631 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!