@planningcenter/react-beautiful-dnd 13.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/LICENSE +13 -0
- package/README.md +178 -0
- package/dist/react-beautiful-dnd.cjs.js +8728 -0
- package/dist/react-beautiful-dnd.cjs.js.flow +3 -0
- package/dist/react-beautiful-dnd.esm.js +8715 -0
- package/dist/react-beautiful-dnd.js +11726 -0
- package/dist/react-beautiful-dnd.min.js +1 -0
- package/package.json +155 -0
- package/src/animation.js +75 -0
- package/src/debug/middleware/action-timing-average.js +52 -0
- package/src/debug/middleware/action-timing.js +16 -0
- package/src/debug/middleware/log.js +26 -0
- package/src/debug/middleware/user-timing.js +16 -0
- package/src/debug/timings.js +86 -0
- package/src/dev-warning.js +50 -0
- package/src/empty.js +6 -0
- package/src/index.js +67 -0
- package/src/invariant.js +33 -0
- package/src/native-with-fallback.js +69 -0
- package/src/screen-reader-message-preset.js +134 -0
- package/src/state/action-creators.js +328 -0
- package/src/state/auto-scroller/auto-scroller-types.js +8 -0
- package/src/state/auto-scroller/can-scroll.js +160 -0
- package/src/state/auto-scroller/fluid-scroller/config.js +25 -0
- package/src/state/auto-scroller/fluid-scroller/did-start-in-scrollable-area.js +1 -0
- package/src/state/auto-scroller/fluid-scroller/get-best-scrollable-droppable.js +77 -0
- package/src/state/auto-scroller/fluid-scroller/get-droppable-scroll-change.js +50 -0
- package/src/state/auto-scroller/fluid-scroller/get-percentage.js +25 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/adjust-for-size-limits.js +30 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/buffer-thresholds/calc-axis-scroll-conditions.js +68 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/buffer-thresholds/get-scroll-conditions.js +56 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/buffer-thresholds/index.js +66 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/dampen-value-by-time.js +48 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/get-distance-thresholds.js +31 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/get-value-from-distance.js +67 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/get-value.js +51 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/index.js +50 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/min-scroll.js +4 -0
- package/src/state/auto-scroller/fluid-scroller/get-scroll/index.js +139 -0
- package/src/state/auto-scroller/fluid-scroller/get-window-scroll-change.js +43 -0
- package/src/state/auto-scroller/fluid-scroller/index.js +99 -0
- package/src/state/auto-scroller/fluid-scroller/scroll.js +80 -0
- package/src/state/auto-scroller/index.js +59 -0
- package/src/state/auto-scroller/jump-scroller.js +139 -0
- package/src/state/axis.js +26 -0
- package/src/state/calculate-drag-impact/calculate-reorder-impact.js +136 -0
- package/src/state/can-start-drag.js +29 -0
- package/src/state/create-store.js +97 -0
- package/src/state/did-start-after-critical.js +9 -0
- package/src/state/dimension-marshal/dimension-marshal-types.js +46 -0
- package/src/state/dimension-marshal/dimension-marshal.js +218 -0
- package/src/state/dimension-marshal/get-initial-publish.js +66 -0
- package/src/state/dimension-marshal/while-dragging-publisher.js +146 -0
- package/src/state/dimension-structures.js +35 -0
- package/src/state/droppable/get-droppable.js +101 -0
- package/src/state/droppable/is-home-of.js +7 -0
- package/src/state/droppable/scroll-droppable.js +53 -0
- package/src/state/droppable/should-use-placeholder.js +7 -0
- package/src/state/droppable/util/clip.js +17 -0
- package/src/state/droppable/util/get-subject.js +63 -0
- package/src/state/droppable/what-is-dragged-over-from-result.js +16 -0
- package/src/state/droppable/what-is-dragged-over.js +16 -0
- package/src/state/droppable/with-placeholder.js +174 -0
- package/src/state/get-center-from-impact/get-client-border-box-center/get-client-from-page-border-box-center.js +29 -0
- package/src/state/get-center-from-impact/get-client-border-box-center/index.js +44 -0
- package/src/state/get-center-from-impact/get-page-border-box-center/index.js +70 -0
- package/src/state/get-center-from-impact/get-page-border-box-center/when-combining.js +39 -0
- package/src/state/get-center-from-impact/get-page-border-box-center/when-reordering.js +112 -0
- package/src/state/get-center-from-impact/move-relative-to.js +66 -0
- package/src/state/get-combined-item-displacement.js +34 -0
- package/src/state/get-displaced-by.js +17 -0
- package/src/state/get-displacement-groups.js +130 -0
- package/src/state/get-drag-impact/get-combine-impact.js +130 -0
- package/src/state/get-drag-impact/get-reorder-impact.js +143 -0
- package/src/state/get-drag-impact/index.js +93 -0
- package/src/state/get-draggables-inside-droppable.js +31 -0
- package/src/state/get-droppable-over.js +158 -0
- package/src/state/get-frame.js +10 -0
- package/src/state/get-home-location.js +7 -0
- package/src/state/get-impact-location.js +16 -0
- package/src/state/get-is-displaced.js +11 -0
- package/src/state/get-lift-effect.js +82 -0
- package/src/state/get-max-scroll.js +30 -0
- package/src/state/is-movement-allowed.js +6 -0
- package/src/state/is-within.js +9 -0
- package/src/state/middleware/auto-scroll.js +38 -0
- package/src/state/middleware/dimension-marshal-stopper.js +20 -0
- package/src/state/middleware/drop/drop-animation-finish-middleware.js +21 -0
- package/src/state/middleware/drop/drop-animation-flush-on-scroll-middleware.js +63 -0
- package/src/state/middleware/drop/drop-middleware.js +146 -0
- package/src/state/middleware/drop/get-drop-duration.js +47 -0
- package/src/state/middleware/drop/get-drop-impact.js +77 -0
- package/src/state/middleware/drop/get-new-home-client-offset.js +54 -0
- package/src/state/middleware/drop/index.js +2 -0
- package/src/state/middleware/focus.js +42 -0
- package/src/state/middleware/lift.js +66 -0
- package/src/state/middleware/pending-drop.js +37 -0
- package/src/state/middleware/responders/async-marshal.js +55 -0
- package/src/state/middleware/responders/expiring-announce.js +44 -0
- package/src/state/middleware/responders/index.js +2 -0
- package/src/state/middleware/responders/is-equal.js +57 -0
- package/src/state/middleware/responders/publisher.js +253 -0
- package/src/state/middleware/responders/responders-middleware.js +75 -0
- package/src/state/middleware/scroll-listener.js +31 -0
- package/src/state/middleware/style.js +22 -0
- package/src/state/middleware/util/validate-dimensions.js +71 -0
- package/src/state/move-in-direction/index.js +84 -0
- package/src/state/move-in-direction/move-cross-axis/get-best-cross-axis-droppable.js +168 -0
- package/src/state/move-in-direction/move-cross-axis/get-closest-draggable.js +79 -0
- package/src/state/move-in-direction/move-cross-axis/index.js +109 -0
- package/src/state/move-in-direction/move-cross-axis/move-to-new-droppable.js +121 -0
- package/src/state/move-in-direction/move-cross-axis/without-starting-displacement.js +31 -0
- package/src/state/move-in-direction/move-in-direction-types.js +9 -0
- package/src/state/move-in-direction/move-to-next-place/index.js +132 -0
- package/src/state/move-in-direction/move-to-next-place/is-totally-visible-in-new-location.js +52 -0
- package/src/state/move-in-direction/move-to-next-place/move-to-next-combine/index.js +97 -0
- package/src/state/move-in-direction/move-to-next-place/move-to-next-index/from-combine.js +52 -0
- package/src/state/move-in-direction/move-to-next-place/move-to-next-index/from-reorder.js +43 -0
- package/src/state/move-in-direction/move-to-next-place/move-to-next-index/index.js +86 -0
- package/src/state/no-impact.js +33 -0
- package/src/state/patch-dimension-map.js +11 -0
- package/src/state/patch-droppable-map.js +10 -0
- package/src/state/position.js +58 -0
- package/src/state/post-reducer/when-moving/refresh-snap.js +67 -0
- package/src/state/post-reducer/when-moving/update.js +120 -0
- package/src/state/publish-while-dragging-in-virtual/adjust-additions-for-scroll-changes.js +58 -0
- package/src/state/publish-while-dragging-in-virtual/index.js +158 -0
- package/src/state/publish-while-dragging-in-virtual/offset-draggable.js +35 -0
- package/src/state/recompute-placeholders.js +99 -0
- package/src/state/rect.js +7 -0
- package/src/state/reducer.js +457 -0
- package/src/state/registry/create-registry.js +162 -0
- package/src/state/registry/registry-types.js +98 -0
- package/src/state/registry/use-registry.js +20 -0
- package/src/state/remove-draggable-from-list.js +13 -0
- package/src/state/scroll-viewport.js +34 -0
- package/src/state/spacing.js +45 -0
- package/src/state/store-types.js +16 -0
- package/src/state/update-displacement-visibility/recompute.js +54 -0
- package/src/state/update-displacement-visibility/speculatively-increase.js +111 -0
- package/src/state/visibility/is-partially-visible-through-frame.js +60 -0
- package/src/state/visibility/is-position-in-frame.js +12 -0
- package/src/state/visibility/is-totally-visible-through-frame-on-axis.js +19 -0
- package/src/state/visibility/is-totally-visible-through-frame.js +18 -0
- package/src/state/visibility/is-visible.js +102 -0
- package/src/state/with-scroll-change/with-all-displacement.js +15 -0
- package/src/state/with-scroll-change/with-droppable-displacement.js +13 -0
- package/src/state/with-scroll-change/with-droppable-scroll.js +13 -0
- package/src/state/with-scroll-change/with-viewport-displacement.js +7 -0
- package/src/types.js +542 -0
- package/src/view/animate-in-out/animate-in-out.jsx +95 -0
- package/src/view/animate-in-out/index.js +2 -0
- package/src/view/check-is-valid-inner-ref.js +15 -0
- package/src/view/context/app-context.js +19 -0
- package/src/view/context/droppable-context.js +11 -0
- package/src/view/context/store-context.js +5 -0
- package/src/view/data-attributes.js +37 -0
- package/src/view/drag-drop-context/app.jsx +273 -0
- package/src/view/drag-drop-context/check-doctype.js +39 -0
- package/src/view/drag-drop-context/check-react-version.js +71 -0
- package/src/view/drag-drop-context/drag-drop-context-types.js +7 -0
- package/src/view/drag-drop-context/drag-drop-context.jsx +68 -0
- package/src/view/drag-drop-context/error-boundary.jsx +88 -0
- package/src/view/drag-drop-context/index.js +2 -0
- package/src/view/drag-drop-context/use-startup-validation.js +13 -0
- package/src/view/drag-drop-context/use-unique-context-id.js +13 -0
- package/src/view/draggable/connected-draggable.js +372 -0
- package/src/view/draggable/draggable-api.jsx +48 -0
- package/src/view/draggable/draggable-types.js +191 -0
- package/src/view/draggable/draggable.jsx +171 -0
- package/src/view/draggable/get-style.js +109 -0
- package/src/view/draggable/index.js +2 -0
- package/src/view/draggable/use-validation.js +70 -0
- package/src/view/droppable/connected-droppable.js +280 -0
- package/src/view/droppable/droppable-types.js +91 -0
- package/src/view/droppable/droppable.jsx +167 -0
- package/src/view/droppable/index.js +2 -0
- package/src/view/droppable/use-validation.js +101 -0
- package/src/view/event-bindings/bind-events.js +39 -0
- package/src/view/event-bindings/event-types.js +14 -0
- package/src/view/get-body-element.js +8 -0
- package/src/view/get-border-box-center-position.js +5 -0
- package/src/view/get-document-element.js +8 -0
- package/src/view/get-elements/find-drag-handle.js +38 -0
- package/src/view/get-elements/find-draggable.js +30 -0
- package/src/view/is-strict-equal.js +2 -0
- package/src/view/is-type-of-element/is-element.js +6 -0
- package/src/view/is-type-of-element/is-html-element.js +6 -0
- package/src/view/is-type-of-element/is-svg-element.js +12 -0
- package/src/view/key-codes.js +13 -0
- package/src/view/placeholder/index.js +2 -0
- package/src/view/placeholder/placeholder-types.js +16 -0
- package/src/view/placeholder/placeholder.jsx +198 -0
- package/src/view/scroll-listener.js +72 -0
- package/src/view/throw-if-invalid-inner-ref.js +15 -0
- package/src/view/use-announcer/index.js +2 -0
- package/src/view/use-announcer/use-announcer.js +80 -0
- package/src/view/use-dev-setup-warning.js +22 -0
- package/src/view/use-dev.js +9 -0
- package/src/view/use-draggable-publisher/get-dimension.js +44 -0
- package/src/view/use-draggable-publisher/index.js +2 -0
- package/src/view/use-draggable-publisher/use-draggable-publisher.js +87 -0
- package/src/view/use-droppable-publisher/check-for-nested-scroll-container.js +27 -0
- package/src/view/use-droppable-publisher/get-closest-scrollable.js +95 -0
- package/src/view/use-droppable-publisher/get-dimension.js +139 -0
- package/src/view/use-droppable-publisher/get-env.js +31 -0
- package/src/view/use-droppable-publisher/get-listener-options.js +12 -0
- package/src/view/use-droppable-publisher/get-scroll.js +7 -0
- package/src/view/use-droppable-publisher/index.js +2 -0
- package/src/view/use-droppable-publisher/is-in-fixed-container.js +21 -0
- package/src/view/use-droppable-publisher/use-droppable-publisher.js +283 -0
- package/src/view/use-focus-marshal/focus-marshal-types.js +13 -0
- package/src/view/use-focus-marshal/index.js +2 -0
- package/src/view/use-focus-marshal/use-focus-marshal.js +129 -0
- package/src/view/use-hidden-text-element/index.js +2 -0
- package/src/view/use-hidden-text-element/use-hidden-text-element.js +60 -0
- package/src/view/use-isomorphic-layout-effect.js +18 -0
- package/src/view/use-previous-ref.js +14 -0
- package/src/view/use-required-context.js +9 -0
- package/src/view/use-sensor-marshal/closest.js +50 -0
- package/src/view/use-sensor-marshal/find-closest-draggable-id-from-event.js +50 -0
- package/src/view/use-sensor-marshal/index.js +5 -0
- package/src/view/use-sensor-marshal/is-event-in-interactive-element.js +66 -0
- package/src/view/use-sensor-marshal/lock.js +48 -0
- package/src/view/use-sensor-marshal/sensors/use-keyboard-sensor.js +243 -0
- package/src/view/use-sensor-marshal/sensors/use-mouse-sensor.js +386 -0
- package/src/view/use-sensor-marshal/sensors/use-touch-sensor.js +461 -0
- package/src/view/use-sensor-marshal/sensors/util/prevent-standard-key-events.js +19 -0
- package/src/view/use-sensor-marshal/sensors/util/supported-page-visibility-event-name.js +29 -0
- package/src/view/use-sensor-marshal/use-sensor-marshal.js +495 -0
- package/src/view/use-sensor-marshal/use-validate-sensor-hooks.js +20 -0
- package/src/view/use-style-marshal/get-styles.js +170 -0
- package/src/view/use-style-marshal/index.js +2 -0
- package/src/view/use-style-marshal/style-marshal-types.js +8 -0
- package/src/view/use-style-marshal/use-style-marshal.js +126 -0
- package/src/view/use-unique-id.js +25 -0
- package/src/view/visually-hidden-style.js +16 -0
- package/src/view/window/get-max-window-scroll.js +19 -0
- package/src/view/window/get-viewport.js +49 -0
- package/src/view/window/get-window-from-el.js +3 -0
- package/src/view/window/get-window-scroll.js +30 -0
- package/src/view/window/scroll-window.js +7 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import { invariant } from '../../invariant';
|
|
3
|
+
import type { DimensionMarshal } from '../dimension-marshal/dimension-marshal-types';
|
|
4
|
+
import type { State, ScrollOptions, LiftRequest } from '../../types';
|
|
5
|
+
import type { MiddlewareStore, Action, Dispatch } from '../store-types';
|
|
6
|
+
import {
|
|
7
|
+
completeDrop,
|
|
8
|
+
initialPublish,
|
|
9
|
+
flush,
|
|
10
|
+
beforeInitialCapture,
|
|
11
|
+
} from '../action-creators';
|
|
12
|
+
import validateDimensions from './util/validate-dimensions';
|
|
13
|
+
|
|
14
|
+
export default (marshal: DimensionMarshal) => ({
|
|
15
|
+
getState,
|
|
16
|
+
dispatch,
|
|
17
|
+
}: MiddlewareStore) => (next: Dispatch) => (action: Action): any => {
|
|
18
|
+
if (action.type !== 'LIFT') {
|
|
19
|
+
next(action);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const { id, clientSelection, movementMode } = action.payload;
|
|
23
|
+
const initial: State = getState();
|
|
24
|
+
|
|
25
|
+
// flush dropping animation if needed
|
|
26
|
+
// this can change the descriptor of the dragging item
|
|
27
|
+
// Will call the onDragEnd responders
|
|
28
|
+
|
|
29
|
+
if (initial.phase === 'DROP_ANIMATING') {
|
|
30
|
+
dispatch(completeDrop({ completed: initial.completed }));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
invariant(getState().phase === 'IDLE', 'Unexpected phase to start a drag');
|
|
34
|
+
|
|
35
|
+
// Removing any placeholders before we capture any starting dimensions
|
|
36
|
+
dispatch(flush());
|
|
37
|
+
|
|
38
|
+
// Let consumers know we are just about to publish
|
|
39
|
+
// We are only publishing a small amount of information as
|
|
40
|
+
// things might change as a result of the onBeforeCapture callback
|
|
41
|
+
dispatch(beforeInitialCapture({ draggableId: id, movementMode }));
|
|
42
|
+
|
|
43
|
+
// will communicate with the marshal to start requesting dimensions
|
|
44
|
+
const scrollOptions: ScrollOptions = {
|
|
45
|
+
shouldPublishImmediately: movementMode === 'SNAP',
|
|
46
|
+
};
|
|
47
|
+
const request: LiftRequest = {
|
|
48
|
+
draggableId: id,
|
|
49
|
+
scrollOptions,
|
|
50
|
+
};
|
|
51
|
+
// Let's get the marshal started!
|
|
52
|
+
const { critical, dimensions, viewport } = marshal.startPublishing(request);
|
|
53
|
+
|
|
54
|
+
validateDimensions(critical, dimensions);
|
|
55
|
+
|
|
56
|
+
// Okay, we are good to start dragging now
|
|
57
|
+
dispatch(
|
|
58
|
+
initialPublish({
|
|
59
|
+
critical,
|
|
60
|
+
dimensions,
|
|
61
|
+
clientSelection,
|
|
62
|
+
movementMode,
|
|
63
|
+
viewport,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import { drop } from '../action-creators';
|
|
3
|
+
import type { State } from '../../types';
|
|
4
|
+
import type { MiddlewareStore, Dispatch, Action } from '../store-types';
|
|
5
|
+
|
|
6
|
+
export default (store: MiddlewareStore) => (next: Dispatch) => (
|
|
7
|
+
action: Action,
|
|
8
|
+
): any => {
|
|
9
|
+
// Always let the action go through first
|
|
10
|
+
next(action);
|
|
11
|
+
|
|
12
|
+
if (action.type !== 'PUBLISH_WHILE_DRAGGING') {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// A bulk replace occurred - check if
|
|
17
|
+
// 1. there is a pending drop
|
|
18
|
+
// 2. that the pending drop is no longer waiting
|
|
19
|
+
|
|
20
|
+
const postActionState: State = store.getState();
|
|
21
|
+
|
|
22
|
+
// no pending drop after the publish
|
|
23
|
+
if (postActionState.phase !== 'DROP_PENDING') {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// the pending drop is still waiting for completion
|
|
28
|
+
if (postActionState.isWaiting) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
store.dispatch(
|
|
33
|
+
drop({
|
|
34
|
+
reason: postActionState.reason,
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import { invariant } from '../../../invariant';
|
|
3
|
+
import { findIndex } from '../../../native-with-fallback';
|
|
4
|
+
|
|
5
|
+
type Entry = {|
|
|
6
|
+
timerId: TimeoutID,
|
|
7
|
+
callback: Function,
|
|
8
|
+
|};
|
|
9
|
+
|
|
10
|
+
export type AsyncMarshal = {|
|
|
11
|
+
add: (fn: Function) => void,
|
|
12
|
+
flush: () => void,
|
|
13
|
+
|};
|
|
14
|
+
|
|
15
|
+
export default () => {
|
|
16
|
+
const entries: Entry[] = [];
|
|
17
|
+
|
|
18
|
+
const execute = (timerId: TimeoutID) => {
|
|
19
|
+
const index: number = findIndex(
|
|
20
|
+
entries,
|
|
21
|
+
(item: Entry): boolean => item.timerId === timerId,
|
|
22
|
+
);
|
|
23
|
+
invariant(index !== -1, 'Could not find timer');
|
|
24
|
+
// delete in place
|
|
25
|
+
const [entry] = entries.splice(index, 1);
|
|
26
|
+
entry.callback();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const add = (fn: Function) => {
|
|
30
|
+
const timerId: TimeoutID = setTimeout(() => execute(timerId));
|
|
31
|
+
const entry: Entry = {
|
|
32
|
+
timerId,
|
|
33
|
+
callback: fn,
|
|
34
|
+
};
|
|
35
|
+
entries.push(entry);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const flush = () => {
|
|
39
|
+
// nothing to flush
|
|
40
|
+
if (!entries.length) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const shallow: Entry[] = [...entries];
|
|
45
|
+
// clearing entries in case a callback adds some more callbacks
|
|
46
|
+
entries.length = 0;
|
|
47
|
+
|
|
48
|
+
shallow.forEach((entry: Entry) => {
|
|
49
|
+
clearTimeout(entry.timerId);
|
|
50
|
+
entry.callback();
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return { add, flush };
|
|
55
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type { Announce } from '../../../types';
|
|
3
|
+
import { warning } from '../../../dev-warning';
|
|
4
|
+
|
|
5
|
+
export type ExpiringAnnounce = Announce & {
|
|
6
|
+
wasCalled: () => boolean,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default (announce: Announce): ExpiringAnnounce => {
|
|
10
|
+
let wasCalled: boolean = false;
|
|
11
|
+
let isExpired: boolean = false;
|
|
12
|
+
|
|
13
|
+
// not allowing async announcements
|
|
14
|
+
const timeoutId: TimeoutID = setTimeout(() => {
|
|
15
|
+
isExpired = true;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const result = (message: string): void => {
|
|
19
|
+
if (wasCalled) {
|
|
20
|
+
warning('Announcement already made. Not making a second announcement');
|
|
21
|
+
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (isExpired) {
|
|
26
|
+
warning(`
|
|
27
|
+
Announcements cannot be made asynchronously.
|
|
28
|
+
Default message has already been announced.
|
|
29
|
+
`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
wasCalled = true;
|
|
34
|
+
announce(message);
|
|
35
|
+
clearTimeout(timeoutId);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// getter for isExpired
|
|
39
|
+
// using this technique so that a consumer cannot
|
|
40
|
+
// set the isExpired or wasCalled flags
|
|
41
|
+
result.wasCalled = (): boolean => wasCalled;
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type { Critical, DraggableLocation, Combine } from '../../../types';
|
|
3
|
+
|
|
4
|
+
export const areLocationsEqual = (
|
|
5
|
+
first: ?DraggableLocation,
|
|
6
|
+
second: ?DraggableLocation,
|
|
7
|
+
): boolean => {
|
|
8
|
+
// if both are null - we are equal
|
|
9
|
+
if (first == null && second == null) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// if one is null - then they are not equal
|
|
14
|
+
if (first == null || second == null) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// compare their actual values
|
|
19
|
+
return (
|
|
20
|
+
first.droppableId === second.droppableId && first.index === second.index
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const isCombineEqual = (first: ?Combine, second: ?Combine): boolean => {
|
|
25
|
+
// if both are null - we are equal
|
|
26
|
+
if (first == null && second == null) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// only one is null
|
|
31
|
+
if (first == null || second == null) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
first.draggableId === second.draggableId &&
|
|
37
|
+
first.droppableId === second.droppableId
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const isCriticalEqual = (first: Critical, second: Critical): boolean => {
|
|
42
|
+
if (first === second) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const isDraggableEqual: boolean =
|
|
47
|
+
first.draggable.id === second.draggable.id &&
|
|
48
|
+
first.draggable.droppableId === second.draggable.droppableId &&
|
|
49
|
+
first.draggable.type === second.draggable.type &&
|
|
50
|
+
first.draggable.index === second.draggable.index;
|
|
51
|
+
|
|
52
|
+
const isDroppableEqual: boolean =
|
|
53
|
+
first.droppable.id === second.droppable.id &&
|
|
54
|
+
first.droppable.type === second.droppable.type;
|
|
55
|
+
|
|
56
|
+
return isDraggableEqual && isDroppableEqual;
|
|
57
|
+
};
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import { invariant } from '../../../invariant';
|
|
3
|
+
import messagePreset from '../../../screen-reader-message-preset';
|
|
4
|
+
import * as timings from '../../../debug/timings';
|
|
5
|
+
import getExpiringAnnounce, {
|
|
6
|
+
type ExpiringAnnounce,
|
|
7
|
+
} from './expiring-announce';
|
|
8
|
+
import getAsyncMarshal, { type AsyncMarshal } from './async-marshal';
|
|
9
|
+
import type {
|
|
10
|
+
DropResult,
|
|
11
|
+
Responders,
|
|
12
|
+
ResponderProvided,
|
|
13
|
+
Critical,
|
|
14
|
+
BeforeCapture,
|
|
15
|
+
DragImpact,
|
|
16
|
+
DraggableLocation,
|
|
17
|
+
Combine,
|
|
18
|
+
DragStart,
|
|
19
|
+
Announce,
|
|
20
|
+
DragUpdate,
|
|
21
|
+
MovementMode,
|
|
22
|
+
DraggableId,
|
|
23
|
+
OnBeforeCaptureResponder,
|
|
24
|
+
OnBeforeDragStartResponder,
|
|
25
|
+
OnDragStartResponder,
|
|
26
|
+
OnDragUpdateResponder,
|
|
27
|
+
OnDragEndResponder,
|
|
28
|
+
} from '../../../types';
|
|
29
|
+
import { isCombineEqual, isCriticalEqual, areLocationsEqual } from './is-equal';
|
|
30
|
+
import { tryGetDestination, tryGetCombine } from '../../get-impact-location';
|
|
31
|
+
|
|
32
|
+
const withTimings = (key: string, fn: Function) => {
|
|
33
|
+
timings.start(key);
|
|
34
|
+
fn();
|
|
35
|
+
timings.finish(key);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const getDragStart = (critical: Critical, mode: MovementMode): DragStart => ({
|
|
39
|
+
draggableId: critical.draggable.id,
|
|
40
|
+
type: critical.droppable.type,
|
|
41
|
+
source: {
|
|
42
|
+
droppableId: critical.droppable.id,
|
|
43
|
+
index: critical.draggable.index,
|
|
44
|
+
},
|
|
45
|
+
mode,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
type AnyPrimaryResponderFn =
|
|
49
|
+
| OnDragStartResponder
|
|
50
|
+
| OnDragUpdateResponder
|
|
51
|
+
| OnDragEndResponder;
|
|
52
|
+
type AnyResponderData = DragStart | DragUpdate | DropResult;
|
|
53
|
+
|
|
54
|
+
const execute = (
|
|
55
|
+
responder: ?AnyPrimaryResponderFn,
|
|
56
|
+
data: AnyResponderData,
|
|
57
|
+
announce: Announce,
|
|
58
|
+
getDefaultMessage: (data: any) => string,
|
|
59
|
+
) => {
|
|
60
|
+
if (!responder) {
|
|
61
|
+
announce(getDefaultMessage(data));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const willExpire: ExpiringAnnounce = getExpiringAnnounce(announce);
|
|
66
|
+
const provided: ResponderProvided = {
|
|
67
|
+
announce: willExpire,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Casting because we are not validating which data type is going into which responder
|
|
71
|
+
responder((data: any), provided);
|
|
72
|
+
|
|
73
|
+
if (!willExpire.wasCalled()) {
|
|
74
|
+
announce(getDefaultMessage(data));
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
type WhileDragging = {|
|
|
79
|
+
mode: MovementMode,
|
|
80
|
+
lastCritical: Critical,
|
|
81
|
+
lastCombine: ?Combine,
|
|
82
|
+
lastLocation: ?DraggableLocation,
|
|
83
|
+
|};
|
|
84
|
+
|
|
85
|
+
export default (getResponders: () => Responders, announce: Announce) => {
|
|
86
|
+
const asyncMarshal: AsyncMarshal = getAsyncMarshal();
|
|
87
|
+
let dragging: ?WhileDragging = null;
|
|
88
|
+
|
|
89
|
+
const beforeCapture = (draggableId: DraggableId, mode: MovementMode) => {
|
|
90
|
+
invariant(
|
|
91
|
+
!dragging,
|
|
92
|
+
'Cannot fire onBeforeCapture as a drag start has already been published',
|
|
93
|
+
);
|
|
94
|
+
withTimings('onBeforeCapture', () => {
|
|
95
|
+
// No use of screen reader for this responder
|
|
96
|
+
const fn: ?OnBeforeCaptureResponder = getResponders().onBeforeCapture;
|
|
97
|
+
if (fn) {
|
|
98
|
+
const before: BeforeCapture = {
|
|
99
|
+
draggableId,
|
|
100
|
+
mode,
|
|
101
|
+
};
|
|
102
|
+
fn(before);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const beforeStart = (critical: Critical, mode: MovementMode) => {
|
|
108
|
+
invariant(
|
|
109
|
+
!dragging,
|
|
110
|
+
'Cannot fire onBeforeDragStart as a drag start has already been published',
|
|
111
|
+
);
|
|
112
|
+
withTimings('onBeforeDragStart', () => {
|
|
113
|
+
// No use of screen reader for this responder
|
|
114
|
+
const fn: ?OnBeforeDragStartResponder = getResponders().onBeforeDragStart;
|
|
115
|
+
if (fn) {
|
|
116
|
+
fn(getDragStart(critical, mode));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const start = (critical: Critical, mode: MovementMode) => {
|
|
122
|
+
invariant(
|
|
123
|
+
!dragging,
|
|
124
|
+
'Cannot fire onBeforeDragStart as a drag start has already been published',
|
|
125
|
+
);
|
|
126
|
+
const data: DragStart = getDragStart(critical, mode);
|
|
127
|
+
dragging = {
|
|
128
|
+
mode,
|
|
129
|
+
lastCritical: critical,
|
|
130
|
+
lastLocation: data.source,
|
|
131
|
+
lastCombine: null,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// we will flush this frame if we receive any responder updates
|
|
135
|
+
asyncMarshal.add(() => {
|
|
136
|
+
withTimings('onDragStart', () =>
|
|
137
|
+
execute(
|
|
138
|
+
getResponders().onDragStart,
|
|
139
|
+
data,
|
|
140
|
+
announce,
|
|
141
|
+
messagePreset.onDragStart,
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Passing in the critical location again as it can change during a drag
|
|
148
|
+
const update = (critical: Critical, impact: DragImpact) => {
|
|
149
|
+
const location: ?DraggableLocation = tryGetDestination(impact);
|
|
150
|
+
const combine: ?Combine = tryGetCombine(impact);
|
|
151
|
+
|
|
152
|
+
invariant(
|
|
153
|
+
dragging,
|
|
154
|
+
'Cannot fire onDragMove when onDragStart has not been called',
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Has the critical changed? Will result in a source change
|
|
158
|
+
const hasCriticalChanged: boolean = !isCriticalEqual(
|
|
159
|
+
critical,
|
|
160
|
+
dragging.lastCritical,
|
|
161
|
+
);
|
|
162
|
+
if (hasCriticalChanged) {
|
|
163
|
+
dragging.lastCritical = critical;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Has the location changed? Will result in a destination change
|
|
167
|
+
const hasLocationChanged: boolean = !areLocationsEqual(
|
|
168
|
+
dragging.lastLocation,
|
|
169
|
+
location,
|
|
170
|
+
);
|
|
171
|
+
if (hasLocationChanged) {
|
|
172
|
+
dragging.lastLocation = location;
|
|
173
|
+
}
|
|
174
|
+
const hasGroupingChanged: boolean = !isCombineEqual(
|
|
175
|
+
dragging.lastCombine,
|
|
176
|
+
combine,
|
|
177
|
+
);
|
|
178
|
+
if (hasGroupingChanged) {
|
|
179
|
+
dragging.lastCombine = combine;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Nothing has changed - no update needed
|
|
183
|
+
if (!hasCriticalChanged && !hasLocationChanged && !hasGroupingChanged) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const data: DragUpdate = {
|
|
188
|
+
...getDragStart(critical, dragging.mode),
|
|
189
|
+
combine,
|
|
190
|
+
destination: location,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
asyncMarshal.add(() => {
|
|
194
|
+
withTimings('onDragUpdate', () =>
|
|
195
|
+
execute(
|
|
196
|
+
getResponders().onDragUpdate,
|
|
197
|
+
data,
|
|
198
|
+
announce,
|
|
199
|
+
messagePreset.onDragUpdate,
|
|
200
|
+
),
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const flush = () => {
|
|
206
|
+
invariant(dragging, 'Can only flush responders while dragging');
|
|
207
|
+
asyncMarshal.flush();
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const drop = (result: DropResult) => {
|
|
211
|
+
invariant(
|
|
212
|
+
dragging,
|
|
213
|
+
'Cannot fire onDragEnd when there is no matching onDragStart',
|
|
214
|
+
);
|
|
215
|
+
dragging = null;
|
|
216
|
+
// not adding to frame marshal - we want this to be done in the same render pass
|
|
217
|
+
// we also want the consumers reorder logic to be in the same render pass
|
|
218
|
+
withTimings('onDragEnd', () =>
|
|
219
|
+
execute(
|
|
220
|
+
getResponders().onDragEnd,
|
|
221
|
+
result,
|
|
222
|
+
announce,
|
|
223
|
+
messagePreset.onDragEnd,
|
|
224
|
+
),
|
|
225
|
+
);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// A non user initiated cancel
|
|
229
|
+
const abort = () => {
|
|
230
|
+
// aborting can happen defensively
|
|
231
|
+
if (!dragging) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const result: DropResult = {
|
|
236
|
+
...getDragStart(dragging.lastCritical, dragging.mode),
|
|
237
|
+
combine: null,
|
|
238
|
+
destination: null,
|
|
239
|
+
reason: 'CANCEL',
|
|
240
|
+
};
|
|
241
|
+
drop(result);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
beforeCapture,
|
|
246
|
+
beforeStart,
|
|
247
|
+
start,
|
|
248
|
+
update,
|
|
249
|
+
flush,
|
|
250
|
+
drop,
|
|
251
|
+
abort,
|
|
252
|
+
};
|
|
253
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import getPublisher from './publisher';
|
|
3
|
+
import type {
|
|
4
|
+
State,
|
|
5
|
+
DropResult,
|
|
6
|
+
Responders,
|
|
7
|
+
Critical,
|
|
8
|
+
Announce,
|
|
9
|
+
} from '../../../types';
|
|
10
|
+
import type {
|
|
11
|
+
Action,
|
|
12
|
+
Middleware,
|
|
13
|
+
MiddlewareStore,
|
|
14
|
+
Dispatch,
|
|
15
|
+
} from '../../store-types';
|
|
16
|
+
|
|
17
|
+
export default (
|
|
18
|
+
getResponders: () => Responders,
|
|
19
|
+
announce: Announce,
|
|
20
|
+
): Middleware => {
|
|
21
|
+
const publisher = getPublisher(
|
|
22
|
+
(getResponders: () => Responders),
|
|
23
|
+
(announce: Announce),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return (store: MiddlewareStore) => (next: Dispatch) => (
|
|
27
|
+
action: Action,
|
|
28
|
+
): any => {
|
|
29
|
+
if (action.type === 'BEFORE_INITIAL_CAPTURE') {
|
|
30
|
+
publisher.beforeCapture(
|
|
31
|
+
action.payload.draggableId,
|
|
32
|
+
action.payload.movementMode,
|
|
33
|
+
);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (action.type === 'INITIAL_PUBLISH') {
|
|
38
|
+
const critical: Critical = action.payload.critical;
|
|
39
|
+
publisher.beforeStart(critical, action.payload.movementMode);
|
|
40
|
+
next(action);
|
|
41
|
+
publisher.start(critical, action.payload.movementMode);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Drag end
|
|
46
|
+
if (action.type === 'DROP_COMPLETE') {
|
|
47
|
+
// it is important that we use the result and not the last impact
|
|
48
|
+
// the last impact might be different to the result for visual reasons
|
|
49
|
+
const result: DropResult = action.payload.completed.result;
|
|
50
|
+
// flushing all pending responders before snapshots are updated
|
|
51
|
+
publisher.flush();
|
|
52
|
+
next(action);
|
|
53
|
+
publisher.drop(result);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// All other responders can fire after we have updated our connected components
|
|
58
|
+
next(action);
|
|
59
|
+
|
|
60
|
+
// Drag state resetting - need to check if
|
|
61
|
+
// we should fire a onDragEnd responder
|
|
62
|
+
if (action.type === 'FLUSH') {
|
|
63
|
+
publisher.abort();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ## Perform drag updates
|
|
68
|
+
// impact of action has already been reduced
|
|
69
|
+
|
|
70
|
+
const state: State = store.getState();
|
|
71
|
+
if (state.phase === 'DRAGGING') {
|
|
72
|
+
publisher.update(state.critical, state.impact);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type { Position } from 'css-box-model';
|
|
3
|
+
import { moveByWindowScroll } from '../action-creators';
|
|
4
|
+
import type { MiddlewareStore, Action, Dispatch } from '../store-types';
|
|
5
|
+
import getScrollListener from '../../view/scroll-listener';
|
|
6
|
+
|
|
7
|
+
// TODO: this is taken from auto-scroll. Let's make it a util
|
|
8
|
+
const shouldEnd = (action: Action): boolean =>
|
|
9
|
+
action.type === 'DROP_COMPLETE' ||
|
|
10
|
+
action.type === 'DROP_ANIMATE' ||
|
|
11
|
+
action.type === 'FLUSH';
|
|
12
|
+
|
|
13
|
+
export default (store: MiddlewareStore) => {
|
|
14
|
+
const listener = getScrollListener({
|
|
15
|
+
onWindowScroll: (newScroll: Position) => {
|
|
16
|
+
store.dispatch(moveByWindowScroll({ newScroll }));
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return (next: Dispatch) => (action: Action): any => {
|
|
21
|
+
if (!listener.isActive() && action.type === 'INITIAL_PUBLISH') {
|
|
22
|
+
listener.start();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (listener.isActive() && shouldEnd(action)) {
|
|
26
|
+
listener.stop();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
next(action);
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type { Action, Dispatch } from '../store-types';
|
|
3
|
+
import type { StyleMarshal } from '../../view/use-style-marshal/style-marshal-types';
|
|
4
|
+
|
|
5
|
+
export default (marshal: StyleMarshal) => () => (next: Dispatch) => (
|
|
6
|
+
action: Action,
|
|
7
|
+
): any => {
|
|
8
|
+
if (action.type === 'INITIAL_PUBLISH') {
|
|
9
|
+
marshal.dragging();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (action.type === 'DROP_ANIMATE') {
|
|
13
|
+
marshal.dropping(action.payload.completed.result.reason);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// this will clear any styles immediately before a reorder
|
|
17
|
+
if (action.type === 'FLUSH' || action.type === 'DROP_COMPLETE') {
|
|
18
|
+
marshal.resting();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
next(action);
|
|
22
|
+
};
|