Showing preview only (3,683K chars total). Download the full file or copy to clipboard to get everything.
Repository: atlassian/pragmatic-drag-and-drop
Branch: main
Commit: 90c7b5885ff0
Files: 951
Total size: 3.3 MB
Directory structure:
gitextract_m34m2yul/
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── jest.config.js
├── package.json
├── packages/
│ ├── auto-scroll/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ ├── playwright/
│ │ │ │ ├── over-element-smoke-test.spec.tsx
│ │ │ │ └── unsafe-overflow-smoke-test.spec.tsx
│ │ │ └── unit/
│ │ │ ├── _util.ts
│ │ │ ├── over-element/
│ │ │ │ ├── allowed-axis.spec.ts
│ │ │ │ ├── can-scroll.spec.ts
│ │ │ │ ├── distance-dampening.spec.ts
│ │ │ │ ├── hitbox.spec.ts
│ │ │ │ ├── max-speed.spec.ts
│ │ │ │ ├── nested-scroll-containers.spec.ts
│ │ │ │ ├── registration.spec.ts
│ │ │ │ ├── start.spec.ts
│ │ │ │ ├── stop.spec.ts
│ │ │ │ ├── time-dampening.spec.ts
│ │ │ │ └── window-scrolling.spec.ts
│ │ │ ├── overflow/
│ │ │ │ ├── allowed-axis.spec.ts
│ │ │ │ ├── can-scroll.spec.ts
│ │ │ │ ├── cross-axis-hitbox.spec.ts
│ │ │ │ ├── main-axis-hitbox.spec.ts
│ │ │ │ ├── nested-elements.spec.ts
│ │ │ │ ├── over-element-should-not-scroll.spec.ts
│ │ │ │ └── provided-hitbox-spacing-type.spec.ts
│ │ │ └── shared/
│ │ │ ├── _util.ts
│ │ │ ├── async-loading.spec.ts
│ │ │ ├── ignore-honey-pot.spec.ts
│ │ │ ├── monitor-binding.spec.ts
│ │ │ └── time-dampening-handover.spec.ts
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ ├── props.mdx
│ │ │ └── unsafe-overflow-scrolling.mdx
│ │ ├── examples/
│ │ │ ├── axis-locking.tsx
│ │ │ ├── lazy-loaded.tsx
│ │ │ ├── nested-scroll.tsx
│ │ │ ├── over-element.tsx
│ │ │ ├── pieces/
│ │ │ │ ├── board-context.ts
│ │ │ │ ├── board.tsx
│ │ │ │ ├── card.tsx
│ │ │ │ ├── lazy-loaded-board.tsx
│ │ │ │ └── table.tsx
│ │ │ ├── unsafe-overflow-box.tsx
│ │ │ ├── unsafe-overflow-only.tsx
│ │ │ ├── unsafe-overflow.tsx
│ │ │ ├── window-scroll-with-scroll-container.tsx
│ │ │ └── window-scroll.tsx
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── entry-point/
│ │ │ │ ├── element.ts
│ │ │ │ ├── external.ts
│ │ │ │ ├── text-selection.ts
│ │ │ │ └── unsafe-overflow/
│ │ │ │ ├── element.ts
│ │ │ │ ├── external.ts
│ │ │ │ └── text-selection.ts
│ │ │ ├── index.ts
│ │ │ ├── internal-types.ts
│ │ │ ├── over-element/
│ │ │ │ ├── data-attributes.ts
│ │ │ │ ├── get-scroll-by.ts
│ │ │ │ ├── make-api.ts
│ │ │ │ └── try-scroll.ts
│ │ │ ├── shared/
│ │ │ │ ├── axis.ts
│ │ │ │ ├── can-scroll-on-edge.ts
│ │ │ │ ├── configuration.ts
│ │ │ │ ├── edges.ts
│ │ │ │ ├── engagement-history.ts
│ │ │ │ ├── get-over-element-hitbox.ts
│ │ │ │ ├── get-percentage-in-range.ts
│ │ │ │ ├── get-scroll-change.ts
│ │ │ │ ├── is-axis-allowed.ts
│ │ │ │ ├── is-within.ts
│ │ │ │ ├── scheduler.ts
│ │ │ │ └── side.ts
│ │ │ └── unsafe-overflow/
│ │ │ ├── get-scroll-by.ts
│ │ │ ├── hitbox.ts
│ │ │ ├── make-api.ts
│ │ │ ├── try-overflow-scroll.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── core/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ ├── playwright/
│ │ │ │ ├── external-files.spec.ts
│ │ │ │ ├── honey-pot.spec.ts
│ │ │ │ ├── iframe.spec.ts
│ │ │ │ ├── scroll-just-enough-into-view.spec.ts
│ │ │ │ ├── stickiness.spec.tsx
│ │ │ │ └── text-selection.spec.ts
│ │ │ └── unit/
│ │ │ ├── _util.ts
│ │ │ ├── android/
│ │ │ │ ├── is-android.spec.ts
│ │ │ │ └── not-android.spec.ts
│ │ │ ├── dependency-guardrails.spec.ts
│ │ │ ├── element/
│ │ │ │ ├── changes-during-a-drag.spec.ts
│ │ │ │ ├── changes-during-a-drop.spec.ts
│ │ │ │ ├── draggable/
│ │ │ │ │ ├── conditional-dragging.spec.ts
│ │ │ │ │ ├── custom-drag-preview.spec.ts
│ │ │ │ │ ├── drag-handle-guardrails.spec.ts
│ │ │ │ │ ├── drag-handle.spec.ts
│ │ │ │ │ ├── get-initial-data-for-external.spec.ts
│ │ │ │ │ ├── get-initial-data.spec.ts
│ │ │ │ │ ├── nested-draggables.spec.ts
│ │ │ │ │ └── start-location.spec.ts
│ │ │ │ ├── dragleave-should-not-update-input.spec.ts
│ │ │ │ ├── drop-target/
│ │ │ │ │ ├── conditional-dropping.spec.ts
│ │ │ │ │ ├── data-collection.spec.ts
│ │ │ │ │ ├── drop-effect.spec.ts
│ │ │ │ │ ├── guardrails.spec.ts
│ │ │ │ │ ├── lift.spec.ts
│ │ │ │ │ └── stickiness.spec.ts
│ │ │ │ ├── dropping-outside-window.spec.ts
│ │ │ │ ├── error-recovery.spec.ts
│ │ │ │ ├── event-ordering/
│ │ │ │ │ ├── all.spec.ts
│ │ │ │ │ ├── callback-data.spec.ts
│ │ │ │ │ ├── drag-start-flushing.spec.ts
│ │ │ │ │ ├── drag-start.spec.ts
│ │ │ │ │ ├── drag-update-atomic.spec.ts
│ │ │ │ │ ├── drag-update.spec.ts
│ │ │ │ │ ├── drag.spec.ts
│ │ │ │ │ ├── drop.spec.ts
│ │ │ │ │ └── generate-drag-preview.spec.ts
│ │ │ │ ├── events-and-adapter-mounting.spec.ts
│ │ │ │ ├── global-event-binding.spec.ts
│ │ │ │ ├── leaving-the-window.spec.ts
│ │ │ │ ├── monitor/
│ │ │ │ │ ├── adding-monitors-during-events.spec.ts
│ │ │ │ │ ├── call-order.spec.ts
│ │ │ │ │ ├── publishing-events.spec.ts
│ │ │ │ │ ├── removing-monitors-during-events.spec.ts
│ │ │ │ │ └── uniqueness.spec.ts
│ │ │ │ ├── previous-location-should-match-last-current.spec.ts
│ │ │ │ ├── public-utils/
│ │ │ │ │ ├── block-dragging-to-iframes.spec.ts
│ │ │ │ │ ├── center-under-pointer.spec.ts
│ │ │ │ │ ├── format-urls-for-external.spec.ts
│ │ │ │ │ ├── pointer-outside-of-preview.spec.ts
│ │ │ │ │ ├── preserve-offset-on-source.spec.ts
│ │ │ │ │ └── set-custom-native-drag-preview.spec.ts
│ │ │ │ ├── repeated-dragging.spec.ts
│ │ │ │ ├── resiliant-against-consumers-stopping-events-during-a-drag.spec.ts
│ │ │ │ ├── resilient-against-multiple-cleanup-calls.spec.ts
│ │ │ │ └── respecting-non-pdnd-code.spec.ts
│ │ │ ├── external/
│ │ │ │ ├── adapter/
│ │ │ │ │ ├── can-monitor.spec.ts
│ │ │ │ │ ├── drag-ownership/
│ │ │ │ │ │ ├── element-adapter.spec.ts
│ │ │ │ │ │ └── uncontrolled-internal-adapter.spec.ts
│ │ │ │ │ ├── drop-effect.spec.ts
│ │ │ │ │ ├── exposing-data.spec.ts
│ │ │ │ │ ├── get-string-data.spec.ts
│ │ │ │ │ ├── global-event-binding.spec.ts
│ │ │ │ │ ├── leaving-the-window.spec.ts
│ │ │ │ │ ├── respecting-non-pdnd-code.spec.ts
│ │ │ │ │ ├── starting-an-external-drag-before-registrations.spec.ts
│ │ │ │ │ └── starting-an-external-drag.spec.ts
│ │ │ │ ├── drop-targets/
│ │ │ │ │ └── nested.spec.ts
│ │ │ │ └── utils/
│ │ │ │ ├── file/
│ │ │ │ │ ├── contains-files.spec.ts
│ │ │ │ │ └── get-files.spec.ts
│ │ │ │ ├── html/
│ │ │ │ │ ├── contains-html.spec.ts
│ │ │ │ │ └── get-html.spec.ts
│ │ │ │ ├── some.spec.ts
│ │ │ │ ├── text/
│ │ │ │ │ ├── contains-text.spec.ts
│ │ │ │ │ └── get-text.spec.ts
│ │ │ │ └── url/
│ │ │ │ ├── contains-urls.spec.ts
│ │ │ │ ├── firefox-fix.spec.ts
│ │ │ │ └── url.spec.ts
│ │ │ ├── honey-pot-fix/
│ │ │ │ ├── _util.ts
│ │ │ │ ├── event-listeners.spec.ts
│ │ │ │ ├── external-adapter-should-not-use-honey-pot.spec.ts
│ │ │ │ ├── finishing.spec.ts
│ │ │ │ ├── get-element-from-point-without-honey-pot.spec.ts
│ │ │ │ ├── mid-drag.spec.ts
│ │ │ │ ├── multiple-operations.spec.ts
│ │ │ │ ├── starting.spec.ts
│ │ │ │ └── text-adapter-smoke-test.spec.ts
│ │ │ ├── public-utils/
│ │ │ │ ├── combine.spec.ts
│ │ │ │ ├── once.spec.ts
│ │ │ │ ├── prevent-unhandled.spec.ts
│ │ │ │ └── reorder.spec.ts
│ │ │ ├── react/
│ │ │ │ └── adding-monitors-during-events.spec.tsx
│ │ │ ├── server-side-usage.spec.ts
│ │ │ ├── test-environment-guardrail.spec.ts
│ │ │ └── text-selection/
│ │ │ ├── adapter/
│ │ │ │ ├── drag-ownership/
│ │ │ │ │ ├── element-adapter.spec.ts
│ │ │ │ │ └── external-adapter.spec.ts
│ │ │ │ ├── event-ordering.spec.ts
│ │ │ │ ├── global-event-binding.spec.ts
│ │ │ │ ├── leaving-the-window.spec.ts
│ │ │ │ ├── respecting-non-pdnd-code.spec.ts
│ │ │ │ ├── starting-a-text-selection-drag-before-registrations.spec.ts
│ │ │ │ └── text-target.spec.ts
│ │ │ └── drop-targets/
│ │ │ └── nested.spec.ts
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ └── index/
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ ├── _util/
│ │ │ │ ├── constants.tsx
│ │ │ │ ├── fallback.ts
│ │ │ │ └── global-styles.tsx
│ │ │ ├── config.jsonc
│ │ │ ├── drag-preview-with-transparency.tsx
│ │ │ ├── element-adapter.tsx
│ │ │ ├── file.tsx
│ │ │ ├── iframe.tsx
│ │ │ ├── native/
│ │ │ │ ├── activity-log.tsx
│ │ │ │ ├── app.tsx
│ │ │ │ ├── content.tsx
│ │ │ │ └── drop-target.tsx
│ │ │ ├── native.tsx
│ │ │ ├── post-drop-bug-fix-simple.tsx
│ │ │ ├── post-drop-bug-fix.tsx
│ │ │ ├── preserve-offset-on-source.tsx
│ │ │ ├── scroll-just-enough-into-view.tsx
│ │ │ ├── stickiness.tsx
│ │ │ ├── text-selection.tsx
│ │ │ └── url.tsx
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── adapter/
│ │ │ │ ├── element-adapter-native-data-key.ts
│ │ │ │ ├── element-adapter.ts
│ │ │ │ ├── external-adapter.ts
│ │ │ │ └── text-selection-adapter.ts
│ │ │ ├── entry-point/
│ │ │ │ ├── cancel-unhandled.ts
│ │ │ │ ├── combine.ts
│ │ │ │ ├── element/
│ │ │ │ │ ├── adapter.ts
│ │ │ │ │ ├── block-dragging-to-iframes.ts
│ │ │ │ │ ├── center-under-pointer.ts
│ │ │ │ │ ├── disable-native-drag-preview.ts
│ │ │ │ │ ├── format-urls-for-external.ts
│ │ │ │ │ ├── pointer-outside-of-preview.ts
│ │ │ │ │ ├── preserve-offset-on-source.ts
│ │ │ │ │ ├── scroll-just-enough-into-view.ts
│ │ │ │ │ └── set-custom-native-drag-preview.ts
│ │ │ │ ├── external/
│ │ │ │ │ ├── adapter.ts
│ │ │ │ │ ├── file.ts
│ │ │ │ │ ├── html.ts
│ │ │ │ │ ├── some.ts
│ │ │ │ │ ├── text.ts
│ │ │ │ │ └── url.ts
│ │ │ │ ├── once.ts
│ │ │ │ ├── prevent-unhandled.ts
│ │ │ │ ├── private/
│ │ │ │ │ └── get-element-from-point-without-honey-pot.ts
│ │ │ │ ├── reorder.ts
│ │ │ │ ├── text-selection/
│ │ │ │ │ └── adapter.ts
│ │ │ │ └── types.ts
│ │ │ ├── honey-pot-fix/
│ │ │ │ ├── get-element-from-point-without-honey-pot.ts
│ │ │ │ ├── honey-pot-data-attribute.ts
│ │ │ │ ├── is-honey-pot-element.ts
│ │ │ │ └── make-honey-pot-fix.ts
│ │ │ ├── index.ts
│ │ │ ├── internal-types.ts
│ │ │ ├── ledger/
│ │ │ │ ├── dispatch-consumer-event.ts
│ │ │ │ ├── lifecycle-manager.ts
│ │ │ │ └── usage-ledger.ts
│ │ │ ├── make-adapter/
│ │ │ │ ├── make-adapter.ts
│ │ │ │ ├── make-drop-target.ts
│ │ │ │ └── make-monitor.ts
│ │ │ ├── public-utils/
│ │ │ │ ├── combine.ts
│ │ │ │ ├── custom-external-data-type-media-type-prefix.ts
│ │ │ │ ├── element/
│ │ │ │ │ ├── block-dragging-to-iframes.ts
│ │ │ │ │ ├── custom-native-drag-preview/
│ │ │ │ │ │ ├── center-under-pointer.ts
│ │ │ │ │ │ ├── pointer-outside-of-preview.ts
│ │ │ │ │ │ ├── preserve-offset-on-source.ts
│ │ │ │ │ │ ├── set-custom-native-drag-preview.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── disable-native-drag-preview.ts
│ │ │ │ │ ├── format-urls-for-external.ts
│ │ │ │ │ └── scroll-just-enough-into-view.ts
│ │ │ │ ├── external/
│ │ │ │ │ ├── file.ts
│ │ │ │ │ ├── html.ts
│ │ │ │ │ ├── native-types.ts
│ │ │ │ │ ├── some.ts
│ │ │ │ │ ├── text.ts
│ │ │ │ │ └── url.ts
│ │ │ │ ├── once.ts
│ │ │ │ ├── prevent-unhandled.ts
│ │ │ │ └── reorder.ts
│ │ │ └── util/
│ │ │ ├── add-attribute.ts
│ │ │ ├── android.ts
│ │ │ ├── changing-window/
│ │ │ │ ├── count-events-for-safari.ts
│ │ │ │ ├── is-entering-window.ts
│ │ │ │ ├── is-from-another-window.ts
│ │ │ │ └── is-leaving-window.ts
│ │ │ ├── detect-broken-drag.ts
│ │ │ ├── get-input.ts
│ │ │ ├── is-firefox.ts
│ │ │ ├── is-safari-on-ios.ts
│ │ │ ├── is-safari.ts
│ │ │ ├── max-z-index.ts
│ │ │ └── media-types/
│ │ │ ├── html-media-type.ts
│ │ │ ├── text-media-type.ts
│ │ │ └── url-media-type.ts
│ │ └── tsconfig.json
│ ├── documentation/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── playwright/
│ │ │ ├── board.spec.ts
│ │ │ └── tree.spec.ts
│ │ ├── constellation/
│ │ │ ├── 00-examples/
│ │ │ │ └── index.mdx
│ │ │ ├── 01-tutorial/
│ │ │ │ └── index.mdx
│ │ │ ├── 05-core-package/
│ │ │ │ ├── 00-adapters/
│ │ │ │ │ ├── 00-element/
│ │ │ │ │ │ ├── about.mdx
│ │ │ │ │ │ ├── drag-previews.mdx
│ │ │ │ │ │ ├── other-utilities.mdx
│ │ │ │ │ │ └── unregistered-elements.mdx
│ │ │ │ │ ├── 01-text-selection/
│ │ │ │ │ │ └── about.mdx
│ │ │ │ │ ├── 02-external/
│ │ │ │ │ │ ├── HTML.mdx
│ │ │ │ │ │ ├── URLs.mdx
│ │ │ │ │ │ ├── about.mdx
│ │ │ │ │ │ ├── custom-media-types.mdx
│ │ │ │ │ │ ├── files.mdx
│ │ │ │ │ │ └── text.mdx
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── 03-drop-targets/
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── 04-monitors/
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── 05-utilities/
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── 06-events/
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── 07-reconciliation/
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── 08-UI-frameworks/
│ │ │ │ │ ├── index.mdx
│ │ │ │ │ └── react.mdx
│ │ │ │ ├── 09-recipes/
│ │ │ │ │ ├── 00-isolating-experiences/
│ │ │ │ │ │ └── index.mdx
│ │ │ │ │ ├── 01-typing-data/
│ │ │ │ │ │ └── index.mdx
│ │ │ │ │ ├── 02-virtualization/
│ │ │ │ │ │ └── index.mdx
│ │ │ │ │ ├── 03-deferred-loading/
│ │ │ │ │ │ ├── index.mdx
│ │ │ │ │ │ └── react.mdx
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── 11-testing/
│ │ │ │ │ ├── about.mdx
│ │ │ │ │ ├── cypress.mdx
│ │ │ │ │ ├── jest-and-jsdom.mdx
│ │ │ │ │ ├── playwright.mdx
│ │ │ │ │ ├── puppeteer.mdx
│ │ │ │ │ └── webdriver.mdx
│ │ │ │ ├── 12-upgrade-guides/
│ │ │ │ │ └── upgrade-guide-0.x-→-1.0.mdx
│ │ │ │ └── index.mdx
│ │ │ ├── 06-optional-packages/
│ │ │ │ └── index.mdx
│ │ │ ├── 07-web-platform-design-constraints/
│ │ │ │ └── index.mdx
│ │ │ ├── 08-design-guidelines/
│ │ │ │ └── index.mdx
│ │ │ ├── 09-accessibility-guidelines/
│ │ │ │ ├── index.mdx
│ │ │ │ └── pattern-table.tsx
│ │ │ ├── assets/
│ │ │ │ ├── check-icon.tsx
│ │ │ │ ├── cross-icon.tsx
│ │ │ │ ├── question-icon.tsx
│ │ │ │ ├── result-text.tsx
│ │ │ │ └── warning-icon.tsx
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ ├── assets/
│ │ │ │ ├── hero.tsx
│ │ │ │ └── logo.tsx
│ │ │ ├── comparison.mdx
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ ├── board-with-multi-drag.tsx
│ │ │ ├── board-with-overflow-scroll.tsx
│ │ │ ├── board.tsx
│ │ │ ├── chess.tsx
│ │ │ ├── config.jsonc
│ │ │ ├── data/
│ │ │ │ ├── pages.ts
│ │ │ │ ├── people/
│ │ │ │ │ ├── images/
│ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ └── processed/
│ │ │ │ │ │ ├── Alexander.ts
│ │ │ │ │ │ ├── Aliza.ts
│ │ │ │ │ │ ├── Alvin.ts
│ │ │ │ │ │ ├── Angie.ts
│ │ │ │ │ │ ├── Arjun.ts
│ │ │ │ │ │ ├── Blair.ts
│ │ │ │ │ │ ├── Claudia.ts
│ │ │ │ │ │ ├── Colin.ts
│ │ │ │ │ │ ├── Ed.ts
│ │ │ │ │ │ ├── Effie.ts
│ │ │ │ │ │ ├── Eliot.ts
│ │ │ │ │ │ ├── Fabian.ts
│ │ │ │ │ │ ├── Gael.ts
│ │ │ │ │ │ ├── Gerard.ts
│ │ │ │ │ │ ├── Hasan.ts
│ │ │ │ │ │ ├── Helena.ts
│ │ │ │ │ │ ├── Ivan.ts
│ │ │ │ │ │ ├── Katina.ts
│ │ │ │ │ │ ├── Lara.ts
│ │ │ │ │ │ ├── Leo.ts
│ │ │ │ │ │ ├── Lydia.ts
│ │ │ │ │ │ ├── Maribel.ts
│ │ │ │ │ │ ├── Milo.ts
│ │ │ │ │ │ ├── Myra.ts
│ │ │ │ │ │ ├── Narul.ts
│ │ │ │ │ │ ├── Norah.ts
│ │ │ │ │ │ ├── Oliver.ts
│ │ │ │ │ │ ├── Rahul.ts
│ │ │ │ │ │ ├── Renato.ts
│ │ │ │ │ │ ├── Steve.ts
│ │ │ │ │ │ ├── Tanya.ts
│ │ │ │ │ │ ├── Tori.ts
│ │ │ │ │ │ └── Vania.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── presidents.tsx
│ │ │ │ ├── quotes/
│ │ │ │ │ ├── data.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── table.tsx
│ │ │ │ ├── tasks.ts
│ │ │ │ ├── tree-legacy.ts
│ │ │ │ └── tree.ts
│ │ │ ├── deferred.tsx
│ │ │ ├── drag-handle-button.tsx
│ │ │ ├── drag-handles.tsx
│ │ │ ├── drawing.tsx
│ │ │ ├── file-drop-without-pragmatic.tsx
│ │ │ ├── file.tsx
│ │ │ ├── flash-prototype.tsx
│ │ │ ├── grid.tsx
│ │ │ ├── guidelines/
│ │ │ │ ├── action-menu-variants.tsx
│ │ │ │ ├── all-drag-handle-variants.tsx
│ │ │ │ ├── delayed-cursor-change.tsx
│ │ │ │ ├── entire-entity-is-draggable-with-drag-handle-button.tsx
│ │ │ │ ├── entire-entity-is-draggable-with-grouped-items.tsx
│ │ │ │ ├── entire-entity-is-draggable.tsx
│ │ │ │ ├── hover-drag-handle-outside-bounds.tsx
│ │ │ │ ├── hover-drag-handle.tsx
│ │ │ │ ├── only-draggable-from-drag-handle.tsx
│ │ │ │ ├── shared/
│ │ │ │ │ ├── action-menu.tsx
│ │ │ │ │ ├── drag-preview.tsx
│ │ │ │ │ └── types.ts
│ │ │ │ └── standalone-card.tsx
│ │ │ ├── guidelines.tsx
│ │ │ ├── icons/
│ │ │ │ ├── invision.tsx
│ │ │ │ ├── portfolio.tsx
│ │ │ │ ├── slack.tsx
│ │ │ │ └── tempo.tsx
│ │ │ ├── iframe-board.tsx
│ │ │ ├── iframe-column.tsx
│ │ │ ├── list-comparison.tsx
│ │ │ ├── list.tsx
│ │ │ ├── manual-focus-restoration.tsx
│ │ │ ├── nested-draggables.tsx
│ │ │ ├── nested-drop-targets.tsx
│ │ │ ├── pieces/
│ │ │ │ ├── backlog/
│ │ │ │ │ ├── container.tsx
│ │ │ │ │ ├── context.tsx
│ │ │ │ │ ├── data.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── list-item.tsx
│ │ │ │ │ └── list.tsx
│ │ │ │ ├── board/
│ │ │ │ │ ├── board-context.tsx
│ │ │ │ │ ├── board.tsx
│ │ │ │ │ ├── card.tsx
│ │ │ │ │ ├── column-context.tsx
│ │ │ │ │ ├── column.tsx
│ │ │ │ │ └── registry.ts
│ │ │ │ ├── board-with-multi-drag/
│ │ │ │ │ ├── board.tsx
│ │ │ │ │ ├── card.tsx
│ │ │ │ │ └── column.tsx
│ │ │ │ ├── board-with-overflow-scroll/
│ │ │ │ │ ├── board.tsx
│ │ │ │ │ ├── card.tsx
│ │ │ │ │ └── column.tsx
│ │ │ │ ├── chess/
│ │ │ │ │ ├── piece.tsx
│ │ │ │ │ └── square.tsx
│ │ │ │ ├── drawing/
│ │ │ │ │ ├── line-overlay.tsx
│ │ │ │ │ └── shape.tsx
│ │ │ │ ├── getting-started/
│ │ │ │ │ ├── chessboard-colored-drop-targets.tsx
│ │ │ │ │ ├── chessboard-draggable.tsx
│ │ │ │ │ ├── chessboard-drop-target.tsx
│ │ │ │ │ ├── chessboard-drop-targets-can-drop.tsx
│ │ │ │ │ ├── chessboard-monitor.tsx
│ │ │ │ │ ├── chessboard-starter-code.tsx
│ │ │ │ │ ├── draggable-piece-in-place.tsx
│ │ │ │ │ ├── draggable-piece-with-data.tsx
│ │ │ │ │ ├── draggable-piece-with-state.tsx
│ │ │ │ │ ├── square-drop-target.tsx
│ │ │ │ │ ├── square-with-can-drop.tsx
│ │ │ │ │ ├── square-with-data.tsx
│ │ │ │ │ └── square-with-hovering-coloring.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-flash-on-drop.tsx
│ │ │ │ │ ├── use-prevent-scrolling-from-arrow-keys.tsx
│ │ │ │ │ ├── use-sortable-field.tsx
│ │ │ │ │ └── use-top-level-wiring.tsx
│ │ │ │ ├── iframe-board/
│ │ │ │ │ ├── card.tsx
│ │ │ │ │ ├── column.tsx
│ │ │ │ │ └── data.ts
│ │ │ │ ├── menu-button/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── pinned-fields/
│ │ │ │ │ ├── data.tsx
│ │ │ │ │ ├── experience/
│ │ │ │ │ │ ├── asana-native-preview.tsx
│ │ │ │ │ │ ├── asana.tsx
│ │ │ │ │ │ ├── current-guidelines-a11y-always-visible.tsx
│ │ │ │ │ │ ├── current-guidelines-a11y-keyboard-only.tsx
│ │ │ │ │ │ ├── current-guidelines.tsx
│ │ │ │ │ │ ├── enhanced-drag-handle.tsx
│ │ │ │ │ │ ├── migration-layer.tsx
│ │ │ │ │ │ ├── rdr-prototype.tsx
│ │ │ │ │ │ └── react-beautiful-dnd.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ └── use-sortable-field.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── major-priority-icon.tsx
│ │ │ │ │ ├── primitives/
│ │ │ │ │ │ ├── asana/
│ │ │ │ │ │ │ ├── constants.tsx
│ │ │ │ │ │ │ ├── drop-indicator.tsx
│ │ │ │ │ │ │ └── field.tsx
│ │ │ │ │ │ └── droppable-area-overlay.tsx
│ │ │ │ │ ├── templates/
│ │ │ │ │ │ ├── asana.tsx
│ │ │ │ │ │ ├── atlassian.tsx
│ │ │ │ │ │ └── react-beautiful-dnd.tsx
│ │ │ │ │ └── use-drag-observer.tsx
│ │ │ │ ├── post-drop-flash/
│ │ │ │ │ └── list.tsx
│ │ │ │ ├── rdr-board/
│ │ │ │ │ ├── board-context.tsx
│ │ │ │ │ ├── board.tsx
│ │ │ │ │ ├── card-stack.tsx
│ │ │ │ │ ├── card.tsx
│ │ │ │ │ ├── column-context.tsx
│ │ │ │ │ ├── column.tsx
│ │ │ │ │ ├── data.tsx
│ │ │ │ │ ├── epic-lozenge.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── rdr-pinned-fields/
│ │ │ │ │ ├── container.tsx
│ │ │ │ │ ├── context.tsx
│ │ │ │ │ ├── data.tsx
│ │ │ │ │ ├── drag-handle-button.tsx
│ │ │ │ │ ├── field.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── list-item.tsx
│ │ │ │ │ ├── list.tsx
│ │ │ │ │ └── major-priority-icon.tsx
│ │ │ │ ├── rdr-subtasks/
│ │ │ │ │ ├── container.tsx
│ │ │ │ │ ├── context.tsx
│ │ │ │ │ ├── data.tsx
│ │ │ │ │ ├── drag-handle-button.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── list-item.tsx
│ │ │ │ │ ├── list.tsx
│ │ │ │ │ └── subtask-icon.tsx
│ │ │ │ ├── subtasks/
│ │ │ │ │ ├── data.tsx
│ │ │ │ │ ├── demo/
│ │ │ │ │ │ ├── current-guidelines-a11y-always-visible.tsx
│ │ │ │ │ │ ├── current-guidelines-a11y-keyboard-only.tsx
│ │ │ │ │ │ ├── current-guidelines.tsx
│ │ │ │ │ │ ├── enhancements.tsx
│ │ │ │ │ │ ├── linear-native-preview.tsx
│ │ │ │ │ │ ├── linear.tsx
│ │ │ │ │ │ ├── migration-layer.tsx
│ │ │ │ │ │ ├── notion.tsx
│ │ │ │ │ │ └── react-beautiful-dnd.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── use-sortable-field.tsx
│ │ │ │ │ │ └── use-top-level-wiring.tsx
│ │ │ │ │ ├── primitives/
│ │ │ │ │ │ ├── linear/
│ │ │ │ │ │ │ ├── constants.tsx
│ │ │ │ │ │ │ ├── in-progress-icon.tsx
│ │ │ │ │ │ │ ├── priority-icon.tsx
│ │ │ │ │ │ │ ├── subtask-container.tsx
│ │ │ │ │ │ │ └── subtask.tsx
│ │ │ │ │ │ ├── major-priority-icon.tsx
│ │ │ │ │ │ ├── notion/
│ │ │ │ │ │ │ ├── constants.tsx
│ │ │ │ │ │ │ ├── drop-indicator.tsx
│ │ │ │ │ │ │ ├── subtask-container.tsx
│ │ │ │ │ │ │ └── subtask.tsx
│ │ │ │ │ │ ├── subtask-container.tsx
│ │ │ │ │ │ ├── subtask-drag-handle.tsx
│ │ │ │ │ │ ├── subtask-icon.tsx
│ │ │ │ │ │ └── subtask.tsx
│ │ │ │ │ └── templates/
│ │ │ │ │ ├── _base.tsx
│ │ │ │ │ └── linear.tsx
│ │ │ │ ├── table/
│ │ │ │ │ ├── constants.tsx
│ │ │ │ │ ├── data.ts
│ │ │ │ │ ├── menu-button.tsx
│ │ │ │ │ ├── render-pieces.tsx
│ │ │ │ │ ├── row.tsx
│ │ │ │ │ ├── table-context.ts
│ │ │ │ │ ├── table-header.tsx
│ │ │ │ │ └── types.ts
│ │ │ │ ├── tree/
│ │ │ │ │ ├── move-dialog.tsx
│ │ │ │ │ ├── tree-context.tsx
│ │ │ │ │ └── tree-item.tsx
│ │ │ │ └── tree-legacy/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── move-dialog.tsx
│ │ │ │ ├── tree-context.tsx
│ │ │ │ └── tree-item.tsx
│ │ │ ├── resizing.tsx
│ │ │ ├── table.tsx
│ │ │ ├── text-selection.tsx
│ │ │ ├── tree-legacy.tsx
│ │ │ ├── tree.tsx
│ │ │ ├── trello-like-board-iframe.tsx
│ │ │ ├── util/
│ │ │ │ ├── constants.tsx
│ │ │ │ ├── fallback.ts
│ │ │ │ └── global-styles.tsx
│ │ │ └── virtual-list.tsx
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ └── codegen.ts
│ │ ├── src/
│ │ │ └── index.ts
│ │ └── tsconfig.json
│ ├── flourish/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ ├── index/
│ │ │ │ ├── about.mdx
│ │ │ │ └── props.mdx
│ │ │ └── trigger-post-move-flash/
│ │ │ ├── examples.mdx
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ ├── basic.tsx
│ │ │ ├── config.jsonc
│ │ │ └── constellation/
│ │ │ └── props-table.tsx
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.tsx
│ │ │ └── trigger-post-move-flash.tsx
│ │ └── tsconfig.json
│ ├── hitbox/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── unit/
│ │ │ ├── _util.ts
│ │ │ ├── closest-edge.spec.ts
│ │ │ ├── get-reorder-destination-index.spec.ts
│ │ │ ├── list-item-memoization.spec.ts
│ │ │ ├── list-item.spec.ts
│ │ │ ├── reorder-with-edge.spec.ts
│ │ │ ├── test-helpers.spec.ts
│ │ │ ├── tree-item-memoization.spec.ts
│ │ │ └── tree-item.spec.ts
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ └── config.jsonc
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── closest-edge.ts
│ │ │ ├── get-reorder-destination-index.ts
│ │ │ ├── index.ts
│ │ │ ├── internal/
│ │ │ │ └── memoize.ts
│ │ │ ├── list-item.ts
│ │ │ ├── reorder-with-edge.ts
│ │ │ ├── tree-item.ts
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ ├── live-region/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── unit/
│ │ │ ├── announce.tsx
│ │ │ ├── cleanup.tsx
│ │ │ └── dom.tsx
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ ├── 00-basic.tsx
│ │ │ ├── 01-list-with-inline-buttons.tsx
│ │ │ └── config.jsonc
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── constants.tsx
│ │ │ └── index.tsx
│ │ └── tsconfig.json
│ ├── react-accessibility/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── unit/
│ │ │ └── ssr.tsx
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ ├── drag-handle-button/
│ │ │ │ ├── about.mdx
│ │ │ │ └── props.mdx
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ ├── config.jsonc
│ │ │ ├── drag-handle-button-small.tsx
│ │ │ ├── drag-handle-button.tsx
│ │ │ └── drag-handle-dropdown-menu.tsx
│ │ ├── extract-react-types/
│ │ │ └── drag-handle-button.tsx
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── drag-handle-button-base.tsx
│ │ │ ├── drag-handle-button-small.tsx
│ │ │ ├── drag-handle-button.tsx
│ │ │ ├── index.tsx
│ │ │ └── types.tsx
│ │ └── tsconfig.json
│ ├── react-beautiful-dnd-autoscroll/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── unit/
│ │ │ ├── _util.tsx
│ │ │ ├── auto-scrolling.spec.ts
│ │ │ ├── get-closest-scrollable.spec.ts
│ │ │ ├── get-max-scroll.spec.ts
│ │ │ ├── get-percentage.spec.ts
│ │ │ └── get-scroll/
│ │ │ ├── dampen-value-by-time.spec.ts
│ │ │ ├── get-distance-threshold.spec.ts
│ │ │ ├── get-scroll-on-axis.spec.ts
│ │ │ ├── get-value-from-distance.spec.ts
│ │ │ ├── get-value.spec.ts
│ │ │ └── index.spec.ts
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ └── props.mdx
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ └── internal/
│ │ │ ├── can-scroll.ts
│ │ │ ├── config.ts
│ │ │ ├── constants.ts
│ │ │ ├── get-closest-scrollable-element.ts
│ │ │ ├── get-max-scroll.ts
│ │ │ ├── get-percentage.ts
│ │ │ ├── get-scroll/
│ │ │ │ ├── get-scroll-on-axis/
│ │ │ │ │ ├── dampen-value-by-time.ts
│ │ │ │ │ ├── get-distance-thresholds.ts
│ │ │ │ │ ├── get-value-from-distance.ts
│ │ │ │ │ ├── get-value.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── index.ts
│ │ │ ├── get-scrollable-scroll-change.ts
│ │ │ ├── get-scrollable.ts
│ │ │ ├── get-window-scroll-change.ts
│ │ │ ├── position.ts
│ │ │ ├── scroll.ts
│ │ │ ├── types.ts
│ │ │ └── window/
│ │ │ ├── get-max-window-scroll.ts
│ │ │ ├── get-viewport.ts
│ │ │ └── get-window-scroll.ts
│ │ └── tsconfig.json
│ ├── react-beautiful-dnd-migration/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ ├── informational-vr-tests/
│ │ │ │ ├── drop-indicator.vr.tsx
│ │ │ │ ├── keyboard-drag-preview.vr.tsx
│ │ │ │ ├── scroll-container.vr.tsx
│ │ │ │ └── smoke.vr.tsx
│ │ │ ├── playwright/
│ │ │ │ └── virtual.spec.tsx
│ │ │ └── unit/
│ │ │ ├── _util.tsx
│ │ │ ├── _utils/
│ │ │ │ ├── board.tsx
│ │ │ │ ├── setup.tsx
│ │ │ │ └── with-set-element-from-point.tsx
│ │ │ ├── abort.test.tsx
│ │ │ ├── batch-updates-for-react-18.test.tsx
│ │ │ ├── browser-focus.test.tsx
│ │ │ ├── destination.test.tsx
│ │ │ ├── draggable/
│ │ │ │ ├── _utils.tsx
│ │ │ │ ├── find-drag-handle.test.tsx
│ │ │ │ ├── keyboard.test.tsx
│ │ │ │ ├── placeholder.test.tsx
│ │ │ │ ├── portal.test.tsx
│ │ │ │ ├── provided.test.tsx
│ │ │ │ └── timing.test.tsx
│ │ │ ├── droppable/
│ │ │ │ ├── auto-scroll.test.tsx
│ │ │ │ ├── closest-edge.test.tsx
│ │ │ │ ├── drop-indicator.test.tsx
│ │ │ │ ├── gap/
│ │ │ │ │ ├── calculate-gap.test.tsx
│ │ │ │ │ └── get-distance.test.tsx
│ │ │ │ ├── is-drop-disabled.test.tsx
│ │ │ │ └── resting.test.tsx
│ │ │ ├── error-handling.test.tsx
│ │ │ ├── live-region.test.tsx
│ │ │ ├── multi-context.test.tsx
│ │ │ ├── ported-from-react-beautiful-dnd/
│ │ │ │ ├── _utils/
│ │ │ │ │ ├── cause-runtime-error.tsx
│ │ │ │ │ └── console.tsx
│ │ │ │ └── unit/
│ │ │ │ ├── integration/
│ │ │ │ │ ├── _utils/
│ │ │ │ │ │ ├── app.tsx
│ │ │ │ │ │ ├── controls.tsx
│ │ │ │ │ │ └── helpers.tsx
│ │ │ │ │ ├── body-removal-before-unmount.test.tsx
│ │ │ │ │ ├── disable-on-start.test.tsx
│ │ │ │ │ ├── drag-drop-context/
│ │ │ │ │ │ ├── error-handling/
│ │ │ │ │ │ │ ├── error-in-react-tree.test.tsx
│ │ │ │ │ │ │ └── error-on-window.test.tsx
│ │ │ │ │ │ ├── on-before-capture/
│ │ │ │ │ │ │ ├── additions.test.tsx
│ │ │ │ │ │ │ └── removals.test.tsx
│ │ │ │ │ │ └── unmount.test.tsx
│ │ │ │ │ ├── drag-handle/
│ │ │ │ │ │ ├── keyboard-sensor/
│ │ │ │ │ │ │ ├── directional-movement.test.tsx
│ │ │ │ │ │ │ ├── no-click-blocking.test.tsx
│ │ │ │ │ │ │ ├── prevent-keyboard-scroll.test.tsx
│ │ │ │ │ │ │ ├── prevent-standard-keys-while-dragging.test.tsx
│ │ │ │ │ │ │ ├── starting-a-drag.test.tsx
│ │ │ │ │ │ │ └── stopping-a-drag.test.tsx
│ │ │ │ │ │ ├── mouse-sensor/
│ │ │ │ │ │ │ └── starting-a-dragging.test.tsx
│ │ │ │ │ │ └── shared-behaviors/
│ │ │ │ │ │ ├── abort-on-error.test.tsx
│ │ │ │ │ │ ├── cancel-while-dragging.test.tsx
│ │ │ │ │ │ ├── cannot-start-when-disabled.test.tsx
│ │ │ │ │ │ ├── cannot-start-when-unmounted.test.tsx
│ │ │ │ │ │ ├── cleanup.test.tsx
│ │ │ │ │ │ ├── contenteditable.test.tsx
│ │ │ │ │ │ ├── interactive-elements.test.tsx
│ │ │ │ │ │ ├── nested-handles.test.tsx
│ │ │ │ │ │ ├── parent-rendering-should-not-kill-drag.test.tsx
│ │ │ │ │ │ └── validate-controls.test.tsx
│ │ │ │ │ ├── draggable/
│ │ │ │ │ │ ├── dragging.test.tsx
│ │ │ │ │ │ ├── portal.test.tsx
│ │ │ │ │ │ ├── resting.test.tsx
│ │ │ │ │ │ └── validation.test.tsx
│ │ │ │ │ ├── droppable/
│ │ │ │ │ │ ├── _placeholder.test.tsx
│ │ │ │ │ │ └── clone.test.tsx
│ │ │ │ │ ├── reorder-render-sync.test.tsx
│ │ │ │ │ ├── responders-integration.test.tsx
│ │ │ │ │ ├── responders-timing.test.tsx
│ │ │ │ │ └── server-side-rendering/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── server-rendering.test.tsx.snap
│ │ │ │ │ ├── client-hydration.test.tsx
│ │ │ │ │ └── server-rendering.test.tsx
│ │ │ │ ├── state/
│ │ │ │ │ └── middleware/
│ │ │ │ │ └── responders/
│ │ │ │ │ ├── abort.test.tsx
│ │ │ │ │ ├── announcements.test.tsx
│ │ │ │ │ ├── flushing.test.tsx
│ │ │ │ │ ├── repeated-use.test.tsx
│ │ │ │ │ ├── start.test.tsx
│ │ │ │ │ └── update.test.tsx
│ │ │ │ └── view/
│ │ │ │ ├── droppable/
│ │ │ │ │ └── inner-ref-validation.test.tsx
│ │ │ │ └── style-marshal/
│ │ │ │ ├── get-styles.test.tsx
│ │ │ │ └── style-marshal.test.tsx
│ │ │ └── virtual.test.tsx
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── codemods/
│ │ │ ├── 0.1.0-adoption-from-rbd-12.tsx
│ │ │ ├── 0.1.0-adoption-from-rbd-13.tsx
│ │ │ ├── __tests__/
│ │ │ │ ├── adoption-from-rbd-12.test.tsx
│ │ │ │ ├── adoption-from-rbd-13.test.tsx
│ │ │ │ └── migration/
│ │ │ │ ├── migrate-12-to-13.test.tsx
│ │ │ │ ├── update-imports.test.tsx
│ │ │ │ ├── warn-about-react-beautiful-dnd-next.test.tsx
│ │ │ │ ├── warn-about-removed-exports.test.tsx
│ │ │ │ └── warn-about-unsupported-props.test.tsx
│ │ │ ├── migrations/
│ │ │ │ ├── migrate-12-to-13.tsx
│ │ │ │ ├── update-imports.tsx
│ │ │ │ ├── warn-about-react-beautiful-dnd-next.tsx
│ │ │ │ ├── warn-about-removed-exports.tsx
│ │ │ │ └── warn-about-unsupported-props.tsx
│ │ │ └── utils.tsx
│ │ ├── constellation/
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ ├── comparison.mdx
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ ├── 00-vertical-list.tsx
│ │ │ ├── 01-board.tsx
│ │ │ ├── 02-react-window.tsx
│ │ │ ├── 03-react-virtualized.tsx
│ │ │ ├── 04-multi-context.tsx
│ │ │ ├── 05-scroll-container.tsx
│ │ │ ├── config.jsonc
│ │ │ ├── data/
│ │ │ │ └── tasks.ts
│ │ │ └── pieces/
│ │ │ ├── card.tsx
│ │ │ ├── column.tsx
│ │ │ ├── example-wrapper.tsx
│ │ │ ├── global-styles.tsx
│ │ │ ├── react-virtualized/
│ │ │ │ └── column.tsx
│ │ │ └── react-window/
│ │ │ └── column.tsx
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── dev-warning.tsx
│ │ │ ├── drag-drop-context/
│ │ │ │ ├── cancel-drag.tsx
│ │ │ │ ├── draggable-location.tsx
│ │ │ │ ├── droppable-registry.tsx
│ │ │ │ ├── error-boundary.tsx
│ │ │ │ ├── get-destination.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── use-hidden-text-element.tsx
│ │ │ │ │ ├── use-keyboard-controls.tsx
│ │ │ │ │ ├── use-pointer-controls.tsx
│ │ │ │ │ └── use-style-marshal.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── internal-context.tsx
│ │ │ │ ├── lifecycle-context.tsx
│ │ │ │ ├── live-region.tsx
│ │ │ │ ├── rbd-invariant.tsx
│ │ │ │ ├── screen-reader.tsx
│ │ │ │ ├── types.tsx
│ │ │ │ └── use-scheduler.tsx
│ │ │ ├── draggable/
│ │ │ │ ├── constants.tsx
│ │ │ │ ├── data.tsx
│ │ │ │ ├── get-draggable-provided-style.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── is-event-in-interactive-element.tsx
│ │ │ │ ├── placeholder.tsx
│ │ │ │ ├── state.tsx
│ │ │ │ └── use-draggable-state-snapshot.tsx
│ │ │ ├── droppable/
│ │ │ │ ├── data.tsx
│ │ │ │ ├── draggable-clone.tsx
│ │ │ │ ├── drop-indicator/
│ │ │ │ │ ├── constants.tsx
│ │ │ │ │ ├── get-dimensions.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── types.tsx
│ │ │ │ ├── droppable-context.tsx
│ │ │ │ ├── gap/
│ │ │ │ │ ├── get-distance.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── state.tsx
│ │ │ │ └── virtual-placeholder.tsx
│ │ │ ├── hooks/
│ │ │ │ ├── use-captured-dimensions.tsx
│ │ │ │ ├── use-cleanup-fn.tsx
│ │ │ │ ├── use-drop-target-for-draggable.tsx
│ │ │ │ ├── use-isomorphic-layout-effect.tsx
│ │ │ │ └── use-keyboard-context.tsx
│ │ │ ├── index.ts
│ │ │ ├── internal-types.tsx
│ │ │ ├── reset-server-context.tsx
│ │ │ └── utils/
│ │ │ ├── attributes.tsx
│ │ │ ├── batch-updates-for-react-16.tsx
│ │ │ ├── find-all-draggables.tsx
│ │ │ ├── find-closest-scroll-container.tsx
│ │ │ ├── find-drag-handle.tsx
│ │ │ ├── find-drop-indicator.tsx
│ │ │ ├── find-element.tsx
│ │ │ ├── find-placeholder.tsx
│ │ │ ├── get-best-cross-axis-droppable.tsx
│ │ │ ├── get-closest-positioned-element.tsx
│ │ │ ├── get-element-by-draggable-location.tsx
│ │ │ └── use-stable.tsx
│ │ └── tsconfig.json
│ ├── react-drop-indicator/
│ │ ├── .npmignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── unit/
│ │ │ └── react-safety.test.tsx
│ │ ├── afm-jira/
│ │ │ └── tsconfig.json
│ │ ├── afm-products/
│ │ │ └── tsconfig.json
│ │ ├── constellation/
│ │ │ └── index/
│ │ │ ├── about.mdx
│ │ │ └── props.mdx
│ │ ├── examples/
│ │ │ ├── 00-closest-edge.tsx
│ │ │ ├── 01-gap.tsx
│ │ │ ├── 11-tree-item.tsx
│ │ │ ├── box-playground.tsx
│ │ │ ├── config.jsonc
│ │ │ ├── constellation/
│ │ │ │ ├── border/
│ │ │ │ │ └── border-showcase.tsx
│ │ │ │ ├── box/
│ │ │ │ │ ├── box-appearance.tsx
│ │ │ │ │ ├── box-edge.tsx
│ │ │ │ │ ├── box-gap.tsx
│ │ │ │ │ ├── box-indent.tsx
│ │ │ │ │ ├── box-overlap.tsx
│ │ │ │ │ └── box-type.tsx
│ │ │ │ ├── group/
│ │ │ │ │ └── group-list.tsx
│ │ │ │ ├── list-item/
│ │ │ │ │ ├── list-item-horizontal.tsx
│ │ │ │ │ └── list-item-vertical.tsx
│ │ │ │ ├── simple-item.tsx
│ │ │ │ └── tree-item.tsx
│ │ │ ├── internal/
│ │ │ │ ├── card.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── list.tsx
│ │ │ │ └── tree-item.tsx
│ │ │ ├── line.tsx
│ │ │ └── outline.tsx
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── border.tsx
│ │ │ ├── box.tsx
│ │ │ ├── group.tsx
│ │ │ ├── index.ts
│ │ │ ├── internal/
│ │ │ │ ├── README.md
│ │ │ │ ├── border.tsx
│ │ │ │ └── line.tsx
│ │ │ ├── internal-types.ts
│ │ │ ├── list-item.tsx
│ │ │ ├── presets.tsx
│ │ │ ├── tree-item.tsx
│ │ │ └── types.ts
│ │ └── tsconfig.json
│ └── unit-testing/
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── LICENSE.md
│ ├── README.md
│ ├── __tests__/
│ │ └── unit/
│ │ ├── dom-rect-polyfill.spec.ts
│ │ └── drag-event-polyfill/
│ │ ├── data-transfer-files.spec.ts
│ │ ├── data-transfer-item-list.spec.ts
│ │ └── data-transfer.spec.ts
│ ├── afm-products/
│ │ └── tsconfig.json
│ ├── constellation/
│ │ └── index/
│ │ ├── about.mdx
│ │ └── props.mdx
│ ├── package.json
│ ├── src/
│ │ ├── dom-rect-polyfill.ts
│ │ ├── drag-event-polyfill.ts
│ │ └── index.ts
│ └── tsconfig.json
├── patches/
│ └── @types+jest+29.5.12.patch
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules
dist
**/.DS_Store
.vscode/*
.idea
.iml
*.code-workspace
.env
yarn-debug.log*
yarn-error.log*
================================================
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 areardon@atlassian.com. The project team will review and investigate all
complaints, and will respond in a way that it deems 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
[http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Thank you for considering contributing to Pragmatic drag and drop!
At this stage, we are not accepting code contributions. This repo is currently a one-way partial
mirror from an internal monorepo at Atlassian. We might change this repo to be a two way mirror in
the future, at which point code contributions would be possible.
At this stage contributions could take the following forms:
Leveraging Github issues for:
- Suggestions
- Bug reports
- Discussions
You _can_ raise a pull request if you would spot a bug / improvement and making a pull request would
be a helpful way to demonstrate things. We will be able make our own changes to Pragmatic drag and
drop, as inspired by these pull requests, but unfortunately at this stage we cannot directly merge
those changes (nor attribute them properly in the Git history).
================================================
FILE: LICENSE
================================================
Copyright 2024 Atlassian Pty Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/alexreardon/files/assets/2182637/4405f071-4d88-4ad7-bcc0-a050420f3f3e" height="372px" width="372px" aria-label="Pragmatic drag and drop logo">
<img src="https://github.com/alexreardon/files/assets/2182637/9e57e0bb-aa9b-4552-affa-59aecf70bfc0" height="372px" width="372px" aria-label="Pragmatic drag and drop logo">
</picture>
_Fast drag and drop for any experience on any tech stack_
[📖 **Documentation**](https://atlassian.design/components/pragmatic-drag-and-drop) | [🤹 **Examples**](https://atlassian.design/components/pragmatic-drag-and-drop/examples) | [🎥 **How it works**](https://www.youtube.com/watch?v=5SQkOyzZLHM)

</div>
<br/>
## About
Pragmatic drag and drop is a low level drag and drop toolchain that enables safe and successful usage of the browsers built in drag and drop functionality. Pragmatic drag and drop can be used with any view layer ([`react`](https://react.dev/), [`svelte`](https://svelte.dev/), [`vue`](https://vuejs.org/), [`angular`](https://angular.io/) and so on). Pragmatic drag and drop is powering some of the biggest products on the web, including [Trello](https://trello.com), [Jira](https://www.atlassian.com/software/jira) and [Confluence](https://www.atlassian.com/software/confluence).
<details>
<summary>Capabilities</summary>
Pragmatic drag and drop consists of a few high level pieces:
1. **Low level drag and drop behavior**
Pragmatic drag and drop contains a core package, and a number of optional packages, that provide you the pieces to create _any_ drag and drop experience.
These pieces are unopinionated about visual language or accessibility, and have no dependency on the Atlassian Design System.
- _Tiny_: ~`4.7kB` core
- _Incremental_: Only use the pieces that you need
- _Headless_: Full rendering and style control
- _Framework agnostic_: Works with any frontend framework
- _Deferred compatible_: Delay the loading the core packages and optional packages in order to further improve page load speeds
- _Flexible_: create any experience you want, make any changes you want during a drag operation.
- _Works everywhere_: Full feature support in Firefox, Safari, and Chrome, iOS and Android
- _Virtualization support_: create any virtual experience you want!
2. **Optional visual outputs**
We have created optional visual outputs (eg our drop indicator) to make it super fast for us to build consistent Atlassian user experiences. Non Atlassian consumers are welcome to use these outputs, create their own that copy the visual styling, or go a totally different direction.
3. **Optional assistive technology controls**
Not all users can achieve pointer based drag and drop experiences. In order to achieve fantastic experiences for assistive technology users, we provide a toolchain to allow you to quickly wire up performant assistive technology friendly flows for any experience.
The optional assistive controls we provide are based on the Atlassian Design System. If you do not want to use the Atlassian Design System, you can use our guidelines and substitute our components with your own components, or you can go about accessibility in a different way if you choose.
</details>
## What is this repository?
This repository is currently one way mirror from our internal monorepo that contains all the code for Pragmatic drag and drop.
<div align="center">
<img src="https://github.com/alexreardon/files/assets/2182637/b45c2dfe-2c54-459e-a3e6-68b2342fe97b" alt="Diagram of how the mirror works" width="600px">
</div>
The intention of this repository is to make public our code, but not to accept code contributions (at this stage). In the future we could explore setting up a two way mirror so that contributions to this repo can also make their way back to our monorepo. You are still welcome to raise issues or suggestions on this repository!
All documentation and `npm` packages are public and available for use by everyone.
## Can I use this with my own Design System?
Yep! Pragmatic drag and drop as a [small core package](https://atlassian.design/components/pragmatic-drag-and-drop/core-package), and then a range of [optional packages](https://atlassian.design/components/pragmatic-drag-and-drop/optional-packages). Some of the optional packages have dependencies on styling solutions (eg `emotion`), view libraries (eg `react`) or on some additional Atlassian outputs (eg `@atlaskit/tokens`). We have separated out optional packages that have other dependencies so they can be easily swapped with your own pieces that use your own tech stack and visual outputs.
## Can I use my own design language?
Yep! We have created some design guidelines which embody how we want to achieve drag and drop in our products, and some of those decisions are embodied in some optional packages. However, you are free to use whatever design language you like, including ours!
## What is `@atlaskit`?
The Pragmatic drag and drop packages are published under the `@atlaskit` namespace on `npm`
```ts
import { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
```
`@atlaskit` is the `npm` namespace that we publish all of our public packages on from inside our internal monorepo. We _could_ look at creating a separate namespace in the future just for Pragmatic drag and drop. If we do that, we'll release some tooling to help folks automatically switch over.
## `npm` release and repo sync timing
This mirror repository is currently being synced with our internal repository once a day. We publish packages to `npm` immediately as we merge new versions into the internal repository. This means that code can be released onto `npm` up to 24 hours _before_ it is available in this mirror repository.
## Credits
Made with love by:
- [Alex Reardon](https://twitter.com/alexandereardon)
- [Declan Warn](https://twitter.com/DeclanWarn)
- [Lewis Healey](https://twitter.com/lewishealey)
- [Eleni Misthos](https://www.linkedin.com/in/elenimisthos/)
- [Jesse Bauer](https://soundcloud.com/jessebauer)
- [Mitch Gavan](https://twitter.com/MitchG23)
- [Michael Abrahamian](https://twitter.com/michaelguitars7)
- [Tim Keir](https://twitter.com/ReDrUmNZ)
- [Greta Ritchard](https://www.linkedin.com/in/gretarit/)
- [Many other folks at Atlassian](https://www.atlassian.com/)
- Logo created by [Michelle Holik](https://twitter.com/michelleholik) and [Vojta Holik](https://twitter.com/vojta_holik)
Pragmatic drag and drop stands on the shoulders of giants, including the folks who created the [drag and drop specifications](https://html.spec.whatwg.org/multipage/dnd.html), implemented drag and drop in browsers, and the many drag and drop libraries that came before this.
================================================
FILE: jest.config.js
================================================
================================================
FILE: package.json
================================================
{
"name": "pragmatic-drag-and-drop",
"private": true,
"version": "1.0.0",
"description": "Pragmatic drag and drop is a low level toolchain that enables fast and successful usage of the browsers built in drag and drop capabilities, for everyone",
"author": "Atlassian Pty Ltd",
"license": "Apache-2.0",
"scripts": {
"postinstall": "patch-package",
"test": "jest --forceExit"
},
"workspaces": [
"packages/*"
],
"dependencies": {
"tslib": "^2.4.0"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"patch-package": "^8.0.0",
"postinstall-postinstall": "^2.1.0",
"typescript": "5.9.2"
}
}
================================================
FILE: packages/auto-scroll/.npmignore
================================================
src/
examples-utils/
examples/
index.ts
docs/
build/
__tests__/
tsconfig.json
tsconfig.app.json
tsconfig.dev.json
================================================
FILE: packages/auto-scroll/CHANGELOG.md
================================================
# @atlaskit/pragmatic-drag-and-drop-auto-scroll
## 2.1.5
### Patch Changes
- [`d3ed1b65a2181`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d3ed1b65a2181) -
Add @atlassian/a11y-jest-testing to devDependencies.
## 2.1.4
### Patch Changes
- [`e4b717d8304e8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e4b717d8304e8) -
Add @atlassian/a11y-jest-testing to devDependencies.
## 2.1.3
### Patch Changes
- [`aa9ff75020fcb`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/aa9ff75020fcb) -
Add @atlassian/a11y-jest-testing to devDependencies.
## 2.1.2
### Patch Changes
- [`beaa6ee463aa8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/beaa6ee463aa8) -
Internal changes to how border radius is applied.
- Updated dependencies
## 2.1.1
### Patch Changes
- [#164244](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/164244)
[`65021fc0267e2`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/65021fc0267e2) -
The cleanup functions returned by the following utilities now only work on the first call. This
was done to prevent unexpected side effects of calling a cleanup function multiple times.
- `@atlaskit/pragmatic-drag-and-drop/adapter/element`
- `draggable`
- `dropTargetForElements`
- `monitorForElements`
- `@atlaskit/pragmatic-drag-and-drop/adapter/text-selection`
- `dropTargetForTextSelection`
- `monitorForTextSelection`
- `@atlaskit/pragmatic-drag-and-drop/adapter/external`
- `dropTargetForExternal`
- `monitorForExternal`
- `@atlaskit/pragmatic-drag-and-drop-auto-scroll/element`
- `autoScrollForElements`
- `autoScrollWindowForElements`
- `@atlaskit/pragmatic-drag-and-drop-auto-scroll/external`
- `autoScrollForExternal`
- `autoScrollWindowForExternal`
- `@atlaskit/pragmatic-drag-and-drop-auto-scroll/text-selection`
- `autoScrollForTextSelection`
- `autoScrollWindowForTextSelection`
- Updated dependencies
## 2.1.0
### Minor Changes
- [#172374](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/172374)
[`4ca6346256c8a`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/4ca6346256c8a) -
Minor increase of time dampening duration. After lots of explorations, we have increased the value
to make it easier for people to avoid the impacts of rapid scroll speed spikes when lifting or
entering into a high scroll speed area.
## 2.0.0
### Major Changes
- [#170839](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/170839)
[`1534389dcb75b`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/1534389dcb75b) -
In order to improve clarity, we have renamed the `from*Edge` (eg `fromTopEdge`) argument
properties to `for*Edge` (eg `forTopEdge`) for the overflow scroller. If you are not using
overflow scrolling, there is nothing you need to do.
```diff
- fromTopEdge
+ forTopEdge
- fromRightEdge
+ forRightEdge
- fromBottomEdge
+ forBottomEdge
- fromLeftEdge
+ forLeftEdge
```
```diff
const unbind = unsafeOverflowAutoScrollForElements({
element,
getOverflow: () => ({
- fromTopEdge: {
+ forTopEdge: {
top: 6000,
right: 6000,
left: 6000,
},
- fromRightEdge: {
+ forRightEdge: {
top: 6000,
right: 6000,
bottom: 6000,
},
- fromBottomEdge: {
+ forBottomEdge: {
right: 6000,
bottom: 6000,
left: 6000,
},
- fromLeftEdge: {
+ forLeftEdge: {
top: 6000,
left: 6000,
bottom: 6000,
},
}),
});
```
We thought that `for*` more accurately represented what was being provided, as these are the
overflow definitions _for_ a defined edge.
We have also improved the types for `for*Edge` so that you do not need to provide redundant cross
axis information if you only want to overflow scroll on the main axis.
```diff
const unbind = unsafeOverflowAutoScrollForElements({
element,
getOverflow: () => ({
forTopEdge: {
top: 100,
+ // no longer need to pass `0` for the cross axis if you don't need it
- right: 0,
- left: 0,
},
forRightEdge: {
right: 100,
- top: 0,
- bottom: 0,
},
forBottomEdge: {
bottom: 100,
- right: 0,
- left: 0,
},
forLeftEdge: {
left: 100,
- top: 0,
- bottom: 0,
},
}),
});
```
When declaring overflow scrolling for an edge, you cannot provide how deep the scrolling should
occur into the element (that is defined by the "over element" overflow scroller). Providing
redundant information for an edge will now also give a type error rather than providing no
feedback.
```ts
const unbind = unsafeOverflowAutoScrollForElements({
element,
getOverflow: () => ({
forTopEdge: {
top: 100,
bottom: 30, // ❌ now a type error
},
forRightEdge: {
right: 100,
left: 10, // ❌ now a type error
},
forBottomEdge: {
bottom: 100,
top: 200, // ❌ now a type error
},
forLeftEdge: {
left: 100,
right: 20, // ❌ now a type error
},
}),
});
```
## 1.4.0
### Minor Changes
- [#116572](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/116572)
[`98c65e7ff719c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/98c65e7ff719c) -
🍯 Introducing "the honey pot fix" which is an improved workaround for a
[painful browser bug](https://issues.chromium.org/issues/41129937).
**Background**
The browser bug causes the browser to think the users pointer is continually depressed at the
point that the user started a drag. This could lead to incorrect events being triggered, and
incorrect styles being applied to elements that the user is not currently over during a drag.
**Outcomes**
- Elements will no longer receive `MouseEvent`s (eg `"mouseenter"` and `"mouseleave"`) during a
drag (which is a violation of the
[drag and drop specification](https://html.spec.whatwg.org/multipage/dnd.html#drag-and-drop-processing-model))
- Elements will no longer apply `:hover` or `:active` styles during a drag. Previously consumers
would need to disable these style rules during a drag to prevent these styles being applied.
- Dramatically improved post drop performance. Our prior solution could require a noticeable delay
due to a large style recalculation after a drop.
### Patch Changes
- Updated dependencies
## 1.3.0
### Minor Changes
- [#95426](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/95426)
[`a58266bf88e6`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/a58266bf88e6) -
Adding axis locking functionality
```diff
+ // `getAllowedAxis` added to element, text selection and external auto scrollers
autoScrollForElements({
element: myElement,
+ getAllowedAxis: (args: ElementGetFeedbackArgs<DragType>) => 'horizontal' | 'vertical' | 'all',
});
autoScrollWindowForElements({
+ getAllowedAxis: (args: WindowGetFeedbackArgs<DragType>) => 'horizontal' | 'vertical' | 'all',
});
unsafeOverflowAutoScrollForElements({
+ getAllowedAxis?: (args: ElementGetFeedbackArgs<DragType>) => AllowedAxis;
})
```
## 1.2.0
### Minor Changes
> `1.2.0` is deprecated on `npm` and should not be used. Shortly after release we decided to change
> this API
- [#94103](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/94103)
[`4e3fb63eb288`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/4e3fb63eb288) -
Added axis locking functionality.
```diff
autoScrollForElements({
element: myElement,
getConfiguration: () => ({
maxScrollSpeed: 'fast' | 'standard',
+ allowedAxis: 'horizontal' | 'vertical' | 'all',
}),
})
```
## 1.1.0
### Minor Changes
- [#94454](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/94454)
[`4b40eb010074`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/4b40eb010074) -
Exposing the unsafe overflow auto scroller for external drags
(`unsafeOverflowAutoScrollForExternal()`). This already existed, but it was not exposed publicly
🤦♂️.
```diff
import {unsafeOverflowAutoScrollForElements from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/unsafe-overflow/element';
import {unsafeOverflowAutoScrollForTextSelection} from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/unsafe-overflow/text-selection';
+ import {unsafeOverflowAutoScrollForExternal} from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/unsafe-overflow/external';
```
## 1.0.4
### Patch Changes
- [#94316](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/94316)
[`35fd5ed8e1d7`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/35fd5ed8e1d7) -
Upgrading internal dependency `bind-event-listener` to `@^3.0.0`
## 1.0.3
### Patch Changes
- [#84398](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/84398)
[`77694db987fc`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/77694db987fc) -
Public release of Pragmatic drag and drop documentation
## 1.0.2
### Patch Changes
- [#83702](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/83702)
[`4d9e25ab4eaa`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/4d9e25ab4eaa) -
Updating the descriptions of Pragmatic drag and drop packages, so they each provide a consistent
description to various consumers, and so they are consistently formed amongst each other.
- `package.json` `description`
- `README.md`
- Website documentation
## 1.0.1
### Patch Changes
- [#83116](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/83116)
[`8d4e99057fe0`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/8d4e99057fe0) -
Upgrade Typescript from `4.9.5` to `5.4.2`
## 1.0.0
### Major Changes
- [#70616](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/70616)
[`42e57ea65fee`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/42e57ea65fee) -
This is our first `major` release (`1.0`) for all Pragmatic drag and drop packages.
For a detailed explanation of these changes, and how to upgrade (automatically) to `1.0` please
see our
[1.0 upgrade guide](http://atlassian.design/components/pragmatic-drag-and-drop/core-package/upgrade-guides/upgrade-guide-for-1.0)
### Patch Changes
- Updated dependencies
## 0.8.1
### Patch Changes
- Updated dependencies
## 0.8.0
### Minor Changes
- [#57337](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/57337)
[`4ad3fa749a5c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/4ad3fa749a5c) -
Adding the ability to increase the maximum automatic scroll speed.
```diff
autoScrollForElements({
element: myElement,
+ getConfiguration: () => ({maxScrollSpeed: 'fast' | 'standard'}),
})
```
`getConfiguration()` is a new _optional_ argument be used with all auto scrolling registration
functions:
- `autoScrollForElements`
- `autoScrollWindowForElements`
- `autoScrollForFiles`
- `autoScrollWindowForFiles`
- `unsafeOverflowForElements`
- `unsafeOverflowForFiles`
```ts
autoScrollForElements({
element: myElement,
getConfiguration: () => ({ maxScrollSpeed : 'fast' })
}),
```
We recommend using the default `"standard"` max scroll speed for most experiences. However, on
_some_ larger experiences, a faster max scroll speed (`"fast"`) can feel better.
## 0.7.0
### Minor Changes
- [#42774](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/42774)
[`66d9475437e`](https://bitbucket.org/atlassian/atlassian-frontend/commits/66d9475437e) - Internal
refactoring to improve clarity and safety
## 0.6.0
### Minor Changes
- [#42668](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/42668)
[`0a4e3f44ba3`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0a4e3f44ba3) - We have
landed a few fixes for "overflow scrolling"
- Fix: Time dampening could be incorrectly reset when transitioning from "over element" auto
scrolling to "overflow" auto scrolling for certain element configurations.
- Fix: Parent "overflow scrolling" registrations could prevent overflow scrolling on children
elements, if the parent was registered first.
- Fix: "overflow scrolling" `canScroll() => false` would incorrectly opt out of "overflow
scrolling" for younger registrations.
## 0.5.0
### Minor Changes
- [#39935](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/39935)
[`20a91012629`](https://bitbucket.org/atlassian/atlassian-frontend/commits/20a91012629) - First
public release of this package. Please refer to documentation for usage and API information.
### Patch Changes
- Updated dependencies
## 0.4.0
### Minor Changes
- [#39303](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/39303)
[`a6d9f3bb566`](https://bitbucket.org/atlassian/atlassian-frontend/commits/a6d9f3bb566) - Adding
optional overflow scrolling API. API information shared directly with Trello
## 0.3.2
### Patch Changes
- Updated dependencies
## 0.3.1
### Patch Changes
- Updated dependencies
## 0.3.0
### Minor Changes
- [#38658](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/38658)
[`7803a90e9c6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/7803a90e9c6) - This
change makes it so that distance dampening is based on the size of the hitbox and not the
container. Now that we clamp the size of the hitbox, our distance dampening needs to be based on
the size of the hitbox, and not the container.
## 0.2.0
### Minor Changes
- [#38630](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/38630)
[`5c643ce004d`](https://bitbucket.org/atlassian/atlassian-frontend/commits/5c643ce004d) - Limiting
the max size of auto scrolling hitboxes. This prevents large elements having giant auto scroll
hitboxes
## 0.1.0
### Minor Changes
- [#38525](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/38525)
[`693af8c5775`](https://bitbucket.org/atlassian/atlassian-frontend/commits/693af8c5775) - Early
release of our new optional drag and drop package for Pragmatic drag and drop. Package release is
only for early integration with Trello.
### Patch Changes
- Updated dependencies
================================================
FILE: packages/auto-scroll/LICENSE.md
================================================
Copyright 2023 Atlassian Pty Ltd
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing permissions and limitations under the
License.
================================================
FILE: packages/auto-scroll/README.md
================================================
## Pragmatic drag and drop
An optional Pragmatic drag and drop package that enables automatic scrolling during a drag operation. This package works with any configuration of scrollable entities, and you can change the configuration of your scrollable entities in any way you like during a drag.
[📖 Documentation](https://atlassian.design/components/pragmatic-drag-and-drop/)
================================================
FILE: packages/auto-scroll/__tests__/playwright/over-element-smoke-test.spec.tsx
================================================
import invariant from 'tiny-invariant';
import { expect, test } from '@af/integration-testing';
test.describe('over element automatic scrolling', () => {
test('should scroll a scrollable element forwards', async ({ page }) => {
await page.visitExample<typeof import('../../examples/over-element.tsx')>('pragmatic-drag-and-drop', 'auto-scroll', 'over-element');
const columnTestId = 'column-0';
const card = page.getByTestId('column-0::item-0');
const column = page.getByTestId(columnTestId);
// first check: ensure the column is not scrolled yet
expect(await column.evaluate((element) => element.scrollTop)).toBe(0);
const columnRect = await column.boundingBox();
invariant(columnRect, 'Could not obtain bounding box from column');
await card.hover();
await page.mouse.down();
// Using 'move' rather than 'hover' as 'hover' also does it's own scrolling
await page.mouse.move(
columnRect.x + columnRect.width / 2,
// Going up a bit from the bottom so we know it is
// our auto scroller and not the browsers built in one
columnRect.y + columnRect.height - 30,
// having one step so we don't trigger the browsers built in auto scroller
{ steps: 1 },
);
await page.waitForFunction((testId) => {
const element = document.querySelector(`[data-testid="${testId}"]`);
if (!element) {
throw new Error(`Unable to find element with test id "${testId}"`);
}
return element.scrollTop > 0;
}, columnTestId);
});
});
================================================
FILE: packages/auto-scroll/__tests__/playwright/unsafe-overflow-smoke-test.spec.tsx
================================================
import invariant from 'tiny-invariant';
import { expect, test } from '@af/integration-testing';
test.describe('over element automatic scrolling', () => {
test('should scroll a scrollable element forwards', async ({ page }) => {
await page.visitExample<typeof import('../../examples/unsafe-overflow-only.tsx')>('pragmatic-drag-and-drop', 'auto-scroll', 'unsafe-overflow-only');
const columnTestId = 'column-0';
const card = page.getByTestId('column-0::item-0');
const column = page.getByTestId(columnTestId);
// first check: ensure the column is not scrolled yet
expect(await column.evaluate((element) => element.scrollTop)).toBe(0);
const columnRect = await column.boundingBox();
invariant(columnRect, 'Could not obtain bounding box from column');
await card.hover();
await page.mouse.down();
// Using 'move' rather than 'hover' as 'hover' also does it's own scrolling
await page.mouse.move(
columnRect.x + columnRect.width / 2,
// Going below the column a bit so we know we are triggering the overflow scroller
columnRect.y + columnRect.height + 100,
{ steps: 20 },
);
await page.waitForFunction((testId) => {
const element = document.querySelector(`[data-testid="${testId}"]`);
if (!element) {
throw new Error(`Unable to find element with test id "${testId}"`);
}
return element.scrollTop > 0;
}, columnTestId);
});
});
================================================
FILE: packages/auto-scroll/__tests__/unit/_util.ts
================================================
import { fireEvent } from '@testing-library/dom';
import invariant from 'tiny-invariant';
import {
type CleanupFn,
type DragLocation,
type DragLocationHistory,
type DropTargetRecord,
type Input,
type Position,
} from '@atlaskit/pragmatic-drag-and-drop/types';
import { type Axis, type Edge } from '../../src/internal-types';
export function getDefaultInput(overrides: Partial<Input> = {}): Input {
const defaults: Input = {
// user input
altKey: false,
button: 0,
buttons: 0,
ctrlKey: false,
metaKey: false,
shiftKey: false,
// coordinates
clientX: 0,
clientY: 0,
pageX: 0,
pageY: 0,
};
return {
...defaults,
...overrides,
};
}
export function appendToBody(...elements: Element[]): CleanupFn {
elements.forEach((element) => {
document.body.appendChild(element);
});
return function removeFromBody() {
elements.forEach((element) => {
document.body.removeChild(element);
});
};
}
export function getEmptyHistory(input: Input = getDefaultInput()): DragLocationHistory {
const noWhere: DragLocation = {
input,
dropTargets: [],
};
return {
initial: noWhere,
previous: {
dropTargets: noWhere.dropTargets,
},
current: noWhere,
};
}
export function getInitialHistory(
dropTargets: DropTargetRecord[],
input: Input = getDefaultInput(),
): DragLocationHistory {
const location: DragLocation = {
input,
dropTargets,
};
return {
initial: location,
current: location,
previous: {
dropTargets: [],
},
};
}
export function setBoundingClientRect(el: HTMLElement, rect: DOMRect): CleanupFn {
const original = el.getBoundingClientRect;
el.getBoundingClientRect = () => rect;
return () => {
el.getBoundingClientRect = original;
};
}
export function tryGetRect(box: Partial<Parameters<typeof getRect>[0]>): DOMRect {
const { top, right, bottom, left } = box;
invariant(typeof top === 'number');
invariant(typeof right === 'number');
invariant(typeof bottom === 'number');
invariant(typeof left === 'number');
return getRect({ top, right, bottom, left });
}
export function getRect(box: {
top: number;
right: number;
bottom: number;
left: number;
}): DOMRect {
return {
top: box.top,
right: box.right,
bottom: box.bottom,
left: box.left,
// calculated
height: box.bottom - box.top,
width: box.right - box.left,
x: box.left,
y: box.top,
toJSON: function () {
return JSON.stringify(this);
},
};
}
// usage: const [A, B, C, D, F] = getElements();
export function getElements(tagName: keyof HTMLElementTagNameMap = 'div'): Iterable<HTMLElement> {
const iterator = {
next() {
return {
done: false,
value: document.createElement(tagName),
};
},
[Symbol.iterator]() {
return iterator;
},
};
return iterator;
}
/**
* Returns a connected tree of elements
* `[grandChild, parent, grandParent]`
*/
export function getBubbleOrderedTree(
tagName: keyof HTMLElementTagNameMap = 'div',
): Iterable<HTMLElement> {
let last: HTMLElement | null;
const iterator = {
next() {
const element = document.createElement(tagName);
if (last) {
element.appendChild(last);
}
last = element;
return {
done: false,
value: element,
};
},
[Symbol.iterator]() {
return iterator;
},
};
return iterator;
}
export const userEvent = {
lift(target: HTMLElement, input?: Partial<Input>): void {
const final: Input = { ...getDefaultInput(), ...input };
// accurate representation of events:
firePointer.down(target, final);
firePointer.move(target, { ...final, clientX: final.clientX + 10 });
// will fire `onGenerateDragPreview`
fireEvent.dragStart(target, final);
firePointer.cancel(target, final);
// after an animation frame we fire `onDragStart`
advanceTimersToNextFrame();
},
drop(target: Element): void {
fireEvent.drop(target);
},
cancel(target: Element = document.body): void {
// A "cancel" (drop on nothing, or pressing "Escape") will
// cause a "dragleave" and then a "dragend"
fireEvent.dragLeave(target);
fireEvent.dragEnd(target);
},
leaveWindow(): void {
fireEvent.dragLeave(document.documentElement, { relatedTarget: null });
},
startExternalDrag({
types,
target = document.body,
}: {
types: string[];
target?: Element;
}): void {
const event = new DragEvent('dragenter', {
cancelable: true,
bubbles: true,
});
for (const type of types) {
// @ts-expect-error
event.dataTransfer?.types.push(type);
}
target.dispatchEvent(event);
advanceTimersToNextFrame();
},
rougePointerMoves(): void {
// first 20 are ignored due to firefox issue
// 21st pointermove will cancel a drag
for (let i = 0; i < 21; i++) {
fireEvent.pointerMove(document.body);
}
},
};
/** Cleanup function to unbind all event listeners */
export async function reset(): Promise<void> {
// cleanup any pending drags
fireEvent.dragEnd(window);
// cleanup honey pot fix
fireEvent.pointerMove(window);
}
export function getBubbleOrderedPath(path: Element[]): Element[] {
const last = path[path.length - 1];
// will happen if you pass in an empty array
if (!last) {
return path;
}
// exit condition: no more parents
if (!last.parentElement) {
return path;
}
// bubble ordered
return getBubbleOrderedPath([...path, last.parentElement]);
}
export function setElementFromPointWithPath(path: Element[]): CleanupFn {
const originalElementFromPoint = document.elementFromPoint;
const originalElementsFromPoint = document.elementsFromPoint;
document.elementsFromPoint = () => path;
document.elementFromPoint = () => path[0] ?? null;
return () => {
document.elementFromPoint = originalElementFromPoint;
document.elementsFromPoint = originalElementsFromPoint;
};
}
export function setElementFromPoint(element: Element | null): CleanupFn {
const path = element ? getBubbleOrderedPath([element]) : [];
return setElementFromPointWithPath(path);
}
/** Release a pending scrollBy (they are scheduled for the next task) */
export function stepScrollBy(): void {
jest.advanceTimersByTime(1);
}
let startTime: number | null = null;
/** Record the initial (mocked) system start time
*
* This is no longer needed once `jest.advanceTimersToNextFrame()` is available
* https://github.com/jestjs/jest/pull/14598
*/
export function setStartSystemTime(): void {
startTime = Date.now();
}
/** Step forward a single animation frame
*
* This is no longer needed once `jest.advanceTimersToNextFrame()` is available
* https://github.com/jestjs/jest/pull/14598
*/
export function advanceTimersToNextFrame(): void {
invariant(
startTime != null,
'Must call `setStartSystemTime` before using `advanceTimersToNextFrame()`',
);
// Stealing logic from sinon fake timers
// https://github.com/sinonjs/fake-timers/blob/fc312b9ce96a4ea2c7e60bb0cccd2c604b75cdbd/src/fake-timers-src.js#L1102-L1105
const timePassedInFrame = (Date.now() - startTime) % 16;
const timeToNextFrame = 16 - timePassedInFrame;
jest.advanceTimersByTime(timeToNextFrame);
}
type BasicElementArgs = {
width: number;
height: number;
x?: number;
y?: number;
id?: string;
};
export function setupNestedScrollContainers(bubbleOrdered: BasicElementArgs[]): HTMLElement[] {
// argument validation
for (let i = 0; i < bubbleOrdered.length - 1; i++) {
const current = bubbleOrdered[i];
const parent = bubbleOrdered[i + 1];
invariant(
current.height >= parent.height,
`validation error: a child's height (${current.height}) was bigger than it's parent (${current.height})`,
);
invariant(
current.width >= parent.width,
`validation error: a child's width (${current.width}) was bigger than it's parent (${current.width})`,
);
}
type Item = { args: BasicElementArgs; element: HTMLElement };
// Making all elements first so we can link everything correctly.
const items: Item[] = bubbleOrdered.map(
(args): Item => ({
args,
element: document.createElement('div'),
}),
);
for (let i = 0; i < items.length; i++) {
const item = items[i];
const parent: Item | undefined = items[i + 1];
const isInnerMost = i === 0;
// Establish parent relationship
if (parent) {
parent.element.appendChild(item.element);
}
// helpful for logging
item.element.id = item.args.id ?? `element-index-${i}-in-${items.length - 1}`;
Object.assign(item.element.style, {
// enabling scrolling in both directions if not the inner most
overflowX: isInnerMost ? undefined : 'auto',
overflowY: isInnerMost ? undefined : 'auto',
height: `${item.args.height}px`,
width: `${item.args.width}px`,
});
item.element.getBoundingClientRect = () => {
// for simplicity, all elements are currently drawn from 0,0
const start: Position = {
x: item.args.x ?? 0,
y: item.args.y ?? 0,
};
const box = DOMRect.fromRect({
x: start.x,
y: start.y,
width: item.args.width,
height: item.args.height,
});
if (!parent) {
return box;
}
// The border box of an element will be shifted by:
// 1. the scroll of a parent
// 2. changes in the x/y of the parent
const parentRect = parent.element.getBoundingClientRect();
// What is the difference between the original parent.getBoundingClientRect() and where it is now?
// Given that we know an element is always starting at `x: 0, y: 0`, the value of `x` and `y` can
// only have changed if a parent was scrolled
const parentChange: Position = {
x: parentRect.x,
y: parentRect.y,
};
const shiftedByParents = DOMRect.fromRect({
x: box.x - parent.element.scrollLeft + parentChange.x,
y: box.y - parent.element.scrollTop + parentChange.y,
width: box.width,
height: box.height,
});
return shiftedByParents;
};
// scroll properties will be based on children
// TODO: could find the maximum height of any child
const child: Item | undefined = items[i - 1];
Object.defineProperties(item.element, {
scrollHeight: {
value: child ? child.args.height : item.args.height,
writable: false,
},
scrollWidth: {
value: child ? child.args.width : item.args.width,
writable: false,
},
});
// Note: these only measure paddingBox, but we are
// not currently using borders so we are all good
Object.defineProperties(item.element, {
clientHeight: {
value: item.args.height,
writable: false,
},
clientWidth: {
value: item.args.width,
writable: false,
},
});
}
return items.map((item) => item.element);
}
export function setupBasicScrollContainer({
scrollContainer = { width: 1000, height: 1000 },
child = { width: 10000, height: 10000 },
}: {
scrollContainer?: { width: number; height: number };
child?: { width: number; height: number };
} = {}): { parentScrollContainer: HTMLElement; child: HTMLElement } {
const elements = setupNestedScrollContainers([child, scrollContainer]);
return {
child: elements[0],
parentScrollContainer: elements[1],
};
}
export type Point = Position & { label: string };
export function getInsidePoints(rect: DOMRect): Point[] {
return [
{ label: 'top left', x: rect.left, y: rect.top },
{ label: 'top right', x: rect.right, y: rect.top },
{ label: 'bottom right', x: rect.right, y: rect.bottom },
{ label: 'bottom left', x: rect.left, y: rect.bottom },
{
label: 'center',
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2,
},
];
}
export function getOutsidePoints(rect: DOMRect): Point[] {
return [
{ label: 'left of top left', x: rect.left - 1, y: rect.top },
{ label: 'top of top left', x: rect.left, y: rect.top - 1 },
{ label: 'right of top right', x: rect.right + 1, y: rect.top },
{ label: 'top of top right', x: rect.right, y: rect.top - 1 },
{ label: 'right of bottom right', x: rect.right + 1, y: rect.bottom },
{ label: 'bottom of bottom right', x: rect.right, y: rect.bottom + 1 },
{ label: 'left of bottom left', x: rect.left - 1, y: rect.bottom },
{ label: 'bottom of bottom left', x: rect.left, y: rect.bottom + 1 },
];
}
export const mainAxisForSide: { [T in Edge]: Axis } = {
bottom: 'vertical',
top: 'vertical',
left: 'horizontal',
right: 'horizontal',
};
export type AxisScroll = Record<Axis, number>;
export type AxisMovement = Record<Axis, boolean>;
export type Event = { type: string } & Partial<AxisMovement>;
export type Scenario = {
label: string;
startPosition: Position;
endPosition: Position;
expectedMovement: AxisMovement;
};
export function getScenarios(rect: DOMRect, offset: number = 0): Scenario[] {
return [
{
label: 'top left',
startPosition: {
x: rect.left,
y: rect.top,
},
endPosition: {
x: rect.left - offset,
y: rect.top - offset,
},
expectedMovement: { horizontal: true, vertical: true },
},
{
label: 'top',
startPosition: {
x: rect.left + rect.width / 2,
y: rect.top,
},
endPosition: {
x: rect.left + rect.width / 2,
y: rect.top - offset,
},
expectedMovement: { horizontal: false, vertical: true },
},
{
label: 'top right',
startPosition: {
x: rect.right,
y: rect.top,
},
endPosition: {
x: rect.right + offset,
y: rect.top - offset,
},
expectedMovement: { horizontal: true, vertical: true },
},
{
label: 'right',
startPosition: {
x: rect.right,
y: rect.top + rect.height / 2,
},
endPosition: {
x: rect.right + offset,
y: rect.top + rect.height / 2,
},
expectedMovement: { horizontal: true, vertical: false },
},
{
label: 'bottom right',
startPosition: {
x: rect.right,
y: rect.bottom,
},
endPosition: {
x: rect.right + offset,
y: rect.bottom + offset,
},
expectedMovement: { horizontal: true, vertical: true },
},
{
label: 'bottom',
startPosition: {
x: rect.left + rect.width / 2,
y: rect.bottom,
},
endPosition: {
x: rect.left + rect.width / 2,
y: rect.bottom + offset,
},
expectedMovement: { horizontal: false, vertical: true },
},
{
label: 'bottom left',
startPosition: {
x: rect.left,
y: rect.bottom,
},
endPosition: {
x: rect.left - offset,
y: rect.bottom + offset,
},
expectedMovement: { horizontal: true, vertical: true },
},
{
label: 'left',
startPosition: {
x: rect.left,
y: rect.top + rect.height / 2,
},
endPosition: {
x: rect.left - offset,
y: rect.top + rect.height / 2,
},
expectedMovement: { horizontal: true, vertical: false },
},
];
}
export function getAxisScroll(container: HTMLElement): AxisScroll {
return {
horizontal: container.scrollLeft,
vertical: container.scrollTop,
};
}
export function hasAxisScrolled(container: HTMLElement, previousScroll: AxisScroll): AxisMovement {
return {
horizontal: container.scrollLeft !== previousScroll.horizontal,
vertical: container.scrollTop !== previousScroll.vertical,
};
}
export function isExpectingScrollEvent(movement: AxisMovement): boolean {
return Object.values(movement).some(Boolean);
}
export function getExpectedEvents(movement: AxisMovement): Event[] {
return isExpectingScrollEvent(movement)
? [
{
type: 'scroll event',
...movement,
},
]
: [];
}
export const firePointer = (() => {
type TTarget = Element | Window | Document;
function makeDispatch(eventName: string) {
return function dispatch(target: TTarget, input: Partial<Input> = {}): void {
const inputWithDefaults = {
...getDefaultInput(),
...input,
};
target.dispatchEvent(
new MouseEvent(eventName, {
bubbles: true,
cancelable: true,
...inputWithDefaults,
}),
);
};
}
return {
down: makeDispatch('pointerdown'),
up: makeDispatch('pointerup'),
move: makeDispatch('pointermove'),
cancel: makeDispatch('pointercancel'),
};
})();
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/allowed-axis.spec.ts
================================================
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import { autoScrollForElements } from '../../../src/entry-point/element';
import { type AllowedAxis } from '../../../src/internal-types';
import {
advanceTimersToNextFrame,
appendToBody,
type AxisScroll,
type Event,
getAxisScroll,
getExpectedEvents,
getScenarios,
hasAxisScrolled,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
setupNestedScrollContainers,
stepScrollBy,
userEvent,
} from '../_util';
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
describe('allowed axis', () => {
const { child, parentScrollContainer: parent } = setupBasicScrollContainer();
const originalScrollTop = parent.scrollTop;
const originalScrollLeft = parent.scrollLeft;
afterEach(() => {
parent.scrollTop = originalScrollTop;
parent.scrollLeft = originalScrollLeft;
});
getScenarios(parent.getBoundingClientRect()).forEach(
({ label, startPosition, expectedMovement }) => {
it(`should only scroll on axis that are allowed - ${label}`, () => {
const events: Event[] = [];
let allowedAxis: AllowedAxis = 'all';
let axisScroll: AxisScroll;
const cleanup = combine(
appendToBody(parent),
draggable({
element: child,
onDragStart: () => events.push({ type: 'draggable:start' }),
}),
dropTargetForElements({
element: child,
onDragStart: () => events.push({ type: 'dropTarget:start' }),
}),
autoScrollForElements({
element: parent,
getAllowedAxis: () => allowedAxis,
}),
setElementFromPoint(child),
bind(parent, {
type: 'scroll',
listener: (event) => {
events.push({
type: 'scroll event',
...hasAxisScrolled(parent, axisScroll),
});
axisScroll = getAxisScroll(parent);
},
}),
);
// Scroll container is now looking over the center of the element
parent.scrollTop = 500;
parent.scrollLeft = 500;
axisScroll = getAxisScroll(parent);
userEvent.lift(child, {
clientX: startPosition.x,
clientY: startPosition.y,
});
expect(events).toEqual([{ type: 'draggable:start' }, { type: 'dropTarget:start' }]);
events.length = 0;
// First frame: allowedAxis is all.
// Expecting no scroll to occur.
// We don't know what the scroll speed should be until a single frame has passed.
advanceTimersToNextFrame();
stepScrollBy();
expect(events).toEqual([]);
// Second frame: allowedAxis is all.
// Expecting a scroll to occur on expected axis.
advanceTimersToNextFrame();
stepScrollBy();
const movement = { ...expectedMovement };
const expectedEvents = getExpectedEvents(movement);
expect(events).toEqual(expectedEvents);
events.length = 0;
// Third frame: allowedAxis is vertical.
// Expecting a scroll to occur on expected axis, except horizontal.
// If neither are expected, expect no scroll.
allowedAxis = 'vertical';
advanceTimersToNextFrame();
stepScrollBy();
const verticalMovement = {
...expectedMovement,
horizontal: false,
};
const expectedVerticalEvents = getExpectedEvents(verticalMovement);
expect(events).toEqual(expectedVerticalEvents);
events.length = 0;
// Fourth frame: allowedAxis is horizontal.
// Expecting a scroll to occur on expected axis, except vertical.
// If neither are expected, expect no scroll.
allowedAxis = 'horizontal';
advanceTimersToNextFrame();
stepScrollBy();
const horizontalMovement = {
...expectedMovement,
vertical: false,
};
const expectedHorizontalEvents = getExpectedEvents(horizontalMovement);
expect(events).toEqual(expectedHorizontalEvents);
cleanup();
});
},
);
});
it('should scroll on available parent axis if child axis are not allowed', () => {
const [child, parent, grandParent] = setupNestedScrollContainers([
{ width: 10000, height: 10000 },
{ width: 1000, height: 1000 },
{ width: 1000, height: 1000 },
]);
const events: Event[] = [];
let parentAllowedAxis: AllowedAxis = 'all';
let parentAxisScroll: AxisScroll;
let grandParentAllowedAxis: AllowedAxis = 'all';
let grandParentAxisScroll: AxisScroll;
const cleanup = combine(
appendToBody(grandParent),
draggable({
element: child,
onDragStart: () => events.push({ type: 'draggable:start' }),
}),
dropTargetForElements({
element: child,
onDragStart: () => events.push({ type: 'dropTarget:start' }),
}),
dropTargetForElements({
element: parent,
onDragStart: () => events.push({ type: 'parent:start' }),
}),
dropTargetForElements({
element: grandParent,
onDragStart: () => events.push({ type: 'grandParent:start' }),
}),
autoScrollForElements({
element: parent,
getAllowedAxis: () => parentAllowedAxis,
}),
autoScrollForElements({
element: grandParent,
getAllowedAxis: () => grandParentAllowedAxis,
}),
setElementFromPoint(child),
bind(parent, {
type: 'scroll',
listener: (event) => {
events.push({
type: 'parent:scroll',
...hasAxisScrolled(parent, parentAxisScroll),
});
parentAxisScroll = getAxisScroll(parent);
},
}),
bind(grandParent, {
type: 'scroll',
listener: (event) => {
events.push({
type: 'grandParent:scroll',
...hasAxisScrolled(grandParent, grandParentAxisScroll),
});
grandParentAxisScroll = getAxisScroll(grandParent);
},
}),
);
// Set some initial scroll on the scroll containers
parent.scrollTop = 60;
parent.scrollLeft = 60;
parentAxisScroll = getAxisScroll(parent);
grandParent.scrollTop = 120;
grandParent.scrollLeft = 120;
grandParentAxisScroll = getAxisScroll(grandParent);
// Lifting the shared top left corner
userEvent.lift(child, {
clientX: grandParent.getBoundingClientRect().left,
clientY: grandParent.getBoundingClientRect().top,
});
expect(events).toEqual([
{ type: 'draggable:start' },
{ type: 'dropTarget:start' },
{ type: 'parent:start' },
{ type: 'grandParent:start' },
]);
events.length = 0;
// First frame: parent allowedAxis is all, grandparent allowedAxis is all.
// Expecting no scroll to occur.
// We don't know what the scroll speed should be until a single frame has passed.
advanceTimersToNextFrame();
stepScrollBy();
expect(events).toEqual([]);
// Second frame: parent allowedAxis is all, grandparent allowedAxis is all.
// Expecting a scroll to occur on both parent axis.
advanceTimersToNextFrame();
stepScrollBy();
expect(events).toEqual([{ type: 'parent:scroll', horizontal: true, vertical: true }]);
events.length = 0;
// Third frame: parent allowedAxis is vertical, grandparent allowedAxis is all.
// Expecting a scroll to occur on parent vertical axis, but not horizontal.
// Expecting a scroll to occur on grandparent horizontal axis, but not vertical.
parentAllowedAxis = 'vertical';
grandParentAllowedAxis = 'all';
advanceTimersToNextFrame();
stepScrollBy();
expect(events).toEqual([
{ type: 'parent:scroll', horizontal: false, vertical: true },
{ type: 'grandParent:scroll', horizontal: true, vertical: false },
]);
events.length = 0;
// Fourth frame: parent allowedAxis is horizontal, grandparent allowedAxis is all.
// Expecting a scroll to occur on parent horizontal axis, but not vertical.
// Expecting a scroll to occur on grandparent vertical axis, but not horizontal.
parentAllowedAxis = 'horizontal';
grandParentAllowedAxis = 'all';
advanceTimersToNextFrame();
stepScrollBy();
expect(events).toEqual([
{ type: 'parent:scroll', horizontal: true, vertical: false },
{ type: 'grandParent:scroll', horizontal: false, vertical: true },
]);
events.length = 0;
cleanup();
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/can-scroll.spec.ts
================================================
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { autoScrollForElements } from '../../../src/entry-point/element';
import {
advanceTimersToNextFrame,
appendToBody,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
userEvent,
} from '../_util';
// Using modern timers as it is important that the system clock moves in sync with the frames.
// We need this as we are keeping track of when a drop target is entered into.
jest.useFakeTimers();
setStartSystemTime();
beforeEach(reset);
it('should not scroll scroll containers that have canScroll: () => false', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
let isAutoScrollingAllowed: boolean = true;
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
}),
autoScrollForElements({
element: parentScrollContainer,
canScroll: () => isAutoScrollingAllowed,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener: () => ordered.push('scroll event'),
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollTop = 500;
parentScrollContainer.scrollLeft = 500;
userEvent.lift(child, { clientX: 1, clientY: 1 });
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// Second frame: an auto scroll will occur
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// disabling auto scrolling for the third frame
// expecting no scroll will occur
isAutoScrollingAllowed = false;
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// enabling auto scrolling for the third frame
// expecting a scroll to occur
isAutoScrollingAllowed = true;
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
cleanup();
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/distance-dampening.spec.ts
================================================
import { fireEvent } from '@testing-library/dom';
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import { autoScrollForElements } from '../../../src/entry-point/element';
import { type Axis, type Side } from '../../../src/internal-types';
import { axisLookup } from '../../../src/shared/axis';
import { getInternalConfig } from '../../../src/shared/configuration';
import {
advanceTimersToNextFrame,
appendToBody,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
tryGetRect,
userEvent,
} from '../_util';
// Using modern timers as it is important that the system clock moves in sync with the frames.
// We need this as we are keeping track of when a drop target is entered into.
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
const defaultConfig = getInternalConfig();
const maxScrollPerFrame = defaultConfig.maxPixelScrollPerSecond / 60;
type Scenario = {
side: Side;
axis: Axis;
};
const scenarios: Scenario[] = [
{
axis: 'vertical',
side: 'start',
},
{
axis: 'vertical',
side: 'end',
},
{
axis: 'horizontal',
side: 'start',
},
{
axis: 'horizontal',
side: 'end',
},
];
scenarios.forEach(({ axis, side }) => {
const scrollProperty = axis === 'vertical' ? 'scrollTop' : 'scrollLeft';
const mainAxisClientPoint = axis === 'vertical' ? 'clientY' : 'clientX';
const crossAxisClientPoint = mainAxisClientPoint === 'clientY' ? 'clientX' : 'clientY';
const { mainAxis, crossAxis } = axisLookup[axis];
it(`should dampen acceleration based on the distance away from an edge [axis: ${axis}, side: ${side}]`, () => {
const { parentScrollContainer, child } = setupBasicScrollContainer({
scrollContainer: { width: 1000, height: 1000 },
// giving us enough room to slowly move down through the hitbox
child: { width: 20000, height: 20000 },
});
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// setting initial scroll
parentScrollContainer[scrollProperty] = child.getBoundingClientRect()[mainAxis.size] / 2;
const parentRect = parentScrollContainer.getBoundingClientRect();
userEvent.lift(child, {
// start or end point on main axis
[mainAxisClientPoint]: parentRect[mainAxis[side]],
// half way point
[crossAxisClientPoint]: parentRect[crossAxis.start] + parentRect[crossAxis.size] / 2,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// on second frame we get our first auto scroll
{
const before = parentScrollContainer[scrollProperty];
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer[scrollProperty];
// end side = scroll amount will increase
// start side = scroll amount will decrease
expect(after - before).toBe(side === 'end' ? 1 : -1);
}
// fast forward so there is no more time dampening
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
ordered.length = 0;
// now expecting to be moving at the maximum speed
const maxScrollInDirection = side === 'end' ? maxScrollPerFrame : -maxScrollPerFrame;
{
const before = parentScrollContainer[scrollProperty];
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer[scrollProperty];
// end side = scroll amount will increase
// start side = scroll amount will decrease
expect(after - before).toBe(maxScrollInDirection);
}
// Okay, we now know that the time dampening is finished
// Let's start our actual test! 😅
const autoScrollHitbox = tryGetRect({
[crossAxis.start]: parentRect[crossAxis.start],
[crossAxis.end]: parentRect[crossAxis.end],
[mainAxis.start]:
side === 'start'
? parentRect[mainAxis.start]
: parentRect[mainAxis.end] - defaultConfig.maxMainAxisHitboxSize,
[mainAxis.end]:
side === 'start'
? parentRect[mainAxis.start] + defaultConfig.maxMainAxisHitboxSize
: parentRect[mainAxis.end],
});
// 1. scroll up to the `startHitboxAtPercentageRemainingOfElement`
// - expect scroll to get bigger as we get closer to edge
const maxSpeedBuffer =
autoScrollHitbox[mainAxis.size] *
defaultConfig.maxScrollAtPercentageRemainingOfHitbox[mainAxis[side]];
// we are currently at the max scroll speed
let previousChange = maxScrollInDirection;
// side: 'start' → moving from the end of the hitbox upwards
// side: 'end' → moving from the start of the hitbox downwards
let currentMainAxisClientPoint =
side === 'start' ? autoScrollHitbox[mainAxis.end] : autoScrollHitbox[mainAxis.start];
const casesHit = {
first: false,
accelerating: [] as number[],
inMaxSpeedBuffer: false,
};
// Move through the hitbox
// side: 'start' → moving from the end of the hitbox upwards
// side: 'end' → moving from the start of the hitbox downwards
while (
side === 'start'
? autoScrollHitbox[mainAxis.start] <= currentMainAxisClientPoint
: currentMainAxisClientPoint <= autoScrollHitbox[mainAxis.end]
) {
fireEvent.dragOver(child, {
[mainAxisClientPoint]: currentMainAxisClientPoint,
[crossAxisClientPoint]: parentRect[crossAxis.start] + parentRect[crossAxis.size] / 2,
});
// the new drag location will not be picked up until the second frame
// after a user input change.
// frame 1: dragOver is throttled
{
const before = parentScrollContainer[scrollProperty];
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer[scrollProperty];
const diff = after - before;
// diff has not changed as we are still using the old input for this frame
expect(previousChange).toBe(diff);
}
// second frame: a scroll should occur based on the updated input
{
const before = parentScrollContainer[scrollProperty];
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer[scrollProperty];
const diff = after - before;
const situation = (() => {
if (!casesHit.first) {
return 'first';
}
// accelerating forwards
if (
side === 'end' &&
currentMainAxisClientPoint < autoScrollHitbox[mainAxis.end] - maxSpeedBuffer
) {
return 'accelerating';
}
// accelerating backwards
if (
side === 'start' &&
currentMainAxisClientPoint > autoScrollHitbox[mainAxis.start] + maxSpeedBuffer
) {
return 'accelerating';
}
return 'in-max-speed-buffer';
})();
// first hit: starting from the smallest scroll amount
if (situation === 'first') {
// side: start → scrolling backwards
// side: start → scrolling forwards
expect(diff).toBe(side === 'start' ? -1 : 1);
casesHit.first = true;
// when the acceleration percentage is less than 1,
// we will roll up to the minimum scroll change of 1px
} else if (situation === 'accelerating') {
casesHit.accelerating.push(diff);
// Using 'or equal to' because scrolls under 1% can result in the minimum scroll of 1px
// There is an assertion outside of this loop to ensure that an acceleration occurred
// scrolling forwards: scroll value is growing
if (side === 'end') {
expect(diff).toBeGreaterThanOrEqual(previousChange);
} else {
// scrolling forwards: scroll value is shrinking
expect(diff).toBeLessThanOrEqual(previousChange);
}
// third case: we are in the max speed buffer
} else {
casesHit.inMaxSpeedBuffer = true;
expect(diff).toBe(maxScrollInDirection);
}
previousChange = diff;
// side: end → scrolling forwards and moving forwards through hitbox
if (side === 'end') {
currentMainAxisClientPoint++;
// side: start → scrolling backwards and moving forwards through hitbox
} else {
currentMainAxisClientPoint--;
}
}
}
expect(casesHit.first).toBe(true);
expect(casesHit.accelerating.length).toBeGreaterThan(0);
expect(casesHit.inMaxSpeedBuffer).toBe(true);
// asserting that acceleration occurred, and that we where not just on a single speed
{
const uniques = Array.from(new Set(casesHit.accelerating.map((value) => Math.round(value))));
const expected = Array.from({ length: maxScrollPerFrame }, (_, index) => {
const value = index + 1;
return side === 'end' ? value : -value;
});
expect(uniques).toEqual(expected);
}
cleanup();
});
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/hitbox.spec.ts
================================================
import { bind } from 'bind-event-listener';
import invariant from 'tiny-invariant';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import { autoScrollForElements } from '../../../src/entry-point/element';
import type { Axis, Side } from '../../../src/internal-types';
import { axisLookup } from '../../../src/shared/axis';
import { getInternalConfig } from '../../../src/shared/configuration';
import {
advanceTimersToNextFrame,
appendToBody,
getInsidePoints,
getOutsidePoints,
getRect,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
userEvent,
} from '../_util';
type Scenario = {
side: Side;
hitbox: DOMRect;
axis: Axis;
};
type Group = {
label: string;
child: HTMLElement;
parentScrollContainer: HTMLElement;
scenarios: Scenario[];
};
const defaultConfig = getInternalConfig();
const smallGroup: Group = (() => {
const { child, parentScrollContainer } = setupBasicScrollContainer({
// where a hitbox would be less than `defaultConfig.max
scrollContainer: { width: 400, height: 400 },
child: { width: 100000, height: 100000 },
});
const rect = parentScrollContainer.getBoundingClientRect();
const scenarios: Scenario[] = [
{
side: 'start',
axis: 'vertical',
hitbox: getRect({
top: rect.top,
left: rect.left,
bottom:
rect.top + rect.height * defaultConfig.startHitboxAtPercentageRemainingOfElement['top'],
right: rect.right,
}),
},
{
side: 'end',
axis: 'vertical',
hitbox: getRect({
top:
rect.bottom -
rect.height * defaultConfig.startHitboxAtPercentageRemainingOfElement['bottom'],
left: rect.left,
bottom: rect.bottom,
right: rect.right,
}),
},
{
side: 'start',
axis: 'horizontal',
hitbox: getRect({
top: rect.top,
left: rect.left,
bottom: rect.bottom,
right:
rect.left + rect.width * defaultConfig.startHitboxAtPercentageRemainingOfElement['top'],
}),
},
{
side: 'end',
axis: 'horizontal',
hitbox: getRect({
top: rect.top,
left:
rect.right -
rect.width * defaultConfig.startHitboxAtPercentageRemainingOfElement['bottom'],
bottom: rect.bottom,
right: rect.right,
}),
},
];
// validating all hitboxes are less than 200px in size
scenarios.forEach((scenario) => {
const { mainAxis } = axisLookup[scenario.axis];
const size =
scenario.hitbox[mainAxis.size] *
defaultConfig.startHitboxAtPercentageRemainingOfElement[mainAxis[scenario.side]];
invariant(
size < defaultConfig.maxMainAxisHitboxSize,
'Expected hitbox to be less than the max hitbox size',
);
});
return {
label: 'Small scroll container',
scenarios,
child,
parentScrollContainer,
};
})();
const largeGroup: Group = (() => {
const { child, parentScrollContainer } = setupBasicScrollContainer({
scrollContainer: { width: 10000, height: 10000 },
child: { width: 100000, height: 100000 },
});
const rect = parentScrollContainer.getBoundingClientRect();
const scenarios: Scenario[] = [
{
side: 'start',
axis: 'vertical',
hitbox: getRect({
top: rect.top,
left: rect.left,
bottom: rect.top + defaultConfig.maxMainAxisHitboxSize,
right: rect.right,
}),
},
{
side: 'end',
axis: 'vertical',
hitbox: getRect({
top: rect.bottom - defaultConfig.maxMainAxisHitboxSize,
left: rect.left,
bottom: rect.bottom,
right: rect.right,
}),
},
{
side: 'start',
axis: 'horizontal',
hitbox: getRect({
top: rect.top,
left: rect.left,
bottom: rect.bottom,
right: rect.left + defaultConfig.maxMainAxisHitboxSize,
}),
},
{
side: 'end',
axis: 'horizontal',
hitbox: getRect({
top: rect.top,
left: rect.right - defaultConfig.maxMainAxisHitboxSize,
bottom: rect.bottom,
right: rect.right,
}),
},
];
// validating all hitboxes would be greater than `defaultConfig.maxMainAxisHitboxSize`
// (and so will be capped to defaultConfig.maxMainAxisHitboxSize later)
scenarios.forEach((scenario) => {
const { mainAxis } = axisLookup[scenario.axis];
const potentialHitboxSize =
rect[mainAxis.size] *
defaultConfig.startHitboxAtPercentageRemainingOfElement[mainAxis[scenario.side]];
invariant(
potentialHitboxSize > defaultConfig.maxMainAxisHitboxSize,
`hitbox size: (${potentialHitboxSize}) is not > (${defaultConfig.maxMainAxisHitboxSize})`,
);
});
return {
label: `Large scroll container (will be capped to ${defaultConfig.maxMainAxisHitboxSize}px hitbox)`,
scenarios,
child,
parentScrollContainer,
};
})();
// Using modern timers as it is important that the system clock moves in sync with the frames.
// We need this as we are keeping track of when a drop target is entered into.
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
[smallGroup, largeGroup].forEach(({ label, parentScrollContainer, child, scenarios }) => {
describe(`Group: ${label}`, () => {
const originalScrollTop = parentScrollContainer.scrollTop;
const originalScrollLeft = parentScrollContainer.scrollLeft;
afterEach(() => {
parentScrollContainer.scrollTop = originalScrollTop;
parentScrollContainer.scrollLeft = originalScrollLeft;
});
scenarios.forEach((scenario) => {
const { mainAxis } = axisLookup[scenario.axis];
const scrollProperty = scenario.axis === 'vertical' ? 'scrollTop' : 'scrollLeft';
describe(`axis: ${scenario.axis}, side: ${scenario.side} [on boundary]`, () => {
getInsidePoints(scenario.hitbox).forEach((point) => {
test(`point: [${point.label}] {x: ${point.x}, y: ${point.y}}`, () => {
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// Scroll container is now looking over the center of the element
const initialScrollValue = child.getBoundingClientRect()[mainAxis.size] / 2;
parentScrollContainer[scrollProperty] = initialScrollValue;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX: point.x,
clientY: point.y,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer[scrollProperty]).toBe(initialScrollValue);
// Triggering another auto scroll - should be the minimum scroll
{
const before = parentScrollContainer[scrollProperty];
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer[scrollProperty];
// only a single scroll event
expect(ordered).toEqual(['scroll event']);
// Scrolling up → scroll value will get lower
// Scrolling down → scroll value will get higher
// Scrolling on the "start" will scroll backwards
// Scrolling on the "end" will scroll forwards
expect(after - before).toBe(scenario.side === 'start' ? -1 : 1);
}
cleanup();
});
});
});
describe(`axis: ${scenario.axis}, side: ${scenario.side} [outside boundary]`, () => {
getOutsidePoints(scenario.hitbox).forEach((point) => {
test(`point: [${point.label}] {x: ${point.x}, y: ${point.y}}`, () => {
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// Scroll container is now looking over the center of the element
const initialScrollValue = child.getBoundingClientRect()[mainAxis.size] / 2;
parentScrollContainer[scrollProperty] = initialScrollValue;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX: point.x,
clientY: point.y,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer[scrollProperty]).toBe(initialScrollValue);
// No auto scroll should be triggered in the next frame
{
const before = parentScrollContainer[scrollProperty];
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer[scrollProperty];
// only a single scroll event
// expect(ordered).toEqual(['scroll event']);
// Scrolling up → scroll value will get lower
// Scrolling down → scroll value will get higher
// Scrolling on the "start" will scroll backwards
// Scrolling on the "end" will scroll forwards
expect(after - before).toBe(0);
}
cleanup();
});
});
});
});
});
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/max-speed.spec.ts
================================================
import { fireEvent } from '@testing-library/dom';
import { bind } from 'bind-event-listener';
import { replaceRaf } from 'raf-stub';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import { autoScrollForElements } from '../../../src/entry-point/element';
import { getInternalConfig } from '../../../src/shared/configuration';
import { appendToBody, reset, setElementFromPoint, setupBasicScrollContainer } from '../_util';
// need to use "legacy" timers so we can control
// the exact amount of time that passes for a frame.
// For "modern" jest timers, the frame rate is locked at 60fps
jest.useFakeTimers({ legacyFakeTimers: true });
replaceRaf();
const startTime = 0;
let currentTime: number = startTime;
jest.spyOn(Date, 'now').mockImplementation(() => currentTime);
beforeEach(reset);
beforeEach(() => {
// @ts-expect-error: raf-stub
requestAnimationFrame.reset();
currentTime = startTime;
});
function stepFrame({ frameDuration }: { frameDuration: number }) {
currentTime += frameDuration;
// @ts-expect-error: raf-stub
requestAnimationFrame.step(1, frameDuration);
}
function stepScrollBy() {
// setTimeout(fn, 0) is released by `jest.advanceTimersByTime(0)` for "legacy" timers
jest.advanceTimersByTime(0);
}
const defaultConfig = getInternalConfig();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
it('should not scroll faster than the target 60fps scroll change on higher frame rate devices', () => {
const frameDuration120fps = 1000 / 120;
const { child, parentScrollContainer } = setupBasicScrollContainer({
child: { height: 10000, width: 10000 },
scrollContainer: { height: 500, width: 500 },
});
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push('scroll event');
},
}),
);
fireEvent.dragStart(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().bottom,
});
// @ts-expect-error: raf-stub
requestAnimationFrame.step(1, frameDuration120fps);
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame after starting, the auto scrolling will be collecting how long the frame took
// but there will be no scroll
stepFrame({ frameDuration: frameDuration120fps });
stepScrollBy();
expect(ordered).toEqual([]);
// Second frame: an auto scroll will occur
stepFrame({ frameDuration: frameDuration120fps });
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// ensure time dampening is finished
{
const loopStartTime = Date.now();
const hit = jest.fn();
while (Date.now() - loopStartTime <= defaultConfig.timeDampeningDurationMs) {
hit();
stepFrame({ frameDuration: frameDuration120fps });
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
}
expect(hit).toHaveBeenCalled();
}
const before = {
scrollTop: parentScrollContainer.scrollTop,
now: Date.now(),
};
stepFrame({ frameDuration: frameDuration120fps });
stepScrollBy();
const after = {
scrollTop: parentScrollContainer.scrollTop,
now: Date.now(),
};
// a scroll occurred
expect(ordered).toEqual(['scroll event']);
// slower than the 60fps speed
expect(after.scrollTop - before.scrollTop).toBeLessThan(
(defaultConfig.maxPixelScrollPerSecond / 1000) * 60,
);
// adjusted the speed for 120fps
const targetScrollPerMs = defaultConfig.maxPixelScrollPerSecond / 1000;
expect(after.scrollTop - before.scrollTop).toBe(
Math.ceil(targetScrollPerMs * frameDuration120fps),
);
cleanup();
});
it('should not make a scroll change bigger than the target 60fps scroll change when running at lower than 60fps', () => {
const frameDuration30fps = 1000 / 30;
const { child, parentScrollContainer } = setupBasicScrollContainer({
child: { height: 10000, width: 10000 },
scrollContainer: { height: 500, width: 500 },
});
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push('scroll event');
},
}),
);
fireEvent.dragStart(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().bottom,
});
stepFrame({ frameDuration: frameDuration30fps });
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame after starting, the auto scrolling will be collecting how long the frame took
// but there will be no scroll
stepFrame({ frameDuration: frameDuration30fps });
stepScrollBy();
expect(ordered).toEqual([]);
// Second frame: an auto scroll will occur
stepFrame({ frameDuration: frameDuration30fps });
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// ensure time dampening is finished
{
const loopStartTime = Date.now();
const hit = jest.fn();
while (Date.now() - loopStartTime <= defaultConfig.timeDampeningDurationMs) {
hit();
stepFrame({ frameDuration: frameDuration30fps });
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
}
expect(hit).toHaveBeenCalled();
}
const before = {
scrollTop: parentScrollContainer.scrollTop,
now: Date.now(),
};
stepFrame({ frameDuration: frameDuration30fps });
stepScrollBy();
const after = {
scrollTop: parentScrollContainer.scrollTop,
now: Date.now(),
};
// a scroll occurred
expect(ordered).toEqual(['scroll event']);
// the same scroll change as if scrolling at 60fps
const targetScrollPerMs = defaultConfig.maxPixelScrollPerSecond / 1000;
const frameDuration60fps = 1000 / 60;
// Accounting for javascript precision inaccuracy caused by `1000 / 60`
expect(after.scrollTop - before.scrollTop).toBeCloseTo(targetScrollPerMs * frameDuration60fps, 1);
cleanup();
});
it('should allow the max speed to be configured', () => {
const frameDuration60fps = 1000 / 60;
const config = getInternalConfig({ maxScrollSpeed: 'fast' });
let maxScrollSpeed: 'fast' | 'standard' = 'fast';
// validation that our scroll speed will be faster
expect(config.maxPixelScrollPerSecond).toBeGreaterThan(defaultConfig.maxPixelScrollPerSecond);
const { child, parentScrollContainer } = setupBasicScrollContainer({
child: { height: 10000, width: 10000 },
scrollContainer: { height: 500, width: 500 },
});
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
}),
autoScrollForElements({
element: parentScrollContainer,
getConfiguration: () => ({
maxScrollSpeed,
}),
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push('scroll event');
},
}),
);
fireEvent.dragStart(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().bottom,
});
// @ts-expect-error: raf-stub
requestAnimationFrame.step(1, frameDuration60fps);
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame after starting, the auto scrolling will be collecting how long the frame took
// but there will be no scroll
stepFrame({ frameDuration: frameDuration60fps });
stepScrollBy();
expect(ordered).toEqual([]);
// Second frame: an auto scroll will occur
stepFrame({ frameDuration: frameDuration60fps });
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// ensure time dampening is finished
{
const loopStartTime = Date.now();
const hit = jest.fn();
while (Date.now() - loopStartTime <= defaultConfig.timeDampeningDurationMs) {
hit();
stepFrame({ frameDuration: frameDuration60fps });
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
}
expect(hit).toHaveBeenCalled();
}
{
const before = {
scrollTop: parentScrollContainer.scrollTop,
};
stepFrame({ frameDuration: frameDuration60fps });
stepScrollBy();
const after = {
scrollTop: parentScrollContainer.scrollTop,
};
// a scroll occurred
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// running at maximum "fast" speed
const targetScrollPerMs = config.maxPixelScrollPerSecond / 1000;
expect(after.scrollTop - before.scrollTop).toBeCloseTo(
// Accounting for javascript precision inaccuracy caused by:
// - `1000 / 60`
// - `after.scrollTop - before.scrollTop`
targetScrollPerMs * frameDuration60fps,
1,
);
}
// changing from "fast" to "standard" scroll speed during a drag
{
maxScrollSpeed = 'standard';
const before = {
scrollTop: parentScrollContainer.scrollTop,
};
stepFrame({ frameDuration: frameDuration60fps });
stepScrollBy();
const after = {
scrollTop: parentScrollContainer.scrollTop,
};
// a scroll occurred
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// running at maximum "standard" speed
const targetScrollPerMs = defaultConfig.maxPixelScrollPerSecond / 1000;
expect(after.scrollTop - before.scrollTop).toBeCloseTo(
// Accounting for javascript precision inaccuracy caused by:
// - `1000 / 60`
// - `after.scrollTop - before.scrollTop`
targetScrollPerMs * frameDuration60fps,
1,
);
}
cleanup();
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/nested-scroll-containers.spec.ts
================================================
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { type Position } from '@atlaskit/pragmatic-drag-and-drop/types';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import { autoScrollForElements } from '../../../src/entry-point/element';
import { isWithin } from '../../../src/shared/is-within'; // this internal util is helpful for what we are trying to do
import {
advanceTimersToNextFrame,
appendToBody,
reset,
setElementFromPoint,
setStartSystemTime,
setupNestedScrollContainers,
stepScrollBy,
userEvent,
} from '../_util';
// Using modern timers as it is important that the system clock moves in sync with the frames.
// We need this as we are keeping track of when a drop target is entered into.
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
it('should scroll inner elements before outer elements [single axis]', () => {
const [child, parent, grandParent] = setupNestedScrollContainers([
// child
{ width: 10000, height: 10000 },
// parent
{ width: 5000, height: 5000 },
// grandparent,
{ width: 1000, height: 1000 },
]);
const ordered: string[] = [];
const cleanup = combine(
appendToBody(grandParent),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('child:start'),
onDrop: () => ordered.push('child:drop'),
}),
dropTargetForElements({
element: parent,
onDragStart: () => ordered.push('parent:start'),
onDrop: () => ordered.push('parent:drop'),
}),
dropTargetForElements({
element: grandParent,
onDragStart: () => ordered.push('grandParent:start'),
onDrop: () => ordered.push('grandParent:drop'),
}),
autoScrollForElements({
element: parent,
}),
autoScrollForElements({
element: grandParent,
}),
setElementFromPoint(child),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === grandParent) {
ordered.push('grandParent:scroll');
return;
}
if (event.target === parent) {
// console.log('parent', parent.scrollTop, parent.scrollLeft);
ordered.push('parent:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
// Set some initial scroll on the scroll containers
// These are in the range where auto scrolling will occur on both
parent.scrollTop = 60;
grandParent.scrollTop = 120;
// lifting the mid point of the top edge
userEvent.lift(child, {
clientX:
grandParent.getBoundingClientRect().left + grandParent.getBoundingClientRect().width / 2,
clientY: grandParent.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'child:start', 'parent:start', 'grandParent:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
{
const hit = jest.fn();
while (parent.scrollTop > 0) {
hit();
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual(['parent:scroll']);
ordered.length = 0;
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
// Now it will scroll the grand parent until it's finished
{
const hit = jest.fn();
while (grandParent.scrollTop > 0) {
hit();
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual(['grandParent:scroll']);
ordered.length = 0;
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
cleanup();
});
it('should scroll inner elements before outer elements [both axis at a time]', () => {
const [child, parent, grandParent] = setupNestedScrollContainers([
// child
{ width: 10000, height: 10000 },
// parent
{ width: 5000, height: 5000 },
// grandParent,
{ width: 1000, height: 1000 },
]);
const ordered: string[] = [];
const cleanup = combine(
appendToBody(grandParent),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('child:start'),
onDrop: () => ordered.push('child:drop'),
}),
dropTargetForElements({
element: parent,
onDragStart: () => ordered.push('parent:start'),
onDrop: () => ordered.push('parent:drop'),
}),
dropTargetForElements({
element: grandParent,
onDragStart: () => ordered.push('grandParent:start'),
onDrop: () => ordered.push('grandParent:drop'),
}),
autoScrollForElements({
element: parent,
}),
autoScrollForElements({
element: grandParent,
}),
setElementFromPoint(child),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === grandParent) {
ordered.push('grandParent:scroll');
return;
}
if (event.target === parent) {
// console.log('parent', parent.scrollTop, parent.scrollLeft);
ordered.push('parent:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
// Set some initial scroll on the scroll containers
parent.scrollTop = 60;
parent.scrollLeft = 60;
grandParent.scrollTop = 120;
grandParent.scrollLeft = 120;
// lifting the shared top left corner
userEvent.lift(child, {
clientX: grandParent.getBoundingClientRect().left,
clientY: grandParent.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'child:start', 'parent:start', 'grandParent:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
{
const hit = jest.fn();
while (parent.scrollTop > 0) {
hit();
const before = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
advanceTimersToNextFrame();
stepScrollBy();
const after = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
// only the parent scrolled
expect(ordered).toEqual(['parent:scroll']);
ordered.length = 0;
// asserting we scrolled in both directions
expect(before.scrollTop).toBeGreaterThan(after.scrollTop);
expect(before.scrollLeft).toBeGreaterThan(after.scrollLeft);
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
// Now it will scroll the grand parent until it's finished
{
const hit = jest.fn();
while (grandParent.scrollTop > 0) {
hit();
const before = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
advanceTimersToNextFrame();
stepScrollBy();
const after = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
// only the grandParent scrolled
expect(ordered).toEqual(['grandParent:scroll']);
ordered.length = 0;
// asserting we scrolled in both directions
expect(before.scrollTop).toBeGreaterThan(after.scrollTop);
expect(before.scrollLeft).toBeGreaterThan(after.scrollLeft);
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
cleanup();
});
it('should only scroll one scroll container per axis [case: inner is scrolling on vertical, parent on both]', () => {
const [child, parent, grandParent] = setupNestedScrollContainers([
// child
{ width: 10000, height: 10000 },
// parent
{ width: 5000, height: 5000 },
// grandparent,
{ width: 1000, height: 1000 },
]);
const ordered: string[] = [];
const cleanup = combine(
appendToBody(grandParent),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('child:start'),
onDrop: () => ordered.push('child:drop'),
}),
dropTargetForElements({
element: parent,
onDragStart: () => ordered.push('parent:start'),
onDrop: () => ordered.push('parent:drop'),
}),
dropTargetForElements({
element: grandParent,
onDragStart: () => ordered.push('grandParent:start'),
onDrop: () => ordered.push('grandParent:drop'),
}),
autoScrollForElements({
element: parent,
}),
autoScrollForElements({
element: grandParent,
}),
setElementFromPoint(child),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === grandParent) {
ordered.push('grandParent:scroll');
return;
}
if (event.target === parent) {
// console.log('parent', parent.scrollTop, parent.scrollLeft);
ordered.push('parent:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
// These values are more magic than I originally planned 😅
// Small amount of scroll on the parent (should finish first)
parent.scrollTop = 10;
// → No available scroll on the left
// Larger amount on the grand parent
// (due to lift point this will accelerate faster than parent)
grandParent.scrollTop = 80;
grandParent.scrollLeft = 80;
const client: Position = {
x: grandParent.getBoundingClientRect().left,
y: grandParent.getBoundingClientRect().top,
};
// validating setup
expect(isWithin({ client, clientRect: parent.getBoundingClientRect() })).toBe(true);
expect(isWithin({ client, clientRect: grandParent.getBoundingClientRect() })).toBe(true);
// lifting the top left corner
userEvent.lift(child, {
clientX: client.x,
clientY: client.y,
});
expect(ordered).toEqual(['draggable:start', 'child:start', 'parent:start', 'grandParent:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// scroll the parent until it cannot scroll any more
{
const hit = jest.fn();
while (parent.scrollTop > 0) {
hit();
const parentBefore = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
const grandParentBefore = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
advanceTimersToNextFrame();
stepScrollBy();
const parentAfter = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
const grandParentAfter = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
// we scroll inner most elements outwards (bubble ordering)
expect(ordered).toEqual(['parent:scroll', 'grandParent:scroll']);
ordered.length = 0;
// parent scrolled on the top, but not on the left
expect(parentBefore.scrollTop).toBeGreaterThan(parentAfter.scrollTop);
expect(parentBefore.scrollLeft).toBe(parentAfter.scrollLeft);
// grand parent not permitted to scroll on the top, but can scroll on left
expect(grandParentBefore.scrollTop).toBe(grandParentAfter.scrollTop);
expect(grandParentBefore.scrollLeft).toBeGreaterThan(grandParentAfter.scrollLeft);
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
// finish off scrolling the grand parent
{
const hit = jest.fn();
while (grandParent.scrollTop > 0 || grandParent.scrollLeft > 0) {
hit();
const grandParentBefore = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
advanceTimersToNextFrame();
stepScrollBy();
const grandParentAfter = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
// only the grandParent scrolled
expect(ordered).toEqual(['grandParent:scroll']);
ordered.length = 0;
expect(grandParentBefore.scrollTop).toBeGreaterThan(grandParentAfter.scrollTop);
// There was already some scroll on the left, so expecting left
// will finish scrolling before the top
expect(grandParentBefore.scrollLeft).toBeGreaterThanOrEqual(grandParentAfter.scrollLeft);
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
cleanup();
});
it('should only scroll one scroll container per axis [case: inner is scrolling on horizontal, parent on both]', () => {
const [child, parent, grandParent] = setupNestedScrollContainers([
// child
{ width: 10000, height: 10000 },
// parent
{ width: 5000, height: 5000 },
// grandparent,
{ width: 1000, height: 1000 },
]);
const ordered: string[] = [];
const cleanup = combine(
appendToBody(grandParent),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('child:start'),
onDrop: () => ordered.push('child:drop'),
}),
dropTargetForElements({
element: parent,
onDragStart: () => ordered.push('parent:start'),
onDrop: () => ordered.push('parent:drop'),
}),
dropTargetForElements({
element: grandParent,
onDragStart: () => ordered.push('grandParent:start'),
onDrop: () => ordered.push('grandParent:drop'),
}),
autoScrollForElements({
element: parent,
}),
autoScrollForElements({
element: grandParent,
}),
setElementFromPoint(child),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === grandParent) {
ordered.push('grandParent:scroll');
return;
}
if (event.target === parent) {
ordered.push('parent:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
// These values are more magic than I originally planned 😅
// Small amount of scroll on the parent (should finish first)
parent.scrollLeft = 10;
// → No available scroll on the top
// Larger amount on the grand parent
// (due to lift point this will accelerate faster than parent)
grandParent.scrollTop = 80;
grandParent.scrollLeft = 80;
const client: Position = {
x: grandParent.getBoundingClientRect().left,
y: grandParent.getBoundingClientRect().top,
};
// validating setup
expect(isWithin({ client, clientRect: parent.getBoundingClientRect() })).toBe(true);
expect(isWithin({ client, clientRect: grandParent.getBoundingClientRect() })).toBe(true);
// lifting the top left corner
userEvent.lift(child, {
clientX: client.x,
clientY: client.y,
});
expect(ordered).toEqual(['draggable:start', 'child:start', 'parent:start', 'grandParent:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// scroll the parent until it cannot scroll any more
{
const hit = jest.fn();
while (parent.scrollLeft > 0) {
hit();
const parentBefore = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
const grandParentBefore = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
advanceTimersToNextFrame();
stepScrollBy();
const parentAfter = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
const grandParentAfter = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
// we scroll inner most elements outwards (bubble ordering)
expect(ordered).toEqual(['parent:scroll', 'grandParent:scroll']);
ordered.length = 0;
// parent scrolled on the left, but not on the top
expect(parentBefore.scrollLeft).toBeGreaterThan(parentAfter.scrollLeft);
expect(parentBefore.scrollTop).toBe(parentAfter.scrollTop);
// grand parent not permitted to scroll on the left, but can scroll on top
expect(grandParentBefore.scrollLeft).toBe(grandParentAfter.scrollLeft);
expect(grandParentBefore.scrollTop).toBeGreaterThan(grandParentAfter.scrollTop);
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
// finish off scrolling the grand parent
{
const hit = jest.fn();
while (grandParent.scrollTop > 0 || grandParent.scrollLeft > 0) {
hit();
const grandParentBefore = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
advanceTimersToNextFrame();
stepScrollBy();
const grandParentAfter = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
// only the grandParent scrolled
expect(ordered).toEqual(['grandParent:scroll']);
ordered.length = 0;
expect(grandParentBefore.scrollLeft).toBeGreaterThan(grandParentAfter.scrollLeft);
// There was already some scroll on the top, so expecting top
// will finish scrolling before the top
expect(grandParentBefore.scrollTop).toBeGreaterThanOrEqual(grandParentAfter.scrollTop);
}
expect(hit.mock.calls.length).toBeGreaterThan(1);
}
cleanup();
});
it('should ignore scroll containers that have `canScroll: () => false` [case: inner is scrolling on horizontal, parent on both]', () => {
const [child, parent, grandParent, greatGrandParent] = setupNestedScrollContainers([
// child
{ width: 10000, height: 10000 },
// parent
{ width: 8000, height: 8000 },
// grandparent,
{ width: 5000, height: 5000 },
// great grandparent,
{ width: 2000, height: 2000 },
]);
const ordered: string[] = [];
const cleanup = combine(
appendToBody(greatGrandParent),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('child:start'),
onDrop: () => ordered.push('child:drop'),
}),
dropTargetForElements({
element: parent,
onDragStart: () => ordered.push('parent:start'),
onDrop: () => ordered.push('parent:drop'),
}),
dropTargetForElements({
element: grandParent,
onDragStart: () => ordered.push('grandParent:start'),
onDrop: () => ordered.push('grandParent:drop'),
}),
dropTargetForElements({
element: greatGrandParent,
onDragStart: () => ordered.push('greatGrandParent:start'),
onDrop: () => ordered.push('greatGrandParent:drop'),
}),
autoScrollForElements({
element: parent,
}),
autoScrollForElements({
element: grandParent,
canScroll: () => false,
}),
autoScrollForElements({
element: greatGrandParent,
}),
setElementFromPoint(child),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === greatGrandParent) {
ordered.push('greatGrandParent:scroll');
return;
}
if (event.target === grandParent) {
ordered.push('grandParent:scroll');
return;
}
if (event.target === parent) {
// console.log('parent', parent.scrollTop, parent.scrollLeft);
ordered.push('parent:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
parent.scrollLeft = 20;
// no scroll available on the top side of the parent
grandParent.scrollTop = 30;
grandParent.scrollLeft = 30;
greatGrandParent.scrollTop = 40;
greatGrandParent.scrollLeft = 40;
// lifting the top left corner
userEvent.lift(child, {
clientX: greatGrandParent.getBoundingClientRect().left,
clientY: greatGrandParent.getBoundingClientRect().top,
});
expect(ordered).toEqual([
'draggable:start',
'child:start',
'parent:start',
'grandParent:start',
'greatGrandParent:start',
]);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// scroll the parent until it cannot scroll any more
const parentBefore = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
const grandParentBefore = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
const greatGrandParentBefore = {
scrollTop: greatGrandParent.scrollTop,
scrollLeft: greatGrandParent.scrollLeft,
};
advanceTimersToNextFrame();
stepScrollBy();
const parentAfter = {
scrollTop: parent.scrollTop,
scrollLeft: parent.scrollLeft,
};
const grandParentAfter = {
scrollTop: grandParent.scrollTop,
scrollLeft: grandParent.scrollLeft,
};
const greatGrandParentAfter = {
scrollTop: greatGrandParent.scrollTop,
scrollLeft: greatGrandParent.scrollLeft,
};
// we scroll inner most elements outwards (bubble ordering)
// grandParent is disabled, so it will be skipped
expect(ordered).toEqual(['parent:scroll', 'greatGrandParent:scroll']);
ordered.length = 0;
// parent scrolled on the left, but not on the top
expect(parentBefore.scrollLeft).toBeGreaterThan(parentAfter.scrollLeft);
expect(parentBefore.scrollTop).toBe(parentAfter.scrollTop);
// no changes to grandParent as scrolling is disabled
expect(grandParentBefore.scrollTop).toBe(grandParentAfter.scrollTop);
expect(grandParentBefore.scrollLeft).toBe(grandParentAfter.scrollLeft);
// great grand parent not permitted to scroll on the left, but can scroll on top
expect(greatGrandParentBefore.scrollLeft).toBe(greatGrandParentAfter.scrollLeft);
expect(greatGrandParentBefore.scrollTop).toBeGreaterThan(greatGrandParentAfter.scrollTop);
cleanup();
});
// TODO: could also add similar tests for scrolling forward, but they are proving extremely difficult to setup well
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/registration.spec.ts
================================================
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import { autoScrollForElements } from '../../../src/entry-point/element';
import {
advanceTimersToNextFrame,
appendToBody,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
userEvent,
} from '../_util';
// Using modern timers as it is important that the system clock moves in sync with the frames.
// We need this as we are keeping track of when a drop target is entered into.
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
it('should not scroll scrollable elements that are not registered', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
// not marking outerScrollContainer as a scroll container
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// setting an initial scroll
parentScrollContainer.scrollTop = 500;
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// on second frame - there would be a scroll is there was a registered scroll container
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
cleanup();
});
it('should not scroll scrollable elements that are no longer registered', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
const unbindAutoScrolling = autoScrollForElements({
element: parentScrollContainer,
});
// setting an initial scroll
parentScrollContainer.scrollTop = 500;
// top center of scroll container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// on second frame we will get a scroll
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// we will no longer get scroll updates after unregistered
unbindAutoScrolling();
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
cleanup();
});
it('should scroll scrollable elements are registered mid drag', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// setting an initial scroll
parentScrollContainer.scrollTop = 500;
// top center of scroll container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// on second frame there is no scroll
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
ordered.length = 0;
// there will be a registration for the third frame, so we will get a scroll
const unbindAutoScrolling = autoScrollForElements({
element: parentScrollContainer,
});
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual(['scroll event']);
unbindAutoScrolling();
cleanup();
});
it('should warn if an elements is registered but are not scrollable', () => {
const { child } = setupBasicScrollContainer();
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
const cleanup = autoScrollForElements({
element: child,
});
expect(warn).toHaveBeenCalled();
cleanup();
warn.mockRestore();
});
it('should log a warning if an existing registration exists for an element', () => {
const { parentScrollContainer } = setupBasicScrollContainer();
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
const cleanup1 = autoScrollForElements({
element: parentScrollContainer,
});
expect(warn).not.toHaveBeenCalled();
const cleanup2 = autoScrollForElements({
element: parentScrollContainer,
});
expect(warn).toHaveBeenCalled();
cleanup1();
cleanup2();
warn.mockRestore();
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/start.spec.ts
================================================
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { autoScrollForElements } from '../../../src/entry-point/element';
import {
advanceTimersToNextFrame,
appendToBody,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
userEvent,
} from '../_util';
jest.useFakeTimers();
setStartSystemTime();
beforeEach(reset);
it('should start automatically scrolling when a drag starts', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollTop = 500;
parentScrollContainer.scrollLeft = 500;
userEvent.lift(child, { clientX: 1, clientY: 1 });
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// Second frame: an auto scroll will occur
advanceTimersToNextFrame();
stepScrollBy();
// Scroll backwards on both axis by 1px
expect(ordered).toEqual(['scroll event {scrollLeft: 499, scrollTop: 499}']);
cleanup();
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/stop.spec.ts
================================================
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import { autoScrollForElements } from '../../../src/entry-point/element';
import {
advanceTimersToNextFrame,
appendToBody,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
userEvent,
} from '../_util';
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
it('should stop scrolling when a drag ends', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollTop = 500;
parentScrollContainer.scrollLeft = 500;
userEvent.lift(child, { clientX: 1, clientY: 1 });
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// Second frame: an auto scroll will occur
advanceTimersToNextFrame();
stepScrollBy();
// Scroll backwards on both axis by 1px
expect(ordered).toEqual(['scroll event {scrollLeft: 499, scrollTop: 499}']);
ordered.length = 0;
// Third frame: auto scrolling should occur again
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual(['scroll event {scrollLeft: 498, scrollTop: 498}']);
ordered.length = 0;
// End the drag
userEvent.drop(child);
expect(ordered).toEqual(['draggable:drop', 'dropTarget:drop']);
ordered.length = 0;
// Fourth frame: no auto scroll should occur
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
cleanup();
});
it('should not start scrolling if the drag is cancelled in the first frame', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollTop = 500;
parentScrollContainer.scrollLeft = 500;
userEvent.lift(child, { clientX: 1, clientY: 1 });
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
// End the drag
userEvent.drop(child);
expect(ordered).toEqual(['draggable:drop', 'dropTarget:drop']);
ordered.length = 0;
// Second frame: an auto scroll will normally have occurred, but the drag was cancelled.
advanceTimersToNextFrame();
stepScrollBy();
// no scroll events should have occurred
expect(ordered).toEqual([]);
cleanup();
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/time-dampening.spec.ts
================================================
import { fireEvent } from '@testing-library/dom';
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import {
autoScrollForElements,
autoScrollWindowForElements,
} from '../../../src/entry-point/element';
import { getInternalConfig } from '../../../src/shared/configuration';
import {
advanceTimersToNextFrame,
appendToBody,
getBubbleOrderedTree,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
userEvent,
} from '../_util';
// Using modern timers as it is important that the system clock moves in sync with the frames.
// We need this as we are keeping track of when a drop target is entered into.
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
const defaultConfig = getInternalConfig();
const maxScrollPerFrame = defaultConfig.maxPixelScrollPerSecond / 60;
beforeEach(() => {
// resetting document scroll
document.documentElement.scrollTop = 0;
document.documentElement.scrollLeft = 0;
});
// Splitting up, right, down and left into separate cases rather than a loop, because doing it
// in one helper loop was super messy and difficult to follow
it('should dampen the acceleration of auto scrolling [new drag] - up', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollTop = child.getBoundingClientRect().height / 2;
const initialScrollTop = parentScrollContainer.scrollTop;
const initialScrollLeft = parentScrollContainer.scrollLeft;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY:
// when on the 'top' side we are scrolling up
parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
let lastScrollTop = parentScrollContainer.scrollTop;
let lastScrollChangeSize = 0;
let engagementStart: number | null = null;
// tracking the various cases to make sure we are actually hitting them
const casesHit = {
// first few scrolls will just be 1px
'initial-acceleration': false,
acceleration: false,
'time-dampening-finished': false,
'time-dampening-finished-last-scroll': false,
};
// Keep going until we cannot scroll any more
while (parentScrollContainer.scrollTop > 0) {
advanceTimersToNextFrame();
stepScrollBy();
// asserting that one scroll event has occurred
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// Engagement not set until first active scroll
if (!engagementStart) {
engagementStart = Date.now();
}
const currentScrollTop = parentScrollContainer.scrollTop;
/**
* Sometimes minus can run into IEEE 754 floating point math issues.
* Example: `256.4 - 241.4` is `14.99999999999972` and not `15` 😮💨
* Never use `.toBe()` with `scrollChange`, only `.toBeCloseTo()`,
* or other _not strictly equal_ assertions (eg `toBeGreaterThan()`)
**/
const scrollChange = currentScrollTop - lastScrollTop;
// we are scrolling backwards so our change will be negative
expect(scrollChange).toBeLessThan(0);
const scrollChangeSize = Math.abs(scrollChange);
lastScrollTop = currentScrollTop;
const now = Date.now();
const duration = now - engagementStart;
// Case 1: in the time dampening period
if (duration < defaultConfig.timeDampeningDurationMs) {
// We are still not at the max scroll speed
expect(scrollChangeSize).not.toBeGreaterThan(defaultConfig.maxPixelScrollPerSecond);
if (scrollChangeSize === 1) {
expect(scrollChangeSize).toBe(1);
casesHit['initial-acceleration'] = true;
} else {
// Each scroll is bigger than the last
expect(scrollChangeSize).toBeGreaterThan(lastScrollChangeSize);
casesHit.acceleration = true;
}
lastScrollChangeSize = scrollChangeSize;
continue;
}
// Case 2: scrolling at max speed, but not finished scrolling
// Expecting max scroll speed
if (parentScrollContainer.scrollTop !== 0) {
expect(scrollChangeSize).toBeCloseTo(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished'] = true;
continue;
}
// Case 3: the last scroll finished the scrolling of the element.
// The last scroll could be slightly less than the max scroll amount
// as there might not have been the max scroll amount left to scroll
expect(scrollChangeSize).toBeLessThanOrEqual(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished-last-scroll'] = true;
// We can finish here (even though the exit condition would catch us too)
break;
}
// scroll container has been scrolled all the way to the top
expect(parentScrollContainer.scrollTop).toBe(0);
// asserting all our cases where hit
expect(casesHit['initial-acceleration']).toBe(true);
expect(casesHit.acceleration).toBe(true);
expect(casesHit['time-dampening-finished']).toBe(true);
expect(casesHit['time-dampening-finished-last-scroll']).toBe(true);
// scrollLeft should not have changed
expect(parentScrollContainer.scrollLeft).toBe(initialScrollLeft);
cleanup();
});
it('should dampen the acceleration of auto scrolling [new drag] - right', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollLeft = child.getBoundingClientRect().width / 2;
const initialScrollLeft = parentScrollContainer.scrollLeft;
const initialScrollTop = parentScrollContainer.scrollTop;
// lifting the mid point of the right edge
userEvent.lift(child, {
clientX: parentScrollContainer.getBoundingClientRect().right,
clientY:
parentScrollContainer.getBoundingClientRect().top +
parentScrollContainer.getBoundingClientRect().height / 2,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollLeft).toBe(initialScrollLeft);
let lastScrollLeft = parentScrollContainer.scrollLeft;
let lastScrollChange = 0;
let engagementStart: number | null = null;
// tracking the various cases to make sure we are actually hitting them
const casesHit = {
// first few scrolls will just be 1px
'initial-acceleration': false,
acceleration: false,
'time-dampening-finished': false,
'time-dampening-finished-last-scroll': false,
};
const maxScrollLeft = parentScrollContainer.scrollWidth - parentScrollContainer.clientWidth;
// Keep going until we cannot scroll any more
while (parentScrollContainer.scrollLeft <= maxScrollLeft) {
advanceTimersToNextFrame();
stepScrollBy();
// asserting that one scroll event has occurred
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// Engagement not set until first active scroll
if (!engagementStart) {
engagementStart = Date.now();
}
const currentScrollLeft = parentScrollContainer.scrollLeft;
/**
* Sometimes minus can run into IEEE 754 floating point math issues.
* Example: `256.4 - 241.4` is `14.99999999999972` and not `15` 😮💨
* Never use `.toBe()` with `scrollChange`, only `.toBeCloseTo()`
* or other _not strictly equal_ assertions (eg `toBeGreaterThan()`)
**/
const scrollChange = currentScrollLeft - lastScrollLeft;
// we are scrolling forward so our change will be positive
expect(scrollChange).toBeGreaterThan(0);
lastScrollLeft = currentScrollLeft;
const now = Date.now();
const duration = now - engagementStart;
// Case 1: in the time dampening period
if (duration < defaultConfig.timeDampeningDurationMs) {
// We are still not at the max scroll speed
expect(scrollChange).not.toBeGreaterThan(defaultConfig.maxPixelScrollPerSecond);
if (scrollChange === 1) {
casesHit['initial-acceleration'] = true;
expect(scrollChange).toBe(1);
} else {
// Each scroll is bigger than the last
casesHit.acceleration = true;
expect(scrollChange).toBeGreaterThan(lastScrollChange);
}
lastScrollChange = scrollChange;
continue;
}
// Case 2: scrolling at max speed, but not finished scrolling
// Expecting max scroll speed
if (parentScrollContainer.scrollLeft < maxScrollLeft) {
expect(scrollChange).toBeCloseTo(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished'] = true;
continue;
}
// Case 3: the last scroll finished the scrolling of the element.
// The last scroll could be slightly less than the max scroll amount
// as there might not have been the max scroll amount left to scroll
expect(scrollChange).toBeLessThanOrEqual(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished-last-scroll'] = true;
// We can finish here (even though the exit condition would catch us too)
break;
}
// scroll container has been scrolled all the way to the top
expect(parentScrollContainer.scrollLeft).toBe(maxScrollLeft);
// asserting all our cases where hit
expect(casesHit['initial-acceleration']).toBe(true);
expect(casesHit.acceleration).toBe(true);
expect(casesHit['time-dampening-finished']).toBe(true);
expect(casesHit['time-dampening-finished-last-scroll']).toBe(true);
// scrollTop should not have changed
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
cleanup();
});
it('should dampen the acceleration of auto scrolling [new drag] - down', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollTop = child.getBoundingClientRect().height / 2;
const initialScrollTop = parentScrollContainer.scrollTop;
const initialScrollLeft = parentScrollContainer.scrollLeft;
// lifting on the mid point of the bottom edge
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().bottom,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
let lastScrollTop = parentScrollContainer.scrollTop;
let lastScrollChange = 0;
let engagementStart: number | null = null;
// tracking the various cases to make sure we are actually hitting them
const casesHit = {
// first few scrolls will just be 1px
'initial-acceleration': false,
acceleration: false,
'time-dampening-finished': false,
'time-dampening-finished-last-scroll': false,
};
const maxScrollTop = parentScrollContainer.scrollHeight - parentScrollContainer.clientHeight;
// Keep going until we cannot scroll any more
while (parentScrollContainer.scrollTop <= maxScrollTop) {
advanceTimersToNextFrame();
stepScrollBy();
// asserting that one scroll event has occurred
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// Engagement not set until first active scroll
if (!engagementStart) {
engagementStart = Date.now();
}
const currentScrollTop = parentScrollContainer.scrollTop;
/**
* Sometimes minus can run into IEEE 754 floating point math issues.
* Example: `256.4 - 241.4` is `14.99999999999972` and not `15` 😮💨
* Never use `.toBe()` with `scrollChange`, only `.toBeCloseTo()`
* or other _not strictly equal_ assertions (eg `toBeGreaterThan()`)
**/
const scrollChange = currentScrollTop - lastScrollTop;
// we are scrolling forward so our change will be positive
expect(scrollChange).toBeGreaterThan(0);
lastScrollTop = currentScrollTop;
const now = Date.now();
const duration = now - engagementStart;
// Case 1: in the time dampening period
if (duration < defaultConfig.timeDampeningDurationMs) {
// We are still not at the max scroll speed
expect(scrollChange).not.toBeGreaterThan(defaultConfig.maxPixelScrollPerSecond);
if (scrollChange === 1) {
expect(scrollChange).toBe(1);
casesHit['initial-acceleration'] = true;
} else {
// Each scroll is bigger than the last
expect(scrollChange).toBeGreaterThan(lastScrollChange);
casesHit.acceleration = true;
}
lastScrollChange = scrollChange;
continue;
}
// Case 2: scrolling at max speed, but not finished scrolling
// Expecting max scroll speed
if (parentScrollContainer.scrollTop < maxScrollTop) {
expect(scrollChange).toBeCloseTo(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished'] = true;
continue;
}
// Case 3: the last scroll finished the scrolling of the element.
// The last scroll could be slightly less than the max scroll amount
// as there might not have been the max scroll amount left to scroll
expect(scrollChange).toBeLessThanOrEqual(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished-last-scroll'] = true;
// We can finish here (even though the exit condition would catch us too)
break;
}
// scroll container has been scrolled all the way to the top
expect(parentScrollContainer.scrollTop).toBe(maxScrollTop);
// asserting all our cases where hit
expect(casesHit['initial-acceleration']).toBe(true);
expect(casesHit.acceleration).toBe(true);
expect(casesHit['time-dampening-finished']).toBe(true);
expect(casesHit['time-dampening-finished-last-scroll']).toBe(true);
// scrollLeft should not have changed
expect(parentScrollContainer.scrollLeft).toBe(initialScrollLeft);
cleanup();
});
it('should dampen the acceleration of auto scrolling [new drag] - left', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(`scroll event`);
},
}),
);
// Scroll container is now looking over the center of the element
parentScrollContainer.scrollLeft = child.getBoundingClientRect().width / 2;
const initialScrollLeft = parentScrollContainer.scrollLeft;
const initialScrollTop = parentScrollContainer.scrollTop;
// lifting on the vertical midpoint of the left edge of the container
userEvent.lift(child, {
clientX: parentScrollContainer.getBoundingClientRect().left,
clientY:
parentScrollContainer.getBoundingClientRect().top +
parentScrollContainer.getBoundingClientRect().height / 2,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollLeft).toBe(initialScrollLeft);
let lastScrollLeft = parentScrollContainer.scrollLeft;
let lastScrollChangeSize = 0;
let engagementStart: number | null = null;
// tracking the various cases to make sure we are actually hitting them
const casesHit = {
// first few scrolls will just be 1px
'initial-acceleration': false,
acceleration: false,
'time-dampening-finished': false,
'time-dampening-finished-last-scroll': false,
};
// Keep going until we cannot scroll any more
while (parentScrollContainer.scrollLeft > 0) {
advanceTimersToNextFrame();
stepScrollBy();
// asserting that one scroll event has occurred
expect(ordered).toEqual(['scroll event']);
ordered.length = 0;
// Engagement not set until first active scroll
if (!engagementStart) {
engagementStart = Date.now();
}
const currentScrollLeft = parentScrollContainer.scrollLeft;
/**
* Sometimes minus can run into IEEE 754 floating point math issues.
* Example: `256.4 - 241.4` is `14.99999999999972` and not `15` 😮💨
* Never use `.toBe()` with `scrollChange`, only `.toBeCloseTo()`
* or other _not strictly equal_ assertions (eg `toBeGreaterThan()`)
**/
const scrollChange = currentScrollLeft - lastScrollLeft;
// we are scrolling backwards so our change will be negative
expect(scrollChange).toBeLessThan(0);
const scrollChangeSize = Math.abs(scrollChange);
lastScrollLeft = currentScrollLeft;
const now = Date.now();
const duration = now - engagementStart;
// Case 1: in the time dampening period
if (duration < defaultConfig.timeDampeningDurationMs) {
if (scrollChangeSize === 1) {
expect(scrollChangeSize).toBe(1);
casesHit['initial-acceleration'] = true;
} else {
// Each scroll is bigger than the last
expect(scrollChangeSize).toBeGreaterThan(lastScrollChangeSize);
casesHit.acceleration = true;
}
lastScrollChangeSize = scrollChangeSize;
continue;
}
// Case 2: scrolling at max speed, but not finished scrolling
// Expecting max scroll speed
if (parentScrollContainer.scrollLeft !== 0) {
expect(scrollChangeSize).toBeCloseTo(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished'] = true;
continue;
}
// Case 3: the last scroll finished the scrolling of the element.
// The last scroll could be slightly less than the max scroll amount
// as there might not have been the max scroll amount left to scroll
expect(scrollChangeSize).toBeLessThanOrEqual(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished-last-scroll'] = true;
// We can finish here (even though the exit condition would catch us too)
break;
}
// scroll container has been scrolled all the way to the top
expect(parentScrollContainer.scrollLeft).toBe(0);
// asserting all our cases where hit
expect(casesHit['initial-acceleration']).toBe(true);
expect(casesHit.acceleration).toBe(true);
expect(casesHit['time-dampening-finished']).toBe(true);
expect(casesHit['time-dampening-finished-last-scroll']).toBe(true);
// scrollTop should not have changed
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
cleanup();
});
it('should dampen the acceleration of auto scrolling [entering into a new drop target]', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const [original] = getBubbleOrderedTree();
const originalRect = DOMRect.fromRect({
x: parentScrollContainer.getBoundingClientRect().x + 20,
y: parentScrollContainer.getBoundingClientRect().y + 20,
width: 100,
height: 100,
});
original.getBoundingClientRect = () => originalRect;
const ordered: string[] = [];
let unsetElementFromPoint = setElementFromPoint(original);
const cleanup = combine(
appendToBody(original),
appendToBody(parentScrollContainer),
draggable({
element: original,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
// Scroll container is now looking over the center of the element
const initialScrollTop = child.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// lifting in center of original
userEvent.lift(original, {
clientX: originalRect.left + originalRect.width / 2,
clientY: originalRect.top + originalRect.height / 2,
});
// not over the inner element
expect(ordered).toEqual(['draggable:start']);
ordered.length = 0;
// we are expecting no auto scrolling as we are currently not over the drop target
for (let i = 0; i < 10; i++) {
advanceTimersToNextFrame();
stepScrollBy();
}
// also just being safe and ensuring we are totally outside any initial time dampening
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
stepScrollBy();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
// dragging over the top center of our scroll container
// while over the 'inner' element
unsetElementFromPoint();
unsetElementFromPoint = setElementFromPoint(child);
fireEvent.dragEnter(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
// we are now over the drop target
expect(ordered).toEqual(['dropTarget:enter']);
// no scrolling has occurred yet
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
let lastScrollTop = parentScrollContainer.scrollTop;
let lastScrollChange = 0;
let engagementStart: number | null = null;
// tracking the various cases to make sure we are actually hitting them
const casesHit = {
acceleration: false,
'time-dampening-finished': false,
'time-dampening-finished-last-scroll': false,
};
// Keep going until we cannot scroll any more
while (parentScrollContainer.scrollTop > 0) {
advanceTimersToNextFrame();
stepScrollBy();
// Engagement not set until first active scroll
if (!engagementStart) {
engagementStart = Date.now();
}
const currentScrollTop = parentScrollContainer.scrollTop;
/**
* Sometimes minus can run into IEEE 754 floating point math issues.
* Example: `256.4 - 241.4` is `14.99999999999972` and not `15` 😮💨
* Never use `.toBe()` with `scrollChange`, only `.toBeCloseTo()`
* or other _not strictly equal_ assertions (eg `toBeGreaterThan()`)
**/
const scrollChange = Math.abs(currentScrollTop - lastScrollTop);
lastScrollTop = currentScrollTop;
const now = Date.now();
const duration = now - engagementStart;
// Case 1: in the time dampening period
if (duration < defaultConfig.timeDampeningDurationMs) {
// We are still not at the max scroll speed
expect(scrollChange).not.toBeGreaterThan(defaultConfig.maxPixelScrollPerSecond);
// Each scroll is bigger than the last
expect(scrollChange).toBeGreaterThan(lastScrollChange);
casesHit.acceleration = true;
continue;
}
// Case 2: scrolling at max speed, but not finished scrolling
// Expecting max scroll speed
if (parentScrollContainer.scrollTop !== 0) {
expect(scrollChange).toBeCloseTo(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished'] = true;
continue;
}
// Case 3: the last scroll finished the scrolling of the element.
// The last scroll could be slightly less than the max scroll amount
// as there might not have been the max scroll amount left to scroll
expect(scrollChange).toBeLessThanOrEqual(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished-last-scroll'] = true;
// We can finish here
break;
}
// scroll container has been scrolled all the way to the top
expect(parentScrollContainer.scrollTop).toBe(0);
// asserting all our cases where hit
expect(casesHit.acceleration).toBe(true);
expect(casesHit['time-dampening-finished']).toBe(true);
expect(casesHit['time-dampening-finished-last-scroll']).toBe(true);
// TODO: pull out into separate test?
// checking that no more scrolls will occur
ordered.length = 0;
jest.advanceTimersByTime(defaultConfig.maxPixelScrollPerSecond * 2);
expect(ordered).toEqual([]);
cleanup();
unsetElementFromPoint();
});
it('should start time dampening from when the element is dragged over, even if auto scrolling is not being triggered', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
bind(parentScrollContainer, {
type: 'scroll',
listener: () => ordered.push('scroll event'),
}),
);
// Scroll container is now looking over the center of the element
const initialScrollTop = child.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// lifting in center of the the scroll container, this should not trigger any auto scrolling
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY:
parentScrollContainer.getBoundingClientRect().top +
parentScrollContainer.getBoundingClientRect().height / 2,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// first frame: no scroll expected even if we were auto scrolling
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// second frame: if we were in a hitbox for auto scrolling, scroll would occur.
// not expecting any scroll event as we are not in a hitbox for auto scrolling.
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// ensuring we are out of the time dampening period
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
stepScrollBy();
// still expecting no scroll events
expect(ordered).toEqual([]);
// moving over the bottom center - this should trigger an auto scroll
fireEvent.dragOver(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().bottom,
});
// not expecting the change to be picked up until the frame after the current frame
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// now scrolling at max speed as time dampening is finished
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(after - before).toBe(maxScrollPerFrame);
expect(ordered).toEqual(['scroll event']);
}
cleanup();
});
it('should reset time dampening when re-entering a scrollable element', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
let unsetElementFromPoint = setElementFromPoint(child);
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
// Scroll container is now looking over the center of the element
const initialScrollTop = child.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
function execute() {
let lastScrollTop = parentScrollContainer.scrollTop;
let lastScrollChange = 0;
let engagementStart: number | null = null;
// tracking the various cases to make sure we are actually hitting them
const casesHit = {
acceleration: false,
'time-dampening-finished': false,
'time-dampening-finished-last-scroll': false,
};
// Keep going until we cannot scroll any more
while (parentScrollContainer.scrollTop > 0) {
advanceTimersToNextFrame();
stepScrollBy();
// Engagement not set until first active scroll
if (!engagementStart) {
engagementStart = Date.now();
}
const currentScrollTop = parentScrollContainer.scrollTop;
/**
* Sometimes minus can run into IEEE 754 floating point math issues.
* Example: `256.4 - 241.4` is `14.99999999999972` and not `15` 😮💨
* Never use `.toBe()` with `scrollChange`, only `.toBeCloseTo()`
* or other _not strictly equal_ assertions (eg `toBeGreaterThan()`)
**/
const scrollChange = Math.abs(currentScrollTop - lastScrollTop);
lastScrollTop = currentScrollTop;
const now = Date.now();
const duration = now - engagementStart;
// Case 1: in the time dampening period
if (duration < defaultConfig.timeDampeningDurationMs) {
// We are still not at the max scroll speed
expect(scrollChange).not.toBeGreaterThan(defaultConfig.maxPixelScrollPerSecond);
// Each scroll is bigger than the last
expect(scrollChange).toBeGreaterThan(lastScrollChange);
casesHit.acceleration = true;
continue;
}
// Case 2: scrolling at max speed, but not finished scrolling
// Expecting max scroll speed
if (parentScrollContainer.scrollTop !== 0) {
expect(scrollChange).toBeCloseTo(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished'] = true;
continue;
}
// Case 3: the last scroll finished the scrolling of the element.
// The last scroll could be slightly less than the max scroll amount
// as there might not have been the max scroll amount left to scroll
expect(scrollChange).toBeLessThanOrEqual(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished-last-scroll'] = true;
// We can finish here
break;
}
// scroll container has been scrolled all the way to the top
expect(parentScrollContainer.scrollTop).toBe(0);
// asserting all our cases where hit
expect(casesHit.acceleration).toBe(true);
expect(casesHit['time-dampening-finished']).toBe(true);
expect(casesHit['time-dampening-finished-last-scroll']).toBe(true);
}
// first auto scroll
execute();
ordered.length = 0;
// leaving the drop target
unsetElementFromPoint();
unsetElementFromPoint = setElementFromPoint(document.body);
fireEvent.dragEnter(document.body);
expect(ordered).toEqual(['dropTarget:leave']);
ordered.length = 0;
// let some time pass
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs * 2);
// no scrolling has occurred in this time
expect(ordered).toEqual([]);
// let's drag back over the drop target
unsetElementFromPoint();
unsetElementFromPoint = setElementFromPoint(child);
fireEvent.dragEnter(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
// we are now over the drop target
expect(ordered).toEqual(['dropTarget:enter']);
ordered.length = 0;
// our auto scroll should be in action
// TODO: be a bit more elegant here?
parentScrollContainer.scrollTop = initialScrollTop;
execute();
cleanup();
unsetElementFromPoint();
});
it('should not reset time dampening if an element is re-registered (in the same frame)', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
);
let unbindAutoScrolling = autoScrollForElements({
element: parentScrollContainer,
});
// Scroll container is now looking over the center of the element
const initialScrollTop = child.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has now been scrolled
expect(parentScrollContainer.scrollTop).toBeLessThan(initialScrollTop);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before - after).toBe(maxScrollPerFrame);
}
// Rebinding the auto scroll element
unbindAutoScrolling();
unbindAutoScrolling = autoScrollForElements({
element: parentScrollContainer,
});
// Triggering another auto scroll - should be at the max speed
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before - after).toBe(maxScrollPerFrame);
}
cleanup();
});
it('should not reset time dampening if window scrolling is re-registered (in the same frame)', () => {
const [element] = getBubbleOrderedTree();
const ordered: string[] = [];
// Setting some large scroll height on the window
Object.defineProperties(document.documentElement, {
scrollHeight: {
value: document.documentElement.clientHeight * 10,
writable: false,
},
});
const cleanup = combine(
appendToBody(element),
setElementFromPoint(element),
draggable({
element: element,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: element,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === document.documentElement) {
ordered.push('window:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
const initialScrollTop = document.documentElement.scrollTop;
let unbindAutoScrolling = autoScrollWindowForElements();
userEvent.lift(element, {
clientX: document.documentElement.clientLeft + document.documentElement.clientWidth / 2,
clientY: document.documentElement.clientLeft + document.documentElement.clientHeight,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(document.documentElement.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has now been scrolled
expect(document.documentElement.scrollTop).toBeGreaterThan(initialScrollTop);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after - before).toBe(maxScrollPerFrame);
}
// Re-registering window scrolling
unbindAutoScrolling();
unbindAutoScrolling = autoScrollWindowForElements();
// Triggering another auto scroll - should be at the max speed
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after - before).toBe(maxScrollPerFrame);
}
unbindAutoScrolling();
cleanup();
});
it('should reset time dampening if a element is re-registered in a future frame', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
let unbindAutoScrolling = autoScrollForElements({
element: parentScrollContainer,
});
// Scroll container is now looking over the center of the element
const initialScrollTop = child.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has now been scrolled
expect(parentScrollContainer.scrollTop).toBeLessThan(initialScrollTop);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before - after).toBe(maxScrollPerFrame);
}
// Unbinding the auto scroll element
unbindAutoScrolling();
// Triggering a scroll - should not scroll the scroll container
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before).toBe(after);
}
// Binding the scrollable element again
unbindAutoScrolling = autoScrollForElements({
element: parentScrollContainer,
});
// Triggering another auto scroll - should be the minimum scroll
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before - after).toBe(1);
}
cleanup();
unbindAutoScrolling();
});
it('should reset time dampening if a element scroll is disabled and re-enabled in a future frame', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
let isAutoScrollingAllowed: boolean = true;
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
canScroll: () => isAutoScrollingAllowed,
}),
);
// Scroll container is now looking over the center of the element
const initialScrollTop = child.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
// scroll container has still not scrolled
expect(ordered).toEqual([]);
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has now been scrolled
expect(parentScrollContainer.scrollTop).toBeLessThan(initialScrollTop);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before - after).toBe(maxScrollPerFrame);
}
// No longer allowing auto scrolling
isAutoScrollingAllowed = false;
// Triggering a scroll - should not scroll the scroll container
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before).toBe(after);
}
// Binding the scrollable element again
isAutoScrollingAllowed = true;
// Triggering another auto scroll - should be the minimum scroll
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before - after).toBe(1);
}
cleanup();
});
it('should reset time dampening if a window scrolling is re-registered in a future frame', () => {
const [element] = getBubbleOrderedTree();
const ordered: string[] = [];
// Setting some large scroll height on the window
Object.defineProperties(document.documentElement, {
scrollHeight: {
value: document.documentElement.clientHeight * 10,
writable: false,
},
});
const cleanup = combine(
appendToBody(element),
setElementFromPoint(element),
draggable({
element: element,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: element,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === document.documentElement) {
ordered.push('window:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
const initialScrollTop = document.documentElement.scrollTop;
let unbindAutoScrolling = autoScrollWindowForElements();
userEvent.lift(element, {
clientX: document.documentElement.clientLeft + document.documentElement.clientWidth / 2,
clientY: document.documentElement.clientLeft + document.documentElement.clientHeight,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(document.documentElement.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has now been scrolled
expect(document.documentElement.scrollTop).toBeGreaterThan(initialScrollTop);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after - before).toBe(maxScrollPerFrame);
}
// un-registering window scrolling
unbindAutoScrolling();
// Triggering another auto scroll - should not scroll
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after).toBe(before);
}
unbindAutoScrolling = autoScrollWindowForElements();
// Triggering another auto scroll - should be the minimum scroll
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after - before).toBe(1);
}
unbindAutoScrolling();
cleanup();
});
it('should reset time dampening if a window scrolling is re-enabled in a future frame', () => {
const [element] = getBubbleOrderedTree();
const ordered: string[] = [];
let isAutoScrollingAllowed: boolean = true;
// Setting some large scroll height on the window
Object.defineProperties(document.documentElement, {
scrollHeight: {
value: document.documentElement.clientHeight * 10,
writable: false,
},
});
const cleanup = combine(
appendToBody(element),
setElementFromPoint(element),
draggable({
element: element,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: element,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollWindowForElements({
canScroll: () => isAutoScrollingAllowed,
}),
bind(window, {
type: 'scroll',
listener: (event) => {
if (event.target === document.documentElement) {
ordered.push('window:scroll');
return;
}
ordered.push('unknown:scroll');
},
// scroll events do not bubble, so leveraging the capture phase
options: { capture: true },
}),
);
const initialScrollTop = document.documentElement.scrollTop;
userEvent.lift(element, {
clientX: document.documentElement.clientLeft + document.documentElement.clientWidth / 2,
clientY: document.documentElement.clientLeft + document.documentElement.clientHeight,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
// scroll container has still not scrolled
expect(ordered).toEqual([]);
expect(document.documentElement.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has now been scrolled
expect(document.documentElement.scrollTop).toBeGreaterThan(initialScrollTop);
expect(ordered).toEqual(['window:scroll']);
ordered.length = 0;
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after - before).toBe(maxScrollPerFrame);
}
// disabling auto scroll
isAutoScrollingAllowed = false;
// Triggering another auto scroll - should not scroll
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after).toBe(before);
}
// re-enabling auto scrolling
isAutoScrollingAllowed = true;
// Triggering another auto scroll - should be the minimum scroll
{
const before = document.documentElement.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = document.documentElement.scrollTop;
expect(after - before).toBe(1);
}
cleanup();
});
it('should not dampen time after the time dampening period has finished [on original axis]', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
// Scroll container is now looking over the center of the element
const initialScrollTop = parentScrollContainer.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// just checking I got the math right
expect(initialScrollTop).toBe(500);
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has still been scrolled
expect(parentScrollContainer.scrollTop).toBeLessThan(initialScrollTop);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// just asserting we have a setup that will execute the test correctly
const beforeScrollTop = parentScrollContainer.scrollTop;
expect(beforeScrollTop).toBeLessThan(initialScrollTop);
// our next scroll should have room for more than the max scroll
// (otherwise we are not testing what we expect)
expect(beforeScrollTop).toBeGreaterThan(maxScrollPerFrame);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
advanceTimersToNextFrame();
stepScrollBy();
const afterScrollTop = parentScrollContainer.scrollTop;
expect(beforeScrollTop - afterScrollTop).toBe(maxScrollPerFrame);
cleanup();
});
it('should not dampen time after the time dampening period has finished [on different axis]', () => {
const { child, parentScrollContainer } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
setElementFromPoint(child),
bind(parentScrollContainer, {
type: 'scroll',
listener() {
ordered.push(
`scroll event {scrollLeft: ${parentScrollContainer.scrollLeft}, scrollTop: ${parentScrollContainer.scrollTop}}`,
);
},
}),
);
// Initial scrolling on the top and left
const initialScrollTop = parentScrollContainer.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
const initialScrollLeft = parentScrollContainer.getBoundingClientRect().width / 2;
parentScrollContainer.scrollLeft = initialScrollLeft;
// checking our initial math is correct
expect(parentScrollContainer.scrollLeft).toBe(500);
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
stepScrollBy();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has been scrolled on the top
expect(parentScrollContainer.scrollTop).toBeLessThan(initialScrollTop);
// scroll container has not been scrolled on the left yet
expect(parentScrollContainer.scrollLeft).toBe(initialScrollLeft);
// ensuring we have enough room to do a max scroll
expect(parentScrollContainer.scrollLeft).toBeGreaterThan(maxScrollPerFrame);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
expect(parentScrollContainer.scrollLeft).toBe(initialScrollLeft);
const rect = parentScrollContainer.getBoundingClientRect();
// mid center on left edge
fireEvent.dragOver(child, {
clientX: rect.left,
clientY: rect.top + rect.height,
});
// first frame: this will update the 'input' for a drag (update changes are throttled inside of a frame)
advanceTimersToNextFrame();
stepScrollBy();
expect(initialScrollLeft).toBe(parentScrollContainer.scrollLeft);
// this should now trigger an auto scroll of the max scroll (no time dampening)
advanceTimersToNextFrame();
stepScrollBy();
expect(initialScrollLeft - parentScrollContainer.scrollLeft).toBe(maxScrollPerFrame);
cleanup();
});
// only checking forward direction, as code path is the same as scroll containers
it('should reset time dampening when doing repeated drag operations', () => {
const { parentScrollContainer, child } = setupBasicScrollContainer();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(parentScrollContainer),
setElementFromPoint(child),
draggable({
element: child,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: child,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollForElements({
element: parentScrollContainer,
}),
);
function dragOperation() {
// Scroll container is now looking over the center of the element
const initialScrollTop = child.getBoundingClientRect().height / 2;
parentScrollContainer.scrollTop = initialScrollTop;
// lifting on the top vertical edge of the container
userEvent.lift(child, {
clientX:
parentScrollContainer.getBoundingClientRect().left +
parentScrollContainer.getBoundingClientRect().width / 2,
clientY: parentScrollContainer.getBoundingClientRect().top,
});
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// on first frame, there is no auto scroll as
// we don't know what the scroll speed should be until
// a single frame has passed
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// scroll container has still not scrolled
expect(parentScrollContainer.scrollTop).toBe(initialScrollTop);
// on the second frame we are performing our initial scroll
// which will mark the first engagement
// (and will also perform the first scroll)
advanceTimersToNextFrame();
stepScrollBy();
// scroll container has now been scrolled
expect(parentScrollContainer.scrollTop).toBeLessThan(initialScrollTop);
// Complete the time dampening duration
jest.advanceTimersByTime(defaultConfig.timeDampeningDurationMs);
// Triggering another frame
// we are expecting the scroll change to be the maximum allowed
{
const before = parentScrollContainer.scrollTop;
advanceTimersToNextFrame();
stepScrollBy();
const after = parentScrollContainer.scrollTop;
expect(before - after).toBe(maxScrollPerFrame);
}
userEvent.drop(child);
expect(ordered).toEqual(['draggable:drop', 'dropTarget:drop']);
ordered.length = 0;
}
// Let's do a few drag operations and ensure that the behaviour is the same
dragOperation();
dragOperation();
dragOperation();
dragOperation();
cleanup();
});
it('should apply time dampening for window scrolling', () => {
const [element] = getBubbleOrderedTree();
const ordered: string[] = [];
const cleanup = combine(
appendToBody(element),
draggable({
element: element,
onDragStart: () => ordered.push('draggable:start'),
onDrop: () => ordered.push('draggable:drop'),
}),
dropTargetForElements({
element: element,
onDragStart: () => ordered.push('dropTarget:start'),
onDragEnter: () => ordered.push('dropTarget:enter'),
onDragLeave: () => ordered.push('dropTarget:leave'),
onDrop: () => ordered.push('dropTarget:drop'),
}),
autoScrollWindowForElements(),
setElementFromPoint(element),
bind(window, {
type: 'scroll',
listener(event) {
if (event.target === document.documentElement) {
ordered.push('window:scroll');
return;
}
ordered.push('unknown:scroll');
},
options: { capture: true },
}),
);
// setting a large vertical amount of available scroll
Object.defineProperties(document.documentElement, {
scrollHeight: {
value: document.documentElement.clientHeight * 10,
writable: false,
},
});
const initialScrollTop = document.documentElement.scrollTop;
const initialScrollLeft = document.documentElement.scrollLeft;
expect(initialScrollTop).toBe(0);
expect(initialScrollLeft).toBe(0);
// starting a drag
userEvent.lift(element);
expect(ordered).toEqual(['draggable:start', 'dropTarget:start']);
ordered.length = 0;
// in the first frame before auto scrolling has started
// we are updating our drag so that we are over
fireEvent.dragEnter(document.body, {
clientX: document.documentElement.clientLeft + document.documentElement.clientWidth / 2,
clientY: document.documentElement.clientTop + document.documentElement.clientHeight,
});
expect(ordered).toEqual(['dropTarget:leave']);
ordered.length = 0;
// in the first frame, there will be no auto scroll
advanceTimersToNextFrame();
expect(ordered).toEqual([]);
// checking window has not been scrolled
expect(document.documentElement.scrollTop).toBe(initialScrollTop);
let lastScrollTop = initialScrollTop;
let lastScrollChange = 0;
let engagementStart: number | null = null;
// tracking the various cases to make sure we are actually hitting them
const casesHit = {
acceleration: false,
'time-dampening-finished': false,
'time-dampening-finished-last-scroll': false,
};
const maxScrollTop =
document.documentElement.scrollHeight - document.documentElement.clientHeight;
// Keep going until we cannot scroll any more
while (document.documentElement.scrollTop <= maxScrollTop) {
advanceTimersToNextFrame();
stepScrollBy();
// asserting that one scroll event has occurred
expect(ordered).toEqual(['window:scroll']);
ordered.length = 0;
// Engagement not set until first active scroll
if (!engagementStart) {
engagementStart = Date.now();
}
const currentScrollTop = document.documentElement.scrollTop;
/**
* Sometimes minus can run into IEEE 754 floating point math issues.
* Example: `256.4 - 241.4` is `14.99999999999972` and not `15` 😮💨
* Never use `.toBe()` with `scrollChange`, only `.toBeCloseTo()`
* or other _not strictly equal_ assertions (eg `toBeGreaterThan()`)
* (which takes into account floating point issues).
**/
const scrollChange = currentScrollTop - lastScrollTop;
// we are scrolling forward so our change will be positive
expect(scrollChange).toBeGreaterThan(0);
lastScrollTop = currentScrollTop;
const now = Date.now();
const duration = now - engagementStart;
// Case 1: in the time dampening period
if (duration < defaultConfig.timeDampeningDurationMs) {
// We are still not at the max scroll speed
expect(scrollChange).not.toBeGreaterThan(defaultConfig.maxPixelScrollPerSecond);
// Each scroll is bigger than the last
expect(scrollChange).toBeGreaterThan(lastScrollChange);
casesHit.acceleration = true;
continue;
}
// Case 2: scrolling at max speed, but not finished scrolling
// Expecting max scroll speed
if (document.documentElement.scrollTop < maxScrollTop) {
expect(scrollChange).toBeCloseTo(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished'] = true;
continue;
}
// Case 3: the last scroll finished the scrolling of the element.
// The last scroll could be slightly less than the max scroll amount
// as there might not have been the max scroll amount left to scroll
expect(scrollChange).toBeLessThanOrEqual(defaultConfig.maxPixelScrollPerSecond / 60);
casesHit['time-dampening-finished-last-scroll'] = true;
// We can finish here (even though the exit condition would catch us too)
break;
}
// scroll container has been scrolled all the way to the top
expect(document.documentElement.scrollTop).toBe(maxScrollTop);
// asserting all our cases where hit
expect(casesHit.acceleration).toBe(true);
expect(casesHit['time-dampening-finished']).toBe(true);
expect(casesHit['time-dampening-finished-last-scroll']).toBe(true);
// scrollLeft should not have changed
expect(document.documentElement.scrollLeft).toBe(initialScrollLeft);
cleanup();
});
================================================
FILE: packages/auto-scroll/__tests__/unit/over-element/window-scrolling.spec.ts
================================================
import { bind } from 'bind-event-listener';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import {
draggable,
dropTargetForElements,
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';
import {
autoScrollForElements,
autoScrollWindowForElements,
} from '../../../src/entry-point/element';
import {
advanceTimersToNextFrame,
appendToBody,
getBubbleOrderedTree,
reset,
setElementFromPoint,
setStartSystemTime,
setupBasicScrollContainer,
stepScrollBy,
userEvent,
} from '../_util';
// Using modern timers as it is important that the system clock moves in sync with the frames.
// We need this as we are keeping track of when a drop target is entered into.
jest.useFakeTimers();
setStartSystemTime();
// This file exposes one or more accessibility violations. Testing is currently skipped but violations need to
// be fixed in a timely manner or result in escalation. Once all violations have been fixed, you can remove
// the next line and associated import. For more information, see go/afm-a11y-tooling:jest
skipAutoA11yFile();
beforeEach(reset);
beforeEach(() => {
document.documentElement.scrollTop = 0;
});
function canScrollOnBottom(element: HTMLElement): boolean {
return Math.ceil(element.scrollTop) + eleme
gitextract_m34m2yul/ ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── jest.config.js ├── package.json ├── packages/ │ ├── auto-scroll/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ ├── playwright/ │ │ │ │ ├── over-element-smoke-test.spec.tsx │ │ │ │ └── unsafe-overflow-smoke-test.spec.tsx │ │ │ └── unit/ │ │ │ ├── _util.ts │ │ │ ├── over-element/ │ │ │ │ ├── allowed-axis.spec.ts │ │ │ │ ├── can-scroll.spec.ts │ │ │ │ ├── distance-dampening.spec.ts │ │ │ │ ├── hitbox.spec.ts │ │ │ │ ├── max-speed.spec.ts │ │ │ │ ├── nested-scroll-containers.spec.ts │ │ │ │ ├── registration.spec.ts │ │ │ │ ├── start.spec.ts │ │ │ │ ├── stop.spec.ts │ │ │ │ ├── time-dampening.spec.ts │ │ │ │ └── window-scrolling.spec.ts │ │ │ ├── overflow/ │ │ │ │ ├── allowed-axis.spec.ts │ │ │ │ ├── can-scroll.spec.ts │ │ │ │ ├── cross-axis-hitbox.spec.ts │ │ │ │ ├── main-axis-hitbox.spec.ts │ │ │ │ ├── nested-elements.spec.ts │ │ │ │ ├── over-element-should-not-scroll.spec.ts │ │ │ │ └── provided-hitbox-spacing-type.spec.ts │ │ │ └── shared/ │ │ │ ├── _util.ts │ │ │ ├── async-loading.spec.ts │ │ │ ├── ignore-honey-pot.spec.ts │ │ │ ├── monitor-binding.spec.ts │ │ │ └── time-dampening-handover.spec.ts │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ ├── props.mdx │ │ │ └── unsafe-overflow-scrolling.mdx │ │ ├── examples/ │ │ │ ├── axis-locking.tsx │ │ │ ├── lazy-loaded.tsx │ │ │ ├── nested-scroll.tsx │ │ │ ├── over-element.tsx │ │ │ ├── pieces/ │ │ │ │ ├── board-context.ts │ │ │ │ ├── board.tsx │ │ │ │ ├── card.tsx │ │ │ │ ├── lazy-loaded-board.tsx │ │ │ │ └── table.tsx │ │ │ ├── unsafe-overflow-box.tsx │ │ │ ├── unsafe-overflow-only.tsx │ │ │ ├── unsafe-overflow.tsx │ │ │ ├── window-scroll-with-scroll-container.tsx │ │ │ └── window-scroll.tsx │ │ ├── package.json │ │ ├── src/ │ │ │ ├── entry-point/ │ │ │ │ ├── element.ts │ │ │ │ ├── external.ts │ │ │ │ ├── text-selection.ts │ │ │ │ └── unsafe-overflow/ │ │ │ │ ├── element.ts │ │ │ │ ├── external.ts │ │ │ │ └── text-selection.ts │ │ │ ├── index.ts │ │ │ ├── internal-types.ts │ │ │ ├── over-element/ │ │ │ │ ├── data-attributes.ts │ │ │ │ ├── get-scroll-by.ts │ │ │ │ ├── make-api.ts │ │ │ │ └── try-scroll.ts │ │ │ ├── shared/ │ │ │ │ ├── axis.ts │ │ │ │ ├── can-scroll-on-edge.ts │ │ │ │ ├── configuration.ts │ │ │ │ ├── edges.ts │ │ │ │ ├── engagement-history.ts │ │ │ │ ├── get-over-element-hitbox.ts │ │ │ │ ├── get-percentage-in-range.ts │ │ │ │ ├── get-scroll-change.ts │ │ │ │ ├── is-axis-allowed.ts │ │ │ │ ├── is-within.ts │ │ │ │ ├── scheduler.ts │ │ │ │ └── side.ts │ │ │ └── unsafe-overflow/ │ │ │ ├── get-scroll-by.ts │ │ │ ├── hitbox.ts │ │ │ ├── make-api.ts │ │ │ ├── try-overflow-scroll.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── core/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ ├── playwright/ │ │ │ │ ├── external-files.spec.ts │ │ │ │ ├── honey-pot.spec.ts │ │ │ │ ├── iframe.spec.ts │ │ │ │ ├── scroll-just-enough-into-view.spec.ts │ │ │ │ ├── stickiness.spec.tsx │ │ │ │ └── text-selection.spec.ts │ │ │ └── unit/ │ │ │ ├── _util.ts │ │ │ ├── android/ │ │ │ │ ├── is-android.spec.ts │ │ │ │ └── not-android.spec.ts │ │ │ ├── dependency-guardrails.spec.ts │ │ │ ├── element/ │ │ │ │ ├── changes-during-a-drag.spec.ts │ │ │ │ ├── changes-during-a-drop.spec.ts │ │ │ │ ├── draggable/ │ │ │ │ │ ├── conditional-dragging.spec.ts │ │ │ │ │ ├── custom-drag-preview.spec.ts │ │ │ │ │ ├── drag-handle-guardrails.spec.ts │ │ │ │ │ ├── drag-handle.spec.ts │ │ │ │ │ ├── get-initial-data-for-external.spec.ts │ │ │ │ │ ├── get-initial-data.spec.ts │ │ │ │ │ ├── nested-draggables.spec.ts │ │ │ │ │ └── start-location.spec.ts │ │ │ │ ├── dragleave-should-not-update-input.spec.ts │ │ │ │ ├── drop-target/ │ │ │ │ │ ├── conditional-dropping.spec.ts │ │ │ │ │ ├── data-collection.spec.ts │ │ │ │ │ ├── drop-effect.spec.ts │ │ │ │ │ ├── guardrails.spec.ts │ │ │ │ │ ├── lift.spec.ts │ │ │ │ │ └── stickiness.spec.ts │ │ │ │ ├── dropping-outside-window.spec.ts │ │ │ │ ├── error-recovery.spec.ts │ │ │ │ ├── event-ordering/ │ │ │ │ │ ├── all.spec.ts │ │ │ │ │ ├── callback-data.spec.ts │ │ │ │ │ ├── drag-start-flushing.spec.ts │ │ │ │ │ ├── drag-start.spec.ts │ │ │ │ │ ├── drag-update-atomic.spec.ts │ │ │ │ │ ├── drag-update.spec.ts │ │ │ │ │ ├── drag.spec.ts │ │ │ │ │ ├── drop.spec.ts │ │ │ │ │ └── generate-drag-preview.spec.ts │ │ │ │ ├── events-and-adapter-mounting.spec.ts │ │ │ │ ├── global-event-binding.spec.ts │ │ │ │ ├── leaving-the-window.spec.ts │ │ │ │ ├── monitor/ │ │ │ │ │ ├── adding-monitors-during-events.spec.ts │ │ │ │ │ ├── call-order.spec.ts │ │ │ │ │ ├── publishing-events.spec.ts │ │ │ │ │ ├── removing-monitors-during-events.spec.ts │ │ │ │ │ └── uniqueness.spec.ts │ │ │ │ ├── previous-location-should-match-last-current.spec.ts │ │ │ │ ├── public-utils/ │ │ │ │ │ ├── block-dragging-to-iframes.spec.ts │ │ │ │ │ ├── center-under-pointer.spec.ts │ │ │ │ │ ├── format-urls-for-external.spec.ts │ │ │ │ │ ├── pointer-outside-of-preview.spec.ts │ │ │ │ │ ├── preserve-offset-on-source.spec.ts │ │ │ │ │ └── set-custom-native-drag-preview.spec.ts │ │ │ │ ├── repeated-dragging.spec.ts │ │ │ │ ├── resiliant-against-consumers-stopping-events-during-a-drag.spec.ts │ │ │ │ ├── resilient-against-multiple-cleanup-calls.spec.ts │ │ │ │ └── respecting-non-pdnd-code.spec.ts │ │ │ ├── external/ │ │ │ │ ├── adapter/ │ │ │ │ │ ├── can-monitor.spec.ts │ │ │ │ │ ├── drag-ownership/ │ │ │ │ │ │ ├── element-adapter.spec.ts │ │ │ │ │ │ └── uncontrolled-internal-adapter.spec.ts │ │ │ │ │ ├── drop-effect.spec.ts │ │ │ │ │ ├── exposing-data.spec.ts │ │ │ │ │ ├── get-string-data.spec.ts │ │ │ │ │ ├── global-event-binding.spec.ts │ │ │ │ │ ├── leaving-the-window.spec.ts │ │ │ │ │ ├── respecting-non-pdnd-code.spec.ts │ │ │ │ │ ├── starting-an-external-drag-before-registrations.spec.ts │ │ │ │ │ └── starting-an-external-drag.spec.ts │ │ │ │ ├── drop-targets/ │ │ │ │ │ └── nested.spec.ts │ │ │ │ └── utils/ │ │ │ │ ├── file/ │ │ │ │ │ ├── contains-files.spec.ts │ │ │ │ │ └── get-files.spec.ts │ │ │ │ ├── html/ │ │ │ │ │ ├── contains-html.spec.ts │ │ │ │ │ └── get-html.spec.ts │ │ │ │ ├── some.spec.ts │ │ │ │ ├── text/ │ │ │ │ │ ├── contains-text.spec.ts │ │ │ │ │ └── get-text.spec.ts │ │ │ │ └── url/ │ │ │ │ ├── contains-urls.spec.ts │ │ │ │ ├── firefox-fix.spec.ts │ │ │ │ └── url.spec.ts │ │ │ ├── honey-pot-fix/ │ │ │ │ ├── _util.ts │ │ │ │ ├── event-listeners.spec.ts │ │ │ │ ├── external-adapter-should-not-use-honey-pot.spec.ts │ │ │ │ ├── finishing.spec.ts │ │ │ │ ├── get-element-from-point-without-honey-pot.spec.ts │ │ │ │ ├── mid-drag.spec.ts │ │ │ │ ├── multiple-operations.spec.ts │ │ │ │ ├── starting.spec.ts │ │ │ │ └── text-adapter-smoke-test.spec.ts │ │ │ ├── public-utils/ │ │ │ │ ├── combine.spec.ts │ │ │ │ ├── once.spec.ts │ │ │ │ ├── prevent-unhandled.spec.ts │ │ │ │ └── reorder.spec.ts │ │ │ ├── react/ │ │ │ │ └── adding-monitors-during-events.spec.tsx │ │ │ ├── server-side-usage.spec.ts │ │ │ ├── test-environment-guardrail.spec.ts │ │ │ └── text-selection/ │ │ │ ├── adapter/ │ │ │ │ ├── drag-ownership/ │ │ │ │ │ ├── element-adapter.spec.ts │ │ │ │ │ └── external-adapter.spec.ts │ │ │ │ ├── event-ordering.spec.ts │ │ │ │ ├── global-event-binding.spec.ts │ │ │ │ ├── leaving-the-window.spec.ts │ │ │ │ ├── respecting-non-pdnd-code.spec.ts │ │ │ │ ├── starting-a-text-selection-drag-before-registrations.spec.ts │ │ │ │ └── text-target.spec.ts │ │ │ └── drop-targets/ │ │ │ └── nested.spec.ts │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ └── index/ │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ ├── _util/ │ │ │ │ ├── constants.tsx │ │ │ │ ├── fallback.ts │ │ │ │ └── global-styles.tsx │ │ │ ├── config.jsonc │ │ │ ├── drag-preview-with-transparency.tsx │ │ │ ├── element-adapter.tsx │ │ │ ├── file.tsx │ │ │ ├── iframe.tsx │ │ │ ├── native/ │ │ │ │ ├── activity-log.tsx │ │ │ │ ├── app.tsx │ │ │ │ ├── content.tsx │ │ │ │ └── drop-target.tsx │ │ │ ├── native.tsx │ │ │ ├── post-drop-bug-fix-simple.tsx │ │ │ ├── post-drop-bug-fix.tsx │ │ │ ├── preserve-offset-on-source.tsx │ │ │ ├── scroll-just-enough-into-view.tsx │ │ │ ├── stickiness.tsx │ │ │ ├── text-selection.tsx │ │ │ └── url.tsx │ │ ├── package.json │ │ ├── src/ │ │ │ ├── adapter/ │ │ │ │ ├── element-adapter-native-data-key.ts │ │ │ │ ├── element-adapter.ts │ │ │ │ ├── external-adapter.ts │ │ │ │ └── text-selection-adapter.ts │ │ │ ├── entry-point/ │ │ │ │ ├── cancel-unhandled.ts │ │ │ │ ├── combine.ts │ │ │ │ ├── element/ │ │ │ │ │ ├── adapter.ts │ │ │ │ │ ├── block-dragging-to-iframes.ts │ │ │ │ │ ├── center-under-pointer.ts │ │ │ │ │ ├── disable-native-drag-preview.ts │ │ │ │ │ ├── format-urls-for-external.ts │ │ │ │ │ ├── pointer-outside-of-preview.ts │ │ │ │ │ ├── preserve-offset-on-source.ts │ │ │ │ │ ├── scroll-just-enough-into-view.ts │ │ │ │ │ └── set-custom-native-drag-preview.ts │ │ │ │ ├── external/ │ │ │ │ │ ├── adapter.ts │ │ │ │ │ ├── file.ts │ │ │ │ │ ├── html.ts │ │ │ │ │ ├── some.ts │ │ │ │ │ ├── text.ts │ │ │ │ │ └── url.ts │ │ │ │ ├── once.ts │ │ │ │ ├── prevent-unhandled.ts │ │ │ │ ├── private/ │ │ │ │ │ └── get-element-from-point-without-honey-pot.ts │ │ │ │ ├── reorder.ts │ │ │ │ ├── text-selection/ │ │ │ │ │ └── adapter.ts │ │ │ │ └── types.ts │ │ │ ├── honey-pot-fix/ │ │ │ │ ├── get-element-from-point-without-honey-pot.ts │ │ │ │ ├── honey-pot-data-attribute.ts │ │ │ │ ├── is-honey-pot-element.ts │ │ │ │ └── make-honey-pot-fix.ts │ │ │ ├── index.ts │ │ │ ├── internal-types.ts │ │ │ ├── ledger/ │ │ │ │ ├── dispatch-consumer-event.ts │ │ │ │ ├── lifecycle-manager.ts │ │ │ │ └── usage-ledger.ts │ │ │ ├── make-adapter/ │ │ │ │ ├── make-adapter.ts │ │ │ │ ├── make-drop-target.ts │ │ │ │ └── make-monitor.ts │ │ │ ├── public-utils/ │ │ │ │ ├── combine.ts │ │ │ │ ├── custom-external-data-type-media-type-prefix.ts │ │ │ │ ├── element/ │ │ │ │ │ ├── block-dragging-to-iframes.ts │ │ │ │ │ ├── custom-native-drag-preview/ │ │ │ │ │ │ ├── center-under-pointer.ts │ │ │ │ │ │ ├── pointer-outside-of-preview.ts │ │ │ │ │ │ ├── preserve-offset-on-source.ts │ │ │ │ │ │ ├── set-custom-native-drag-preview.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── disable-native-drag-preview.ts │ │ │ │ │ ├── format-urls-for-external.ts │ │ │ │ │ └── scroll-just-enough-into-view.ts │ │ │ │ ├── external/ │ │ │ │ │ ├── file.ts │ │ │ │ │ ├── html.ts │ │ │ │ │ ├── native-types.ts │ │ │ │ │ ├── some.ts │ │ │ │ │ ├── text.ts │ │ │ │ │ └── url.ts │ │ │ │ ├── once.ts │ │ │ │ ├── prevent-unhandled.ts │ │ │ │ └── reorder.ts │ │ │ └── util/ │ │ │ ├── add-attribute.ts │ │ │ ├── android.ts │ │ │ ├── changing-window/ │ │ │ │ ├── count-events-for-safari.ts │ │ │ │ ├── is-entering-window.ts │ │ │ │ ├── is-from-another-window.ts │ │ │ │ └── is-leaving-window.ts │ │ │ ├── detect-broken-drag.ts │ │ │ ├── get-input.ts │ │ │ ├── is-firefox.ts │ │ │ ├── is-safari-on-ios.ts │ │ │ ├── is-safari.ts │ │ │ ├── max-z-index.ts │ │ │ └── media-types/ │ │ │ ├── html-media-type.ts │ │ │ ├── text-media-type.ts │ │ │ └── url-media-type.ts │ │ └── tsconfig.json │ ├── documentation/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ └── playwright/ │ │ │ ├── board.spec.ts │ │ │ └── tree.spec.ts │ │ ├── constellation/ │ │ │ ├── 00-examples/ │ │ │ │ └── index.mdx │ │ │ ├── 01-tutorial/ │ │ │ │ └── index.mdx │ │ │ ├── 05-core-package/ │ │ │ │ ├── 00-adapters/ │ │ │ │ │ ├── 00-element/ │ │ │ │ │ │ ├── about.mdx │ │ │ │ │ │ ├── drag-previews.mdx │ │ │ │ │ │ ├── other-utilities.mdx │ │ │ │ │ │ └── unregistered-elements.mdx │ │ │ │ │ ├── 01-text-selection/ │ │ │ │ │ │ └── about.mdx │ │ │ │ │ ├── 02-external/ │ │ │ │ │ │ ├── HTML.mdx │ │ │ │ │ │ ├── URLs.mdx │ │ │ │ │ │ ├── about.mdx │ │ │ │ │ │ ├── custom-media-types.mdx │ │ │ │ │ │ ├── files.mdx │ │ │ │ │ │ └── text.mdx │ │ │ │ │ └── index.mdx │ │ │ │ ├── 03-drop-targets/ │ │ │ │ │ └── index.mdx │ │ │ │ ├── 04-monitors/ │ │ │ │ │ └── index.mdx │ │ │ │ ├── 05-utilities/ │ │ │ │ │ └── index.mdx │ │ │ │ ├── 06-events/ │ │ │ │ │ └── index.mdx │ │ │ │ ├── 07-reconciliation/ │ │ │ │ │ └── index.mdx │ │ │ │ ├── 08-UI-frameworks/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ └── react.mdx │ │ │ │ ├── 09-recipes/ │ │ │ │ │ ├── 00-isolating-experiences/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── 01-typing-data/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── 02-virtualization/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── 03-deferred-loading/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ └── react.mdx │ │ │ │ │ └── index.mdx │ │ │ │ ├── 11-testing/ │ │ │ │ │ ├── about.mdx │ │ │ │ │ ├── cypress.mdx │ │ │ │ │ ├── jest-and-jsdom.mdx │ │ │ │ │ ├── playwright.mdx │ │ │ │ │ ├── puppeteer.mdx │ │ │ │ │ └── webdriver.mdx │ │ │ │ ├── 12-upgrade-guides/ │ │ │ │ │ └── upgrade-guide-0.x-→-1.0.mdx │ │ │ │ └── index.mdx │ │ │ ├── 06-optional-packages/ │ │ │ │ └── index.mdx │ │ │ ├── 07-web-platform-design-constraints/ │ │ │ │ └── index.mdx │ │ │ ├── 08-design-guidelines/ │ │ │ │ └── index.mdx │ │ │ ├── 09-accessibility-guidelines/ │ │ │ │ ├── index.mdx │ │ │ │ └── pattern-table.tsx │ │ │ ├── assets/ │ │ │ │ ├── check-icon.tsx │ │ │ │ ├── cross-icon.tsx │ │ │ │ ├── question-icon.tsx │ │ │ │ ├── result-text.tsx │ │ │ │ └── warning-icon.tsx │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ ├── assets/ │ │ │ │ ├── hero.tsx │ │ │ │ └── logo.tsx │ │ │ ├── comparison.mdx │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ ├── board-with-multi-drag.tsx │ │ │ ├── board-with-overflow-scroll.tsx │ │ │ ├── board.tsx │ │ │ ├── chess.tsx │ │ │ ├── config.jsonc │ │ │ ├── data/ │ │ │ │ ├── pages.ts │ │ │ │ ├── people/ │ │ │ │ │ ├── images/ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ └── processed/ │ │ │ │ │ │ ├── Alexander.ts │ │ │ │ │ │ ├── Aliza.ts │ │ │ │ │ │ ├── Alvin.ts │ │ │ │ │ │ ├── Angie.ts │ │ │ │ │ │ ├── Arjun.ts │ │ │ │ │ │ ├── Blair.ts │ │ │ │ │ │ ├── Claudia.ts │ │ │ │ │ │ ├── Colin.ts │ │ │ │ │ │ ├── Ed.ts │ │ │ │ │ │ ├── Effie.ts │ │ │ │ │ │ ├── Eliot.ts │ │ │ │ │ │ ├── Fabian.ts │ │ │ │ │ │ ├── Gael.ts │ │ │ │ │ │ ├── Gerard.ts │ │ │ │ │ │ ├── Hasan.ts │ │ │ │ │ │ ├── Helena.ts │ │ │ │ │ │ ├── Ivan.ts │ │ │ │ │ │ ├── Katina.ts │ │ │ │ │ │ ├── Lara.ts │ │ │ │ │ │ ├── Leo.ts │ │ │ │ │ │ ├── Lydia.ts │ │ │ │ │ │ ├── Maribel.ts │ │ │ │ │ │ ├── Milo.ts │ │ │ │ │ │ ├── Myra.ts │ │ │ │ │ │ ├── Narul.ts │ │ │ │ │ │ ├── Norah.ts │ │ │ │ │ │ ├── Oliver.ts │ │ │ │ │ │ ├── Rahul.ts │ │ │ │ │ │ ├── Renato.ts │ │ │ │ │ │ ├── Steve.ts │ │ │ │ │ │ ├── Tanya.ts │ │ │ │ │ │ ├── Tori.ts │ │ │ │ │ │ └── Vania.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── presidents.tsx │ │ │ │ ├── quotes/ │ │ │ │ │ ├── data.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── table.tsx │ │ │ │ ├── tasks.ts │ │ │ │ ├── tree-legacy.ts │ │ │ │ └── tree.ts │ │ │ ├── deferred.tsx │ │ │ ├── drag-handle-button.tsx │ │ │ ├── drag-handles.tsx │ │ │ ├── drawing.tsx │ │ │ ├── file-drop-without-pragmatic.tsx │ │ │ ├── file.tsx │ │ │ ├── flash-prototype.tsx │ │ │ ├── grid.tsx │ │ │ ├── guidelines/ │ │ │ │ ├── action-menu-variants.tsx │ │ │ │ ├── all-drag-handle-variants.tsx │ │ │ │ ├── delayed-cursor-change.tsx │ │ │ │ ├── entire-entity-is-draggable-with-drag-handle-button.tsx │ │ │ │ ├── entire-entity-is-draggable-with-grouped-items.tsx │ │ │ │ ├── entire-entity-is-draggable.tsx │ │ │ │ ├── hover-drag-handle-outside-bounds.tsx │ │ │ │ ├── hover-drag-handle.tsx │ │ │ │ ├── only-draggable-from-drag-handle.tsx │ │ │ │ ├── shared/ │ │ │ │ │ ├── action-menu.tsx │ │ │ │ │ ├── drag-preview.tsx │ │ │ │ │ └── types.ts │ │ │ │ └── standalone-card.tsx │ │ │ ├── guidelines.tsx │ │ │ ├── icons/ │ │ │ │ ├── invision.tsx │ │ │ │ ├── portfolio.tsx │ │ │ │ ├── slack.tsx │ │ │ │ └── tempo.tsx │ │ │ ├── iframe-board.tsx │ │ │ ├── iframe-column.tsx │ │ │ ├── list-comparison.tsx │ │ │ ├── list.tsx │ │ │ ├── manual-focus-restoration.tsx │ │ │ ├── nested-draggables.tsx │ │ │ ├── nested-drop-targets.tsx │ │ │ ├── pieces/ │ │ │ │ ├── backlog/ │ │ │ │ │ ├── container.tsx │ │ │ │ │ ├── context.tsx │ │ │ │ │ ├── data.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── list-item.tsx │ │ │ │ │ └── list.tsx │ │ │ │ ├── board/ │ │ │ │ │ ├── board-context.tsx │ │ │ │ │ ├── board.tsx │ │ │ │ │ ├── card.tsx │ │ │ │ │ ├── column-context.tsx │ │ │ │ │ ├── column.tsx │ │ │ │ │ └── registry.ts │ │ │ │ ├── board-with-multi-drag/ │ │ │ │ │ ├── board.tsx │ │ │ │ │ ├── card.tsx │ │ │ │ │ └── column.tsx │ │ │ │ ├── board-with-overflow-scroll/ │ │ │ │ │ ├── board.tsx │ │ │ │ │ ├── card.tsx │ │ │ │ │ └── column.tsx │ │ │ │ ├── chess/ │ │ │ │ │ ├── piece.tsx │ │ │ │ │ └── square.tsx │ │ │ │ ├── drawing/ │ │ │ │ │ ├── line-overlay.tsx │ │ │ │ │ └── shape.tsx │ │ │ │ ├── getting-started/ │ │ │ │ │ ├── chessboard-colored-drop-targets.tsx │ │ │ │ │ ├── chessboard-draggable.tsx │ │ │ │ │ ├── chessboard-drop-target.tsx │ │ │ │ │ ├── chessboard-drop-targets-can-drop.tsx │ │ │ │ │ ├── chessboard-monitor.tsx │ │ │ │ │ ├── chessboard-starter-code.tsx │ │ │ │ │ ├── draggable-piece-in-place.tsx │ │ │ │ │ ├── draggable-piece-with-data.tsx │ │ │ │ │ ├── draggable-piece-with-state.tsx │ │ │ │ │ ├── square-drop-target.tsx │ │ │ │ │ ├── square-with-can-drop.tsx │ │ │ │ │ ├── square-with-data.tsx │ │ │ │ │ └── square-with-hovering-coloring.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-flash-on-drop.tsx │ │ │ │ │ ├── use-prevent-scrolling-from-arrow-keys.tsx │ │ │ │ │ ├── use-sortable-field.tsx │ │ │ │ │ └── use-top-level-wiring.tsx │ │ │ │ ├── iframe-board/ │ │ │ │ │ ├── card.tsx │ │ │ │ │ ├── column.tsx │ │ │ │ │ └── data.ts │ │ │ │ ├── menu-button/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── pinned-fields/ │ │ │ │ │ ├── data.tsx │ │ │ │ │ ├── experience/ │ │ │ │ │ │ ├── asana-native-preview.tsx │ │ │ │ │ │ ├── asana.tsx │ │ │ │ │ │ ├── current-guidelines-a11y-always-visible.tsx │ │ │ │ │ │ ├── current-guidelines-a11y-keyboard-only.tsx │ │ │ │ │ │ ├── current-guidelines.tsx │ │ │ │ │ │ ├── enhanced-drag-handle.tsx │ │ │ │ │ │ ├── migration-layer.tsx │ │ │ │ │ │ ├── rdr-prototype.tsx │ │ │ │ │ │ └── react-beautiful-dnd.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ └── use-sortable-field.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── major-priority-icon.tsx │ │ │ │ │ ├── primitives/ │ │ │ │ │ │ ├── asana/ │ │ │ │ │ │ │ ├── constants.tsx │ │ │ │ │ │ │ ├── drop-indicator.tsx │ │ │ │ │ │ │ └── field.tsx │ │ │ │ │ │ └── droppable-area-overlay.tsx │ │ │ │ │ ├── templates/ │ │ │ │ │ │ ├── asana.tsx │ │ │ │ │ │ ├── atlassian.tsx │ │ │ │ │ │ └── react-beautiful-dnd.tsx │ │ │ │ │ └── use-drag-observer.tsx │ │ │ │ ├── post-drop-flash/ │ │ │ │ │ └── list.tsx │ │ │ │ ├── rdr-board/ │ │ │ │ │ ├── board-context.tsx │ │ │ │ │ ├── board.tsx │ │ │ │ │ ├── card-stack.tsx │ │ │ │ │ ├── card.tsx │ │ │ │ │ ├── column-context.tsx │ │ │ │ │ ├── column.tsx │ │ │ │ │ ├── data.tsx │ │ │ │ │ ├── epic-lozenge.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── rdr-pinned-fields/ │ │ │ │ │ ├── container.tsx │ │ │ │ │ ├── context.tsx │ │ │ │ │ ├── data.tsx │ │ │ │ │ ├── drag-handle-button.tsx │ │ │ │ │ ├── field.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── list-item.tsx │ │ │ │ │ ├── list.tsx │ │ │ │ │ └── major-priority-icon.tsx │ │ │ │ ├── rdr-subtasks/ │ │ │ │ │ ├── container.tsx │ │ │ │ │ ├── context.tsx │ │ │ │ │ ├── data.tsx │ │ │ │ │ ├── drag-handle-button.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── list-item.tsx │ │ │ │ │ ├── list.tsx │ │ │ │ │ └── subtask-icon.tsx │ │ │ │ ├── subtasks/ │ │ │ │ │ ├── data.tsx │ │ │ │ │ ├── demo/ │ │ │ │ │ │ ├── current-guidelines-a11y-always-visible.tsx │ │ │ │ │ │ ├── current-guidelines-a11y-keyboard-only.tsx │ │ │ │ │ │ ├── current-guidelines.tsx │ │ │ │ │ │ ├── enhancements.tsx │ │ │ │ │ │ ├── linear-native-preview.tsx │ │ │ │ │ │ ├── linear.tsx │ │ │ │ │ │ ├── migration-layer.tsx │ │ │ │ │ │ ├── notion.tsx │ │ │ │ │ │ └── react-beautiful-dnd.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── use-sortable-field.tsx │ │ │ │ │ │ └── use-top-level-wiring.tsx │ │ │ │ │ ├── primitives/ │ │ │ │ │ │ ├── linear/ │ │ │ │ │ │ │ ├── constants.tsx │ │ │ │ │ │ │ ├── in-progress-icon.tsx │ │ │ │ │ │ │ ├── priority-icon.tsx │ │ │ │ │ │ │ ├── subtask-container.tsx │ │ │ │ │ │ │ └── subtask.tsx │ │ │ │ │ │ ├── major-priority-icon.tsx │ │ │ │ │ │ ├── notion/ │ │ │ │ │ │ │ ├── constants.tsx │ │ │ │ │ │ │ ├── drop-indicator.tsx │ │ │ │ │ │ │ ├── subtask-container.tsx │ │ │ │ │ │ │ └── subtask.tsx │ │ │ │ │ │ ├── subtask-container.tsx │ │ │ │ │ │ ├── subtask-drag-handle.tsx │ │ │ │ │ │ ├── subtask-icon.tsx │ │ │ │ │ │ └── subtask.tsx │ │ │ │ │ └── templates/ │ │ │ │ │ ├── _base.tsx │ │ │ │ │ └── linear.tsx │ │ │ │ ├── table/ │ │ │ │ │ ├── constants.tsx │ │ │ │ │ ├── data.ts │ │ │ │ │ ├── menu-button.tsx │ │ │ │ │ ├── render-pieces.tsx │ │ │ │ │ ├── row.tsx │ │ │ │ │ ├── table-context.ts │ │ │ │ │ ├── table-header.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── tree/ │ │ │ │ │ ├── move-dialog.tsx │ │ │ │ │ ├── tree-context.tsx │ │ │ │ │ └── tree-item.tsx │ │ │ │ └── tree-legacy/ │ │ │ │ ├── constants.ts │ │ │ │ ├── move-dialog.tsx │ │ │ │ ├── tree-context.tsx │ │ │ │ └── tree-item.tsx │ │ │ ├── resizing.tsx │ │ │ ├── table.tsx │ │ │ ├── text-selection.tsx │ │ │ ├── tree-legacy.tsx │ │ │ ├── tree.tsx │ │ │ ├── trello-like-board-iframe.tsx │ │ │ ├── util/ │ │ │ │ ├── constants.tsx │ │ │ │ ├── fallback.ts │ │ │ │ └── global-styles.tsx │ │ │ └── virtual-list.tsx │ │ ├── package.json │ │ ├── scripts/ │ │ │ └── codegen.ts │ │ ├── src/ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── flourish/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ ├── index/ │ │ │ │ ├── about.mdx │ │ │ │ └── props.mdx │ │ │ └── trigger-post-move-flash/ │ │ │ ├── examples.mdx │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ ├── basic.tsx │ │ │ ├── config.jsonc │ │ │ └── constellation/ │ │ │ └── props-table.tsx │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.tsx │ │ │ └── trigger-post-move-flash.tsx │ │ └── tsconfig.json │ ├── hitbox/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ └── unit/ │ │ │ ├── _util.ts │ │ │ ├── closest-edge.spec.ts │ │ │ ├── get-reorder-destination-index.spec.ts │ │ │ ├── list-item-memoization.spec.ts │ │ │ ├── list-item.spec.ts │ │ │ ├── reorder-with-edge.spec.ts │ │ │ ├── test-helpers.spec.ts │ │ │ ├── tree-item-memoization.spec.ts │ │ │ └── tree-item.spec.ts │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ └── config.jsonc │ │ ├── package.json │ │ ├── src/ │ │ │ ├── closest-edge.ts │ │ │ ├── get-reorder-destination-index.ts │ │ │ ├── index.ts │ │ │ ├── internal/ │ │ │ │ └── memoize.ts │ │ │ ├── list-item.ts │ │ │ ├── reorder-with-edge.ts │ │ │ ├── tree-item.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── live-region/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ └── unit/ │ │ │ ├── announce.tsx │ │ │ ├── cleanup.tsx │ │ │ └── dom.tsx │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ ├── 00-basic.tsx │ │ │ ├── 01-list-with-inline-buttons.tsx │ │ │ └── config.jsonc │ │ ├── package.json │ │ ├── src/ │ │ │ ├── constants.tsx │ │ │ └── index.tsx │ │ └── tsconfig.json │ ├── react-accessibility/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ └── unit/ │ │ │ └── ssr.tsx │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ ├── drag-handle-button/ │ │ │ │ ├── about.mdx │ │ │ │ └── props.mdx │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ ├── config.jsonc │ │ │ ├── drag-handle-button-small.tsx │ │ │ ├── drag-handle-button.tsx │ │ │ └── drag-handle-dropdown-menu.tsx │ │ ├── extract-react-types/ │ │ │ └── drag-handle-button.tsx │ │ ├── package.json │ │ ├── src/ │ │ │ ├── drag-handle-button-base.tsx │ │ │ ├── drag-handle-button-small.tsx │ │ │ ├── drag-handle-button.tsx │ │ │ ├── index.tsx │ │ │ └── types.tsx │ │ └── tsconfig.json │ ├── react-beautiful-dnd-autoscroll/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ └── unit/ │ │ │ ├── _util.tsx │ │ │ ├── auto-scrolling.spec.ts │ │ │ ├── get-closest-scrollable.spec.ts │ │ │ ├── get-max-scroll.spec.ts │ │ │ ├── get-percentage.spec.ts │ │ │ └── get-scroll/ │ │ │ ├── dampen-value-by-time.spec.ts │ │ │ ├── get-distance-threshold.spec.ts │ │ │ ├── get-scroll-on-axis.spec.ts │ │ │ ├── get-value-from-distance.spec.ts │ │ │ ├── get-value.spec.ts │ │ │ └── index.spec.ts │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ └── props.mdx │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ └── internal/ │ │ │ ├── can-scroll.ts │ │ │ ├── config.ts │ │ │ ├── constants.ts │ │ │ ├── get-closest-scrollable-element.ts │ │ │ ├── get-max-scroll.ts │ │ │ ├── get-percentage.ts │ │ │ ├── get-scroll/ │ │ │ │ ├── get-scroll-on-axis/ │ │ │ │ │ ├── dampen-value-by-time.ts │ │ │ │ │ ├── get-distance-thresholds.ts │ │ │ │ │ ├── get-value-from-distance.ts │ │ │ │ │ ├── get-value.ts │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── get-scrollable-scroll-change.ts │ │ │ ├── get-scrollable.ts │ │ │ ├── get-window-scroll-change.ts │ │ │ ├── position.ts │ │ │ ├── scroll.ts │ │ │ ├── types.ts │ │ │ └── window/ │ │ │ ├── get-max-window-scroll.ts │ │ │ ├── get-viewport.ts │ │ │ └── get-window-scroll.ts │ │ └── tsconfig.json │ ├── react-beautiful-dnd-migration/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ ├── informational-vr-tests/ │ │ │ │ ├── drop-indicator.vr.tsx │ │ │ │ ├── keyboard-drag-preview.vr.tsx │ │ │ │ ├── scroll-container.vr.tsx │ │ │ │ └── smoke.vr.tsx │ │ │ ├── playwright/ │ │ │ │ └── virtual.spec.tsx │ │ │ └── unit/ │ │ │ ├── _util.tsx │ │ │ ├── _utils/ │ │ │ │ ├── board.tsx │ │ │ │ ├── setup.tsx │ │ │ │ └── with-set-element-from-point.tsx │ │ │ ├── abort.test.tsx │ │ │ ├── batch-updates-for-react-18.test.tsx │ │ │ ├── browser-focus.test.tsx │ │ │ ├── destination.test.tsx │ │ │ ├── draggable/ │ │ │ │ ├── _utils.tsx │ │ │ │ ├── find-drag-handle.test.tsx │ │ │ │ ├── keyboard.test.tsx │ │ │ │ ├── placeholder.test.tsx │ │ │ │ ├── portal.test.tsx │ │ │ │ ├── provided.test.tsx │ │ │ │ └── timing.test.tsx │ │ │ ├── droppable/ │ │ │ │ ├── auto-scroll.test.tsx │ │ │ │ ├── closest-edge.test.tsx │ │ │ │ ├── drop-indicator.test.tsx │ │ │ │ ├── gap/ │ │ │ │ │ ├── calculate-gap.test.tsx │ │ │ │ │ └── get-distance.test.tsx │ │ │ │ ├── is-drop-disabled.test.tsx │ │ │ │ └── resting.test.tsx │ │ │ ├── error-handling.test.tsx │ │ │ ├── live-region.test.tsx │ │ │ ├── multi-context.test.tsx │ │ │ ├── ported-from-react-beautiful-dnd/ │ │ │ │ ├── _utils/ │ │ │ │ │ ├── cause-runtime-error.tsx │ │ │ │ │ └── console.tsx │ │ │ │ └── unit/ │ │ │ │ ├── integration/ │ │ │ │ │ ├── _utils/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── controls.tsx │ │ │ │ │ │ └── helpers.tsx │ │ │ │ │ ├── body-removal-before-unmount.test.tsx │ │ │ │ │ ├── disable-on-start.test.tsx │ │ │ │ │ ├── drag-drop-context/ │ │ │ │ │ │ ├── error-handling/ │ │ │ │ │ │ │ ├── error-in-react-tree.test.tsx │ │ │ │ │ │ │ └── error-on-window.test.tsx │ │ │ │ │ │ ├── on-before-capture/ │ │ │ │ │ │ │ ├── additions.test.tsx │ │ │ │ │ │ │ └── removals.test.tsx │ │ │ │ │ │ └── unmount.test.tsx │ │ │ │ │ ├── drag-handle/ │ │ │ │ │ │ ├── keyboard-sensor/ │ │ │ │ │ │ │ ├── directional-movement.test.tsx │ │ │ │ │ │ │ ├── no-click-blocking.test.tsx │ │ │ │ │ │ │ ├── prevent-keyboard-scroll.test.tsx │ │ │ │ │ │ │ ├── prevent-standard-keys-while-dragging.test.tsx │ │ │ │ │ │ │ ├── starting-a-drag.test.tsx │ │ │ │ │ │ │ └── stopping-a-drag.test.tsx │ │ │ │ │ │ ├── mouse-sensor/ │ │ │ │ │ │ │ └── starting-a-dragging.test.tsx │ │ │ │ │ │ └── shared-behaviors/ │ │ │ │ │ │ ├── abort-on-error.test.tsx │ │ │ │ │ │ ├── cancel-while-dragging.test.tsx │ │ │ │ │ │ ├── cannot-start-when-disabled.test.tsx │ │ │ │ │ │ ├── cannot-start-when-unmounted.test.tsx │ │ │ │ │ │ ├── cleanup.test.tsx │ │ │ │ │ │ ├── contenteditable.test.tsx │ │ │ │ │ │ ├── interactive-elements.test.tsx │ │ │ │ │ │ ├── nested-handles.test.tsx │ │ │ │ │ │ ├── parent-rendering-should-not-kill-drag.test.tsx │ │ │ │ │ │ └── validate-controls.test.tsx │ │ │ │ │ ├── draggable/ │ │ │ │ │ │ ├── dragging.test.tsx │ │ │ │ │ │ ├── portal.test.tsx │ │ │ │ │ │ ├── resting.test.tsx │ │ │ │ │ │ └── validation.test.tsx │ │ │ │ │ ├── droppable/ │ │ │ │ │ │ ├── _placeholder.test.tsx │ │ │ │ │ │ └── clone.test.tsx │ │ │ │ │ ├── reorder-render-sync.test.tsx │ │ │ │ │ ├── responders-integration.test.tsx │ │ │ │ │ ├── responders-timing.test.tsx │ │ │ │ │ └── server-side-rendering/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── server-rendering.test.tsx.snap │ │ │ │ │ ├── client-hydration.test.tsx │ │ │ │ │ └── server-rendering.test.tsx │ │ │ │ ├── state/ │ │ │ │ │ └── middleware/ │ │ │ │ │ └── responders/ │ │ │ │ │ ├── abort.test.tsx │ │ │ │ │ ├── announcements.test.tsx │ │ │ │ │ ├── flushing.test.tsx │ │ │ │ │ ├── repeated-use.test.tsx │ │ │ │ │ ├── start.test.tsx │ │ │ │ │ └── update.test.tsx │ │ │ │ └── view/ │ │ │ │ ├── droppable/ │ │ │ │ │ └── inner-ref-validation.test.tsx │ │ │ │ └── style-marshal/ │ │ │ │ ├── get-styles.test.tsx │ │ │ │ └── style-marshal.test.tsx │ │ │ └── virtual.test.tsx │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── codemods/ │ │ │ ├── 0.1.0-adoption-from-rbd-12.tsx │ │ │ ├── 0.1.0-adoption-from-rbd-13.tsx │ │ │ ├── __tests__/ │ │ │ │ ├── adoption-from-rbd-12.test.tsx │ │ │ │ ├── adoption-from-rbd-13.test.tsx │ │ │ │ └── migration/ │ │ │ │ ├── migrate-12-to-13.test.tsx │ │ │ │ ├── update-imports.test.tsx │ │ │ │ ├── warn-about-react-beautiful-dnd-next.test.tsx │ │ │ │ ├── warn-about-removed-exports.test.tsx │ │ │ │ └── warn-about-unsupported-props.test.tsx │ │ │ ├── migrations/ │ │ │ │ ├── migrate-12-to-13.tsx │ │ │ │ ├── update-imports.tsx │ │ │ │ ├── warn-about-react-beautiful-dnd-next.tsx │ │ │ │ ├── warn-about-removed-exports.tsx │ │ │ │ └── warn-about-unsupported-props.tsx │ │ │ └── utils.tsx │ │ ├── constellation/ │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ ├── comparison.mdx │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ ├── 00-vertical-list.tsx │ │ │ ├── 01-board.tsx │ │ │ ├── 02-react-window.tsx │ │ │ ├── 03-react-virtualized.tsx │ │ │ ├── 04-multi-context.tsx │ │ │ ├── 05-scroll-container.tsx │ │ │ ├── config.jsonc │ │ │ ├── data/ │ │ │ │ └── tasks.ts │ │ │ └── pieces/ │ │ │ ├── card.tsx │ │ │ ├── column.tsx │ │ │ ├── example-wrapper.tsx │ │ │ ├── global-styles.tsx │ │ │ ├── react-virtualized/ │ │ │ │ └── column.tsx │ │ │ └── react-window/ │ │ │ └── column.tsx │ │ ├── package.json │ │ ├── src/ │ │ │ ├── dev-warning.tsx │ │ │ ├── drag-drop-context/ │ │ │ │ ├── cancel-drag.tsx │ │ │ │ ├── draggable-location.tsx │ │ │ │ ├── droppable-registry.tsx │ │ │ │ ├── error-boundary.tsx │ │ │ │ ├── get-destination.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-hidden-text-element.tsx │ │ │ │ │ ├── use-keyboard-controls.tsx │ │ │ │ │ ├── use-pointer-controls.tsx │ │ │ │ │ └── use-style-marshal.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── internal-context.tsx │ │ │ │ ├── lifecycle-context.tsx │ │ │ │ ├── live-region.tsx │ │ │ │ ├── rbd-invariant.tsx │ │ │ │ ├── screen-reader.tsx │ │ │ │ ├── types.tsx │ │ │ │ └── use-scheduler.tsx │ │ │ ├── draggable/ │ │ │ │ ├── constants.tsx │ │ │ │ ├── data.tsx │ │ │ │ ├── get-draggable-provided-style.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── is-event-in-interactive-element.tsx │ │ │ │ ├── placeholder.tsx │ │ │ │ ├── state.tsx │ │ │ │ └── use-draggable-state-snapshot.tsx │ │ │ ├── droppable/ │ │ │ │ ├── data.tsx │ │ │ │ ├── draggable-clone.tsx │ │ │ │ ├── drop-indicator/ │ │ │ │ │ ├── constants.tsx │ │ │ │ │ ├── get-dimensions.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.tsx │ │ │ │ ├── droppable-context.tsx │ │ │ │ ├── gap/ │ │ │ │ │ ├── get-distance.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── state.tsx │ │ │ │ └── virtual-placeholder.tsx │ │ │ ├── hooks/ │ │ │ │ ├── use-captured-dimensions.tsx │ │ │ │ ├── use-cleanup-fn.tsx │ │ │ │ ├── use-drop-target-for-draggable.tsx │ │ │ │ ├── use-isomorphic-layout-effect.tsx │ │ │ │ └── use-keyboard-context.tsx │ │ │ ├── index.ts │ │ │ ├── internal-types.tsx │ │ │ ├── reset-server-context.tsx │ │ │ └── utils/ │ │ │ ├── attributes.tsx │ │ │ ├── batch-updates-for-react-16.tsx │ │ │ ├── find-all-draggables.tsx │ │ │ ├── find-closest-scroll-container.tsx │ │ │ ├── find-drag-handle.tsx │ │ │ ├── find-drop-indicator.tsx │ │ │ ├── find-element.tsx │ │ │ ├── find-placeholder.tsx │ │ │ ├── get-best-cross-axis-droppable.tsx │ │ │ ├── get-closest-positioned-element.tsx │ │ │ ├── get-element-by-draggable-location.tsx │ │ │ └── use-stable.tsx │ │ └── tsconfig.json │ ├── react-drop-indicator/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ └── unit/ │ │ │ └── react-safety.test.tsx │ │ ├── afm-jira/ │ │ │ └── tsconfig.json │ │ ├── afm-products/ │ │ │ └── tsconfig.json │ │ ├── constellation/ │ │ │ └── index/ │ │ │ ├── about.mdx │ │ │ └── props.mdx │ │ ├── examples/ │ │ │ ├── 00-closest-edge.tsx │ │ │ ├── 01-gap.tsx │ │ │ ├── 11-tree-item.tsx │ │ │ ├── box-playground.tsx │ │ │ ├── config.jsonc │ │ │ ├── constellation/ │ │ │ │ ├── border/ │ │ │ │ │ └── border-showcase.tsx │ │ │ │ ├── box/ │ │ │ │ │ ├── box-appearance.tsx │ │ │ │ │ ├── box-edge.tsx │ │ │ │ │ ├── box-gap.tsx │ │ │ │ │ ├── box-indent.tsx │ │ │ │ │ ├── box-overlap.tsx │ │ │ │ │ └── box-type.tsx │ │ │ │ ├── group/ │ │ │ │ │ └── group-list.tsx │ │ │ │ ├── list-item/ │ │ │ │ │ ├── list-item-horizontal.tsx │ │ │ │ │ └── list-item-vertical.tsx │ │ │ │ ├── simple-item.tsx │ │ │ │ └── tree-item.tsx │ │ │ ├── internal/ │ │ │ │ ├── card.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── list.tsx │ │ │ │ └── tree-item.tsx │ │ │ ├── line.tsx │ │ │ └── outline.tsx │ │ ├── package.json │ │ ├── src/ │ │ │ ├── border.tsx │ │ │ ├── box.tsx │ │ │ ├── group.tsx │ │ │ ├── index.ts │ │ │ ├── internal/ │ │ │ │ ├── README.md │ │ │ │ ├── border.tsx │ │ │ │ └── line.tsx │ │ │ ├── internal-types.ts │ │ │ ├── list-item.tsx │ │ │ ├── presets.tsx │ │ │ ├── tree-item.tsx │ │ │ └── types.ts │ │ └── tsconfig.json │ └── unit-testing/ │ ├── .npmignore │ ├── CHANGELOG.md │ ├── LICENSE.md │ ├── README.md │ ├── __tests__/ │ │ └── unit/ │ │ ├── dom-rect-polyfill.spec.ts │ │ └── drag-event-polyfill/ │ │ ├── data-transfer-files.spec.ts │ │ ├── data-transfer-item-list.spec.ts │ │ └── data-transfer.spec.ts │ ├── afm-products/ │ │ └── tsconfig.json │ ├── constellation/ │ │ └── index/ │ │ ├── about.mdx │ │ └── props.mdx │ ├── package.json │ ├── src/ │ │ ├── dom-rect-polyfill.ts │ │ ├── drag-event-polyfill.ts │ │ └── index.ts │ └── tsconfig.json ├── patches/ │ └── @types+jest+29.5.12.patch └── tsconfig.json
SYMBOL INDEX (1663 symbols across 512 files)
FILE: packages/auto-scroll/__tests__/unit/_util.ts
function getDefaultInput (line 15) | function getDefaultInput(overrides: Partial<Input> = {}): Input {
function appendToBody (line 38) | function appendToBody(...elements: Element[]): CleanupFn {
function getEmptyHistory (line 50) | function getEmptyHistory(input: Input = getDefaultInput()): DragLocation...
function getInitialHistory (line 65) | function getInitialHistory(
function setBoundingClientRect (line 83) | function setBoundingClientRect(el: HTMLElement, rect: DOMRect): CleanupFn {
function tryGetRect (line 92) | function tryGetRect(box: Partial<Parameters<typeof getRect>[0]>): DOMRect {
function getRect (line 102) | function getRect(box: {
function getElements (line 125) | function getElements(tagName: keyof HTMLElementTagNameMap = 'div'): Iter...
function getBubbleOrderedTree (line 144) | function getBubbleOrderedTree(
method lift (line 170) | lift(target: HTMLElement, input?: Partial<Input>): void {
method drop (line 183) | drop(target: Element): void {
method cancel (line 186) | cancel(target: Element = document.body): void {
method leaveWindow (line 192) | leaveWindow(): void {
method startExternalDrag (line 195) | startExternalDrag({
method rougePointerMoves (line 213) | rougePointerMoves(): void {
function reset (line 223) | async function reset(): Promise<void> {
function getBubbleOrderedPath (line 231) | function getBubbleOrderedPath(path: Element[]): Element[] {
function setElementFromPointWithPath (line 245) | function setElementFromPointWithPath(path: Element[]): CleanupFn {
function setElementFromPoint (line 258) | function setElementFromPoint(element: Element | null): CleanupFn {
function stepScrollBy (line 264) | function stepScrollBy(): void {
function setStartSystemTime (line 275) | function setStartSystemTime(): void {
function advanceTimersToNextFrame (line 284) | function advanceTimersToNextFrame(): void {
type BasicElementArgs (line 297) | type BasicElementArgs = {
function setupNestedScrollContainers (line 304) | function setupNestedScrollContainers(bubbleOrdered: BasicElementArgs[]):...
function setupBasicScrollContainer (line 425) | function setupBasicScrollContainer({
type Point (line 439) | type Point = Position & { label: string };
function getInsidePoints (line 440) | function getInsidePoints(rect: DOMRect): Point[] {
function getOutsidePoints (line 454) | function getOutsidePoints(rect: DOMRect): Point[] {
type AxisScroll (line 474) | type AxisScroll = Record<Axis, number>;
type AxisMovement (line 475) | type AxisMovement = Record<Axis, boolean>;
type Event (line 476) | type Event = { type: string } & Partial<AxisMovement>;
type Scenario (line 477) | type Scenario = {
function getScenarios (line 484) | function getScenarios(rect: DOMRect, offset: number = 0): Scenario[] {
function getAxisScroll (line 585) | function getAxisScroll(container: HTMLElement): AxisScroll {
function hasAxisScrolled (line 592) | function hasAxisScrolled(container: HTMLElement, previousScroll: AxisScr...
function isExpectingScrollEvent (line 599) | function isExpectingScrollEvent(movement: AxisMovement): boolean {
function getExpectedEvents (line 603) | function getExpectedEvents(movement: AxisMovement): Event[] {
type TTarget (line 615) | type TTarget = Element | Window | Document;
function makeDispatch (line 616) | function makeDispatch(eventName: string) {
FILE: packages/auto-scroll/__tests__/unit/over-element/distance-dampening.spec.ts
type Scenario (line 42) | type Scenario = {
method listener (line 101) | listener() {
FILE: packages/auto-scroll/__tests__/unit/over-element/hitbox.spec.ts
type Scenario (line 29) | type Scenario = {
type Group (line 35) | type Group = {
method listener (line 245) | listener() {
method listener (line 321) | listener() {
FILE: packages/auto-scroll/__tests__/unit/over-element/max-speed.spec.ts
function stepFrame (line 34) | function stepFrame({ frameDuration }: { frameDuration: number }) {
function stepScrollBy (line 40) | function stepScrollBy() {
method listener (line 77) | listener() {
method listener (line 170) | listener() {
method listener (line 268) | listener() {
FILE: packages/auto-scroll/__tests__/unit/over-element/registration.spec.ts
method listener (line 56) | listener() {
method listener (line 112) | listener() {
method listener (line 181) | listener() {
FILE: packages/auto-scroll/__tests__/unit/over-element/start.spec.ts
method listener (line 46) | listener() {
FILE: packages/auto-scroll/__tests__/unit/over-element/stop.spec.ts
method listener (line 54) | listener() {
method listener (line 131) | listener() {
FILE: packages/auto-scroll/__tests__/unit/over-element/time-dampening.spec.ts
method listener (line 73) | listener() {
method listener (line 224) | listener() {
method listener (line 373) | listener() {
method listener (line 522) | listener() {
method listener (line 681) | listener() {
method listener (line 924) | listener() {
function execute (line 957) | function execute() {
method listener (line 1281) | listener() {
method listener (line 1717) | listener() {
method listener (line 1805) | listener() {
function dragOperation (line 1909) | function dragOperation() {
method listener (line 1994) | listener(event) {
FILE: packages/auto-scroll/__tests__/unit/over-element/window-scrolling.spec.ts
function canScrollOnBottom (line 42) | function canScrollOnBottom(element: HTMLElement): boolean {
FILE: packages/auto-scroll/__tests__/unit/overflow/allowed-axis.spec.ts
constant OUTSIDE_OFFSET (line 40) | const OUTSIDE_OFFSET = 10;
FILE: packages/auto-scroll/__tests__/unit/overflow/cross-axis-hitbox.spec.ts
type Scenario (line 54) | type Scenario = {
function getOverElementMainHitboxSize (line 89) | function getOverElementMainHitboxSize(edge: Edge) {
FILE: packages/auto-scroll/__tests__/unit/overflow/main-axis-hitbox.spec.ts
type Scenario (line 52) | type Scenario = {
FILE: packages/auto-scroll/__tests__/unit/overflow/over-element-should-not-scroll.spec.ts
method listener (line 92) | listener() {
FILE: packages/auto-scroll/__tests__/unit/overflow/provided-hitbox-spacing-type.spec.ts
type GetOverflowFn (line 7) | type GetOverflowFn = Parameters<typeof unsafeOverflowAutoScrollForElemen...
type ProvidedHitboxSpacing (line 8) | type ProvidedHitboxSpacing = ReturnType<GetOverflowFn>;
FILE: packages/auto-scroll/__tests__/unit/shared/_util.ts
function findHoneyPot (line 5) | function findHoneyPot(): Element | null {
function getHoneyPot (line 9) | function getHoneyPot(): HTMLElement {
FILE: packages/auto-scroll/__tests__/unit/shared/ignore-honey-pot.spec.ts
method listener (line 50) | listener() {
FILE: packages/auto-scroll/__tests__/unit/shared/time-dampening-handover.spec.ts
method listener (line 70) | listener() {
function dragBelowParent (line 113) | function dragBelowParent() {
function dragOntoParentBottomEdge (line 123) | function dragOntoParentBottomEdge() {
function isInTimeDampeningPeriod (line 137) | function isInTimeDampeningPeriod() {
FILE: packages/auto-scroll/examples/axis-locking.tsx
function AxisLocking (line 5) | function AxisLocking(): React.JSX.Element {
FILE: packages/auto-scroll/examples/lazy-loaded.tsx
function LazyLoaded (line 5) | function LazyLoaded(): React.JSX.Element {
FILE: packages/auto-scroll/examples/nested-scroll.tsx
type ItemType (line 33) | type ItemType = {
function Item (line 47) | function Item({ item }: { item: ItemType }) {
function getItems (line 68) | function getItems({ listId, count }: { listId: string; count: number }):...
function List (line 80) | function List({ listId, children }: { listId: string; children?: ReactEl...
function WindowScroll (line 104) | function WindowScroll(): React.JSX.Element {
FILE: packages/auto-scroll/examples/over-element.tsx
function OverElement (line 13) | function OverElement(): React.JSX.Element {
FILE: packages/auto-scroll/examples/pieces/board-context.ts
type TBoardContext (line 5) | type TBoardContext = {
FILE: packages/auto-scroll/examples/pieces/board.tsx
function useRequiredContext (line 14) | function useRequiredContext<TContextValue>(
type TItem (line 22) | type TItem = { id: string };
type TColumn (line 23) | type TColumn = {
function Column (line 40) | function Column({ column }: { column: TColumn }) {
function getColumns (line 76) | function getColumns({ count }: { count: number }): TColumn[] {
function Board (line 92) | function Board(): React.JSX.Element {
FILE: packages/auto-scroll/examples/pieces/card.tsx
type TItem (line 34) | type TItem = { id: string };
type CardState (line 36) | type CardState =
function Card (line 57) | function Card({ item }: { item: TItem }): React.JSX.Element {
function CardPreview (line 113) | function CardPreview({ rect }: { rect: DOMRect }) {
FILE: packages/auto-scroll/examples/pieces/lazy-loaded-board.tsx
type TItem (line 13) | type TItem = { id: string };
type TColumn (line 14) | type TColumn = {
function Column (line 31) | function Column({ column }: { column: TColumn }) {
type LoadingState (line 92) | type LoadingState = 'pending' | 'loading' | 'loaded';
function getColumns (line 106) | function getColumns({ count }: { count: number }): TColumn[] {
function Board (line 122) | function Board(): React.JSX.Element {
FILE: packages/auto-scroll/examples/pieces/table.tsx
type TItem (line 14) | type TItem = { id: string };
constant COLUMN_COUNT (line 16) | const COLUMN_COUNT = 8;
function getItems (line 19) | function getItems({ count }: { count: number }): TItem[] {
function Cell (line 25) | function Cell({ isSticky, children }: PropsWithChildren<{ isSticky?: boo...
function Row (line 33) | function Row({ item }: { item: TItem }) {
function Table (line 49) | function Table(): React.JSX.Element {
FILE: packages/auto-scroll/examples/unsafe-overflow-box.tsx
function getHugeContent (line 12) | function getHugeContent(): string {
function Example (line 43) | function Example(): React.JSX.Element {
FILE: packages/auto-scroll/examples/unsafe-overflow-only.tsx
function UnsafeOverflowOnly (line 62) | function UnsafeOverflowOnly(): React.JSX.Element {
FILE: packages/auto-scroll/examples/unsafe-overflow.tsx
function UnsafeOverflow (line 70) | function UnsafeOverflow(): React.JSX.Element {
FILE: packages/auto-scroll/examples/window-scroll-with-scroll-container.tsx
type ItemType (line 33) | type ItemType = {
function Item (line 47) | function Item({ item }: { item: ItemType }) {
function WindowScroll (line 83) | function WindowScroll(): React.JSX.Element {
FILE: packages/auto-scroll/examples/window-scroll.tsx
type ItemType (line 33) | type ItemType = {
function Item (line 47) | function Item({ item }: { item: ItemType }) {
function WindowScroll (line 79) | function WindowScroll(): React.JSX.Element {
FILE: packages/auto-scroll/src/internal-types.ts
type ElementGetFeedbackArgs (line 3) | type ElementGetFeedbackArgs<DragType extends AllDragTypes> = {
type WindowGetFeedbackArgs (line 18) | type WindowGetFeedbackArgs<DragType extends AllDragTypes> = Omit<
type Spacing (line 23) | type Spacing = {
type Edge (line 30) | type Edge = keyof Spacing;
type EngagementHistoryEntry (line 32) | type EngagementHistoryEntry = {
type InternalConfig (line 36) | type InternalConfig = {
type PublicConfig (line 44) | type PublicConfig = Partial<{
type ElementAutoScrollArgs (line 48) | type ElementAutoScrollArgs<DragType extends AllDragTypes> = {
type WindowAutoScrollArgs (line 55) | type WindowAutoScrollArgs<DragType extends AllDragTypes> = {
type Side (line 61) | type Side = 'start' | 'end';
type Axis (line 62) | type Axis = 'vertical' | 'horizontal';
type AllowedAxis (line 63) | type AllowedAxis = Axis | 'all';
FILE: packages/auto-scroll/src/over-element/data-attributes.ts
function addScrollableAttribute (line 6) | function addScrollableAttribute(element: Element): CleanupFn {
FILE: packages/auto-scroll/src/over-element/get-scroll-by.ts
type ScrollableEdge (line 17) | type ScrollableEdge = {
function getRectDefault (line 22) | function getRectDefault(element: Element) {
function getScrollBy (line 26) | function getScrollBy({
FILE: packages/auto-scroll/src/over-element/make-api.ts
function makeApi (line 16) | function makeApi<DragType extends AllDragTypes>({
FILE: packages/auto-scroll/src/over-element/try-scroll.ts
type AvailableScrollDirection (line 17) | type AvailableScrollDirection = { top: boolean; left: boolean };
function isScrollingAvailable (line 19) | function isScrollingAvailable(value: AvailableScrollDirection): boolean {
function tryScrollElements (line 23) | function tryScrollElements<DragType extends AllDragTypes>({
function tryScrollWindow (line 125) | function tryScrollWindow<DragType extends AllDragTypes>({
function tryScroll (line 191) | function tryScroll<DragType extends AllDragTypes>({
FILE: packages/auto-scroll/src/shared/configuration.ts
function getInternalConfig (line 47) | function getInternalConfig(provided?: PublicConfig | undefined): Interna...
FILE: packages/auto-scroll/src/shared/engagement-history.ts
function markAndGetEngagement (line 6) | function markAndGetEngagement(element: Element): EngagementHistoryEntry {
function markEngagement (line 20) | function markEngagement(element: Element): void {
function clearUnusedEngagements (line 24) | function clearUnusedEngagements(fn: () => void): void {
function clearEngagementHistory (line 42) | function clearEngagementHistory(): void {
FILE: packages/auto-scroll/src/shared/get-over-element-hitbox.ts
function makeGetHitbox (line 6) | function makeGetHitbox({ edge, axis }: { edge: Edge; axis: Axis }) {
FILE: packages/auto-scroll/src/shared/get-percentage-in-range.ts
function getPercentageInRange (line 1) | function getPercentageInRange({
FILE: packages/auto-scroll/src/shared/get-scroll-change.ts
function getMaxScrollChange (line 10) | function getMaxScrollChange({
function getDistanceDampening (line 32) | function getDistanceDampening({
function getScrollChange (line 74) | function getScrollChange({
FILE: packages/auto-scroll/src/shared/is-axis-allowed.ts
function isAxisAllowed (line 3) | function isAxisAllowed(axis: Axis, allowedAxis: AllowedAxis): boolean {
FILE: packages/auto-scroll/src/shared/is-within.ts
function isWithin (line 3) | function isWithin({
FILE: packages/auto-scroll/src/shared/scheduler.ts
type State (line 11) | type State<DragType extends AllDragTypes> =
type OnFrameFn (line 32) | type OnFrameFn<DragType extends AllDragTypes> = (args: {
type Scheduler (line 41) | type Scheduler<DragType extends AllDragTypes> = {
function getScheduler (line 53) | function getScheduler<DragType extends AllDragTypes>(
function makeScheduler (line 67) | function makeScheduler<DragType extends AllDragTypes>(
FILE: packages/auto-scroll/src/unsafe-overflow/get-scroll-by.ts
type HitboxForEdge (line 18) | type HitboxForEdge = {
function getIsDistanceDampeningEnabled (line 26) | function getIsDistanceDampeningEnabled(value: HitboxForEdge): boolean {
function getSpacingFromProvided (line 30) | function getSpacingFromProvided(value: Partial<Spacing> | undefined): Sp...
function getHitboxSpacing (line 39) | function getHitboxSpacing(provided: ProvidedHitboxSpacing): HitboxSpacing {
function getScrollBy (line 48) | function getScrollBy<DragType extends AllDragTypes>({
FILE: packages/auto-scroll/src/unsafe-overflow/hitbox.ts
function makeGetHitbox (line 10) | function makeGetHitbox({ axis, side }: { axis: Axis; side: Side }) {
FILE: packages/auto-scroll/src/unsafe-overflow/make-api.ts
function makeApi (line 13) | function makeApi<DragType extends AllDragTypes>({
FILE: packages/auto-scroll/src/unsafe-overflow/try-overflow-scroll.ts
function tryOverflowScrollElements (line 9) | function tryOverflowScrollElements<DragType extends AllDragTypes>({
FILE: packages/auto-scroll/src/unsafe-overflow/types.ts
type VerticalEdges (line 5) | type VerticalEdges = ['top' | 'bottom'];
type HorizontalEdges (line 6) | type HorizontalEdges = ['left' | 'right'];
type CrossAxisEdges (line 7) | type CrossAxisEdges<T extends Edge> = T extends VerticalEdges[number]
type HitboxSpacing (line 12) | type HitboxSpacing = {
type ProvidedHitboxSpacing (line 17) | type ProvidedHitboxSpacing = {
type UnsafeOverflowAutoScrollArgs (line 31) | type UnsafeOverflowAutoScrollArgs<DragType extends AllDragTypes> =
FILE: packages/core/__tests__/playwright/external-files.spec.ts
function getElement (line 8) | async function getElement(page: Page, selector: string) {
FILE: packages/core/__tests__/playwright/honey-pot.spec.ts
type Data (line 5) | type Data = {
method toContainData (line 14) | async toContainData(locator: Locator, expected: Partial<Data>) {
FILE: packages/core/__tests__/playwright/iframe.spec.ts
function center (line 5) | function center(box: { x: number; y: number; height: number; width: numb...
function realisticDragTo (line 30) | async function realisticDragTo({ page, start, end }: { page: Page; start...
function setup (line 50) | async function setup({ page }: { page: Page }) {
FILE: packages/core/__tests__/playwright/scroll-just-enough-into-view.spec.ts
function getScrollTop (line 5) | async function getScrollTop(locator: Locator) {
FILE: packages/core/__tests__/unit/_util.ts
function getDefaultInput (line 13) | function getDefaultInput(overrides: Partial<Input> = {}): Input {
function appendToBody (line 36) | function appendToBody(...elements: Element[]): CleanupFn {
function getEmptyHistory (line 48) | function getEmptyHistory(input: Input = getDefaultInput()): DragLocation...
function getInitialHistory (line 63) | function getInitialHistory(
function setBoundingClientRect (line 81) | function setBoundingClientRect(el: HTMLElement, rect: DOMRect): CleanupFn {
function getRect (line 90) | function getRect(box: {
function getBubbleOrderedPath (line 112) | function getBubbleOrderedPath(path: Element[]): Element[] {
function setElementFromPointWithPath (line 126) | function setElementFromPointWithPath(path: Element[]): CleanupFn {
function setElementFromPoint (line 139) | function setElementFromPoint(element: Element | null): CleanupFn {
function getElements (line 148) | function getElements<TagName extends keyof HTMLElementTagNameMap>(
function getBubbleOrderedTree (line 170) | function getBubbleOrderedTree(
type SimpleItem (line 195) | type SimpleItem = { data: string; type: NativeMediaType } | File;
function addItemsToEvent (line 196) | function addItemsToEvent({ event, items }: { event: DragEvent; items: Si...
method startExternal (line 207) | startExternal({
method startInternal (line 224) | startInternal({ items, target }: { items: SimpleItem[]; target: Element ...
method startTextSelectionDrag (line 234) | startTextSelectionDrag({ element = document.body }: { element: Element }...
method drop (line 256) | drop({
function isTextNode (line 270) | function isTextNode(node: Node): node is Text {
function getFirstTextNode (line 274) | function getFirstTextNode(element: Element): Text {
function withDefaults (line 297) | function withDefaults(input?: Partial<Input>): Input {
method lift (line 305) | lift(target: HTMLElement, input?: Partial<Input>): void {
method drop (line 312) | drop(target: Element, input?: Partial<Input>): void {
method cancel (line 315) | cancel(target: Element = document.body, input?: Partial<Input>): void {
method leaveWindow (line 322) | leaveWindow(): void {
method rougePointerMoves (line 325) | rougePointerMoves(): void {
function reset (line 335) | function reset(): void {
function makeDispatch (line 349) | function makeDispatch(eventName: string) {
function clearSelection (line 376) | function clearSelection(): void {
function select (line 380) | function select(element: HTMLElement): CleanupFn {
FILE: packages/core/__tests__/unit/android/is-android.spec.ts
function setAndroidUserAgent (line 18) | function setAndroidUserAgent(): CleanupFn {
method listener (line 53) | listener(event) {
method listener (line 89) | listener(event) {
method listener (line 127) | listener(event) {
method onDrop (line 200) | onDrop({ source }) {
FILE: packages/core/__tests__/unit/android/not-android.spec.ts
method listener (line 38) | listener(event) {
method onDrop (line 79) | onDrop({ source }) {
FILE: packages/core/__tests__/unit/element/changes-during-a-drag.spec.ts
function getLabel (line 400) | function getLabel({
function add (line 412) | function add({ id, eventName }: { id: string; eventName: string }) {
FILE: packages/core/__tests__/unit/element/dragleave-should-not-update-input.spec.ts
function getEntry (line 23) | function getEntry(label: string, current: { clientX: number; clientY: nu...
FILE: packages/core/__tests__/unit/element/drop-target/drop-effect.spec.ts
function getChangingEffects (line 144) | function getChangingEffects(...effects: DropTargetAllowedDropEffect[]) {
FILE: packages/core/__tests__/unit/element/drop-target/lift.spec.ts
type Args (line 369) | type Args = Parameters<typeof dropTargetForElements>[0];
type GetDataArgs (line 370) | type GetDataArgs = Parameters<NonNullable<Args['getData']>>[0];
FILE: packages/core/__tests__/unit/element/previous-location-should-match-last-current.spec.ts
function getLookup (line 16) | function getLookup() {
FILE: packages/core/__tests__/unit/element/public-utils/block-dragging-to-iframes.spec.ts
function isPointerEventsBlocked (line 18) | function isPointerEventsBlocked(iframe: HTMLIFrameElement): boolean {
FILE: packages/core/__tests__/unit/element/public-utils/center-under-pointer.spec.ts
function makeMock (line 29) | function makeMock(
method onGenerateDragPreview (line 42) | onGenerateDragPreview({ nativeSetDragImage }) {
FILE: packages/core/__tests__/unit/element/public-utils/pointer-outside-of-preview.spec.ts
function makeMock (line 21) | function makeMock(
method onGenerateDragPreview (line 34) | onGenerateDragPreview({ nativeSetDragImage }) {
function makeMock (line 98) | function makeMock(
method onGenerateDragPreview (line 111) | onGenerateDragPreview({ nativeSetDragImage }) {
FILE: packages/core/__tests__/unit/element/public-utils/preserve-offset-on-source.spec.ts
function makeMock (line 49) | function makeMock(
method render (line 71) | render({ container }) {
function makeMock (line 119) | function makeMock(
method render (line 141) | render({ container }) {
FILE: packages/core/__tests__/unit/element/public-utils/set-custom-native-drag-preview.spec.ts
method onGenerateDragPreview (line 38) | onGenerateDragPreview({ nativeSetDragImage }) {
method onGenerateDragPreview (line 76) | onGenerateDragPreview({ nativeSetDragImage }) {
function makeMock (line 126) | function makeMock(
method onGenerateDragPreview (line 140) | onGenerateDragPreview({ nativeSetDragImage }) {
function makeMock (line 180) | function makeMock(
method onGenerateDragPreview (line 193) | onGenerateDragPreview({ nativeSetDragImage }) {
function makeMock (line 237) | function makeMock(
method onGenerateDragPreview (line 250) | onGenerateDragPreview({ nativeSetDragImage }) {
FILE: packages/core/__tests__/unit/element/resiliant-against-consumers-stopping-events-during-a-drag.spec.ts
function onEvent (line 13) | function onEvent(event: DragEvent) {
function onEvent (line 114) | function onEvent(event: DragEvent) {
FILE: packages/core/__tests__/unit/external/adapter/exposing-data.spec.ts
function sort (line 26) | function sort<Value>(array: readonly Value[]): Value[] {
function getKeys (line 42) | function getKeys<Obj extends Record<string, unknown>>(obj: Obj): (keyof ...
function addFakeDataToEvent (line 46) | function addFakeDataToEvent(event: DragEvent) {
FILE: packages/core/__tests__/unit/external/adapter/get-string-data.spec.ts
function getBucket (line 18) | function getBucket() {
FILE: packages/core/__tests__/unit/external/adapter/leaving-the-window.spec.ts
method onDragStart (line 20) | onDragStart(args) {
method onDrop (line 24) | onDrop(args) {
FILE: packages/core/__tests__/unit/external/adapter/starting-an-external-drag.spec.ts
method onDragStart (line 81) | onDragStart(args) {
FILE: packages/core/__tests__/unit/external/utils/url/firefox-fix.spec.ts
type Scenario (line 86) | type Scenario = {
FILE: packages/core/__tests__/unit/external/utils/url/url.spec.ts
type Scenario (line 71) | type Scenario = {
FILE: packages/core/__tests__/unit/honey-pot-fix/_util.ts
function findHoneyPot (line 5) | function findHoneyPot(): Element | null {
function getHoneyPot (line 9) | function getHoneyPot(): HTMLElement {
FILE: packages/core/__tests__/unit/honey-pot-fix/event-listeners.spec.ts
function clearMocks (line 16) | function clearMocks() {
FILE: packages/core/__tests__/unit/honey-pot-fix/finishing.spec.ts
type Item (line 12) | type Item = {
FILE: packages/core/__tests__/unit/public-utils/once.spec.ts
type Person (line 48) | type Person = {
function getAge (line 51) | function getAge(this: Person): number {
function add (line 74) | function add(a: number, b: number): number {
FILE: packages/core/__tests__/unit/public-utils/prevent-unhandled.spec.ts
function cancel (line 13) | function cancel(target: Element): DragEvent {
function drop (line 20) | function drop(target: Element): DragEvent {
method onDragStart (line 34) | onDragStart() {
method onDrop (line 38) | onDrop() {
method onDragStart (line 66) | onDragStart() {
method onDrop (line 70) | onDrop() {
method onDragStart (line 119) | onDragStart() {
method onDrop (line 123) | onDrop() {
method onDragStart (line 155) | onDragStart() {
method onDrop (line 159) | onDrop() {
method onDragStart (line 193) | onDragStart() {
method onDrop (line 199) | onDrop() {
method onDragStart (line 286) | onDragStart() {
method onDrop (line 290) | onDrop() {
method onDragStart (line 383) | onDragStart() {
method onDrop (line 389) | onDrop() {
FILE: packages/core/__tests__/unit/react/adding-monitors-during-events.spec.tsx
function add (line 19) | function add({ label, isDragging }: { label: string; isDragging: boolean...
function App (line 23) | function App() {
function add (line 98) | function add({ label, isDragging }: { label: string; isDragging: boolean...
function App (line 102) | function App() {
FILE: packages/core/__tests__/unit/test-environment-guardrail.spec.ts
method onGenerateDragPreview (line 22) | onGenerateDragPreview() {
method onDragStart (line 25) | onDragStart() {
method onDragStart (line 53) | onDragStart() {
method onDragStart (line 87) | onDragStart() {
FILE: packages/core/__tests__/unit/text-selection/adapter/event-ordering.spec.ts
type Entry (line 20) | type Entry = {
function getDropTargets (line 26) | function getDropTargets(location: TextSelectionEventBasePayload['locatio...
FILE: packages/core/__tests__/unit/text-selection/adapter/leaving-the-window.spec.ts
method onDragStart (line 14) | onDragStart() {
method onDrop (line 17) | onDrop() {
FILE: packages/core/examples/_util/global-styles.tsx
function GlobalStyles (line 19) | function GlobalStyles(): React.JSX.Element {
FILE: packages/core/examples/drag-preview-with-transparency.tsx
function FakeText (line 21) | function FakeText() {
function Preview (line 37) | function Preview() {
type ItemState (line 46) | type ItemState =
function ItemNoOffset (line 51) | function ItemNoOffset() {
function ItemOffsetFromPointer (line 83) | function ItemOffsetFromPointer() {
function ItemCenter (line 116) | function ItemCenter() {
function ItemPreserveOffsetOnSource (line 149) | function ItemPreserveOffsetOnSource() {
function Example (line 185) | function Example(): React.JSX.Element {
FILE: packages/core/examples/element-adapter.tsx
function Example (line 1) | function Example() {
FILE: packages/core/examples/file.tsx
function FileList (line 54) | function FileList({ uploads }: { uploads: File[] }) {
function Uploader (line 67) | function Uploader() {
function Example (line 120) | function Example(): React.JSX.Element {
FILE: packages/core/examples/iframe.tsx
function IframeOuter (line 40) | function IframeOuter(): React.JSX.Element {
FILE: packages/core/examples/native.tsx
type DragState (line 74) | type DragState =
function CurrentlyDragging (line 91) | function CurrentlyDragging() {
function DropTarget (line 169) | function DropTarget() {
function App (line 301) | function App() {
function Example (line 313) | function Example(): React.JSX.Element {
FILE: packages/core/examples/native/activity-log.tsx
function ActivityLog (line 10) | function ActivityLog(): React.JSX.Element {
FILE: packages/core/examples/native/app.tsx
function App (line 24) | function App(): React.JSX.Element {
FILE: packages/core/examples/native/content.tsx
type CardState (line 33) | type CardState = 'idle' | 'generate-preview' | 'dragging';
function Card (line 47) | function Card() {
function CardWithExternal (line 75) | function CardWithExternal() {
function DraggableAnchor (line 109) | function DraggableAnchor() {
function DraggableAnchorWithNewUrl (line 126) | function DraggableAnchorWithNewUrl() {
function DraggableAnchorWithCustomPreview (line 147) | function DraggableAnchorWithCustomPreview() {
function DraggableImage (line 178) | function DraggableImage() {
function DraggableImageWithCustomPreview (line 192) | function DraggableImageWithCustomPreview() {
function Content (line 220) | function Content(): React.JSX.Element {
FILE: packages/core/examples/native/drop-target.tsx
type State (line 47) | type State = 'idle' | 'potential' | 'over';
function DropTarget (line 55) | function DropTarget(): React.JSX.Element {
FILE: packages/core/examples/post-drop-bug-fix-simple.tsx
function Card (line 60) | function Card({ cardId }: { cardId: string }) {
type Card (line 126) | type Card = {
function getCards (line 129) | function getCards() {
function DropTest (line 139) | function DropTest() {
function Example (line 186) | function Example(): React.JSX.Element {
FILE: packages/core/examples/post-drop-bug-fix.tsx
function Card (line 101) | function Card({
type Card (line 200) | type Card = {
function getCards (line 203) | function getCards() {
function DropTest (line 215) | function DropTest({ layout }: { layout: 'vertical' | 'horizontal' }) {
function DragEndTest (line 256) | function DragEndTest() {
function Example (line 302) | function Example(): React.JSX.Element {
FILE: packages/core/examples/preserve-offset-on-source.tsx
type CardDragState (line 16) | type CardDragState = 'idle' | 'preview' | 'dragging';
function Card (line 30) | function Card({ id, isPreview = false }: { id: string; isPreview?: boole...
function CardList (line 96) | function CardList({ cardIds }: { cardIds: string[] }) {
function Example (line 108) | function Example(): React.JSX.Element {
FILE: packages/core/examples/scroll-just-enough-into-view.tsx
function Draggable (line 52) | function Draggable({ testId }: { testId: string }) {
function DropTarget (line 79) | function DropTarget({ children, testId }: { children: ReactNode; testId:...
function Example (line 98) | function Example(): React.JSX.Element {
FILE: packages/core/examples/stickiness.tsx
type ItemData (line 11) | type ItemData = {
function ListItem (line 83) | function ListItem({ itemData, index }: { itemData: ItemData; index: numb...
function StickinessExample (line 122) | function StickinessExample(): React.JSX.Element {
FILE: packages/core/examples/text-selection.tsx
type DropTargetState (line 20) | type DropTargetState = 'idle' | 'potential' | 'over';
function DropTarget (line 44) | function DropTarget() {
function TextSelectionDragging (line 97) | function TextSelectionDragging(): React.JSX.Element {
FILE: packages/core/examples/url.tsx
function App (line 51) | function App() {
function Example (line 115) | function Example(): React.JSX.Element {
FILE: packages/core/src/adapter/element-adapter.ts
type DraggableGetFeedbackArgs (line 32) | type DraggableGetFeedbackArgs = {
type DraggableArgs (line 47) | type DraggableArgs = {
function addToRegistry (line 76) | function addToRegistry(args: DraggableArgs): CleanupFn {
method mount (line 89) | mount(api: AdapterAPI<ElementDragType>): CleanupFn {
function draggable (line 335) | function draggable(args: DraggableArgs): CleanupFn {
type ElementEventBasePayload (line 374) | type ElementEventBasePayload = BaseEventPayload<ElementDragType>;
type ElementEventPayloadMap (line 377) | type ElementEventPayloadMap = EventPayloadMap<ElementDragType>;
type ElementDropTargetEventBasePayload (line 380) | type ElementDropTargetEventBasePayload = DropTargetEventBasePayload<Elem...
type ElementDropTargetEventPayloadMap (line 383) | type ElementDropTargetEventPayloadMap = DropTargetEventPayloadMap<Elemen...
type ElementGetFeedbackArgs (line 386) | type ElementGetFeedbackArgs = DraggableGetFeedbackArgs;
type ElementDropTargetGetFeedbackArgs (line 389) | type ElementDropTargetGetFeedbackArgs = DropTargetGetFeedbackArgs<Elemen...
type ElementMonitorGetFeedbackArgs (line 392) | type ElementMonitorGetFeedbackArgs = MonitorGetFeedbackArgs<ElementDragT...
FILE: packages/core/src/adapter/external-adapter.ts
function isAnAvailableType (line 26) | function isAnAvailableType({ type, value }: { type: string; value: strin...
function getAvailableTypes (line 40) | function getAvailableTypes(transfer: DataTransfer): NativeMediaType[] {
function getAvailableItems (line 46) | function getAvailableItems(dataTransfer: DataTransfer): DataTransferItem...
method mount (line 71) | mount(api: AdapterAPI<ExternalDragType>): CleanupFn {
type StripEventsForDropTargets (line 190) | type StripEventsForDropTargets<T> = Omit<T, 'onGenerateDragPreview' | 'o...
type StripEventsForMonitors (line 191) | type StripEventsForMonitors<T> = Omit<T, 'onGenerateDragPreview'>;
function dropTargetForExternal (line 193) | function dropTargetForExternal(
function monitorForExternal (line 200) | function monitorForExternal(
type State (line 218) | type State =
function clear (line 234) | function clear() {
function bindEndEvents (line 243) | function bindEndEvents() {
method listener (line 263) | listener() {
type ExternalEventBasePayload (line 283) | type ExternalEventBasePayload = BaseEventPayload<ExternalDragType>;
type ExternalEventPayloadMap (line 286) | type ExternalEventPayloadMap = StripEventsForMonitors<EventPayloadMap<Ex...
type ExternalDropTargetEventBasePayload (line 289) | type ExternalDropTargetEventBasePayload = DropTargetEventBasePayload<Ext...
type ExternalDropTargetEventPayloadMap (line 292) | type ExternalDropTargetEventPayloadMap = StripEventsForDropTargets<
type ExternalDropTargetGetFeedbackArgs (line 297) | type ExternalDropTargetGetFeedbackArgs = DropTargetGetFeedbackArgs<Exter...
type ExternalMonitorGetFeedbackArgs (line 300) | type ExternalMonitorGetFeedbackArgs = MonitorGetFeedbackArgs<ExternalDra...
FILE: packages/core/src/adapter/text-selection-adapter.ts
function findTextNode (line 26) | function findTextNode(event: DragEvent): Text | null {
method mount (line 85) | mount(api: AdapterAPI<TextSelectionDragType>): CleanupFn {
type StripPreviewEvent (line 170) | type StripPreviewEvent<T> = Omit<T, 'onGenerateDragPreview'>;
function dropTargetForTextSelection (line 172) | function dropTargetForTextSelection(
function monitorForTextSelection (line 188) | function monitorForTextSelection(
type TextSelectionEventBasePayload (line 196) | type TextSelectionEventBasePayload = BaseEventPayload<TextSelectionDragT...
type TextSelectionEventPayloadMap (line 199) | type TextSelectionEventPayloadMap = StripPreviewEvent<
type TextSelectionDropTargetEventBasePayload (line 204) | type TextSelectionDropTargetEventBasePayload =
type TextSelectionDropTargetEventPayloadMap (line 208) | type TextSelectionDropTargetEventPayloadMap = StripPreviewEvent<
type TextSelectionMonitorGetFeedbackArgs (line 213) | type TextSelectionMonitorGetFeedbackArgs = MonitorGetFeedbackArgs<TextSe...
type TextSelectionDropTargetGetFeedbackArgs (line 216) | type TextSelectionDropTargetGetFeedbackArgs =
FILE: packages/core/src/honey-pot-fix/get-element-from-point-without-honey-pot.ts
function getElementFromPointWithoutHoneypot (line 5) | function getElementFromPointWithoutHoneypot(client: Position): Element |...
FILE: packages/core/src/honey-pot-fix/is-honey-pot-element.ts
function isHoneyPotElement (line 3) | function isHoneyPotElement(target: EventTarget | null): boolean {
FILE: packages/core/src/honey-pot-fix/make-honey-pot-fix.ts
function floorToClosestPixel (line 26) | function floorToClosestPixel(point: Position): Position {
function pullBackByHalfHoneyPotSize (line 37) | function pullBackByHalfHoneyPotSize(point: Position): Position {
function preventGoingBackwardsOffScreen (line 48) | function preventGoingBackwardsOffScreen(point: Position): Position {
function preventGoingForwardsOffScreen (line 59) | function preventGoingForwardsOffScreen(point: Position): Position {
function getHoneyPotRectFor (line 69) | function getHoneyPotRectFor({ client }: { client: Position }): DOMRect {
function getRectStyles (line 84) | function getRectStyles({ clientRect }: { clientRect: DOMRect }): Partial...
function isWithin (line 93) | function isWithin({ client, clientRect }: { client: Position; clientRect...
type FinishHoneyPotArgs (line 104) | type FinishHoneyPotArgs = { current: Position };
type FinishHoneyPotFn (line 106) | type FinishHoneyPotFn = (args: FinishHoneyPotArgs) => void;
function mountHoneyPot (line 141) | function mountHoneyPot({ initial }: { initial: Position }): FinishHoneyP...
function makeHoneyPotFix (line 240) | function makeHoneyPotFix(): {
FILE: packages/core/src/internal-types.ts
type CleanupFn (line 1) | type CleanupFn = () => void;
type DropTargetAllowedDropEffect (line 9) | type DropTargetAllowedDropEffect = Exclude<DataTransfer['dropEffect'], '...
type DropTargetRecord (line 14) | type DropTargetRecord = {
type Position (line 38) | type Position = { x: number; y: number };
type Serializable (line 40) | type Serializable = {
type Region (line 43) | type Region = 'internal' | 'external';
type ElementDragPayload (line 45) | type ElementDragPayload = {
type ElementDragType (line 51) | type ElementDragType = {
type NativeMediaType (line 66) | type NativeMediaType =
type ExternalDragPayload (line 76) | type ExternalDragPayload = {
type ExternalDragType (line 117) | type ExternalDragType = {
type TextSelectionDragPayload (line 124) | type TextSelectionDragPayload = {
type TextSelectionDragType (line 141) | type TextSelectionDragType = {
type AllDragTypes (line 147) | type AllDragTypes = ElementDragType | ExternalDragType | TextSelectionDr...
type AdapterAPI (line 149) | type AdapterAPI<DragType extends AllDragTypes> = {
type Input (line 154) | type Input = {
type DragLocation (line 169) | type DragLocation = {
type DragLocationHistory (line 184) | type DragLocationHistory = {
type BaseEventPayload (line 212) | type BaseEventPayload<DragType extends AllDragTypes> = {
type EventPayloadMap (line 223) | type EventPayloadMap<DragType extends AllDragTypes> = {
type AllEvents (line 261) | type AllEvents<DragType extends AllDragTypes> = {
type MonitorGetFeedbackArgs (line 267) | type MonitorGetFeedbackArgs<DragType extends AllDragTypes> = {
type MonitorArgs (line 278) | type MonitorArgs<DragType extends AllDragTypes> = Partial<AllEvents<Drag...
type DropTargetGetFeedbackArgs (line 282) | type DropTargetGetFeedbackArgs<DragType extends AllDragTypes> = {
type DropTargetLocalizedData (line 297) | type DropTargetLocalizedData = {
type DropTargetEventBasePayload (line 305) | type DropTargetEventBasePayload<DragType extends AllDragTypes> = BaseEve...
type DropTargetEventPayloadMap (line 310) | type DropTargetEventPayloadMap<DragType extends AllDragTypes> = {
type DropTargetArgs (line 332) | type DropTargetArgs<DragType extends AllDragTypes> = {
type DropTargetAPI (line 380) | type DropTargetAPI<DragType extends AllDragTypes> = {
FILE: packages/core/src/ledger/dispatch-consumer-event.ts
function schedule (line 15) | function schedule(fn: () => void) {
function flush (line 25) | function flush() {
function makeDispatch (line 36) | function makeDispatch<DragType extends AllDragTypes>({
FILE: packages/core/src/ledger/lifecycle-manager.ts
function canStart (line 23) | function canStart(): boolean {
function getNativeSetDragImage (line 27) | function getNativeSetDragImage(event: DragEvent): DataTransfer['setDragI...
function hasHierarchyChanged (line 36) | function hasHierarchyChanged({
function start (line 56) | function start<DragType extends AllDragTypes>({
function setDropEffectOnEvent (line 339) | function setDropEffectOnEvent({
function getStartLocation (line 353) | function getStartLocation<DragType extends AllDragTypes>({
FILE: packages/core/src/ledger/usage-ledger.ts
type Entry (line 3) | type Entry<TypeKey extends AllDragTypes['type']> = {
type Ledger (line 10) | interface Ledger extends Map<AllDragTypes['type'], Entry<AllDragTypes['t...
function registerUsage (line 17) | function registerUsage<TypeKey extends AllDragTypes['type']>({
function register (line 41) | function register<TypeKey extends AllDragTypes['type']>(args: {
FILE: packages/core/src/make-adapter/make-adapter.ts
function makeAdapter (line 16) | function makeAdapter<DragType extends AllDragTypes>({
FILE: packages/core/src/make-adapter/make-drop-target.ts
function copyReverse (line 16) | function copyReverse<Value>(array: Value[]): Value[] {
function makeDropTarget (line 20) | function makeDropTarget<DragType extends AllDragTypes>({
FILE: packages/core/src/make-adapter/make-monitor.ts
type DraggingState (line 10) | type DraggingState<DragType extends AllDragTypes> = {
function makeMonitor (line 15) | function makeMonitor<DragType extends AllDragTypes>(): {
FILE: packages/core/src/public-utils/combine.ts
function combine (line 4) | function combine(...fns: CleanupFn[]): CleanupFn {
FILE: packages/core/src/public-utils/element/block-dragging-to-iframes.ts
function setStyle (line 10) | function setStyle(
function tryStart (line 31) | function tryStart(): void {
function blockDraggingToIFrames (line 74) | function blockDraggingToIFrames({ element }: { element: HTMLElement }): ...
FILE: packages/core/src/public-utils/element/custom-native-drag-preview/pointer-outside-of-preview.ts
type CSSValue (line 10) | type CSSValue = string;
function pointerOutsideOfPreview (line 34) | function pointerOutsideOfPreview(point: { x: CSSValue; y: CSSValue }): G...
FILE: packages/core/src/public-utils/element/custom-native-drag-preview/preserve-offset-on-source.ts
function preserveOffsetOnSource (line 5) | function preserveOffsetOnSource({
FILE: packages/core/src/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.ts
type CleanupFn (line 11) | type CleanupFn = () => void;
type RenderFn (line 14) | type RenderFn = ({
function defaultOffset (line 25) | function defaultOffset(): Position {
function setCustomNativeDragPreview (line 44) | function setCustomNativeDragPreview({
FILE: packages/core/src/public-utils/element/custom-native-drag-preview/types.ts
type GetOffsetFn (line 15) | type GetOffsetFn = (args: { container: HTMLElement }) => Position;
FILE: packages/core/src/public-utils/element/disable-native-drag-preview.ts
function disableNativeDragPreview (line 27) | function disableNativeDragPreview({
FILE: packages/core/src/public-utils/element/format-urls-for-external.ts
function formatURLsForExternal (line 31) | function formatURLsForExternal(urls: string[]): string {
FILE: packages/core/src/public-utils/element/scroll-just-enough-into-view.ts
function scrollJustEnoughIntoView (line 5) | function scrollJustEnoughIntoView({ element }: { element: Element }): vo...
FILE: packages/core/src/public-utils/external/file.ts
function containsFiles (line 3) | function containsFiles({ source }: ContainsSource): boolean {
function getFiles (line 8) | function getFiles({ source }: ContainsSource): File[] {
FILE: packages/core/src/public-utils/external/html.ts
function containsHTML (line 5) | function containsHTML({ source }: ContainsSource): boolean {
function getHTML (line 9) | function getHTML({ source }: ContainsSource): string | null {
FILE: packages/core/src/public-utils/external/native-types.ts
type ContainsSource (line 10) | type ContainsSource = { source: ExternalDragPayload };
type PredicateFn (line 11) | type PredicateFn = (args: ContainsSource) => boolean;
FILE: packages/core/src/public-utils/external/some.ts
function some (line 21) | function some(...predicates: PredicateFn[]): PredicateFn {
FILE: packages/core/src/public-utils/external/text.ts
function containsText (line 5) | function containsText({ source }: ContainsSource): boolean {
function getText (line 10) | function getText({ source }: ContainsSource): string | null {
FILE: packages/core/src/public-utils/external/url.ts
function containsURLs (line 16) | function containsURLs({ source }: ContainsSource): boolean {
function getURLs (line 20) | function getURLs({ source }: ContainsSource): string[] {
FILE: packages/core/src/public-utils/once.ts
function once (line 2) | function once<TFunc extends (...args: any[]) => any>(
FILE: packages/core/src/public-utils/prevent-unhandled.ts
function acceptDrop (line 6) | function acceptDrop(event: DragEvent) {
function start (line 28) | function start(): void {
function cleanup (line 66) | function cleanup() {
function stop (line 81) | function stop(): void {
FILE: packages/core/src/public-utils/reorder.ts
function reorder (line 6) | function reorder<Value>({
FILE: packages/core/src/util/add-attribute.ts
function addAttribute (line 3) | function addAttribute(
FILE: packages/core/src/util/changing-window/count-events-for-safari.ts
function isEnteringWindowInSafari (line 19) | function isEnteringWindowInSafari({ dragEnter }: { dragEnter: DragEvent ...
function isLeavingWindowInSafari (line 26) | function isLeavingWindowInSafari({ dragLeave }: { dragLeave: DragEvent }...
type State (line 49) | type State = {
function getInitialState (line 54) | function getInitialState(): State {
function resetState (line 63) | function resetState() {
FILE: packages/core/src/util/changing-window/is-entering-window.ts
function isEnteringWindow (line 7) | function isEnteringWindow({ dragEnter }: { dragEnter: DragEvent }): bool...
FILE: packages/core/src/util/changing-window/is-from-another-window.ts
function isNodeLike (line 7) | function isNodeLike(target: EventTarget): target is Node {
function isFromAnotherWindow (line 14) | function isFromAnotherWindow(eventTarget: EventTarget): boolean {
FILE: packages/core/src/util/changing-window/is-leaving-window.ts
function isLeavingWindow (line 7) | function isLeavingWindow({ dragLeave }: { dragLeave: DragEvent }): boole...
FILE: packages/core/src/util/detect-broken-drag.ts
function getBindingsForBrokenDrags (line 1) | function getBindingsForBrokenDrags({ onDragEnd }: { onDragEnd: () => voi...
FILE: packages/core/src/util/get-input.ts
function getInput (line 3) | function getInput(event: DragEvent): Input {
FILE: packages/documentation/__tests__/playwright/board.spec.ts
function getColumnHeader (line 6) | function getColumnHeader(page: Page, columnId: string) {
function getItem (line 10) | function getItem(page: Page, itemId: string) {
function getColumnOrder (line 14) | async function getColumnOrder(page: Page): Promise<string[]> {
function getCardOrder (line 20) | function getCardOrder(page: Page, columnId: string): Promise<(string | n...
FILE: packages/documentation/__tests__/playwright/tree.spec.ts
type TScenario (line 7) | type TScenario = {
FILE: packages/documentation/constellation/09-accessibility-guidelines/pattern-table.tsx
type PatternTableProps (line 3) | type PatternTableProps = {
FILE: packages/documentation/constellation/assets/check-icon.tsx
function CheckIcon (line 6) | function CheckIcon() {
FILE: packages/documentation/constellation/assets/cross-icon.tsx
function CheckIcon (line 6) | function CheckIcon() {
FILE: packages/documentation/constellation/assets/question-icon.tsx
function CheckIcon (line 6) | function CheckIcon() {
FILE: packages/documentation/constellation/assets/result-text.tsx
function ResultText (line 16) | function ResultText({ children }: { children: string }) {
FILE: packages/documentation/constellation/assets/warning-icon.tsx
function CheckIcon (line 6) | function CheckIcon() {
FILE: packages/documentation/constellation/index/assets/hero.tsx
type State (line 19) | type State = { type: 'idle' } | { type: 'preview'; container: HTMLElemen...
function Hero (line 40) | function Hero() {
FILE: packages/documentation/constellation/index/assets/logo.tsx
type Mode (line 9) | type Mode = 'standard' | 'alternative';
function Logo (line 28) | function Logo({ mode }: { mode: Mode }) {
FILE: packages/documentation/examples/board-with-multi-drag.tsx
type SortUserIdsArgs (line 95) | type SortUserIdsArgs = {
type MultiDragReorderArgs (line 128) | type MultiDragReorderArgs = {
function BoardExample (line 188) | function BoardExample(): React.JSX.Element {
FILE: packages/documentation/examples/board-with-overflow-scroll.tsx
function BoardExample (line 16) | function BoardExample(): React.JSX.Element {
FILE: packages/documentation/examples/board.tsx
type Outcome (line 20) | type Outcome =
type Trigger (line 40) | type Trigger = 'pointer' | 'keyboard';
type Operation (line 42) | type Operation = {
type BoardState (line 47) | type BoardState = {
function BoardExample (line 53) | function BoardExample(): React.JSX.Element {
FILE: packages/documentation/examples/chess.tsx
type coord (line 15) | type coord = [number, number];
type PieceRecord (line 17) | type PieceRecord = {
method onDrop (line 67) | onDrop({ source, location }) {
FILE: packages/documentation/examples/data/pages.ts
type Page (line 1) | type Page = {
FILE: packages/documentation/examples/data/people/index.tsx
type Person (line 39) | type Person = {
function getPerson (line 103) | function getPerson(): Person {
function getPersonFromPosition (line 108) | function getPersonFromPosition({ position }: { position: number }): Pers...
function getPeopleFromPosition (line 121) | function getPeopleFromPosition({
function getPeople (line 131) | function getPeople({ amount }: { amount: number }): Person[] {
type ColumnType (line 135) | type ColumnType = {
type ColumnMap (line 140) | type ColumnMap = { [columnId: string]: ColumnType };
function getData (line 142) | function getData({
function getBasicData (line 168) | function getBasicData() {
FILE: packages/documentation/examples/data/presidents.tsx
type President (line 1) | type President = {
type RowOrder (line 71) | type RowOrder = number[];
function getInitialRowOrder (line 73) | function getInitialRowOrder(): RowOrder {
type Column (line 77) | type Column = 'name' | 'party' | 'term';
type ColumnOrder (line 79) | type ColumnOrder = Column[];
function getInitialColumnOrder (line 87) | function getInitialColumnOrder(): ColumnOrder {
FILE: packages/documentation/examples/data/quotes/data.ts
constant BMO (line 22) | const BMO: Author = {
FILE: packages/documentation/examples/data/quotes/types.ts
type Position (line 1) | type Position = {
type Author (line 6) | type Author = {
type Quote (line 17) | type Quote = {
type AuthorQuoteMap (line 23) | type AuthorQuoteMap = {
FILE: packages/documentation/examples/data/table.tsx
type TableRowData (line 6) | type TableRowData = {
type TableColumnData (line 19) | type TableColumnData = { id: string; label: string };
FILE: packages/documentation/examples/data/tasks.ts
type Item (line 1) | type Item = {
type ColumnType (line 5) | type ColumnType = {
type ColumnMap (line 10) | type ColumnMap = { [columnId: string]: ColumnType };
function getItems (line 12) | function getItems({ count, startColumnId }: { count: number; startColumn...
function getInitialData (line 21) | function getInitialData() {
FILE: packages/documentation/examples/data/tree-legacy.ts
type TreeItem (line 5) | type TreeItem = {
type TreeState (line 12) | type TreeState = {
function getInitialTreeState (line 17) | function getInitialTreeState(): TreeState {
function getInitialData (line 21) | function getInitialData(): TreeItem[] {
type TreeAction (line 71) | type TreeAction =
method remove (line 93) | remove(data: TreeItem[], id: string): TreeItem[] {
method insertBefore (line 106) | insertBefore(data: TreeItem[], targetId: string, newItem: TreeItem): Tre...
method insertAfter (line 120) | insertAfter(data: TreeItem[], targetId: string, newItem: TreeItem): Tree...
method insertChild (line 136) | insertChild(data: TreeItem[], targetId: string, newItem: TreeItem): Tree...
method find (line 158) | find(data: TreeItem[], itemId: string): TreeItem | undefined {
method getPathToItem (line 172) | getPathToItem({
method hasChildren (line 195) | hasChildren(item: TreeItem): boolean {
function treeStateReducer (line 200) | function treeStateReducer(state: TreeState, action: TreeAction): TreeSta...
function toggle (line 258) | function toggle(item: TreeItem): TreeItem {
function getChildItems (line 328) | function getChildItems(data: TreeItem[], targetId: string) {
FILE: packages/documentation/examples/data/tree.ts
type TreeItem (line 5) | type TreeItem = {
type TreeState (line 12) | type TreeState = {
function getInitialTreeState (line 17) | function getInitialTreeState(): TreeState {
function getInitialData (line 21) | function getInitialData(): TreeItem[] {
type TreeAction (line 71) | type TreeAction =
method remove (line 93) | remove(data: TreeItem[], id: string): TreeItem[] {
method insertBefore (line 106) | insertBefore(data: TreeItem[], targetId: string, newItem: TreeItem): Tre...
method insertAfter (line 120) | insertAfter(data: TreeItem[], targetId: string, newItem: TreeItem): Tree...
method insertChild (line 136) | insertChild(data: TreeItem[], targetId: string, newItem: TreeItem): Tree...
method find (line 158) | find(data: TreeItem[], itemId: string): TreeItem | undefined {
method getPathToItem (line 172) | getPathToItem({
method hasChildren (line 195) | hasChildren(item: TreeItem): boolean {
function treeStateReducer (line 200) | function treeStateReducer(state: TreeState, action: TreeAction): TreeSta...
function toggle (line 251) | function toggle(item: TreeItem): TreeItem {
function getChildItems (line 321) | function getChildItems(data: TreeItem[], targetId: string) {
FILE: packages/documentation/examples/deferred.tsx
function FileList (line 50) | function FileList({ uploads }: { uploads: File[] }) {
function Uploader (line 63) | function Uploader() {
function Example (line 171) | function Example(): React.JSX.Element {
FILE: packages/documentation/examples/drag-handle-button.tsx
function Item (line 47) | function Item({
type ItemData (line 138) | type ItemData = { label: string };
type ReorderItem (line 142) | type ReorderItem = (args: { item: ItemData; direction: 'up' | 'down' }) ...
type ExampleContextProps (line 144) | type ExampleContextProps = {
function getItemPosition (line 152) | function getItemPosition({ index, itemCount }: { index: number; itemCoun...
function DragHandleButtonExample (line 172) | function DragHandleButtonExample(): React.JSX.Element {
FILE: packages/documentation/examples/drawing.tsx
type SwatchColor (line 78) | type SwatchColor = keyof typeof swatchColorMap;
function Swatch (line 80) | function Swatch({
function DrawingExample (line 118) | function DrawingExample(): React.JSX.Element {
FILE: packages/documentation/examples/file-drop-without-pragmatic.tsx
function Example (line 79) | function Example(): React.JSX.Element {
FILE: packages/documentation/examples/file.tsx
type UserUpload (line 81) | type UserUpload = {
function Uploader (line 182) | function Uploader() {
function Example (line 340) | function Example(): React.JSX.Element {
FILE: packages/documentation/examples/flash-prototype.tsx
function isDurationKey (line 16) | function isDurationKey(value: unknown): value is Durations {
function isEasingKey (line 28) | function isEasingKey(value: unknown): value is keyof typeof easingMap {
function PostDropFlashPrototype (line 38) | function PostDropFlashPrototype(): React.JSX.Element {
function OptionLabel (line 86) | function OptionLabel({ children, description }: { children: ReactNode; d...
function FlashParameterForm (line 202) | function FlashParameterForm({ onChange }: { onChange: React.FormEventHan...
FILE: packages/documentation/examples/grid.tsx
function getInstanceId (line 29) | function getInstanceId() {
type State (line 48) | type State = 'idle' | 'dragging' | 'over';
function Grid (line 110) | function Grid(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines.tsx
function GuidelinesExample (line 15) | function GuidelinesExample(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/action-menu-variants.tsx
function ActionMenuVariants (line 10) | function ActionMenuVariants(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/all-drag-handle-variants.tsx
function AllDragHandleVariants (line 12) | function AllDragHandleVariants(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/delayed-cursor-change.tsx
function DelayedCursorChange (line 56) | function DelayedCursorChange(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/entire-entity-is-draggable-with-drag-handle-button.tsx
function EntireEntityIsDraggableWithDragHandleButton (line 38) | function EntireEntityIsDraggableWithDragHandleButton(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/entire-entity-is-draggable-with-grouped-items.tsx
function GroupedActionMenu (line 21) | function GroupedActionMenu() {
function EntireEntityIsDraggableWithGroupedItems (line 98) | function EntireEntityIsDraggableWithGroupedItems(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/entire-entity-is-draggable.tsx
function EntireEntityIsDraggable (line 39) | function EntireEntityIsDraggable(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/hover-drag-handle-outside-bounds.tsx
function HoverDragHandleOutsideBounds (line 76) | function HoverDragHandleOutsideBounds(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/hover-drag-handle.tsx
function HoverDragHandle (line 65) | function HoverDragHandle(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/only-draggable-from-drag-handle.tsx
function OnlyDraggableFromDragHandle (line 41) | function OnlyDraggableFromDragHandle(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/shared/action-menu.tsx
function ActionMenu (line 7) | function ActionMenu(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/shared/drag-preview.tsx
function DragPreview (line 15) | function DragPreview(): React.JSX.Element {
FILE: packages/documentation/examples/guidelines/shared/types.ts
type DraggableState (line 1) | type DraggableState =
FILE: packages/documentation/examples/guidelines/standalone-card.tsx
function ImpliedDraggable (line 18) | function ImpliedDraggable(): React.JSX.Element {
FILE: packages/documentation/examples/iframe-board.tsx
function LinkToProject (line 31) | function LinkToProject() {
function IFrameBoard (line 45) | function IFrameBoard(): React.JSX.Element {
FILE: packages/documentation/examples/iframe-column.tsx
function IFrameColumn (line 5) | function IFrameColumn(): React.JSX.Element {
FILE: packages/documentation/examples/list-comparison.tsx
function Item (line 52) | function Item({
function ItemPreview (line 83) | function ItemPreview({ children }: { children: ReactNode }) {
type Solution (line 87) | type Solution = 'pdnd' | 'rbd';
function ItemCaption (line 140) | function ItemCaption({
function Section (line 198) | function Section({ children, backgroundColor }: { children: ReactNode; b...
function SectionHeader (line 216) | function SectionHeader({
function SubSectionHeader (line 260) | function SubSectionHeader({ title, description }: { title: ReactNode; de...
function TabPanel (line 288) | function TabPanel({ children, ...props }: TabPanelProps) {
function ListComparison (line 296) | function ListComparison(): React.JSX.Element {
FILE: packages/documentation/examples/list.tsx
type ItemPosition (line 45) | type ItemPosition = 'first' | 'last' | 'middle' | 'only';
type CleanupFn (line 47) | type CleanupFn = () => void;
type ItemEntry (line 49) | type ItemEntry = { itemId: string; element: HTMLElement };
type ListContextValue (line 51) | type ListContextValue = {
function useListContext (line 64) | function useListContext() {
type Item (line 70) | type Item = {
type ItemData (line 76) | type ItemData = {
function getItemData (line 83) | function getItemData({
function isItemData (line 100) | function isItemData(data: Record<string | symbol, unknown>): data is Ite...
function getItemPosition (line 104) | function getItemPosition({ index, items }: { index: number; items: Item[...
type DraggableState (line 140) | type DraggableState =
function DropDownContent (line 166) | function DropDownContent({ position, index }: { position: ItemPosition; ...
function ListItem (line 222) | function ListItem({
function getItemRegistry (line 414) | function getItemRegistry() {
type ListState (line 432) | type ListState = {
function ListExample (line 442) | function ListExample(): React.JSX.Element {
FILE: packages/documentation/examples/manual-focus-restoration.tsx
type TeamId (line 34) | type TeamId = 'blue' | 'red';
function TeamArea (line 48) | function TeamArea({
type State (line 79) | type State = {
function getInstanceId (line 92) | function getInstanceId() {
function ManualFocusRestoration (line 98) | function ManualFocusRestoration(): React.JSX.Element {
function Player (line 176) | function Player() {
FILE: packages/documentation/examples/nested-draggables.tsx
function Item (line 48) | function Item({
function DropTarget (line 121) | function DropTarget() {
function Example (line 160) | function Example(): React.JSX.Element {
FILE: packages/documentation/examples/nested-drop-targets.tsx
function DropTarget (line 40) | function DropTarget({ targetId, children }: { targetId: string; children...
function Draggable (line 114) | function Draggable() {
function Example (line 132) | function Example(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/backlog/container.tsx
function BacklogContainer (line 18) | function BacklogContainer({ children }: { children: ReactNode }): React....
function BacklogHeader (line 43) | function BacklogHeader() {
FILE: packages/documentation/examples/pieces/backlog/context.tsx
type ItemPosition (line 9) | type ItemPosition = 'first' | 'last' | 'middle' | 'only';
type CleanupFn (line 11) | type CleanupFn = () => void;
type ListContextProps (line 13) | type ListContextProps = {
function useListContext (line 26) | function useListContext() {
FILE: packages/documentation/examples/pieces/backlog/data.tsx
type ItemData (line 1) | type ItemData = {
FILE: packages/documentation/examples/pieces/backlog/index.tsx
function BacklogPrototype (line 6) | function BacklogPrototype(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/backlog/list-item.tsx
type DraggableState (line 80) | type DraggableState =
function ListItem (line 108) | function ListItem({ itemData }: { itemData: ItemData }): React.JSX.Eleme...
FILE: packages/documentation/examples/pieces/backlog/list.tsx
type ListState (line 63) | type ListState = {
function ListExample (line 73) | function ListExample(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/board-with-multi-drag/board.tsx
function Board (line 24) | function Board({ children }: { children: ReactNode }): React.JSX.Element {
FILE: packages/documentation/examples/pieces/board-with-multi-drag/card.tsx
type DraggableState (line 35) | type DraggableState =
type CardPrimitiveProps (line 89) | type CardPrimitiveProps = {
type CardProps (line 147) | type CardProps = {
method getOffset (line 180) | getOffset() {
method render (line 192) | render({ container }) {
FILE: packages/documentation/examples/pieces/board-with-multi-drag/column.tsx
type State (line 60) | type State =
type ColumnProps (line 100) | type ColumnProps = {
function SafariColumnPreview (line 257) | function SafariColumnPreview({ column }: { column: ColumnType }) {
FILE: packages/documentation/examples/pieces/board-with-overflow-scroll/board.tsx
function Board (line 45) | function Board({ children }: { children: ReactNode }): React.JSX.Element {
FILE: packages/documentation/examples/pieces/board-with-overflow-scroll/card.tsx
type DraggableState (line 35) | type DraggableState =
type CardPrimitiveProps (line 69) | type CardPrimitiveProps = {
method getOffset (line 122) | getOffset() {
method render (line 134) | render({ container }) {
FILE: packages/documentation/examples/pieces/board-with-overflow-scroll/column.tsx
type State (line 76) | type State =
function SafariColumnPreview (line 278) | function SafariColumnPreview({ column }: { column: ColumnType }) {
FILE: packages/documentation/examples/pieces/board/board-context.tsx
type BoardContextValue (line 9) | type BoardContextValue = {
function useBoardContext (line 43) | function useBoardContext(): BoardContextValue {
FILE: packages/documentation/examples/pieces/board/board.tsx
type BoardProps (line 9) | type BoardProps = {
FILE: packages/documentation/examples/pieces/board/card.tsx
type State (line 47) | type State =
type CardPrimitiveProps (line 87) | type CardPrimitiveProps = {
function MoveToOtherColumnItem (line 94) | function MoveToOtherColumnItem({
function LazyDropdownItems (line 115) | function LazyDropdownItems({ userId }: { userId: string }) {
method render (line 264) | render({ container }) {
FILE: packages/documentation/examples/pieces/board/column-context.tsx
type ColumnContextProps (line 5) | type ColumnContextProps = {
function useColumnContext (line 13) | function useColumnContext(): ColumnContextProps {
FILE: packages/documentation/examples/pieces/board/column.tsx
type State (line 94) | type State =
method onDrop (line 192) | onDrop() {
function SafariColumnPreview (line 329) | function SafariColumnPreview({ column }: { column: ColumnType }) {
function ActionMenu (line 339) | function ActionMenu() {
function ActionMenuItems (line 347) | function ActionMenuItems() {
function DropdownMenuTrigger (line 383) | function DropdownMenuTrigger({ triggerRef, ...triggerProps }: CustomTrig...
FILE: packages/documentation/examples/pieces/board/registry.ts
type CardEntry (line 5) | type CardEntry = {
type ColumnEntry (line 10) | type ColumnEntry = {
function createRegistry (line 18) | function createRegistry() {
FILE: packages/documentation/examples/pieces/chess/piece.tsx
type PieceType (line 23) | type PieceType = 'king' | 'pawn';
FILE: packages/documentation/examples/pieces/chess/square.tsx
type SquareProps (line 22) | interface SquareProps {
type State (line 43) | type State =
method onDragStart (line 94) | onDragStart({ source }) {
method onDrop (line 123) | onDrop() {
FILE: packages/documentation/examples/pieces/drawing/line-overlay.tsx
type Point (line 13) | type Point = { x: number; y: number };
type LineOverlayHandle (line 15) | type LineOverlayHandle = {
function setPoints (line 47) | function setPoints(
function createLine (line 69) | function createLine() {
FILE: packages/documentation/examples/pieces/drawing/shape.tsx
type ShapeType (line 20) | type ShapeType = (typeof shapes)[number];
method canDrag (line 95) | canDrag() {
method getInitialData (line 98) | getInitialData() {
method onDrag (line 101) | onDrag({ location, source }) {
method onGenerateDragPreview (line 111) | onGenerateDragPreview() {
method onDragStart (line 116) | onDragStart() {
method getData (line 124) | getData() {
method canDrop (line 127) | canDrop({ source }) {
FILE: packages/documentation/examples/pieces/getting-started/chessboard-colored-drop-targets.tsx
type Coord (line 13) | type Coord = [number, number];
type PieceRecord (line 15) | type PieceRecord = {
type PieceType (line 20) | type PieceType = 'king' | 'pawn';
function isCoord (line 22) | function isCoord(token: unknown): token is Coord {
function isPieceType (line 30) | function isPieceType(value: unknown): value is PieceType {
function isEqualCoord (line 34) | function isEqualCoord(c1: Coord, c2: Coord): boolean {
function canMove (line 45) | function canMove(
function renderSquares (line 68) | function renderSquares(pieces: PieceRecord[]) {
function Chessboard (line 86) | function Chessboard(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/chessboard-draggable.tsx
type Coord (line 12) | type Coord = [number, number];
type PieceRecord (line 14) | type PieceRecord = {
type PieceType (line 19) | type PieceType = 'king' | 'pawn';
function isEqualCoord (line 21) | function isEqualCoord(c1: Coord, c2: Coord): boolean {
function renderSquares (line 32) | function renderSquares(pieces: PieceRecord[]) {
function Chessboard (line 52) | function Chessboard(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/chessboard-drop-target.tsx
type Coord (line 13) | type Coord = [number, number];
type PieceRecord (line 15) | type PieceRecord = {
type PieceType (line 20) | type PieceType = 'king' | 'pawn';
function isEqualCoord (line 22) | function isEqualCoord(c1: Coord, c2: Coord): boolean {
function renderSquares (line 33) | function renderSquares(pieces: PieceRecord[]) {
function Chessboard (line 47) | function Chessboard(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/chessboard-drop-targets-can-drop.tsx
type Coord (line 13) | type Coord = [number, number];
type PieceRecord (line 15) | type PieceRecord = {
type PieceType (line 20) | type PieceType = 'king' | 'pawn';
function isCoord (line 22) | function isCoord(token: unknown): token is Coord {
function isPieceType (line 30) | function isPieceType(value: unknown): value is PieceType {
function isEqualCoord (line 34) | function isEqualCoord(c1: Coord, c2: Coord): boolean {
function canMove (line 45) | function canMove(
function renderSquares (line 68) | function renderSquares(pieces: PieceRecord[]) {
function Chessboard (line 86) | function Chessboard(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/chessboard-monitor.tsx
type Coord (line 15) | type Coord = [number, number];
type PieceRecord (line 17) | type PieceRecord = {
type PieceType (line 22) | type PieceType = 'king' | 'pawn';
function isCoord (line 24) | function isCoord(token: unknown): token is Coord {
function isPieceType (line 32) | function isPieceType(value: unknown): value is PieceType {
function isEqualCoord (line 36) | function isEqualCoord(c1: Coord, c2: Coord): boolean {
function canMove (line 47) | function canMove(
function renderSquares (line 70) | function renderSquares(pieces: PieceRecord[]) {
function Chessboard (line 88) | function Chessboard(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/chessboard-starter-code.tsx
type Coord (line 13) | type Coord = [number, number];
type PieceRecord (line 15) | type PieceRecord = {
type PieceType (line 20) | type PieceType = 'king' | 'pawn';
type PieceProps (line 22) | type PieceProps = {
function isEqualCoord (line 27) | function isEqualCoord(c1: Coord, c2: Coord): boolean {
function renderSquares (line 38) | function renderSquares(pieces: PieceRecord[]) {
function Chessboard (line 58) | function Chessboard(): React.JSX.Element {
function Piece (line 67) | function Piece({ image, alt }: PieceProps) {
function King (line 71) | function King(): React.JSX.Element {
function Pawn (line 75) | function Pawn(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/draggable-piece-in-place.tsx
type PieceType (line 16) | type PieceType = 'king' | 'pawn';
type PieceProps (line 18) | type PieceProps = {
function Piece (line 23) | function Piece({ image, alt }: PieceProps) {
function King (line 38) | function King(): React.JSX.Element {
function Pawn (line 42) | function Pawn(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/draggable-piece-with-data.tsx
type PieceType (line 18) | type PieceType = 'king' | 'pawn';
type PieceProps (line 20) | type PieceProps = {
function King (line 55) | function King({ location }: { location: [number, number] }): React.JSX.E...
function Pawn (line 59) | function Pawn({ location }: { location: [number, number] }): React.JSX.E...
FILE: packages/documentation/examples/pieces/getting-started/draggable-piece-with-state.tsx
type PieceType (line 16) | type PieceType = 'king' | 'pawn';
type PieceProps (line 18) | type PieceProps = {
function Piece (line 23) | function Piece({ image, alt }: PieceProps) {
function King (line 50) | function King(): React.JSX.Element {
function Pawn (line 54) | function Pawn(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/square-drop-target.tsx
type SquareProps (line 16) | interface SquareProps {
function getColor (line 29) | function getColor(isDraggedOver: boolean, isDark: boolean): string {
function Square (line 36) | function Square({ location, children }: SquareProps): React.JSX.Element {
FILE: packages/documentation/examples/pieces/getting-started/square-with-can-drop.tsx
type SquareProps (line 23) | interface SquareProps {
type HoveredState (line 29) | type HoveredState = 'idle' | 'validMove' | 'invalidMove';
function getColor (line 39) | function getColor(state: HoveredState, isDark: boolean): string {
function Square (line 48) | function Square({ pieces, location, children }: SquareProps): React.JSX....
FILE: packages/documentation/examples/pieces/getting-started/square-with-data.tsx
type SquareProps (line 23) | interface SquareProps {
type HoveredState (line 29) | type HoveredState = 'idle' | 'validMove' | 'invalidMove';
function getColor (line 39) | function getColor(state: HoveredState, isDark: boolean): string {
function Square (line 48) | function Square({ pieces, location, children }: SquareProps): React.JSX....
FILE: packages/documentation/examples/pieces/getting-started/square-with-hovering-coloring.tsx
type SquareProps (line 22) | interface SquareProps {
type HoveredState (line 28) | type HoveredState = 'idle' | 'validMove' | 'invalidMove';
function getColor (line 38) | function getColor(state: HoveredState, isDark: boolean): string {
function Square (line 47) | function Square({ pieces, location, children }: SquareProps): React.JSX....
FILE: packages/documentation/examples/pieces/hooks/use-flash-on-drop.tsx
function useFlashOnDrop (line 9) | function useFlashOnDrop({
FILE: packages/documentation/examples/pieces/hooks/use-prevent-scrolling-from-arrow-keys.tsx
function usePreventScrollingFromArrowKeys (line 11) | function usePreventScrollingFromArrowKeys({
FILE: packages/documentation/examples/pieces/hooks/use-sortable-field.tsx
type ShouldHideDropIndicatorArgs (line 18) | type ShouldHideDropIndicatorArgs = {
type UseSortableFieldArgs (line 24) | type UseSortableFieldArgs = {
function shouldHideDropIndicator (line 48) | function shouldHideDropIndicator({
type DragState (line 60) | type DragState = 'idle' | 'preview' | 'dragging';
function useSortableField (line 62) | function useSortableField({
FILE: packages/documentation/examples/pieces/hooks/use-top-level-wiring.tsx
type UseToplevelWiringArgs (line 11) | type UseToplevelWiringArgs<DataItem> = {
type ReorderItem (line 18) | type ReorderItem = (args: { id: string; action: 'up' | 'down' }) => void;
function dispatchAfterDropEvent (line 20) | function dispatchAfterDropEvent(detail: { id: string; type: string }) {
function useTopLevelWiring (line 38) | function useTopLevelWiring<DataItem extends { id: string }>({
FILE: packages/documentation/examples/pieces/iframe-board/card.tsx
type State (line 39) | type State =
type CardPrimitiveProps (line 75) | type CardPrimitiveProps = {
method render (line 136) | render({ container }) {
FILE: packages/documentation/examples/pieces/iframe-board/column.tsx
type State (line 63) | type State = { type: 'idle' } | { type: 'is-card-over' };
function getPeopleFromSharedPool (line 83) | function getPeopleFromSharedPool(): Person[] {
function Column (line 104) | function Column({ columnId }: { columnId: string }): React.JSX.Element {
FILE: packages/documentation/examples/pieces/iframe-board/data.ts
type TCard (line 6) | type TCard = {
function getCard (line 12) | function getCard({ cardId, columnId }: { cardId: string; columnId: strin...
function isCard (line 20) | function isCard(data: Record<string | symbol, unknown>): data is TCard {
type TColumnDropTarget (line 25) | type TColumnDropTarget = {
function getColumnDropTarget (line 30) | function getColumnDropTarget({ columnId }: { columnId: string }): TColum...
function isColumnDropTarget (line 37) | function isColumnDropTarget(
type TCardDropTarget (line 44) | type TCardDropTarget = {
function getCardDropTarget (line 50) | function getCardDropTarget({
function isCardDropTarget (line 64) | function isCardDropTarget(data: Record<string | symbol, unknown>): data ...
function getCardDataForExternal (line 71) | function getCardDataForExternal(person: Person) {
function isAndroid (line 93) | function isAndroid(): boolean {
function isDraggingExternalCard (line 97) | function isDraggingExternalCard({ source }: { source: ExternalDragPayloa...
function getDroppedExternalCardId (line 108) | function getDroppedExternalCardId({
FILE: packages/documentation/examples/pieces/menu-button/index.tsx
type ChildrenRenderFn (line 24) | type ChildrenRenderFn = (args: { children: ReactElement; isSelected: boo...
function MenuButton (line 28) | function MenuButton({
type MenuButtonTriggerOwnProps (line 84) | type MenuButtonTriggerOwnProps = {
type MenuButtonTriggerProps (line 90) | type MenuButtonTriggerProps = CustomTriggerProps & MenuButtonTriggerOwnP...
function MenuButtonTrigger (line 92) | function MenuButtonTrigger({
FILE: packages/documentation/examples/pieces/pinned-fields/data.tsx
type DataItem (line 20) | type DataItem = {
FILE: packages/documentation/examples/pieces/pinned-fields/experience/asana-native-preview.tsx
function DraggableField (line 15) | function DraggableField({ index, item }: DraggableFieldProps) {
function AsanaFieldsWithNativePreview (line 54) | function AsanaFieldsWithNativePreview(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/experience/asana.tsx
function DragPreview (line 15) | function DragPreview({
function DraggableField (line 76) | function DraggableField({ index, item }: DraggableFieldProps) {
function AsanaFields (line 107) | function AsanaFields(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/experience/current-guidelines-a11y-always-visible.tsx
function DraggableField (line 25) | function DraggableField({
function PinnedFieldsWithCurrentGuidelinesA11yAlwaysVisible (line 83) | function PinnedFieldsWithCurrentGuidelinesA11yAlwaysVisible(): React.JSX...
FILE: packages/documentation/examples/pieces/pinned-fields/experience/current-guidelines-a11y-keyboard-only.tsx
function DraggableField (line 44) | function DraggableField({
function PinnedFieldsWithCurrentGuidelinesA11yKeyboardOnly (line 94) | function PinnedFieldsWithCurrentGuidelinesA11yKeyboardOnly(): React.JSX....
FILE: packages/documentation/examples/pieces/pinned-fields/experience/current-guidelines.tsx
function DraggableField (line 23) | function DraggableField({
function PinnedFieldsWithCurrentGuidelines (line 52) | function PinnedFieldsWithCurrentGuidelines(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/experience/enhanced-drag-handle.tsx
function DraggableFieldPreview (line 37) | function DraggableFieldPreview({ children }: { children: ReactNode }) {
function DraggableField (line 51) | function DraggableField({ index, item, data, reorderItem }: DraggableFie...
function PinnedFieldsEnhancedDragHandle (line 135) | function PinnedFieldsEnhancedDragHandle(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/experience/migration-layer.tsx
function PinnedFieldReactBeautifulDnd (line 12) | function PinnedFieldReactBeautifulDnd(): React.JSX.Element {
function PinnedFieldReactBeautifulDndNoDraggingOutline (line 24) | function PinnedFieldReactBeautifulDndNoDraggingOutline(): React.JSX.Elem...
function PinnedFieldReactBeautifulDndSubtle (line 36) | function PinnedFieldReactBeautifulDndSubtle(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/experience/rdr-prototype.tsx
function DraggableFieldPreview (line 37) | function DraggableFieldPreview({ children }: { children: ReactNode }) {
function DraggableField (line 51) | function DraggableField({ index, item, data, reorderItem }: DraggableFie...
function PinnedFieldsPrototype (line 135) | function PinnedFieldsPrototype(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/experience/react-beautiful-dnd.tsx
function PinnedFieldReactBeautifulDnd (line 8) | function PinnedFieldReactBeautifulDnd(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/hooks/use-sortable-field.tsx
type UseSortableFieldArgs (line 18) | type UseSortableFieldArgs = {
function shouldHideDropIndicator (line 33) | function shouldHideDropIndicator({
function useSortableField (line 49) | function useSortableField({
FILE: packages/documentation/examples/pieces/pinned-fields/index.tsx
function FieldLabel (line 73) | function FieldLabel({ children }: { children: ReactNode }): React.JSX.El...
type FieldProps (line 91) | type FieldProps = HTMLAttributes<HTMLDivElement> & {
function PinnedFieldsContainer (line 137) | function PinnedFieldsContainer({ children }: { children: ReactNode }): R...
function FieldContentWithIcon (line 165) | function FieldContentWithIcon({
FILE: packages/documentation/examples/pieces/pinned-fields/major-priority-icon.tsx
function MajorPriorityIcon (line 3) | function MajorPriorityIcon(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/primitives/asana/drop-indicator.tsx
function DropIndicator (line 54) | function DropIndicator({ edge }: { edge: Edge }): React.JSX.Element {
FILE: packages/documentation/examples/pieces/pinned-fields/primitives/asana/field.tsx
type FieldProps (line 48) | type FieldProps = {
function FieldPreview (line 86) | function FieldPreview({ children }: { children: ReactNode }): React.JSX....
FILE: packages/documentation/examples/pieces/pinned-fields/primitives/droppable-area-overlay.tsx
type DroppableAreaOverlayAppearance (line 51) | type DroppableAreaOverlayAppearance = 'default' | 'borderless' | 'subtle';
type DroppableAreaOverlayProps (line 53) | type DroppableAreaOverlayProps = {
function DroppableAreaOverlay (line 67) | function DroppableAreaOverlay({
FILE: packages/documentation/examples/pieces/pinned-fields/templates/asana.tsx
type DataItem (line 13) | type DataItem = {
type DraggableFieldProps (line 57) | type DraggableFieldProps = { index: number; item: DataItem };
type AsanaFieldsTemplateProps (line 59) | type AsanaFieldsTemplateProps = {
function AsanaFieldsTemplate (line 64) | function AsanaFieldsTemplate({
FILE: packages/documentation/examples/pieces/pinned-fields/templates/atlassian.tsx
type DraggableFieldProps (line 7) | type DraggableFieldProps = {
type PinnedFieldsAtlassianTemplateProps (line 14) | type PinnedFieldsAtlassianTemplateProps = {
function PinnedFieldsAtlassianTemplate (line 19) | function PinnedFieldsAtlassianTemplate({
FILE: packages/documentation/examples/pieces/pinned-fields/templates/react-beautiful-dnd.tsx
function DraggableField (line 23) | function DraggableField({
type TemplateProps (line 50) | type TemplateProps = {
function PinnedFieldsReactBeautifulDndTemplate (line 60) | function PinnedFieldsReactBeautifulDndTemplate({
FILE: packages/documentation/examples/pieces/pinned-fields/use-drag-observer.tsx
type DragObserverState (line 7) | type DragObserverState =
type DragObserver (line 16) | type DragObserver = {
function createDragObserver (line 23) | function createDragObserver() {
function useDragObserver (line 51) | function useDragObserver(): DragObserver {
FILE: packages/documentation/examples/pieces/post-drop-flash/list.tsx
type ItemPosition (line 43) | type ItemPosition = 'first' | 'last' | 'middle' | 'only';
type CleanupFn (line 45) | type CleanupFn = () => void;
type ListContextProps (line 47) | type ListContextProps = {
function useListContext (line 61) | function useListContext() {
type ItemData (line 67) | type ItemData = {
type DraggableState (line 92) | type DraggableState =
function ListItem (line 118) | function ListItem({ itemData }: { itemData: ItemData }) {
function LazyDropdownContent (line 261) | function LazyDropdownContent({ itemData }: { itemData: ItemData }) {
type ListState (line 341) | type ListState = {
function ListExample (line 351) | function ListExample({
FILE: packages/documentation/examples/pieces/rdr-board/board-context.tsx
type BoardContextProps (line 7) | type BoardContextProps = {
function useBoardContext (line 32) | function useBoardContext(): BoardContextProps {
FILE: packages/documentation/examples/pieces/rdr-board/board.tsx
type BoardProps (line 13) | type BoardProps = {
FILE: packages/documentation/examples/pieces/rdr-board/card-stack.tsx
function CardStack (line 56) | function CardStack({
FILE: packages/documentation/examples/pieces/rdr-board/card.tsx
type DraggableState (line 54) | type DraggableState =
type CardPrimitiveProps (line 111) | type CardPrimitiveProps = {
function MoveToOtherColumnItem (line 120) | function MoveToOtherColumnItem({
function LazyDropdownItems (line 141) | function LazyDropdownItems({ item }: { item: CardData }) {
method getOffset (line 312) | getOffset() {
method render (line 324) | render({ container }) {
FILE: packages/documentation/examples/pieces/rdr-board/column-context.tsx
type ColumnContextProps (line 5) | type ColumnContextProps = {
function useColumnContext (line 13) | function useColumnContext(): ColumnContextProps {
FILE: packages/documentation/examples/pieces/rdr-board/column.tsx
type IdleState (line 81) | type IdleState = { type: 'idle' };
type DropTargetState (line 83) | type DropTargetState =
type DraggableState (line 88) | type DraggableState =
method onDrop (line 147) | onDrop() {
function ColumnPreview (line 262) | function ColumnPreview({ column }: { column: ColumnType }) {
function ActionMenu (line 272) | function ActionMenu() {
function ActionMenuItems (line 280) | function ActionMenuItems() {
function DropdownMenuTrigger (line 316) | function DropdownMenuTrigger({ triggerRef, ...triggerProps }: CustomTrig...
FILE: packages/documentation/examples/pieces/rdr-board/data.tsx
type Epic (line 1) | type Epic = 'forms' | 'accounts' | 'billing';
type CardData (line 3) | type CardData = {
type ColumnType (line 9) | type ColumnType = {
type ColumnMap (line 14) | type ColumnMap = { [columnId: string]: ColumnType };
function getInitialData (line 16) | function getInitialData() {
FILE: packages/documentation/examples/pieces/rdr-board/epic-lozenge.tsx
function EpicLozenge (line 13) | function EpicLozenge({ epic }: { epic: Epic }): React.JSX.Element {
FILE: packages/documentation/examples/pieces/rdr-board/index.tsx
type Operation (line 18) | type Operation =
type BoardState (line 38) | type BoardState = {
function createRegistry (line 48) | function createRegistry() {
function BoardPrototype (line 76) | function BoardPrototype(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/container.tsx
function FieldsContainer (line 33) | function FieldsContainer({
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/context.tsx
type ItemPosition (line 9) | type ItemPosition = 'first' | 'last' | 'middle' | 'only';
type CleanupFn (line 11) | type CleanupFn = () => void;
type ListContextProps (line 13) | type ListContextProps = {
function useListContext (line 26) | function useListContext() {
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/data.tsx
type ItemData (line 19) | type ItemData = {
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/drag-handle-button.tsx
type DragHandleButtonProps (line 45) | type DragHandleButtonProps = Omit<CustomTriggerProps, 'triggerRef'>;
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/field.tsx
function FieldContentWithIcon (line 29) | function FieldContentWithIcon({
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/index.tsx
function PinnedFieldsPrototype (line 9) | function PinnedFieldsPrototype(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/list-item.tsx
type DraggableState (line 63) | type DraggableState =
function ListItem (line 98) | function ListItem({
function LazyDropdownContent (line 244) | function LazyDropdownContent({ itemData }: { itemData: ItemData }) {
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/list.tsx
type ListState (line 27) | type ListState = {
function ListExample (line 37) | function ListExample({
FILE: packages/documentation/examples/pieces/rdr-pinned-fields/major-priority-icon.tsx
function MajorPriorityIcon (line 3) | function MajorPriorityIcon(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/rdr-subtasks/container.tsx
function BacklogContainer (line 18) | function BacklogContainer({ children }: { children: ReactNode }): React....
function BacklogHeader (line 43) | function BacklogHeader() {
FILE: packages/documentation/examples/pieces/rdr-subtasks/context.tsx
type ItemPosition (line 9) | type ItemPosition = 'first' | 'last' | 'middle' | 'only';
type CleanupFn (line 11) | type CleanupFn = () => void;
type ListContextProps (line 13) | type ListContextProps = {
function useListContext (line 26) | function useListContext() {
FILE: packages/documentation/examples/pieces/rdr-subtasks/data.tsx
type ItemData (line 1) | type ItemData = {
FILE: packages/documentation/examples/pieces/rdr-subtasks/drag-handle-button.tsx
type DragHandleButtonProps (line 51) | type DragHandleButtonProps = Omit<CustomTriggerProps, 'triggerRef'>;
FILE: packages/documentation/examples/pieces/rdr-subtasks/index.tsx
function SubtasksPrototype (line 5) | function SubtasksPrototype(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/rdr-subtasks/list-item.tsx
type DraggableState (line 60) | type DraggableState =
function ListItem (line 108) | function ListItem({ itemData }: { itemData: ItemData }): React.JSX.Eleme...
function LazyDropdownContent (line 271) | function LazyDropdownContent({ itemData }: { itemData: ItemData }) {
FILE: packages/documentation/examples/pieces/rdr-subtasks/list.tsx
type ListState (line 27) | type ListState = {
function ListExample (line 37) | function ListExample(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/rdr-subtasks/subtask-icon.tsx
function SubtaskIcon (line 3) | function SubtaskIcon(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/data.tsx
type DataItem (line 1) | type DataItem = {
FILE: packages/documentation/examples/pieces/subtasks/demo/current-guidelines-a11y-always-visible.tsx
type DraggableSubtaskProps (line 21) | type DraggableSubtaskProps = SubtaskProps & {
function DraggableSubtask (line 33) | function DraggableSubtask({
function SubtasksCurrentGuidelinesA11yAlwaysVisible (line 71) | function SubtasksCurrentGuidelinesA11yAlwaysVisible(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/current-guidelines-a11y-keyboard-only.tsx
type DraggableSubtaskProps (line 22) | type DraggableSubtaskProps = SubtaskProps & {
function DraggableSubtask (line 52) | function DraggableSubtask({
function SubtasksCurrentGuidelinesA11yKeyboardOnly (line 99) | function SubtasksCurrentGuidelinesA11yKeyboardOnly(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/current-guidelines.tsx
type DraggableSubtaskProps (line 20) | type DraggableSubtaskProps = SubtaskProps & {
function DraggableSubtask (line 32) | function DraggableSubtask({ index, id, ...subtaskProps }: DraggableSubta...
function SubtaskCurrentGuidelines (line 55) | function SubtaskCurrentGuidelines(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/enhancements.tsx
function DraggableSubtaskPreview (line 41) | function DraggableSubtaskPreview({ children }: { children: ReactNode }) {
type DraggableSubtaskProps (line 50) | type DraggableSubtaskProps = SubtaskProps & {
function DraggableSubtask (line 101) | function DraggableSubtask({
function SubtaskEnhanced (line 195) | function SubtaskEnhanced(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/linear-native-preview.tsx
function DragPreview (line 35) | function DragPreview({
function DraggableSubtask (line 43) | function DraggableSubtask({ index, item }: DraggableSubtaskProps) {
function LinearTaskReorderingNativePreview (line 84) | function LinearTaskReorderingNativePreview(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/linear.tsx
function DragPreview (line 42) | function DragPreview({
function DraggableSubtask (line 181) | function DraggableSubtask({ index, item }: DraggableSubtaskProps) {
function LinearTaskReordering (line 214) | function LinearTaskReordering(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/migration-layer.tsx
type DraggableSubtaskProps (line 15) | type DraggableSubtaskProps = SubtaskProps & {
function DraggableSubtask (line 19) | function DraggableSubtask({ index, ...subtaskProps }: DraggableSubtaskPr...
function SubtasksMigrationLayer (line 40) | function SubtasksMigrationLayer(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/notion.tsx
type DraggableSubtaskProps (line 20) | type DraggableSubtaskProps = Omit<SubtaskProps, 'dragState'> & {
function DraggableSubtask (line 32) | function DraggableSubtask({ index, id, ...subtaskProps }: DraggableSubta...
function SubtasksNotion (line 62) | function SubtasksNotion(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/demo/react-beautiful-dnd.tsx
type DraggableSubtaskProps (line 16) | type DraggableSubtaskProps = SubtaskProps & {
function DraggableSubtask (line 20) | function DraggableSubtask({ index, ...subtaskProps }: DraggableSubtaskPr...
function SubtaskReactBeautifulDnd (line 36) | function SubtaskReactBeautifulDnd(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/hooks/use-sortable-field.tsx
type UseSortableFieldArgs (line 18) | type UseSortableFieldArgs = {
function shouldHideDropIndicator (line 33) | function shouldHideDropIndicator({
type DragState (line 49) | type DragState = 'idle' | 'preview' | 'dragging';
function useSortableField (line 51) | function useSortableField({
FILE: packages/documentation/examples/pieces/subtasks/hooks/use-top-level-wiring.tsx
type UseToplevelWiringArgs (line 11) | type UseToplevelWiringArgs<DataItem> = {
type ReorderItem (line 21) | type ReorderItem = (args: { id: string; action: 'up' | 'down' }) => void;
function useTopLevelWiring (line 31) | function useTopLevelWiring<DataItem extends { id: string }>({
FILE: packages/documentation/examples/pieces/subtasks/primitives/linear/in-progress-icon.tsx
function LinearInProgressIcon (line 5) | function LinearInProgressIcon(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/primitives/linear/priority-icon.tsx
function LinearPriorityIcon (line 3) | function LinearPriorityIcon({
FILE: packages/documentation/examples/pieces/subtasks/primitives/linear/subtask-container.tsx
type SubtaskContainerProps (line 21) | type SubtaskContainerProps = HTMLAttributes<HTMLDivElement> & {
FILE: packages/documentation/examples/pieces/subtasks/primitives/linear/subtask.tsx
function SubtaskGroup (line 61) | function SubtaskGroup({ children }: { children: ReactNode }) {
type SubtaskAppearance (line 65) | type SubtaskAppearance = 'default' | 'overlay' | 'disabled';
type SubtaskProps (line 95) | type SubtaskProps = HTMLAttributes<HTMLDivElement> & {
FILE: packages/documentation/examples/pieces/subtasks/primitives/major-priority-icon.tsx
function MajorPriorityIcon (line 3) | function MajorPriorityIcon(): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/primitives/notion/drop-indicator.tsx
function DropIndicator (line 35) | function DropIndicator({ edge, gap }: { edge: Edge; gap: string }): Reac...
FILE: packages/documentation/examples/pieces/subtasks/primitives/notion/subtask-container.tsx
type SubtaskContainerProps (line 23) | type SubtaskContainerProps = HTMLAttributes<HTMLDivElement> & {
function Heading (line 45) | function Heading({ children }: { children: ReactNode }) {
FILE: packages/documentation/examples/pieces/subtasks/primitives/notion/subtask.tsx
type SubtaskAppearance (line 33) | type SubtaskAppearance = 'default' | 'overlay' | 'disabled';
type SubtaskProps (line 64) | type SubtaskProps = HTMLAttributes<HTMLDivElement> & {
function Cell (line 85) | function Cell({ children }: { children: ReactNode }) {
FILE: packages/documentation/examples/pieces/subtasks/primitives/subtask-container.tsx
type SubtaskContainerProps (line 25) | type SubtaskContainerProps = HTMLAttributes<HTMLDivElement> & {
FILE: packages/documentation/examples/pieces/subtasks/primitives/subtask-drag-handle.tsx
type SubtaskDragHandleProps (line 84) | type SubtaskDragHandleProps = {
function SubtaskDragHandleTrigger (line 89) | function SubtaskDragHandleTrigger({
FILE: packages/documentation/examples/pieces/subtasks/primitives/subtask-icon.tsx
function SubtaskObjectIcon (line 5) | function SubtaskObjectIcon(): React.JSX.Element {
function SubtaskIcon (line 40) | function SubtaskIcon({ isIconHidden = false }): React.JSX.Element {
FILE: packages/documentation/examples/pieces/subtasks/primitives/subtask.tsx
function SubtaskGroup (line 49) | function SubtaskGroup({ children }: { children: ReactNode }) {
type SubtaskAppearance (line 64) | type SubtaskAppearance = 'default' | 'overlay' | 'disabled';
type SubtaskProps (line 91) | type SubtaskProps = HTMLAttributes<HTMLDivElement> & {
FILE: packages/documentation/examples/pieces/subtasks/templates/_base.tsx
type DraggableSubtaskProps (line 6) | type DraggableSubtaskProps = { index: number; item: DataItem };
type SubtasksBaseTemplateProps (line 8) | type SubtasksBaseTemplateProps = {
function SubtasksBaseTemplate (line 14) | function SubtasksBaseTemplate({
FILE: packages/documentation/examples/pieces/subtasks/templates/linear.tsx
type LinearTemplateProps (line 7) | type LinearTemplateProps = Omit<SubtasksBaseTemplateProps, 'Wrapper'>;
function LinearTemplate (line 9) | function LinearTemplate({
FILE: packages/documentation/examples/pieces/table/data.ts
function getStableValues (line 11) | function getStableValues({
function getItems (line 37) | function getItems({ amount }: { amount: number }): Item[] {
FILE: packages/documentation/examples/pieces/table/render-pieces.tsx
function getField (line 18) | function getField({ item, property }: { item: Item; property: keyof Item...
function getProperty (line 43) | function getProperty(value: keyof Item): string {
function getStatus (line 53) | function getStatus(value: Status): ReactElement {
FILE: packages/documentation/examples/pieces/table/row.tsx
type State (line 49) | type State =
method getInitialData (line 102) | getInitialData() {
method onGenerateDragPreview (line 105) | onGenerateDragPreview({ nativeSetDragImage }) {
method canDrop (line 122) | canDrop({ source }) {
method getData (line 129) | getData({ input, element }) {
method onDragEnter (line 137) | onDragEnter(args) {
method onDrag (line 143) | onDrag(args) {
method onDragLeave (line 160) | onDragLeave() {
method onDrop (line 163) | onDrop() {
function Preview (line 226) | function Preview({ item, properties }: { item: Item; properties: (keyof ...
FILE: packages/documentation/examples/pieces/table/table-context.ts
type UnregisterFn (line 5) | type UnregisterFn = () => void;
type ItemContextValue (line 7) | type ItemContextValue = {
FILE: packages/documentation/examples/pieces/table/table-header.tsx
type HeaderState (line 37) | type HeaderState =
function clamp (line 84) | function clamp({ value, min, max }: { value: number; min: number; max: n...
type ColumnType (line 93) | type ColumnType = 'first-of-many' | 'middle-of-many' | 'last-of-many' | ...
function getColumnType (line 189) | function getColumnType({
function TableHeader (line 208) | function TableHeader({
function ColumnPreview (line 481) | function ColumnPreview({ property }: { property: keyof Item }) {
FILE: packages/documentation/examples/pieces/table/types.ts
type Status (line 5) | type Status = 'todo' | 'in-progress' | 'done';
type Item (line 7) | type Item = {
type ItemRegistration (line 14) | type ItemRegistration = {
type ReorderFunction (line 20) | type ReorderFunction = (args: {
FILE: packages/documentation/examples/pieces/tree-legacy/move-dialog.tsx
type FormData (line 19) | type FormData = {
function MoveDialog (line 24) | function MoveDialog({
function PositionSelectField (line 127) | function PositionSelectField({
FILE: packages/documentation/examples/pieces/tree-legacy/tree-context.tsx
type TreeContextValue (line 11) | type TreeContextValue = {
type DependencyContext (line 33) | type DependencyContext = {
FILE: packages/documentation/examples/pieces/tree-legacy/tree-item.tsx
function ChildIcon (line 46) | function ChildIcon() {
function GroupIcon (line 54) | function GroupIcon({ isOpen }: { isOpen: boolean }) {
function Icon (line 59) | function Icon({ item }: { item: TreeItemType }) {
function Preview (line 139) | function Preview({ item }: { item: TreeItemType }) {
function getParentLevelOfInstruction (line 147) | function getParentLevelOfInstruction(instruction: Instruction): number {
function delay (line 157) | function delay({ waitMs: timeMs, fn }: { waitMs: number; fn: () => void ...
function updateIsParentOfInstruction (line 245) | function updateIsParentOfInstruction({ location }: { location: DragLocat...
function onChange (line 253) | function onChange({ self, source }: ElementDropTargetEventBasePayload) {
method onDrop (line 348) | onDrop() {
FILE: packages/documentation/examples/pieces/tree/move-dialog.tsx
type FormData (line 19) | type FormData = {
function MoveDialog (line 24) | function MoveDialog({
function PositionSelectField (line 127) | function PositionSelectField({
FILE: packages/documentation/examples/pieces/tree/tree-context.tsx
type TreeContextValue (line 11) | type TreeContextValue = {
type DependencyContext (line 33) | type DependencyContext = {
FILE: packages/documentation/examples/pieces/tree/tree-item.tsx
function ChildIcon (line 42) | function ChildIcon() {
function GroupIcon (line 50) | function GroupIcon({ isOpen }: { isOpen: boolean }) {
function Icon (line 55) | function Icon({ item }: { item: TreeItemType }) {
function Preview (line 137) | function Preview({ item }: { item: TreeItemType }) {
function delay (line 141) | function delay({ waitMs: timeMs, fn }: { waitMs: number; fn: () => void ...
function onChange (line 196) | function onChange({ self }: ElementDropTargetEventBasePayload) {
function onChange (line 306) | function onChange({ location, self }: ElementDropTargetEventBasePayload) {
FILE: packages/documentation/examples/resizing.tsx
function Icon (line 34) | function Icon({ src, alt }: { src: string; alt: string }) {
type State (line 133) | type State =
function getProposedWidth (line 147) | function getProposedWidth({
function Sidebar (line 161) | function Sidebar() {
function Item (line 238) | function Item({ itemId }: { itemId: string }) {
function Content (line 255) | function Content() {
function Container (line 280) | function Container(): React.JSX.Element {
FILE: packages/documentation/examples/table.tsx
function extractIndex (line 62) | function extractIndex(data: Record<string, unknown>) {
type Operation (line 70) | type Operation =
function Table (line 80) | function Table(): React.JSX.Element {
FILE: packages/documentation/examples/text-selection.tsx
function TextSelection (line 14) | function TextSelection(): React.JSX.Element {
FILE: packages/documentation/examples/tree-legacy.tsx
type CleanupFn (line 52) | type CleanupFn = () => void;
function createTreeItemRegistry (line 54) | function createTreeItemRegistry() {
function Tree (line 75) | function Tree(): React.JSX.Element {
FILE: packages/documentation/examples/tree.tsx
type CleanupFn (line 50) | type CleanupFn = () => void;
function createTreeItemRegistry (line 52) | function createTreeItemRegistry() {
function TreeLegacy (line 73) | function TreeLegacy(): React.JSX.Element {
FILE: packages/documentation/examples/trello-like-board-iframe.tsx
function TrelloLikeBoardIframe (line 19) | function TrelloLikeBoardIframe(): React.JSX.Element {
FILE: packages/documentation/examples/util/global-styles.tsx
function GlobalStyles (line 19) | function GlobalStyles(): React.JSX.Element {
FILE: packages/documentation/examples/virtual-list.tsx
type ItemPosition (line 48) | type ItemPosition = 'first' | 'last' | 'middle' | 'only';
type CleanupFn (line 50) | type CleanupFn = () => void;
type ItemEntry (line 52) | type ItemEntry = { itemId: string; element: HTMLElement };
type ListContextValue (line 54) | type ListContextValue = {
function useListContext (line 67) | function useListContext() {
type Item (line 73) | type Item = {
type ItemData (line 79) | type ItemData = {
function getItemData (line 86) | function getItemData({
function isItemData (line 103) | function isItemData(data: Record<string | symbol, unknown>): data is Ite...
function getItemPosition (line 107) | function getItemPosition({ index, items }: { index: number; items: Item[...
type ItemState (line 157) | type ItemState =
function DropDownContent (line 184) | function DropDownContent({ position, index }: { position: ItemPosition; ...
function predicate (line 264) | function predicate({ source }: { source: ElementDragPayload }): boolean {
method onGenerateDragPreview (line 280) | onGenerateDragPreview({ nativeSetDragImage }) {
method onDragStart (line 294) | onDragStart() {
method onDrop (line 297) | onDrop() {
method getData (line 305) | getData({ input }) {
method onDrag (line 312) | onDrag({ self }) {
method onDragLeave (line 322) | onDragLeave() {
method onDrop (line 325) | onDrop() {
function getItems (line 424) | function getItems({ amount }: { amount: number }): Item[] {
function getItemRegistry (line 443) | function getItemRegistry() {
type ListState (line 468) | type ListState = {
function ListExample (line 478) | function ListExample(): React.JSX.Element {
FILE: packages/documentation/scripts/codegen.ts
function generateSVGDataURIs (line 8) | async function generateSVGDataURIs() {
FILE: packages/flourish/examples/basic.tsx
function BasicExample (line 17) | function BasicExample(): React.JSX.Element {
FILE: packages/flourish/src/trigger-post-move-flash.tsx
function triggerPostMoveFlash (line 10) | function triggerPostMoveFlash(element: HTMLElement): void {
FILE: packages/hitbox/__tests__/unit/_util.ts
function getDefaultInput (line 3) | function getDefaultInput(overrides: Partial<Input> = {}): Input {
function getRect (line 26) | function getRect(box: {
function between (line 47) | function between(inner: number, outer: number): number {
FILE: packages/hitbox/__tests__/unit/closest-edge.spec.ts
type Scenario (line 17) | type Scenario = {
FILE: packages/hitbox/__tests__/unit/list-item.spec.ts
type TOperationArgs (line 10) | type TOperationArgs = Parameters<typeof attachInstruction>[1]['operation...
type Axis (line 24) | type Axis = (typeof axis)[number];
function getInputs (line 43) | function getInputs(axis: Axis) {
function block (line 120) | function block(args: TOperationArgs): TOperationArgs {
type TExpectationMap (line 139) | type TExpectationMap = {
FILE: packages/hitbox/__tests__/unit/tree-item.spec.ts
type Scenario (line 12) | type Scenario = {
type Point (line 37) | type Point = Position & { label: string };
function getPoints (line 39) | function getPoints(rect: DOMRect): Point[] {
function createPullBackScenario (line 209) | function createPullBackScenario({
FILE: packages/hitbox/src/closest-edge.ts
type Edge (line 5) | type Edge = EdgeRaw;
function attachClosestEdge (line 22) | function attachClosestEdge(
function extractClosestEdge (line 61) | function extractClosestEdge(userData: Record<string | symbol, unknown>):...
FILE: packages/hitbox/src/get-reorder-destination-index.ts
function getReorderDestinationIndex (line 3) | function getReorderDestinationIndex({
FILE: packages/hitbox/src/internal/memoize.ts
type TData (line 1) | type TData = Record<string, unknown>;
function isShallowEqual (line 3) | function isShallowEqual(a: Record<string, unknown>, b: Record<string, un...
function stable (line 16) | function stable<T extends TData>(isEqual: (a: T, b: T) => boolean = isSh...
FILE: packages/hitbox/src/list-item.ts
type Operation (line 5) | type Operation = 'reorder-before' | 'reorder-after' | 'combine';
type Axis (line 7) | type Axis = 'horizontal' | 'vertical';
type Instruction (line 9) | type Instruction = {
type AxisDefinition (line 35) | type AxisDefinition = (typeof axisLookup)[keyof typeof axisLookup];
function reorderAndCombine (line 37) | function reorderAndCombine({
function reorder (line 61) | function reorder({
type Availability (line 84) | type Availability = 'available' | 'not-available' | 'blocked';
function isPossible (line 86) | function isPossible(...values: Availability[]): boolean {
function isNotAvailable (line 90) | function isNotAvailable(...values: Availability[]): boolean {
function attachInstruction (line 126) | function attachInstruction(
function extractInstruction (line 229) | function extractInstruction(userData: Record<string | symbol, unknown>):...
FILE: packages/hitbox/src/reorder-with-edge.ts
function reorderWithEdge (line 6) | function reorderWithEdge<Value>({
FILE: packages/hitbox/src/tree-item.ts
type ItemMode (line 5) | type ItemMode = 'standard' | 'expanded' | 'last-in-group';
type Instruction (line 7) | type Instruction =
function getCenter (line 36) | function getCenter(rect: DOMRect): Position {
function standardHitbox (line 43) | function standardHitbox({
function getInstruction (line 65) | function getInstruction({
function areInstructionsEqual (line 136) | function areInstructionsEqual(a: Instruction, b: Instruction): boolean {
function applyInstructionBlock (line 151) | function applyInstructionBlock({
function attachInstruction (line 169) | function attachInstruction(
function extractInstruction (line 191) | function extractInstruction(userData: Record<string | symbol, unknown>):...
FILE: packages/hitbox/src/types.ts
type Edge (line 1) | type Edge = 'top' | 'right' | 'bottom' | 'left';
FILE: packages/live-region/examples/00-basic.tsx
function BasicExample (line 5) | function BasicExample(): React.JSX.Element {
FILE: packages/live-region/examples/01-list-with-inline-buttons.tsx
type ItemData (line 20) | type ItemData = { id: string; label: string };
type Action (line 22) | type Action = { type: 'MOVE_UP' | 'MOVE_DOWN'; id: string };
function App (line 122) | function App(): React.JSX.Element {
FILE: packages/live-region/src/index.tsx
function createNode (line 29) | function createNode(): HTMLElement {
function getNode (line 47) | function getNode(): HTMLElement {
function tryClearTimer (line 56) | function tryClearTimer() {
function announce (line 66) | function announce(message: string): void {
function cleanup (line 93) | function cleanup(): void {
FILE: packages/react-accessibility/examples/drag-handle-button-small.tsx
function DragHandleButtonSmallExample (line 5) | function DragHandleButtonSmallExample(): React.JSX.Element {
FILE: packages/react-accessibility/examples/drag-handle-button.tsx
function DragHandleButtonExample (line 5) | function DragHandleButtonExample(): React.JSX.Element {
FILE: packages/react-accessibility/examples/drag-handle-dropdown-menu.tsx
function DragHandleDropdownMenuExample (line 9) | function DragHandleDropdownMenuExample(): React.JSX.Element {
FILE: packages/react-accessibility/src/drag-handle-button-base.tsx
type DragHandleButtonAppearance (line 30) | type DragHandleButtonAppearance = 'default' | 'subtle' | 'selected';
FILE: packages/react-accessibility/src/types.tsx
type DragHandleButtonAppearance (line 3) | type DragHandleButtonAppearance = 'default' | 'subtle' | 'selected';
type DragHandleButtonProps (line 5) | type DragHandleButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
type DragHandleIconProps (line 26) | type DragHandleIconProps = {
FILE: packages/react-beautiful-dnd-autoscroll/__tests__/unit/_util.tsx
function getDefaultInput (line 3) | function getDefaultInput(overrides: Partial<Input> = {}): Input {
function getRect (line 26) | function getRect(box: {
function getElements (line 49) | function getElements(tagName: keyof HTMLElementTagNameMap = 'div'): Iter...
FILE: packages/react-beautiful-dnd-autoscroll/__tests__/unit/get-scroll/get-value.spec.ts
type Args (line 20) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/index.ts
type WhileDragging (line 6) | type WhileDragging = {
function tryScroll (line 25) | function tryScroll(fakeScrollCallback?: () => void) {
function loop (line 44) | function loop() {
function updateInput (line 82) | function updateInput({ input }: { input: Input }): void {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/can-scroll.ts
type CanPartiallyScrollArgs (line 8) | type CanPartiallyScrollArgs = {
type GetRemainderArgs (line 21) | type GetRemainderArgs = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-closest-scrollable-element.ts
type Overflow (line 3) | type Overflow = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-max-scroll.ts
type Args (line 5) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-percentage.ts
type Args (line 3) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-scroll/get-scroll-on-axis/get-distance-thresholds.ts
type DistanceThresholds (line 8) | type DistanceThresholds = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-scroll/get-scroll-on-axis/get-value.ts
type Args (line 9) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-scroll/get-scroll-on-axis/index.ts
type GetOnAxisArgs (line 10) | type GetOnAxisArgs = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-scroll/index.ts
type Args (line 16) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-scrollable-scroll-change.ts
type Args (line 9) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/get-window-scroll-change.ts
type Args (line 9) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/scroll.ts
type Args (line 11) | type Args = {
FILE: packages/react-beautiful-dnd-autoscroll/src/internal/types.ts
type AxisDirection (line 5) | type AxisDirection = 'horizontal' | 'vertical';
type VerticalAxis (line 7) | type VerticalAxis = {
type HorizontalAxis (line 15) | type HorizontalAxis = {
type Axis (line 23) | type Axis = VerticalAxis | HorizontalAxis;
type Spacing (line 25) | type Spacing = {
type ScrollSize (line 32) | type ScrollSize = {
type ScrollDetails (line 37) | type ScrollDetails = {
type Scrollable (line 43) | type Scrollable = {
type Viewport (line 48) | type Viewport = {
type ScrollBehavior (line 53) | type ScrollBehavior =
FILE: packages/react-beautiful-dnd-migration/__tests__/informational-vr-tests/drop-indicator.vr.tsx
function getDropTargetPoint (line 26) | function getDropTargetPoint({
function dragToElement (line 54) | async function dragToElement({
FILE: packages/react-beautiful-dnd-migration/__tests__/informational-vr-tests/smoke.vr.tsx
function dragAndDrop (line 23) | async function dragAndDrop({
FILE: packages/react-beautiful-dnd-migration/__tests__/playwright/virtual.spec.tsx
function getDraggableSelector (line 7) | function getDraggableSelector(draggableId: string) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/_util.tsx
function setElementFromPoint (line 8) | function setElementFromPoint(el: Element | null): CleanupFn {
function getDroppable (line 21) | function getDroppable(droppableId: DroppableId, container: HTMLElement):...
function findPlaceholderInDroppable (line 27) | function findPlaceholderInDroppable(
function getPlaceholder (line 35) | function getPlaceholder(): HTMLElement {
function hasPlaceholderInDroppable (line 41) | function hasPlaceholderInDroppable(
function findDropIndicator (line 48) | function findDropIndicator(
function hasDropIndicator (line 57) | function hasDropIndicator(droppableId: DroppableId, container: HTMLEleme...
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/_utils/board.tsx
type BoardProps (line 13) | type BoardProps = Partial<Responders>;
function noop (line 15) | function noop() {}
function Board (line 17) | function Board({ onDragEnd = noop, ...responders }: BoardProps): React.J...
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/_utils/setup.tsx
function setup (line 1) | function setup(): void {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/_utils/with-set-element-from-point.tsx
function withSetElementFromPoint (line 3) | function withSetElementFromPoint(dragHandle: HTMLElement, callback: Func...
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/abort.test.tsx
function App (line 21) | function App(props: Partial<DragDropContextProps>) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/batch-updates-for-react-18.test.tsx
type BatchFunction (line 1) | type BatchFunction = (callback: () => void) => void;
function setupMocks (line 3) | async function setupMocks({
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/destination.test.tsx
function dragAndDrop (line 37) | function dragAndDrop({
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/draggable/_utils.tsx
type Item (line 12) | type Item = {
function renderApp (line 23) | function renderApp(items: Item[] = defaultItems) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/draggable/find-drag-handle.test.tsx
function App (line 15) | function App({ children }: { children: ReactNode }) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/draggable/keyboard.test.tsx
function liftNode (line 387) | function liftNode(): Event {
function dropNode (line 402) | function dropNode(): Event {
function CrossAxisApp (line 436) | function CrossAxisApp() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/draggable/placeholder.test.tsx
function Board (line 23) | function Board() {
function getAllColumnDroppableIds (line 68) | function getAllColumnDroppableIds() {
function isOver (line 74) | function isOver(element: HTMLElement) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/draggable/timing.test.tsx
function getRect (line 12) | function getRect({ x = 0, y = 0, width = 0, height = 0 }: DOMRectInit): ...
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/droppable/auto-scroll.test.tsx
function List (line 13) | function List() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/droppable/closest-edge.test.tsx
function List (line 13) | function List({ direction, onDragEnd }: { direction: Direction; onDragEn...
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/droppable/drop-indicator.test.tsx
function Board (line 37) | function Board({ mode = 'standard', columnSpy }: { mode?: DroppableMode;...
function getAllColumnDroppableIds (line 85) | function getAllColumnDroppableIds() {
function isOver (line 91) | function isOver(element: HTMLElement) {
function findDropIndicator (line 95) | function findDropIndicator(droppableId: DroppableId, container: HTMLElem...
function hasDropIndicator (line 101) | function hasDropIndicator(droppableId: DroppableId, container: HTMLEleme...
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/droppable/gap/calculate-gap.test.tsx
function App (line 10) | function App({ direction }: { direction?: Direction }) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/droppable/gap/get-distance.test.tsx
function getRects (line 10) | function getRects({ dx, dy }: { dx: number; dy: number }): [DOMRect, DOM...
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/droppable/is-drop-disabled.test.tsx
type AppProps (line 31) | type AppProps = {
function AppInner (line 37) | function AppInner(droppableProvided: DroppableProvided) {
function OuterDroppable (line 57) | function OuterDroppable({ children }: { children: ReactNode }) {
function App (line 70) | function App({ onDragStart, onDragUpdate, onDragEnd }: AppProps) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/droppable/resting.test.tsx
function App (line 8) | function App({ spy }: { spy?: jest.Mock }) {
function getSnapshots (line 21) | function getSnapshots(spy: jest.Mock): DroppableStateSnapshot[] {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/error-handling.test.tsx
type AppProps (line 17) | type AppProps = Partial<DragDropContextProps> & {
function getRuntimeError (line 21) | function getRuntimeError(): Event {
function App (line 28) | function App({ shouldThrow = false, ...props }: AppProps) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/multi-context.test.tsx
type ItemData (line 22) | type ItemData = { id: string }[];
function noop (line 29) | function noop() {}
function VerticalList (line 31) | function VerticalList({
function App (line 70) | function App({
function getResponders (line 91) | function getResponders() {
method onPendingDragStart (line 270) | onPendingDragStart(args) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/_utils/cause-runtime-error.tsx
function getRuntimeError (line 1) | function getRuntimeError(): Event {
function causeRuntimeError (line 8) | function causeRuntimeError(): void {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/_utils/console.tsx
function noop (line 1) | function noop() {}
type ConsoleFunction (line 3) | type ConsoleFunction = 'warn' | 'error';
function withConsole (line 5) | function withConsole(type: ConsoleFunction, fn: () => void, message?: st...
function withoutConsole (line 22) | function withoutConsole(type: ConsoleFunction, fn: () => void) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/_utils/app.tsx
function noop (line 20) | function noop() {}
type Item (line 22) | type Item = {
type RenderItem (line 32) | type RenderItem = (
type Props (line 57) | type Props = {
function getItems (line 75) | function getItems() {
function withDefaultBool (line 86) | function withDefaultBool(value: boolean | null | undefined, defaultValue...
function App (line 94) | function App(props: Props): React.JSX.Element {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/_utils/controls.tsx
type Control (line 14) | type Control = {
function simpleLift (line 23) | function simpleLift(control: Control, handle: HTMLElement): void {
function getTransitionEnd (line 28) | function getTransitionEnd(propertyName: string = 'transform'): Event {
function mouseLiftExtended (line 39) | function mouseLiftExtended(
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/_utils/helpers.tsx
function getOffset (line 16) | function getOffset(el: HTMLElement): Position {
function getDropReason (line 35) | function getDropReason(onDragEnd: jest.Mock): DropReason {
function isDragging (line 42) | function isDragging(el: HTMLElement): boolean {
function isDropAnimating (line 46) | function isDropAnimating(el: HTMLElement): boolean {
function isCombining (line 50) | function isCombining(el: HTMLElement): boolean {
function isCombineTarget (line 54) | function isCombineTarget(el: HTMLElement): boolean {
function isClone (line 58) | function isClone(el: HTMLElement): boolean {
function isOver (line 62) | function isOver(el: HTMLElement): string | null {
type Call (line 81) | type Call = [DraggableProvided, DraggableStateSnapshot, DraggableRubric];
function getLast (line 108) | function getLast<T>(values: T[]): T | null {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/disable-on-start.test.tsx
type AppProps (line 27) | type AppProps = {
function App (line 33) | function App(props: AppProps) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/drag-drop-context/error-handling/error-on-window.test.tsx
function getRuntimeError (line 20) | function getRuntimeError(): Event {
function getRbdErrorEvent (line 27) | function getRbdErrorEvent(): Event {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/drag-drop-context/on-before-capture/additions.test.tsx
function AnotherChunk (line 27) | function AnotherChunk() {
function Root (line 50) | function Root() {
function getIndex (line 75) | function getIndex(el: HTMLElement): number {
function Root (line 88) | function Root() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/drag-drop-context/on-before-capture/removals.test.tsx
function getIndex (line 16) | function getIndex(el: HTMLElement): number {
function Root (line 26) | function Root() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/drag-handle/shared-behaviors/cleanup.test.tsx
function getCallCount (line 14) | function getCallCount(mySpy: jest.SpyInstance): number {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/drag-handle/shared-behaviors/nested-handles.test.tsx
function Board (line 21) | function Board() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/draggable/validation.test.tsx
function App (line 22) | function App() {
function App (line 52) | function App() {
function App (line 82) | function App() {
function App (line 112) | function App() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/reorder-render-sync.test.tsx
type Task (line 20) | type Task = {
type TaskItemProps (line 25) | type TaskItemProps = {
function TaskItem (line 30) | function TaskItem({ task, provided }: TaskItemProps) {
type InnerListProps (line 44) | type InnerListProps = {
function App (line 74) | function App() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/responders-integration.test.tsx
type Props (line 31) | type Props = {
function App (line 35) | function App({ responders }: Props) {
function getHandle (line 97) | function getHandle(): HTMLElement {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/responders-timing.test.tsx
type ItemProps (line 20) | type ItemProps = {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/integration/server-side-rendering/client-hydration.test.tsx
function noop (line 11) | function noop() {}
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/state/middleware/responders/abort.test.tsx
function App (line 23) | function App(props: Partial<DragDropContextProps>) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/state/middleware/responders/announcements.test.tsx
type Case (line 33) | type Case = {
function getDragStart (line 40) | function getDragStart(): DragStart {
method [current.responder] (line 138) | [current.responder]() {}
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/state/middleware/responders/flushing.test.tsx
function App (line 16) | function App(props: Partial<DragDropContextProps>) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/state/middleware/responders/repeated-use.test.tsx
function App (line 19) | function App(props: Partial<DragDropContextProps>) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/state/middleware/responders/start.test.tsx
function App (line 21) | function App(props: Partial<DragDropContextProps>) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/state/middleware/responders/update.test.tsx
function App (line 25) | function App() {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/ported-from-react-beautiful-dnd/unit/view/style-marshal/style-marshal.test.tsx
function getStyleTagSelector (line 21) | function getStyleTagSelector(contextId: ContextId) {
function App (line 32) | function App({ nonce }: { nonce?: string }) {
function renderApp (line 57) | function renderApp(args?: { nonce?: string }) {
FILE: packages/react-beautiful-dnd-migration/__tests__/unit/virtual.test.tsx
function noop (line 24) | function noop() {}
type Item (line 26) | type Item = { id: string };
function FakeVirtualRenderer (line 36) | function FakeVirtualRenderer({
function DraggableContent (line 63) | function DraggableContent({ provided, item }: { provided: DraggableProvi...
function VirtualList (line 82) | function VirtualList({
function getResponders (line 110) | function getResponders() {
FILE: packages/react-beautiful-dnd-migration/codemods/__tests__/migration/migrate-12-to-13.test.tsx
function getExpectedMessage (line 14) | function getExpectedMessage({ indent }: { indent: number }) {
FILE: packages/react-beautiful-dnd-migration/codemods/__tests__/migration/warn-about-removed-exports.test.tsx
function getExpectedComment (line 17) | function getExpectedComment({ indent }: { indent: number }) {
FILE: packages/react-beautiful-dnd-migration/codemods/migrations/migrate-12-to-13.tsx
method DragDropContext (line 13) | DragDropContext(j: JSCodeshift, path: ASTPath<JSXElement>) {
method Draggable (line 19) | Draggable(j: JSCodeshift, path: ASTPath<JSXElement>) {
method Droppable (line 33) | Droppable(j: JSCodeshift, path: ASTPath<JSXElement>) {
function migrate12to13 (line 39) | function migrate12to13(j: JSCodeshift, source: Collection<Node>): void {
FILE: packages/react-beautiful-dnd-migration/codemods/migrations/update-imports.tsx
function updateImports (line 10) | function updateImports(j: core.JSCodeshift, source: Collection<Node>): v...
FILE: packages/react-beautiful-dnd-migration/codemods/migrations/warn-about-react-beautiful-dnd-next.tsx
function warnAboutReactBeautifulDndNext (line 8) | function warnAboutReactBeautifulDndNext(j: JSCodeshift, source: Collecti...
FILE: packages/react-beautiful-dnd-migration/codemods/migrations/warn-about-removed-exports.tsx
function warnAboutRemovedExports (line 19) | function warnAboutRemovedExports(j: core.JSCodeshift, source: Collection...
FILE: packages/react-beautiful-dnd-migration/codemods/migrations/warn-about-unsupported-props.tsx
function getWarningMessage (line 25) | function getWarningMessage(reason: string) {
function warnAboutUnsupportedProps (line 37) | function warnAboutUnsupportedProps(j: JSCodeshift, source: Collection<No...
FILE: packages/react-beautiful-dnd-migration/codemods/utils.tsx
function getImportDeclarationsForPackage (line 3) | function getImportDeclarationsForPackage(
function getImportDeclarationsForRbd (line 11) | function getImportDeclarationsForRbd(
function shouldRunCodemodOnFile (line 18) | function shouldRunCodemodOnFile(j: JSCodeshift, source: Collection<Node>...
type ComponentName (line 30) | type ComponentName = (typeof componentNameList)[number];
function isComponentName (line 32) | function isComponentName(str: string): str is ComponentName {
function getImportedRbdComponentNames (line 36) | function getImportedRbdComponentNames(
function getJSXElementName (line 57) | function getJSXElementName(node: JSXElement): string | null {
function getRbdElementsInFile (line 65) | function getRbdElementsInFile(
type CallbackArgs (line 78) | type CallbackArgs = {
function forEachRbdElementInFile (line 84) | function forEachRbdElementInFile(
FILE: packages/react-beautiful-dnd-migration/examples/00-vertical-list.tsx
type ItemData (line 16) | type ItemData = {
function Card (line 37) | function Card({ quote, index }: { quote: ItemData; index: number }) {
function List (line 56) | function List({ items }: { items: ItemData[] }) {
function App (line 77) | function App() {
function VerticalListExample (line 110) | function VerticalListExample(): React.JSX.Element {
FILE: packages/react-beautiful-dnd-migration/examples/01-board.tsx
function BoardExample (line 25) | function BoardExample() {
FILE: packages/react-beautiful-dnd-migration/examples/02-react-window.tsx
function BoardExample (line 25) | function BoardExample() {
FILE: packages/react-beautiful-dnd-migration/examples/03-react-virtualized.tsx
function BoardExample (line 25) | function BoardExample() {
FILE: packages/react-beautiful-dnd-migration/examples/04-multi-context.tsx
function VerticalList (line 15) | function VerticalList() {
function MultiContextExample (line 49) | function MultiContextExample(): React.JSX.Element {
FILE: packages/react-beautiful-dnd-migration/examples/05-scroll-container.tsx
type ItemData (line 18) | type ItemData = {
function Card (line 39) | function Card({ quote, index }: { quote: ItemData; index: number }) {
function List (line 60) | function List({ items }: { items: ItemData[] }) {
function App (line 81) | function App(): React.JSX.Element {
function VerticalListExample (line 140) | function VerticalListExample(): React.JSX.Element {
FILE: packages/react-beautiful-dnd-migration/examples/data/tasks.ts
type Item (line 5) | type Item = {
type ColumnType (line 9) | type ColumnType = {
type ColumnMap (line 14) | type ColumnMap = { [columnId: string]: ColumnType };
function getItems (line 16) | function getItems({ count, startColumnId }: { count: number; startColumn...
type Data (line 25) | type Data = {
function getInitialData (line 30) | function getInitialData(): Data {
function reorderColumn (line 51) | function reorderColumn(data: Data, { source, destination }: DropResult):...
function reorderCard (line 72) | function reorderCard(data: Data, { source, destination }: DropResult): D...
function moveCard (line 99) | function moveCard(data: Data, { source, destination, draggableId }: Drop...
function clearColumn (line 135) | function clearColumn(data: Data, columnId: string): Data {
FILE: packages/react-beautiful-dnd-migration/examples/pieces/card.tsx
function DragIcon (line 47) | function DragIcon({ state }: { state: DraggableState }) {
type DraggableState (line 62) | type DraggableState = 'idle' | 'generate-preview' | 'dragging';
function CardText (line 76) | function CardText({ state }: { state: DraggableState }) {
type CardProps (line 84) | type CardProps = {
function CardInner (line 90) | function CardInner({
FILE: packages/react-beautiful-dnd-migration/examples/pieces/column.tsx
type ColumnProps (line 70) | type ColumnProps = {
FILE: packages/react-beautiful-dnd-migration/examples/pieces/example-wrapper.tsx
type SwitcherProps (line 27) | type SwitcherProps = {
type Library (line 33) | type Library = 'migration' | 'rbd';
function ExampleWrapper (line 45) | function ExampleWrapper({ children }: SwitcherProps): React.JSX.Element {
type Components (line 65) | type Components = {
function useDependency (line 76) | function useDependency(): Components {
FILE: packages/react-beautiful-dnd-migration/examples/pieces/global-styles.tsx
function GlobalStyles (line 15) | function GlobalStyles(): React.JSX.Element {
FILE: packages/react-beautiful-dnd-migration/examples/pieces/react-virtualized/column.tsx
type ColumnProps (line 47) | type ColumnProps = {
constant GUTTER_SIZE (line 53) | const GUTTER_SIZE = 8;
FILE: packages/react-beautiful-dnd-migration/examples/pieces/react-window/column.tsx
type ColumnProps (line 46) | type ColumnProps = {
constant GUTTER_SIZE (line 52) | const GUTTER_SIZE = 8;
FILE: packages/react-beautiful-dnd-migration/src/dev-warning.tsx
function noop (line 4) | function noop() {}
type Log (line 6) | type Log = (type: 'error' | 'warn', message: string) => void;
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/cancel-drag.tsx
function cancelPointerDrag (line 9) | function cancelPointerDrag(): void {
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/draggable-location.tsx
function getDraggableLocationFromDraggableData (line 16) | function getDraggableLocationFromDraggableData({
function getDraggableLocationFromDroppableData (line 58) | function getDraggableLocationFromDroppableData({
function getDraggableLocation (line 104) | function getDraggableLocation(location: DragLocation): DraggableLocation...
function isSameLocation (line 133) | function isSameLocation(a: DraggableLocation | null, b: DraggableLocatio...
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/droppable-registry.tsx
type DroppableRegistryEntry (line 7) | type DroppableRegistryEntry = {
type Register (line 17) | type Register = (entry: DroppableRegistryEntry) => CleanupFn;
type GetEntry (line 19) | type GetEntry = ({
type UpdateListener (line 25) | type UpdateListener = (entry: DroppableRegistryEntry) => void;
type SetUpdateListener (line 27) | type SetUpdateListener = (updateListener: UpdateListener) => void;
type DroppableRegistry (line 29) | type DroppableRegistry = {
function createDroppableRegistry (line 35) | function createDroppableRegistry() {
function useDroppableRegistry (line 60) | function useDroppableRegistry(): DroppableRegistry {
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/error-boundary.tsx
type ErrorBoundaryProps (line 14) | type ErrorBoundaryProps = {
function ErrorBoundaryInner (line 23) | function ErrorBoundaryInner({ children, dragController }: ErrorBoundaryP...
class ErrorBoundary (line 85) | class ErrorBoundary extends React.Component<ErrorBoundaryProps> {
method componentDidCatch (line 86) | componentDidCatch(err: Error): void {
method getDerivedStateFromError (line 98) | static getDerivedStateFromError(): void {
method render (line 102) | render(): React.JSX.Element {
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/get-destination.tsx
function getActualDestination (line 11) | function getActualDestination({
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/hooks/use-hidden-text-element.tsx
function getHiddenTextElementId (line 5) | function getHiddenTextElementId(contextId: string) {
type UseHiddenTextElementArgs (line 9) | type UseHiddenTextElementArgs = {
function useHiddenTextElement (line 14) | function useHiddenTextElement({ contextId, text }: UseHiddenTextElementA...
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/hooks/use-keyboard-controls.tsx
type KeyHandlerData (line 18) | type KeyHandlerData = {
type KeyHandler (line 24) | type KeyHandler = (event: KeyboardEvent, data: KeyHandlerData) => void;
function scrollToTop (line 36) | function scrollToTop(element: HTMLElement): void {
method prev (line 46) | prev(event: KeyboardEvent, { dragController }: KeyHandlerData) {
method next (line 90) | next(event: KeyboardEvent, { dragController, contextId }: KeyHandlerData) {
method prev (line 151) | prev(event: KeyboardEvent, { dragController, droppableRegistry, contextI...
method next (line 187) | next(event: KeyboardEvent, { dragController, droppableRegistry, contextI...
function preventDefault (line 226) | function preventDefault(event: Event) {
function useKeyboardControls (line 264) | function useKeyboardControls({
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/hooks/use-pointer-controls.tsx
function usePointerControls (line 17) | function usePointerControls({
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/hooks/use-style-marshal.tsx
function getRuleString (line 25) | function getRuleString({ selector, styles }: { selector: string; styles:...
function getDragHandleRuleString (line 35) | function getDragHandleRuleString(contextId: ContextId): string {
type ContextIdAndNonce (line 56) | type ContextIdAndNonce = {
function createStyleEl (line 61) | function createStyleEl({ contextId, nonce }: ContextIdAndNonce): HTMLSty...
function createStyleManager (line 71) | function createStyleManager({ contextId, nonce }: ContextIdAndNonce): Cl...
function useStyleMarshal (line 84) | function useStyleMarshal({ contextId, nonce }: ContextIdAndNonce): void {
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/index.tsx
function resetServerContext (line 53) | function resetServerContext(): void {
function getContextId (line 57) | function getContextId() {
function getOffset (line 61) | function getOffset(args: { element: HTMLElement; mode: DroppableMode }) {
function DragDropContext (line 69) | function DragDropContext({
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/internal-context.tsx
type DragDropContextValue (line 7) | type DragDropContextValue = {
function useDragDropContext (line 28) | function useDragDropContext() {
function DragDropContextProvider (line 34) | function DragDropContextProvider({
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/lifecycle-context.tsx
type DispatchData (line 25) | type DispatchData = {
type LifecycleResponders (line 42) | type LifecycleResponders = {
type LifecycleEvent (line 46) | type LifecycleEvent = keyof LifecycleResponders;
type Registry (line 48) | type Registry = {
type AddResponder (line 52) | type AddResponder = <Event extends LifecycleEvent>(
type Dispatch (line 57) | type Dispatch = <Event extends LifecycleEvent>(event: Event, data: Dispa...
type LifecycleManager (line 59) | type LifecycleManager = {
function createRegistry (line 64) | function createRegistry(): Registry {
function createLifecycleManager (line 73) | function createLifecycleManager(): LifecycleManager {
function useLifecycle (line 99) | function useLifecycle(): LifecycleManager {
type MonitorForLifecycle (line 105) | type MonitorForLifecycle = (args: Partial<LifecycleResponders>) => Clean...
function LifecycleContextProvider (line 109) | function LifecycleContextProvider({
function useMonitorForLifecycle (line 142) | function useMonitorForLifecycle(): MonitorForLifecycle {
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/live-region.tsx
function createNode (line 39) | function createNode(): HTMLElement {
function getNode (line 50) | function getNode(): HTMLElement {
function announce (line 60) | function announce(message: string): void {
function cleanup (line 68) | function cleanup(): void {
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/rbd-invariant.tsx
class RbdInvariant (line 4) | class RbdInvariant extends Error {
method constructor (line 5) | constructor(message: string) {
method toString (line 10) | toString(): string {
function rbdInvariant (line 17) | function rbdInvariant(condition: unknown, message?: string): asserts con...
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/screen-reader.tsx
function getPosition (line 11) | function getPosition(location: DraggableLocation) {
method onDragStart (line 16) | onDragStart({ source }: DragStart): string {
method onDragUpdate (line 21) | onDragUpdate({ source, destination }: DragUpdate): string {
method onDragEnd (line 37) | onDragEnd({ source, destination, reason }: DropResult): string {
type EventName (line 59) | type EventName = keyof typeof defaultMessage;
type EventData (line 60) | type EventData<Event extends EventName> = Parameters<(typeof defaultMess...
function getDefaultMessage (line 62) | function getDefaultMessage<Event extends EventName>(
function getProvided (line 70) | function getProvided<Event extends EventName>(
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/types.tsx
type DragState (line 5) | type DragState =
type DragController (line 29) | type DragController = {
type StartKeyboardDrag (line 45) | type StartKeyboardDrag = (args: {
FILE: packages/react-beautiful-dnd-migration/src/drag-drop-context/use-scheduler.tsx
type Callback (line 5) | type Callback = () => void;
type Scheduler (line 7) | type Scheduler = {
type Queue (line 19) | type Queue =
function createScheduler (line 29) | function createScheduler(): Scheduler {
function useScheduler (line 85) | function useScheduler(): Scheduler {
FILE: packages/react-beautiful-dnd-migration/src/draggable/data.tsx
type DraggableData (line 14) | type DraggableData = {
function isDraggableData (line 45) | function isDraggableData(data: Record<string | symbol, unknown>): data i...
function useDraggableData (line 54) | function useDraggableData({
FILE: packages/react-beautiful-dnd-migration/src/draggable/get-draggable-provided-style.tsx
function getDraggingStyle (line 31) | function getDraggingStyle({
function getDraggableProvidedStyle (line 57) | function getDraggableProvidedStyle({
FILE: packages/react-beautiful-dnd-migration/src/draggable/index.tsx
function Draggable (line 43) | function Draggable({
FILE: packages/react-beautiful-dnd-migration/src/draggable/is-event-in-interactive-element.tsx
type TagNameMap (line 11) | type TagNameMap = {
function isAnInteractiveElement (line 26) | function isAnInteractiveElement(parent: Element, current: Element | null...
function isEventInInteractiveElement (line 60) | function isEventInInteractiveElement(draggable: Element, event: Event): ...
FILE: packages/react-beautiful-dnd-migration/src/draggable/state.tsx
type DraggableIdleState (line 26) | type DraggableIdleState = {
type PointerLocation (line 31) | type PointerLocation = {
type DraggablePreviewOffset (line 40) | type DraggablePreviewOffset = {
type DraggableDraggingState (line 49) | type DraggableDraggingState = {
type DraggableHidingState (line 63) | type DraggableHidingState = {
type DraggableState (line 69) | type DraggableState = DraggableIdleState | DraggableDraggingState | Drag...
type UpdateKeyboardPayload (line 71) | type UpdateKeyboardPayload = {
type DraggableAction (line 79) | type DraggableAction =
function getHidingState (line 113) | function getHidingState(mode: MovementMode): DraggableHidingState {
type GetKeyboardPreviewOffsetData (line 117) | type GetKeyboardPreviewOffsetData = {
method initial (line 125) | initial({
method home (line 149) | home({
method away (line 189) | away({
function updateKeyboardPreview (line 240) | function updateKeyboardPreview(
function startDrag (line 276) | function startDrag(
function reducer (line 297) | function reducer(state: DraggableState, action: DraggableAction): Dragga...
FILE: packages/react-beautiful-dnd-migration/src/draggable/use-draggable-state-snapshot.tsx
function useDraggableStateSnapshot (line 5) | function useDraggableStateSnapshot({
FILE: packages/react-beautiful-dnd-migration/src/droppable/data.tsx
type DroppableData (line 13) | type DroppableData = {
function isDroppableData (line 35) | function isDroppableData(data: Record<string | symbol, unknown>): data i...
function useDroppableData (line 44) | function useDroppableData({
FILE: packages/react-beautiful-dnd-migration/src/droppable/draggable-clone.tsx
function getBody (line 32) | function getBody() {
function DraggableCloneInner (line 41) | function DraggableCloneInner({
function DraggableClone (line 136) | function DraggableClone({
FILE: packages/react-beautiful-dnd-migration/src/droppable/drop-indicator/get-dimensions.tsx
function measureDraggable (line 20) | function measureDraggable({
function measurePlaceholder (line 65) | function measurePlaceholder({
function getDroppableOffset (line 95) | function getDroppableOffset({
function measureDroppable (line 124) | function measureDroppable({
function getIndicatorSizeAndOffset (line 148) | function getIndicatorSizeAndOffset({
FILE: packages/react-beautiful-dnd-migration/src/droppable/drop-indicator/index.tsx
type DropIndicatorProps (line 25) | type DropIndicatorProps = {
function getDynamicStyles (line 84) | function getDynamicStyles({
method onPrePendingDragUpdate (line 185) | onPrePendingDragUpdate({ update, targetLocation }) {
FILE: packages/react-beautiful-dnd-migration/src/droppable/drop-indicator/types.tsx
type IndicatorSizeAndOffset (line 1) | type IndicatorSizeAndOffset = {
FILE: packages/react-beautiful-dnd-migration/src/droppable/droppable-context.tsx
type DroppableContextProps (line 7) | type DroppableContextProps = {
function useDroppableContext (line 23) | function useDroppableContext() {
function useParentDroppableId (line 35) | function useParentDroppableId() {
FILE: packages/react-beautiful-dnd-migration/src/droppable/gap/get-distance.tsx
function getDistance (line 23) | function getDistance({
FILE: packages/react-beautiful-dnd-migration/src/droppable/gap/index.tsx
function getDroppableId (line 9) | function getDroppableId(element: HTMLElement) {
function getIndex (line 13) | function getIndex(element: HTMLElement): number {
function calculateGap (line 25) | function calculateGap({
function getGapOffset (line 71) | function getGapOffset({
FILE: packages/react-beautiful-dnd-migration/src/droppable/index.tsx
function Droppable (line 34) | function Droppable({
FILE: packages/react-beautiful-dnd-migration/src/droppable/state.tsx
type DroppableState (line 5) | type DroppableState = {
type DroppableAction (line 11) | type DroppableAction =
function reducer (line 22) | function reducer(state: DroppableState, action: DroppableAction): Droppa...
FILE: packages/react-beautiful-dnd-migration/src/droppable/virtual-placeholder.tsx
function VirtualPlaceholder (line 24) | function VirtualPlaceholder({
FILE: packages/react-beautiful-dnd-migration/src/hooks/use-captured-dimensions.tsx
type DraggableDimensions (line 3) | type DraggableDimensions = {
function getDraggableDimensions (line 8) | function getDraggableDimensions(element: HTMLElement): DraggableDimensio...
function useDraggableDimensions (line 17) | function useDraggableDimensions(): DraggableDimensions | null {
FILE: packages/react-beautiful-dnd-migration/src/hooks/use-cleanup-fn.tsx
function createCleanupManager (line 7) | function createCleanupManager() {
function useCleanupFn (line 22) | function useCleanupFn() {
FILE: packages/react-beautiful-dnd-migration/src/hooks/use-drop-target-for-draggable.tsx
function useDropTargetForDraggable (line 11) | function useDropTargetForDraggable({
FILE: packages/react-beautiful-dnd-migration/src/hooks/use-keyboard-context.tsx
function useKeyboardContext (line 3) | function useKeyboardContext() {
FILE: packages/react-beautiful-dnd-migration/src/internal-types.tsx
type DragSource (line 4) | type DragSource = {
type Action (line 10) | type Action<Name extends string, Payload = undefined> = Payload extends ...
type CleanupFn (line 14) | type CleanupFn = () => void;
FILE: packages/react-beautiful-dnd-migration/src/utils/attributes.tsx
type LeafOf (line 35) | type LeafOf<Object extends Record<string, any>, Value = Object[keyof Obj...
type Attribute (line 38) | type Attribute = LeafOf<typeof attributes> | LeafOf<typeof customAttribu...
function getAttribute (line 40) | function getAttribute(element: HTMLElement, attribute: Attribute): string {
type CleanUpFn (line 46) | type CleanUpFn = () => void;
function setAttributes (line 48) | function setAttributes(
FILE: packages/react-beautiful-dnd-migration/src/utils/batch-updates-for-react-16.tsx
function batchUpdatesForReact16 (line 25) | function batchUpdatesForReact16(callback: () => void): void {
FILE: packages/react-beautiful-dnd-migration/src/utils/find-all-draggables.tsx
function findAllDraggables (line 4) | function findAllDraggables({
FILE: packages/react-beautiful-dnd-migration/src/utils/find-closest-scroll-container.tsx
function findClosestScrollContainer (line 4) | function findClosestScrollContainer(element: HTMLElement): HTMLElement |...
FILE: packages/react-beautiful-dnd-migration/src/utils/find-drag-handle.tsx
function findDragHandle (line 8) | function findDragHandle({
FILE: packages/react-beautiful-dnd-migration/src/utils/find-drop-indicator.tsx
function findDropIndicator (line 4) | function findDropIndicator() {
FILE: packages/react-beautiful-dnd-migration/src/utils/find-element.tsx
type SelectorFragment (line 6) | type SelectorFragment = { attribute: string; value?: string };
function getSelector (line 19) | function getSelector(...fragments: SelectorFragment[]): string {
function findElement (line 36) | function findElement(...fragments: SelectorFragment[]): HTMLElement | nu...
function findElementAll (line 41) | function findElementAll(...fragments: SelectorFragment[]): HTMLElement[] {
function getElement (line 49) | function getElement(...fragments: SelectorFragment[]): HTMLElement {
FILE: packages/react-beautiful-dnd-migration/src/utils/find-placeholder.tsx
function findPlaceholder (line 6) | function findPlaceholder(contextId: ContextId) {
FILE: packages/react-beautiful-dnd-migration/src/utils/get-best-cross-axis-droppable.tsx
function getDroppablesOfType (line 8) | function getDroppablesOfType({
function getBestCrossAxisDroppable (line 26) | function getBestCrossAxisDroppable({
FILE: packages/react-beautiful-dnd-migration/src/utils/get-closest-positioned-element.tsx
function getClosestAbsolutePositionedElement (line 6) | function getClosestAbsolutePositionedElement(element: HTMLElement): HTML...
function getClosestPositionedElement (line 23) | function getClosestPositionedElement({
FILE: packages/react-beautiful-dnd-migration/src/utils/get-element-by-draggable-location.tsx
function getElementByDraggableLocation (line 6) | function getElementByDraggableLocation(
FILE: packages/react-beautiful-dnd-migration/src/utils/use-stable.tsx
function useStable (line 6) | function useStable<Value>(value: Value): () => Value {
FILE: packages/react-drop-indicator/examples/00-closest-edge.tsx
function ClosestEdgeExample (line 10) | function ClosestEdgeExample(): React.JSX.Element {
FILE: packages/react-drop-indicator/examples/01-gap.tsx
function ClosestEdgeExample (line 8) | function ClosestEdgeExample(): React.JSX.Element {
FILE: packages/react-drop-indicator/examples/11-tree-item.tsx
function Example (line 64) | function Example({ direction = 'ltr' }: { direction: 'ltr' | 'rtl' }) {
function RTLTree (line 81) | function RTLTree() {
FILE: packages/react-drop-indicator/examples/box-playground.tsx
function AllExamples (line 31) | function AllExamples() {
FILE: packages/react-drop-indicator/examples/constellation/border/border-showcase.tsx
function BorderShowcaseExample (line 8) | function BorderShowcaseExample(): React.JSX.Element {
FILE: packages/react-drop-indicator/examples/constellation/box/box-appearance.tsx
function AppearanceExample (line 20) | function AppearanceExample() {
FILE: packages/react-drop-indicator/examples/constellation/box/box-edge.tsx
function EdgeExample (line 19) | function EdgeExample() {
FILE: packages/react-drop-indicator/examples/constellation/box/box-gap.tsx
function GapExample (line 30) | function GapExample() {
FILE: packages/react-drop-indicator/examples/constellation/box/box-indent.tsx
function IndentExample (line 26) | function IndentExample() {
FILE: packages/react-drop-indicator/examples/constellation/box/box-overlap.tsx
function OverlapExample (line 43) | function OverlapExample() {
FILE: packages/react-drop-indicator/examples/constellation/box/box-type.tsx
function TypeExample (line 20) | function TypeExample() {
FILE: packages/react-drop-indicator/examples/constellation/group/group-list.tsx
function Item (line 21) | function Item({ content }: { content: ReactNode }) {
function GroupExample (line 32) | function GroupExample() {
FILE: packages/react-drop-indicator/examples/constellation/list-item/list-item-horizontal.tsx
function ListItemHorizontalExample (line 9) | function ListItemHorizontalExample(): React.JSX.Element {
FILE: packages/react-drop-indicator/examples/constellation/list-item/list-item-vertical.tsx
function ListItemVerticalExample (line 9) | function ListItemVerticalExample(): React.JSX.Element {
FILE: packages/react-drop-indicator/examples/constellation/simple-item.tsx
function Item (line 27) | function Item({
FILE: packages/react-drop-indicator/examples/constellation/tree-item.tsx
function getLabel (line 77) | function getLabel(instruction: Instruction): string {
function TreeItem (line 87) | function TreeItem({
function Example (line 115) | function Example() {
FILE: packages/react-drop-indicator/examples/internal/card.tsx
type CardProps (line 14) | type CardProps = {
FILE: packages/react-drop-indicator/examples/internal/list.tsx
function Item (line 27) | function Item({ item, indicator }: { item: TItem; indicator?: ReactNode ...
type TItem (line 36) | type TItem = {
function getItems (line 40) | function getItems({ amount }: { amount: number }): TItem[] {
type Orientation (line 63) | type Orientation = 'vertical' | 'horizontal';
function List (line 65) | function List({
FILE: packages/react-drop-indicator/examples/internal/tree-item.tsx
function getLabel (line 27) | function getLabel(instruction: Instruction): string {
function TreeItem (line 37) | function TreeItem({
FILE: packages/react-drop-indicator/examples/line.tsx
function Example (line 29) | function Example({
function DefaultExample (line 109) | function DefaultExample() {
function EdgeTopTypeTerminalGap0px (line 122) | function EdgeTopTypeTerminalGap0px() {
function EdgeRightTypeTerminalGap0px (line 126) | function EdgeRightTypeTerminalGap0px() {
function EdgeBottomTypeTerminalGap0px (line 130) | function EdgeBottomTypeTerminalGap0px() {
function EdgeLeftTypeTerminalGap0px (line 134) | function EdgeLeftTypeTerminalGap0px() {
function EdgeTopTypeTerminalGapTokenSpace100 (line 138) | function EdgeTopTypeTerminalGapTokenSpace100() {
function EdgeRightTypeTerminalGapTokenSpace100 (line 142) | function EdgeRightTypeTerminalGapTokenSpace100() {
function EdgeBottomTypeTerminalGapTokenSpace100 (line 146) | function EdgeBottomTypeTerminalGapTokenSpace100() {
function EdgeLeftTypeTerminalGapTokenSpace100 (line 150) | function EdgeLeftTypeTerminalGapTokenSpace100() {
function EdgeTopTypeNoTerminalGap0px (line 154) | function EdgeTopTypeNoTerminalGap0px() {
function EdgeRightTypeNoTerminalGap0px (line 158) | function EdgeRightTypeNoTerminalGap0px() {
function EdgeBottomTypeNoTerminalGap0px (line 162) | function EdgeBottomTypeNoTerminalGap0px() {
function EdgeLeftTypeNoTerminalGap0px (line 166) | function EdgeLeftTypeNoTerminalGap0px() {
function EdgeTopTypeNoTerminalGapTokenSpace100 (line 170) | function EdgeTopTypeNoTerminalGapTokenSpace100() {
function EdgeRightTypeNoTerminalGapTokenSpace100 (line 174) | function EdgeRightTypeNoTerminalGapTokenSpace100() {
function EdgeBottomTypeNoTerminalGapTokenSpace100 (line 178) | function EdgeBottomTypeNoTerminalGapTokenSpace100() {
function EdgeLeftTypeNoTerminalGapTokenSpace100 (line 182) | function EdgeLeftTypeNoTerminalGapTokenSpace100() {
function EdgeTopTypeTerminalNoBleedGap0px (line 186) | function EdgeTopTypeTerminalNoBleedGap0px() {
function EdgeRightTypeTerminalNoBleedGap0px (line 190) | function EdgeRightTypeTerminalNoBleedGap0px() {
function EdgeBottomTypeTerminalNoBleedGap0px (line 194) | function EdgeBottomTypeTerminalNoBleedGap0px() {
function EdgeLeftTypeTerminalNoBleedGap0px (line 198) | function EdgeLeftTypeTerminalNoBleedGap0px() {
function EdgeTopTypeTerminalNoBleedGapTokenSpace100 (line 202) | function EdgeTopTypeTerminalNoBleedGapTokenSpace100() {
function EdgeRightTypeTerminalNoBleedGapTokenSpace100 (line 206) | function EdgeRightTypeTerminalNoBleedGapTokenSpace100() {
function EdgeBottomTypeTerminalNoBleedGapTokenSpace100 (line 210) | function EdgeBottomTypeTerminalNoBleedGapTokenSpace100() {
function EdgeLeftTypeTerminalNoBleedGapTokenSpace100 (line 214) | function EdgeLeftTypeTerminalNoBleedGapTokenSpace100() {
function EdgeTopTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace200 (line 225) | function EdgeTopTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace200() {
function EdgeRightTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace200 (line 230) | function EdgeRightTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace200...
function EdgeBottomTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace200 (line 235) | function EdgeBottomTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace20...
function EdgeLeftTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace200 (line 240) | function EdgeLeftTypeTerminalNoBleedGapTokenSpace100IndentTokenSpace200() {
function ColorWarning (line 252) | function ColorWarning() {
function ColorDiscovery (line 256) | function ColorDiscovery() {
FILE: packages/react-drop-indicator/examples/outline.tsx
type Options (line 31) | type Options = {
function Target (line 43) | function Target(options: Partial<Options>) {
function Example (line 55) | function Example(options: Partial<Options>) {
function DefaultExample (line 78) | function DefaultExample() {
function StrokeColorDefault (line 82) | function StrokeColorDefault() {
function StrokeColorWarning (line 86) | function StrokeColorWarning() {
function CustomBorderRadius (line 90) | function CustomBorderRadius() {
function Inset (line 94) | function Inset() {
FILE: packages/react-drop-indicator/src/border.tsx
function DropIndicator (line 7) | function DropIndicator({
FILE: packages/react-drop-indicator/src/box.tsx
type DropIndicatorProps (line 8) | type DropIndicatorProps = {
function DropIndicator (line 74) | function DropIndicator({
FILE: packages/react-drop-indicator/src/internal-types.ts
type CSSSize (line 13) | type CSSSize = string;
type CSSColor (line 29) | type CSSColor = string;
type Appearance (line 31) | type Appearance = 'default' | 'warning';
FILE: packages/react-drop-indicator/src/internal/border.tsx
function Border (line 29) | function Border({
FILE: packages/react-drop-indicator/src/internal/line.tsx
type Orientation (line 16) | type Orientation = 'horizontal' | 'vertical';
type LineType (line 100) | type LineType = 'terminal' | 'no-terminal' | 'terminal-no-bleed';
function Line (line 114) | function Line({
FILE: packages/react-drop-indicator/src/list-item.tsx
type LineProps (line 24) | type LineProps = ComponentProps<typeof Line>;
function DropIndicator (line 26) | function DropIndicator({
FILE: packages/react-drop-indicator/src/tree-item.tsx
type DropIndicatorProps (line 8) | type DropIndicatorProps = {
function getElement (line 12) | function getElement({
function DropIndicator (line 41) | function DropIndicator({ instruction }: DropIndicatorProps) {
FILE: packages/unit-testing/src/dom-rect-polyfill.ts
class DOMRect (line 12) | class DOMRect {
method constructor (line 22) | constructor(x = 0, y = 0, width = 0, height = 0) {
method fromRect (line 36) | static fromRect(rectangle: DOMRectInit | undefined) {
method toJSON (line 40) | toJSON() {
FILE: packages/unit-testing/src/drag-event-polyfill.ts
method add (line 58) | add(stringValueOrFile: string | File, stringMimeType?: string): DataTran...
method remove (line 123) | remove(index: number): void {
method clear (line 130) | clear(): void {
function getFullFormat (line 139) | function getFullFormat(formatOrShorthand: string): {
method constructor (line 166) | constructor() {
method types (line 183) | get types(): string[] {
method files (line 200) | get files(): FileList {
method clearData (line 232) | clearData(format?: string): void {
method getData (line 262) | getData(format: string): string {
method setData (line 298) | setData(format: string, data: string): void {
method setDragImage (line 307) | setDragImage() {
method constructor (line 316) | constructor(
method pageX (line 344) | get pageX() {
method pageY (line 347) | get pageY() {
Condensed preview — 951 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,852K chars).
[
{
"path": ".gitignore",
"chars": 109,
"preview": "node_modules\ndist\n\n**/.DS_Store\n\n.vscode/*\n.idea\n.iml\n*.code-workspace\n\n.env\nyarn-debug.log*\nyarn-error.log*\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3221,
"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": 844,
"preview": "# Contributing\n\nThank you for considering contributing to Pragmatic drag and drop!\n\nAt this stage, we are not accepting "
},
{
"path": "LICENSE",
"chars": 558,
"preview": "Copyright 2024 Atlassian Pty Ltd\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this f"
},
{
"path": "README.md",
"chars": 6896,
"preview": "<div align=\"center\">\n<picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/alexreardon/fil"
},
{
"path": "jest.config.js",
"chars": 0,
"preview": ""
},
{
"path": "package.json",
"chars": 676,
"preview": "{\n\t\"name\": \"pragmatic-drag-and-drop\",\n\t\"private\": true,\n\t\"version\": \"1.0.0\",\n\t\"description\": \"Pragmatic drag and drop is"
},
{
"path": "packages/auto-scroll/.npmignore",
"chars": 114,
"preview": "src/\nexamples-utils/\nexamples/\nindex.ts\ndocs/\nbuild/\n__tests__/\ntsconfig.json\ntsconfig.app.json\ntsconfig.dev.json\n"
},
{
"path": "packages/auto-scroll/CHANGELOG.md",
"chars": 15009,
"preview": "# @atlaskit/pragmatic-drag-and-drop-auto-scroll\n\n## 2.1.5\n\n### Patch Changes\n\n- [`d3ed1b65a2181`](https://bitbucket.org/"
},
{
"path": "packages/auto-scroll/LICENSE.md",
"chars": 558,
"preview": "Copyright 2023 Atlassian Pty Ltd\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this f"
},
{
"path": "packages/auto-scroll/README.md",
"chars": 377,
"preview": "## Pragmatic drag and drop\n\nAn optional Pragmatic drag and drop package that enables automatic scrolling during a drag o"
},
{
"path": "packages/auto-scroll/__tests__/playwright/over-element-smoke-test.spec.tsx",
"chars": 1475,
"preview": "import invariant from 'tiny-invariant';\n\nimport { expect, test } from '@af/integration-testing';\n\ntest.describe('over el"
},
{
"path": "packages/auto-scroll/__tests__/playwright/unsafe-overflow-smoke-test.spec.tsx",
"chars": 1389,
"preview": "import invariant from 'tiny-invariant';\n\nimport { expect, test } from '@af/integration-testing';\n\ntest.describe('over el"
},
{
"path": "packages/auto-scroll/__tests__/unit/_util.ts",
"chars": 15793,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport {\n\ttype CleanupFn,\n\tty"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/allowed-axis.spec.ts",
"chars": 8308,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/can-scroll.spec.ts",
"chars": 2535,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/distance-dampening.spec.ts",
"chars": 9824,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/hitbox.spec.ts",
"chars": 11045,
"preview": "import { bind } from 'bind-event-listener';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '@atlaskit/"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/max-speed.spec.ts",
"chars": 10857,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\nimport { replaceRaf } from"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/nested-scroll-containers.spec.ts",
"chars": 22234,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/registration.spec.ts",
"chars": 7270,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/start.spec.ts",
"chars": 2028,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/stop.spec.ts",
"chars": 4682,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/time-dampening.spec.ts",
"chars": 69033,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/__tests__/unit/over-element/window-scrolling.spec.ts",
"chars": 22136,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/overflow/allowed-axis.spec.ts",
"chars": 5326,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { unsafeOverflowAu"
},
{
"path": "packages/auto-scroll/__tests__/unit/overflow/can-scroll.spec.ts",
"chars": 11485,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/__tests__/unit/overflow/cross-axis-hitbox.spec.ts",
"chars": 11210,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/__tests__/unit/overflow/main-axis-hitbox.spec.ts",
"chars": 9590,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\nimport invariant from 'tin"
},
{
"path": "packages/auto-scroll/__tests__/unit/overflow/nested-elements.spec.ts",
"chars": 9650,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/__tests__/unit/overflow/over-element-should-not-scroll.spec.ts",
"chars": 4290,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/__tests__/unit/overflow/provided-hitbox-spacing-type.spec.ts",
"chars": 1485,
"preview": "import { type unsafeOverflowAutoScrollForElements } from '../../../src/entry-point/unsafe-overflow/element';\n\nconst isEq"
},
{
"path": "packages/auto-scroll/__tests__/unit/shared/_util.ts",
"chars": 579,
"preview": "import invariant from 'tiny-invariant';\n\nconst honeyPotSelector = '[data-pdnd-honey-pot]';\n\nexport function findHoneyPot"
},
{
"path": "packages/auto-scroll/__tests__/unit/shared/async-loading.spec.ts",
"chars": 3171,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/__tests__/unit/shared/ignore-honey-pot.spec.ts",
"chars": 2340,
"preview": "import { bind } from 'bind-event-listener';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport"
},
{
"path": "packages/auto-scroll/__tests__/unit/shared/monitor-binding.spec.ts",
"chars": 2862,
"preview": "import { reset, setStartSystemTime, setupNestedScrollContainers } from '../_util';\n\n// Using modern timers as it is impo"
},
{
"path": "packages/auto-scroll/__tests__/unit/shared/time-dampening-handover.spec.ts",
"chars": 6071,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\n\nimport { combine } from '"
},
{
"path": "packages/auto-scroll/afm-jira/tsconfig.json",
"chars": 644,
"preview": "{\n\t\"extends\": \"../../../../tsconfig.local-consumption.json\",\n\t\"compilerOptions\": {\n\t\t\"target\": \"es5\",\n\t\t\"outDir\": \"../.."
},
{
"path": "packages/auto-scroll/afm-products/tsconfig.json",
"chars": 643,
"preview": "{\n\t\"extends\": \"../../../../tsconfig.local-consumption.json\",\n\t\"compilerOptions\": {\n\t\t\"target\": \"es5\",\n\t\t\"outDir\": \"../.."
},
{
"path": "packages/auto-scroll/constellation/index/about.mdx",
"chars": 16597,
"preview": "---\norder: 0\ntitle: Auto scroll\ndescription: An optional package that enables automatic scrolling during a drag operatio"
},
{
"path": "packages/auto-scroll/constellation/index/props.mdx",
"chars": 0,
"preview": ""
},
{
"path": "packages/auto-scroll/constellation/index/unsafe-overflow-scrolling.mdx",
"chars": 7607,
"preview": "---\norder: 1\ntitle: Unsafe overflow scrolling\ndescription: Continuing to scroll after leaving a scrollable element\n---\n\n"
},
{
"path": "packages/auto-scroll/examples/axis-locking.tsx",
"chars": 149,
"preview": "import React from 'react';\n\nimport { Table } from './pieces/table';\n\nexport default function AxisLocking(): React.JSX.El"
},
{
"path": "packages/auto-scroll/examples/lazy-loaded.tsx",
"chars": 160,
"preview": "import React from 'react';\n\nimport { Board } from './pieces/lazy-loaded-board';\n\nexport default function LazyLoaded(): R"
},
{
"path": "packages/auto-scroll/examples/nested-scroll.tsx",
"chars": 3186,
"preview": "/* eslint-disable @atlaskit/design-system/no-nested-styles */\n/**\n * @jsxRuntime classic\n * @jsx jsx\n */\nimport { Fragme"
},
{
"path": "packages/auto-scroll/examples/over-element.tsx",
"chars": 490,
"preview": "import React from 'react';\n\nimport { autoScrollForElements } from '../src/entry-point/element';\n\nimport { Board } from '"
},
{
"path": "packages/auto-scroll/examples/pieces/board-context.ts",
"chars": 319,
"preview": "import { createContext } from 'react';\n\nimport { type autoScrollForElements } from '../../src/entry-point/element';\n\nexp"
},
{
"path": "packages/auto-scroll/examples/pieces/board.tsx",
"chars": 3024,
"preview": "import React, { useContext, useEffect, useRef, useState } from 'react';\n\nimport invariant from 'tiny-invariant';\n\nimport"
},
{
"path": "packages/auto-scroll/examples/pieces/card.tsx",
"chars": 3626,
"preview": "import React, { Fragment, useEffect, useRef, useState } from 'react';\n\nimport { createPortal } from 'react-dom';\nimport "
},
{
"path": "packages/auto-scroll/examples/pieces/lazy-loaded-board.tsx",
"chars": 4846,
"preview": "import React, { useEffect, useRef, useState } from 'react';\n\nimport { bind } from 'bind-event-listener';\nimport invarian"
},
{
"path": "packages/auto-scroll/examples/pieces/table.tsx",
"chars": 3191,
"preview": "import React, { type PropsWithChildren, useEffect, useRef, useState } from 'react';\n\nimport invariant from 'tiny-invaria"
},
{
"path": "packages/auto-scroll/examples/unsafe-overflow-box.tsx",
"chars": 2345,
"preview": "import React, { useEffect, useRef, useState } from 'react';\n\nimport invariant from 'tiny-invariant';\n\nimport { combine }"
},
{
"path": "packages/auto-scroll/examples/unsafe-overflow-only.tsx",
"chars": 1530,
"preview": "import React from 'react';\n\nimport { type autoScrollForElements } from '../src/entry-point/element';\nimport { unsafeOver"
},
{
"path": "packages/auto-scroll/examples/unsafe-overflow.tsx",
"chars": 1729,
"preview": "import React from 'react';\n\nimport { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\n\nimport { autoScrollFor"
},
{
"path": "packages/auto-scroll/examples/window-scroll-with-scroll-container.tsx",
"chars": 2849,
"preview": "/* eslint-disable @atlaskit/design-system/no-nested-styles */\n/**\n * @jsxRuntime classic\n * @jsx jsx\n */\nimport React, {"
},
{
"path": "packages/auto-scroll/examples/window-scroll.tsx",
"chars": 2369,
"preview": "/* eslint-disable @atlaskit/design-system/no-nested-styles */\n/**\n * @jsxRuntime classic\n * @jsx jsx\n */\nimport React, {"
},
{
"path": "packages/auto-scroll/package.json",
"chars": 1390,
"preview": "{\n \"name\": \"@atlaskit/pragmatic-drag-and-drop-auto-scroll\",\n \"version\": \"2.1.5\",\n \"description\": \"An optional Pragmat"
},
{
"path": "packages/auto-scroll/src/entry-point/element.ts",
"chars": 315,
"preview": "import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\n\nimport { makeApi } from '../ove"
},
{
"path": "packages/auto-scroll/src/entry-point/external.ts",
"chars": 316,
"preview": "import { monitorForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter';\n\nimport { makeApi } from '../ov"
},
{
"path": "packages/auto-scroll/src/entry-point/text-selection.ts",
"chars": 342,
"preview": "import { monitorForTextSelection } from '@atlaskit/pragmatic-drag-and-drop/text-selection/adapter';\n\nimport { makeApi } "
},
{
"path": "packages/auto-scroll/src/entry-point/unsafe-overflow/element.ts",
"chars": 284,
"preview": "import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\n\nimport { makeApi } from '../../"
},
{
"path": "packages/auto-scroll/src/entry-point/unsafe-overflow/external.ts",
"chars": 285,
"preview": "import { monitorForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter';\n\nimport { makeApi } from '../.."
},
{
"path": "packages/auto-scroll/src/entry-point/unsafe-overflow/text-selection.ts",
"chars": 306,
"preview": "import { monitorForTextSelection } from '@atlaskit/pragmatic-drag-and-drop/text-selection/adapter';\n\nimport { makeApi } "
},
{
"path": "packages/auto-scroll/src/index.ts",
"chars": 19,
"preview": "export default {};\n"
},
{
"path": "packages/auto-scroll/src/internal-types.ts",
"chars": 1737,
"preview": "import type { AllDragTypes, Input } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nexport type ElementGetFeedbackArgs<"
},
{
"path": "packages/auto-scroll/src/over-element/data-attributes.ts",
"chars": 354,
"preview": "import type { CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nexport const dataAttribute = 'data-auto-scrol"
},
{
"path": "packages/auto-scroll/src/over-element/get-scroll-by.ts",
"chars": 3173,
"preview": "import type { Input, Position } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nimport type {\n\tAllowedAxis,\n\tAxis,\n\tEdg"
},
{
"path": "packages/auto-scroll/src/over-element/make-api.ts",
"chars": 3521,
"preview": "import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';\nimport { once } from '@atlaskit/pragmatic-drag-and-"
},
{
"path": "packages/auto-scroll/src/over-element/try-scroll.ts",
"chars": 5530,
"preview": "import type { AllDragTypes, Input } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nimport {\n\ttype AllowedAxis,\n\ttype E"
},
{
"path": "packages/auto-scroll/src/shared/axis.ts",
"chars": 357,
"preview": "const vertical = {\n\tstart: 'top',\n\tend: 'bottom',\n\tpoint: 'y',\n\tsize: 'height',\n} as const;\n\nconst horizontal = {\n\tstart"
},
{
"path": "packages/auto-scroll/src/shared/can-scroll-on-edge.ts",
"chars": 870,
"preview": "import { type Edge } from '../internal-types';\n\nexport const canScrollOnEdge: {\n\t[key in Edge]: (element: Element) => bo"
},
{
"path": "packages/auto-scroll/src/shared/configuration.ts",
"chars": 1833,
"preview": "import type { InternalConfig, PublicConfig } from '../internal-types';\n\nconst baseConfig = {\n\tstartHitboxAtPercentageRem"
},
{
"path": "packages/auto-scroll/src/shared/edges.ts",
"chars": 262,
"preview": "import { type Axis, type Edge } from '../internal-types';\n\nexport const edges: Edge[] = ['top', 'right', 'bottom', 'left"
},
{
"path": "packages/auto-scroll/src/shared/engagement-history.ts",
"chars": 1019,
"preview": "import { type EngagementHistoryEntry } from '../internal-types';\n\nconst ledger: Map<Element, EngagementHistoryEntry> = n"
},
{
"path": "packages/auto-scroll/src/shared/get-over-element-hitbox.ts",
"chars": 1575,
"preview": "import type { Axis, Edge, InternalConfig, Side } from '../internal-types';\n\nimport { axisLookup } from './axis';\nimport "
},
{
"path": "packages/auto-scroll/src/shared/get-percentage-in-range.ts",
"chars": 439,
"preview": "export function getPercentageInRange({\n\tstartOfRange,\n\tendOfRange,\n\tvalue,\n}: {\n\tstartOfRange: number;\n\tendOfRange: numb"
},
{
"path": "packages/auto-scroll/src/shared/get-scroll-change.ts",
"chars": 4035,
"preview": "import { type Position } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nimport type { Axis, Edge, EngagementHistoryEnt"
},
{
"path": "packages/auto-scroll/src/shared/is-axis-allowed.ts",
"chars": 202,
"preview": "import { type AllowedAxis, type Axis } from '../internal-types';\n\nexport function isAxisAllowed(axis: Axis, allowedAxis:"
},
{
"path": "packages/auto-scroll/src/shared/is-within.ts",
"chars": 419,
"preview": "import type { Position } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nexport function isWithin({\n\tclient,\n\tclientRec"
},
{
"path": "packages/auto-scroll/src/shared/scheduler.ts",
"chars": 4453,
"preview": "import { getElementFromPointWithoutHoneypot } from '@atlaskit/pragmatic-drag-and-drop/private/get-element-from-point-wit"
},
{
"path": "packages/auto-scroll/src/shared/side.ts",
"chars": 180,
"preview": "import type { Edge, Side } from '../internal-types';\n\nexport const mainAxisSideLookup: { [Key in Edge]: Side } = {\n\ttop:"
},
{
"path": "packages/auto-scroll/src/unsafe-overflow/get-scroll-by.ts",
"chars": 6437,
"preview": "import type { AllDragTypes, Input, Position } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nimport type { AllowedAxis"
},
{
"path": "packages/auto-scroll/src/unsafe-overflow/hitbox.ts",
"chars": 2654,
"preview": "import type { Axis, Edge, InternalConfig, Side } from '../internal-types';\nimport { axisLookup } from '../shared/axis';\n"
},
{
"path": "packages/auto-scroll/src/unsafe-overflow/make-api.ts",
"chars": 1232,
"preview": "import type {\n\tAllDragTypes,\n\tBaseEventPayload,\n\tCleanupFn,\n\tMonitorArgs,\n} from '@atlaskit/pragmatic-drag-and-drop/type"
},
{
"path": "packages/auto-scroll/src/unsafe-overflow/try-overflow-scroll.ts",
"chars": 1973,
"preview": "import type { AllDragTypes, Input } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nimport { type ElementGetFeedbackArg"
},
{
"path": "packages/auto-scroll/src/unsafe-overflow/types.ts",
"chars": 1177,
"preview": "import type { AllDragTypes } from '@atlaskit/pragmatic-drag-and-drop/types';\n\nimport { type Edge, type ElementAutoScroll"
},
{
"path": "packages/auto-scroll/tsconfig.json",
"chars": 381,
"preview": "{\n \"extends\": \"../../tsconfig.json\",\n \"include\": [\n \"__tests__/**/*.ts\",\n \"__tests__/**/*.tsx\",\n \"docs/**/*.t"
},
{
"path": "packages/core/.npmignore",
"chars": 114,
"preview": "src/\nexamples-utils/\nexamples/\nindex.ts\ndocs/\nbuild/\n__tests__/\ntsconfig.json\ntsconfig.app.json\ntsconfig.dev.json\n"
},
{
"path": "packages/core/CHANGELOG.md",
"chars": 42189,
"preview": "# @atlaskit/pragmatic-drag-and-drop\n\n## 1.7.9\n\n### Patch Changes\n\n- [`acb61d1d6efd9`](https://bitbucket.org/atlassian/at"
},
{
"path": "packages/core/LICENSE.md",
"chars": 558,
"preview": "Copyright 2022 Atlassian Pty Ltd\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this f"
},
{
"path": "packages/core/README.md",
"chars": 213,
"preview": "# Pragmatic drag and drop\n\n> Fast drag and drop for any experience on any tech stack\n\nThe core package for Pragmatic dra"
},
{
"path": "packages/core/__tests__/playwright/external-files.spec.ts",
"chars": 3264,
"preview": "import { readFileSync } from 'fs';\nimport path from 'path';\n\nimport invariant from 'tiny-invariant';\n\nimport { expect, t"
},
{
"path": "packages/core/__tests__/playwright/honey-pot.spec.ts",
"chars": 5440,
"preview": "import invariant from 'tiny-invariant';\n\nimport { expect as baseExpect, type Locator, test } from '@af/integration-testi"
},
{
"path": "packages/core/__tests__/playwright/iframe.spec.ts",
"chars": 9226,
"preview": "import invariant from 'tiny-invariant';\n\nimport { BROWSERS, expect, fixTest, type Locator, type Page, test } from '@af/i"
},
{
"path": "packages/core/__tests__/playwright/scroll-just-enough-into-view.spec.ts",
"chars": 4075,
"preview": "import invariant from 'tiny-invariant';\n\nimport { expect, type Locator, test } from '@af/integration-testing';\n\nasync fu"
},
{
"path": "packages/core/__tests__/playwright/stickiness.spec.tsx",
"chars": 1611,
"preview": "import { expect, test } from '@af/integration-testing';\n\ntest.describe('stickiness', () => {\n\ttest('should hold on to th"
},
{
"path": "packages/core/__tests__/playwright/text-selection.spec.ts",
"chars": 1394,
"preview": "import { expect, test } from '@af/integration-testing';\n\ntest.describe('text selection', () => {\n\ttest('dragging text se"
},
{
"path": "packages/core/__tests__/unit/_util.ts",
"chars": 9079,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport {\n\ttype CleanupFn,\n\tty"
},
{
"path": "packages/core/__tests__/unit/android/is-android.spec.ts",
"chars": 6810,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\nimport invariant from 'tin"
},
{
"path": "packages/core/__tests__/unit/android/not-android.spec.ts",
"chars": 3469,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind } from 'bind-event-listener';\nimport invariant from 'tin"
},
{
"path": "packages/core/__tests__/unit/dependency-guardrails.spec.ts",
"chars": 2298,
"preview": "// @atlaskit/pragmatic-drag-and-drop is a public (open source) package.\n// These tests guard against accidentally growin"
},
{
"path": "packages/core/__tests__/unit/element/changes-during-a-drag.spec.ts",
"chars": 15537,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport {\n"
},
{
"path": "packages/core/__tests__/unit/element/changes-during-a-drop.spec.ts",
"chars": 5506,
"preview": "import { combine } from '../../../src/entry-point/combine';\nimport {\n\tdraggable,\n\tdropTargetForElements,\n\tmonitorForElem"
},
{
"path": "packages/core/__tests__/unit/element/draggable/conditional-dragging.spec.ts",
"chars": 2865,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/draggable/custom-drag-preview.spec.ts",
"chars": 3056,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/draggable/drag-handle-guardrails.spec.ts",
"chars": 1599,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport { draggable } from '../../../../src/entry-point/el"
},
{
"path": "packages/core/__tests__/unit/element/draggable/drag-handle.spec.ts",
"chars": 3369,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/draggable/get-initial-data-for-external.spec.ts",
"chars": 4106,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { elementAdapterNativeDataKey } from '../../../../src/adapter/"
},
{
"path": "packages/core/__tests__/unit/element/draggable/get-initial-data.spec.ts",
"chars": 2494,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/draggable/nested-draggables.spec.ts",
"chars": 1016,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport { draggable } from '../../../../src/entry-point/el"
},
{
"path": "packages/core/__tests__/unit/element/draggable/start-location.spec.ts",
"chars": 1271,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport { draggable, dropTargetForElements } from '../../."
},
{
"path": "packages/core/__tests__/unit/element/dragleave-should-not-update-input.spec.ts",
"chars": 5638,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport {\n"
},
{
"path": "packages/core/__tests__/unit/element/drop-target/conditional-dropping.spec.ts",
"chars": 6591,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/drop-target/data-collection.spec.ts",
"chars": 3268,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/drop-target/drop-effect.spec.ts",
"chars": 12270,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/element/drop-target/guardrails.spec.ts",
"chars": 1352,
"preview": "import { dropTargetForElements } from '../../../../src/entry-point/element/adapter';\nimport { dropTargetForExternal } fr"
},
{
"path": "packages/core/__tests__/unit/element/drop-target/lift.spec.ts",
"chars": 11723,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/drop-target/stickiness.spec.ts",
"chars": 26864,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/dropping-outside-window.spec.ts",
"chars": 1405,
"preview": "import { combine } from '../../../src/entry-point/combine';\nimport { draggable } from '../../../src/entry-point/element/"
},
{
"path": "packages/core/__tests__/unit/element/error-recovery.spec.ts",
"chars": 786,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/all.spec.ts",
"chars": 2829,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/callback-data.spec.ts",
"chars": 26266,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/drag-start-flushing.spec.ts",
"chars": 6160,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/drag-start.spec.ts",
"chars": 1417,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/drag-update-atomic.spec.ts",
"chars": 3808,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/drag-update.spec.ts",
"chars": 9653,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/drag.spec.ts",
"chars": 10054,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/drop.spec.ts",
"chars": 9785,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/event-ordering/generate-drag-preview.spec.ts",
"chars": 1379,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/events-and-adapter-mounting.spec.ts",
"chars": 2538,
"preview": "import { combine } from '../../../src/entry-point/combine';\nimport {\n\tdraggable,\n\tdropTargetForElements,\n\tmonitorForElem"
},
{
"path": "packages/core/__tests__/unit/element/global-event-binding.spec.ts",
"chars": 16054,
"preview": "// Note: not using '@testing-library/dom' in this file as it can\n// add it's own \"error\" event listeners when other even"
},
{
"path": "packages/core/__tests__/unit/element/leaving-the-window.spec.ts",
"chars": 1304,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/element/monitor/adding-monitors-during-events.spec.ts",
"chars": 1596,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/monitor/call-order.spec.ts",
"chars": 1709,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/monitor/publishing-events.spec.ts",
"chars": 12106,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/monitor/removing-monitors-during-events.spec.ts",
"chars": 2510,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport {\n\tdraggable,\n\tdropTargetForElements,\n\tmonitorForE"
},
{
"path": "packages/core/__tests__/unit/element/monitor/uniqueness.spec.ts",
"chars": 860,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/element/previous-location-should-match-last-current.spec.ts",
"chars": 14229,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/element/public-utils/block-dragging-to-iframes.spec.ts",
"chars": 7604,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';\n\nimp"
},
{
"path": "packages/core/__tests__/unit/element/public-utils/center-under-pointer.spec.ts",
"chars": 2506,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/element/public-utils/format-urls-for-external.spec.ts",
"chars": 1102,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport { draggable } from '../../../../src/entry-point/el"
},
{
"path": "packages/core/__tests__/unit/element/public-utils/pointer-outside-of-preview.spec.ts",
"chars": 4982,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/element/public-utils/preserve-offset-on-source.spec.ts",
"chars": 5290,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/element/public-utils/set-custom-native-drag-preview.spec.ts",
"chars": 8407,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/element/repeated-dragging.spec.ts",
"chars": 3676,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/element/resiliant-against-consumers-stopping-events-during-a-drag.spec.ts",
"chars": 5702,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bindAll } from 'bind-event-listener';\n\nimport { combine } fro"
},
{
"path": "packages/core/__tests__/unit/element/resilient-against-multiple-cleanup-calls.spec.ts",
"chars": 2216,
"preview": "import { combine } from '../../../src/entry-point/combine';\nimport { draggable, dropTargetForElements } from '../../../s"
},
{
"path": "packages/core/__tests__/unit/element/respecting-non-pdnd-code.spec.ts",
"chars": 10980,
"preview": "import { createEvent, fireEvent } from '@testing-library/dom';\nimport { bind, bindAll } from 'bind-event-listener';\n\nimp"
},
{
"path": "packages/core/__tests__/unit/external/adapter/can-monitor.spec.ts",
"chars": 2052,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/external/adapter/drag-ownership/element-adapter.spec.ts",
"chars": 4363,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';\n\nimp"
},
{
"path": "packages/core/__tests__/unit/external/adapter/drag-ownership/uncontrolled-internal-adapter.spec.ts",
"chars": 1392,
"preview": "import { skipAutoA11yFile } from '@atlassian/a11y-jest-testing';\n\nimport { combine } from '../../../../../src/entry-poin"
},
{
"path": "packages/core/__tests__/unit/external/adapter/drop-effect.spec.ts",
"chars": 3155,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/external/adapter/exposing-data.spec.ts",
"chars": 12253,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bindAll } from 'bind-event-listener';\nimport invariant from '"
},
{
"path": "packages/core/__tests__/unit/external/adapter/get-string-data.spec.ts",
"chars": 4140,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { elementAdapterNative"
},
{
"path": "packages/core/__tests__/unit/external/adapter/global-event-binding.spec.ts",
"chars": 6492,
"preview": "// Note: not using '@testing-library/dom' in this file as it can\n// add it's own \"error\" event listeners when other even"
},
{
"path": "packages/core/__tests__/unit/external/adapter/leaving-the-window.spec.ts",
"chars": 1076,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport {\n\tdropTargetForExternal,\n\tmonitorForExternal,\n} f"
},
{
"path": "packages/core/__tests__/unit/external/adapter/respecting-non-pdnd-code.spec.ts",
"chars": 2535,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport { bind, bindAll } from 'bind-event-listener';\n\nimport { combine"
},
{
"path": "packages/core/__tests__/unit/external/adapter/starting-an-external-drag-before-registrations.spec.ts",
"chars": 1588,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/external/adapter/starting-an-external-drag.spec.ts",
"chars": 3616,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport {\n\tdropTargetForExternal,\n\tmonitorForExternal,\n} f"
},
{
"path": "packages/core/__tests__/unit/external/drop-targets/nested.spec.ts",
"chars": 1589,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/external/utils/file/contains-files.spec.ts",
"chars": 4829,
"preview": "import invariant from 'tiny-invariant';\n\nimport { combine } from '../../../../../src/entry-point/combine';\nimport {\n\tdro"
},
{
"path": "packages/core/__tests__/unit/external/utils/file/get-files.spec.ts",
"chars": 6090,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/external/utils/html/contains-html.spec.ts",
"chars": 3614,
"preview": "import invariant from 'tiny-invariant';\n\nimport { combine } from '../../../../../src/entry-point/combine';\nimport {\n\tdro"
},
{
"path": "packages/core/__tests__/unit/external/utils/html/get-html.spec.ts",
"chars": 4551,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/external/utils/some.spec.ts",
"chars": 4393,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/external/utils/text/contains-text.spec.ts",
"chars": 3606,
"preview": "import invariant from 'tiny-invariant';\n\nimport { combine } from '../../../../../src/entry-point/combine';\nimport {\n\tdro"
},
{
"path": "packages/core/__tests__/unit/external/utils/text/get-text.spec.ts",
"chars": 4534,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/external/utils/url/contains-urls.spec.ts",
"chars": 5045,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/external/utils/url/firefox-fix.spec.ts",
"chars": 6399,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/external/utils/url/url.spec.ts",
"chars": 5982,
"preview": "import { fireEvent } from '@testing-library/dom';\nimport invariant from 'tiny-invariant';\n\nimport { combine } from '../."
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/_util.ts",
"chars": 579,
"preview": "import invariant from 'tiny-invariant';\n\nconst honeyPotSelector = '[data-pdnd-honey-pot]';\n\nexport function findHoneyPot"
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/event-listeners.spec.ts",
"chars": 8022,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/external-adapter-should-not-use-honey-pot.spec.ts",
"chars": 857,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { monitorForExternal } from '../../../src/entry-point/external"
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/finishing.spec.ts",
"chars": 7004,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/get-element-from-point-without-honey-pot.spec.ts",
"chars": 2401,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/mid-drag.spec.ts",
"chars": 9060,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport {\n"
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/multiple-operations.spec.ts",
"chars": 6552,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/starting.spec.ts",
"chars": 9838,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/honey-pot-fix/text-adapter-smoke-test.spec.ts",
"chars": 1866,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/public-utils/combine.spec.ts",
"chars": 400,
"preview": "import { combine } from '../../../src/entry-point/combine';\n\nit('should call all combined functions', () => {\n\tconst ord"
},
{
"path": "packages/core/__tests__/unit/public-utils/once.spec.ts",
"chars": 1814,
"preview": "import { once } from '../../../src/entry-point/once';\n\nit('should only call an underlying function once', () => {\n\tconst"
},
{
"path": "packages/core/__tests__/unit/public-utils/prevent-unhandled.spec.ts",
"chars": 10749,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../src/entry-point/combine';\nimport { "
},
{
"path": "packages/core/__tests__/unit/public-utils/reorder.spec.ts",
"chars": 2180,
"preview": "import { reorder } from '../../../src/entry-point/reorder';\n\nit('should reorder a list', () => {\n\texpect(\n\t\treorder({\n\t\t"
},
{
"path": "packages/core/__tests__/unit/react/adding-monitors-during-events.spec.tsx",
"chars": 5158,
"preview": "import React, { useLayoutEffect, useRef, useState } from 'react';\n\n// Using '@testing-library/react' rather than '@testi"
},
{
"path": "packages/core/__tests__/unit/server-side-usage.spec.ts",
"chars": 2143,
"preview": "// Ideally we would use the \"@jest-environment node\" file pragma,\n// but global test setup uses `window` too much\n// So "
},
{
"path": "packages/core/__tests__/unit/test-environment-guardrail.spec.ts",
"chars": 2832,
"preview": "import { combine } from '../../src/entry-point/combine';\nimport { draggable } from '../../src/entry-point/element/adapte"
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/drag-ownership/element-adapter.spec.ts",
"chars": 1026,
"preview": "import { combine } from '../../../../../src/entry-point/combine';\nimport { draggable, monitorForElements } from '../../."
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/drag-ownership/external-adapter.spec.ts",
"chars": 749,
"preview": "import { combine } from '../../../../../src/entry-point/combine';\nimport { monitorForExternal } from '../../../../../src"
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/event-ordering.spec.ts",
"chars": 8743,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/global-event-binding.spec.ts",
"chars": 6653,
"preview": "// Note: not using '@testing-library/dom' in this file as it can\n// add it's own \"error\" event listeners when other even"
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/leaving-the-window.spec.ts",
"chars": 1060,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport { monitorForTextSelection } from '../../../../src/"
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/respecting-non-pdnd-code.spec.ts",
"chars": 2378,
"preview": "import { createEvent, fireEvent } from '@testing-library/dom';\nimport { bind, bindAll } from 'bind-event-listener';\n\nimp"
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/starting-a-text-selection-drag-before-registrations.spec.ts",
"chars": 1659,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/__tests__/unit/text-selection/adapter/text-target.spec.ts",
"chars": 1383,
"preview": "import { combine } from '../../../../src/entry-point/combine';\nimport { monitorForTextSelection } from '../../../../src/"
},
{
"path": "packages/core/__tests__/unit/text-selection/drop-targets/nested.spec.ts",
"chars": 1808,
"preview": "import { fireEvent } from '@testing-library/dom';\n\nimport { combine } from '../../../../src/entry-point/combine';\nimport"
},
{
"path": "packages/core/afm-jira/tsconfig.json",
"chars": 600,
"preview": "{\n\t\"extends\": \"../../../../tsconfig.local-consumption.json\",\n\t\"compilerOptions\": {\n\t\t\"target\": \"es5\",\n\t\t\"outDir\": \"../.."
},
{
"path": "packages/core/afm-products/tsconfig.json",
"chars": 570,
"preview": "{\n\t\"extends\": \"../../../../tsconfig.local-consumption.json\",\n\t\"compilerOptions\": {\n\t\t\"target\": \"es5\",\n\t\t\"outDir\": \"../.."
},
{
"path": "packages/core/constellation/index/props.mdx",
"chars": 17,
"preview": "---\norder: 1\n---\n"
},
{
"path": "packages/core/examples/_util/constants.tsx",
"chars": 217,
"preview": "export const gridSize = 8;\n\n/**\n * The space between each column in a board.\n */\nexport const columnGap: number = 2 * gr"
},
{
"path": "packages/core/examples/_util/fallback.ts",
"chars": 40,
"preview": "export const fallbackColor = '#44475a';\n"
}
]
// ... and 751 more files (download for full content)
About this extraction
This page contains the full source code of the atlassian/pragmatic-drag-and-drop GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 951 files (3.3 MB), approximately 928.2k tokens, and a symbol index with 1663 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.