react-beautiful-dnd
Advanced tools
Comparing version 12.0.0-alpha.6 to 12.0.0-alpha.7
{ | ||
"name": "react-beautiful-dnd", | ||
"version": "12.0.0-alpha.6", | ||
"version": "12.0.0-alpha.7", | ||
"description": "Beautiful and accessible drag and drop for lists with React", | ||
@@ -36,2 +36,3 @@ "author": "Alex Reardon <areardon@atlassian.com>", | ||
"scripts": { | ||
"test:accessibility": "lighthouse http://localhost:9002/iframe.html?id=single-vertical-list--basic --chrome-flags='--headless' --output=json --output=html --output-path=./test-reports/lighthouse/a11y.json && node a11y-audit-parse.js", | ||
"test": "jest --config ./jest.config.js", | ||
@@ -59,10 +60,10 @@ "test:ci": "jest test --maxWorkers=2", | ||
"dependencies": { | ||
"@babel/runtime-corejs2": "^7.4.5", | ||
"css-box-model": "^1.1.2", | ||
"memoize-one": "^5.0.4", | ||
"raf-schd": "^4.0.1", | ||
"@babel/runtime-corejs2": "^7.5.2", | ||
"css-box-model": "^1.1.3", | ||
"memoize-one": "^5.0.5", | ||
"raf-schd": "^4.0.2", | ||
"react-redux": "^7.1.0", | ||
"redux": "^4.0.1", | ||
"tiny-invariant": "^1.0.4", | ||
"use-memo-one": "^1.1.0" | ||
"redux": "^4.0.2", | ||
"tiny-invariant": "^1.0.5", | ||
"use-memo-one": "^1.1.1" | ||
}, | ||
@@ -72,7 +73,7 @@ "devDependencies": { | ||
"@atlaskit/theme": "^9.1.1", | ||
"@babel/core": "^7.4.5", | ||
"@babel/plugin-proposal-class-properties": "^7.4.4", | ||
"@babel/plugin-transform-modules-commonjs": "^7.4.4", | ||
"@babel/plugin-transform-runtime": "^7.4.4", | ||
"@babel/preset-env": "^7.4.5", | ||
"@babel/core": "^7.5.0", | ||
"@babel/plugin-proposal-class-properties": "^7.5.0", | ||
"@babel/plugin-transform-modules-commonjs": "^7.5.0", | ||
"@babel/plugin-transform-runtime": "^7.5.0", | ||
"@babel/preset-env": "^7.5.2", | ||
"@babel/preset-flow": "^7.0.0", | ||
@@ -90,3 +91,3 @@ "@babel/preset-react": "^7.0.0", | ||
"babel-loader": "^8.0.6", | ||
"babel-plugin-dev-expression": "^0.2.1", | ||
"babel-plugin-dev-expression": "^0.2.2", | ||
"babel-plugin-emotion": "^10.0.14", | ||
@@ -112,15 +113,16 @@ "cross-env": "^5.2.0", | ||
"fs-extra": "^8.0.1", | ||
"globby": "^9.2.0", | ||
"globby": "^10.0.1", | ||
"jest": "^24.8.0", | ||
"jest-junit": "^6.4.0", | ||
"jest-watch-typeahead": "^0.3.1", | ||
"lighthouse": "^4.3.1", | ||
"markdown-it": "^8.4.2", | ||
"prettier": "^1.18.2", | ||
"raf-stub": "^2.0.2", | ||
"raf-stub": "^3.0.0", | ||
"react": "^16.8.6", | ||
"react-dom": "^16.8.6", | ||
"react-test-renderer": "^16.8.6", | ||
"react-window": "^1.8.3", | ||
"react-window": "^1.8.5", | ||
"rimraf": "^2.6.3", | ||
"rollup": "^1.16.2", | ||
"rollup": "^1.16.6", | ||
"rollup-plugin-babel": "^4.3.3", | ||
@@ -144,3 +146,3 @@ "rollup-plugin-commonjs": "^10.0.0", | ||
"wait-port": "^0.2.2", | ||
"webpack": "^4.35.0" | ||
"webpack": "^4.35.3" | ||
}, | ||
@@ -147,0 +149,0 @@ "peerDependencies": { |
@@ -34,3 +34,2 @@ // @flow | ||
const subject: Rect = draggable.page.marginBox; | ||
// 1. Can we scroll the viewport? | ||
@@ -37,0 +36,0 @@ if (state.isWindowScrollAllowed) { |
@@ -8,3 +8,6 @@ // @flow | ||
// TODO: memoization needed? | ||
export default memoizeOne((axis: Axis, displaceBy: Position): DisplacedBy => { | ||
export default memoizeOne(function getDisplacedBy( | ||
axis: Axis, | ||
displaceBy: Position, | ||
): DisplacedBy { | ||
const displacement: number = displaceBy[axis.line]; | ||
@@ -11,0 +14,0 @@ return { |
@@ -8,6 +8,4 @@ // @flow | ||
DroppableDimension, | ||
DisplacementMap, | ||
DisplacementGroups, | ||
DisplacedBy, | ||
DraggableIdMap, | ||
} from '../types'; | ||
@@ -89,42 +87,46 @@ import { isPartiallyVisible } from './visibility/is-visible'; | ||
}: Args): DisplacementGroups { | ||
const invisible: DraggableIdMap = {}; | ||
const visible: DisplacementMap = {}; | ||
const all: DraggableId[] = []; | ||
return afterDragging.reduce( | ||
function process( | ||
groups: DisplacementGroups, | ||
draggable: DraggableDimension, | ||
): DisplacementGroups { | ||
const target: Rect = getTarget(draggable, displacedBy); | ||
const id: DraggableId = draggable.descriptor.id; | ||
afterDragging.forEach(function process(draggable: DraggableDimension) { | ||
const target: Rect = getTarget(draggable, displacedBy); | ||
const id: DraggableId = draggable.descriptor.id; | ||
groups.all.push(id); | ||
all.push(id); | ||
const isVisible: boolean = isPartiallyVisible({ | ||
target, | ||
destination, | ||
viewport, | ||
withDroppableDisplacement: true, | ||
}); | ||
const isVisible: boolean = isPartiallyVisible({ | ||
// TODO: borderBox? | ||
target, | ||
destination, | ||
viewport, | ||
withDroppableDisplacement: true, | ||
}); | ||
if (!isVisible) { | ||
groups.invisible[draggable.descriptor.id] = true; | ||
return groups; | ||
} | ||
if (!isVisible) { | ||
invisible[draggable.descriptor.id] = true; | ||
return; | ||
} | ||
// item is visible | ||
// item is visible | ||
const shouldAnimate: boolean = getShouldAnimate( | ||
id, | ||
last, | ||
forceShouldAnimate, | ||
); | ||
const shouldAnimate: boolean = getShouldAnimate( | ||
id, | ||
last, | ||
forceShouldAnimate, | ||
); | ||
const displacement: Displacement = { | ||
draggableId: id, | ||
shouldAnimate, | ||
}; | ||
const displacement: Displacement = { | ||
draggableId: id, | ||
shouldAnimate, | ||
}; | ||
visible[id] = displacement; | ||
}); | ||
return { visible, all, invisible }; | ||
groups.visible[id] = displacement; | ||
return groups; | ||
}, | ||
{ | ||
all: [], | ||
visible: {}, | ||
invisible: {}, | ||
}, | ||
); | ||
} |
// @flow | ||
import invariant from 'tiny-invariant'; | ||
import messagePreset from '../util/screen-reader-message-preset'; | ||
import messagePreset from '../../../screen-reader-message-preset'; | ||
import * as timings from '../../../debug/timings'; | ||
@@ -5,0 +5,0 @@ import getExpiringAnnounce, { |
@@ -21,7 +21,7 @@ // @flow | ||
return (next: Dispatch) => (action: Action): any => { | ||
if (action.type === 'INITIAL_PUBLISH') { | ||
if (!listener.isActive() && action.type === 'INITIAL_PUBLISH') { | ||
listener.start(); | ||
} | ||
if (shouldEnd(action)) { | ||
if (listener.isActive() && shouldEnd(action)) { | ||
listener.stop(); | ||
@@ -28,0 +28,0 @@ } |
@@ -83,2 +83,5 @@ // @flow | ||
// We are moving from being between two displaced items | ||
// backwards onto the first one | ||
// need to find the first item before the closest | ||
@@ -93,3 +96,3 @@ const indexOfClosest: number = findIndex( | ||
// cannot move before start of set | ||
// There is no displaced item before | ||
if (proposedIndex < 0) { | ||
@@ -96,0 +99,0 @@ return null; |
// @flow | ||
import type { DragImpact, Displacement } from '../../types'; | ||
import getDisplacementMap from '../get-displacement-map'; | ||
// import getDisplacementMap from '../get-displacement-map'; | ||
@@ -5,0 +5,0 @@ export default (impact: DragImpact): DragImpact => { |
@@ -9,2 +9,3 @@ // @flow | ||
export type ContextId = Id; | ||
export type ElementId = Id; | ||
@@ -11,0 +12,0 @@ export type DroppableMode = 'STANDARD' | 'VIRTUAL'; |
// @flow | ||
import React from 'react'; | ||
import type { DraggableId, ContextId } from '../../types'; | ||
import type { DraggableId, ContextId, ElementId } from '../../types'; | ||
import type { DimensionMarshal } from '../../state/dimension-marshal/dimension-marshal-types'; | ||
@@ -13,4 +13,5 @@ import type { FocusMarshal } from '../use-focus-marshal/focus-marshal-types'; | ||
isMovementAllowed: () => boolean, | ||
liftInstructionId: ElementId, | ||
|}; | ||
export default React.createContext<?AppContextValue>(null); |
@@ -27,2 +27,3 @@ // @flow | ||
Sensor, | ||
ElementId, | ||
} from '../../types'; | ||
@@ -42,2 +43,3 @@ import type { Store, Action } from '../../state/store-types'; | ||
import useAnnouncer from '../use-announcer'; | ||
import useDragHandleDescription from '../use-lift-instruction'; | ||
import AppContext, { type AppContextValue } from '../context/app-context'; | ||
@@ -59,2 +61,3 @@ import useStartupValidation from './use-startup-validation'; | ||
enableDefaultSensors?: ?boolean, | ||
liftInstruction: string, | ||
|}; | ||
@@ -79,3 +82,3 @@ | ||
export default function App(props: Props) { | ||
const { contextId, setOnError, sensors } = props; | ||
const { contextId, setOnError, sensors, liftInstruction } = props; | ||
const lazyStoreRef: LazyStoreRef = useRef<?Store>(null); | ||
@@ -93,2 +96,7 @@ | ||
const announce: Announce = useAnnouncer(contextId); | ||
const liftInstructionId: ElementId = useDragHandleDescription( | ||
contextId, | ||
liftInstruction, | ||
); | ||
const styleMarshal: StyleMarshal = useStyleMarshal(contextId); | ||
@@ -141,8 +149,8 @@ | ||
createStore({ | ||
announce, | ||
autoScroller, | ||
dimensionMarshal, | ||
focusMarshal, | ||
getResponders, | ||
styleMarshal, | ||
announce, | ||
autoScroller, | ||
getResponders, | ||
}), | ||
@@ -198,2 +206,3 @@ [ | ||
isMovementAllowed: getIsMovementAllowed, | ||
liftInstructionId, | ||
}), | ||
@@ -206,2 +215,3 @@ [ | ||
getIsMovementAllowed, | ||
liftInstructionId, | ||
], | ||
@@ -208,0 +218,0 @@ ); |
@@ -6,2 +6,3 @@ // @flow | ||
import ErrorBoundary from '../error-boundary'; | ||
import preset from '../../screen-reader-message-preset'; | ||
import App from './app'; | ||
@@ -16,2 +17,3 @@ | ||
enableDefaultSensors?: ?boolean, | ||
liftInstruction?: string, | ||
|}; | ||
@@ -28,2 +30,4 @@ | ||
const contextId: ContextId = useMemo(() => `${instanceCount++}`, []); | ||
const liftInstruction: string = | ||
props.liftInstruction || preset.liftInstruction; | ||
@@ -35,3 +39,8 @@ // We need the error boundary to be on the outside of App | ||
{setOnError => ( | ||
<App setOnError={setOnError} contextId={contextId} {...props}> | ||
<App | ||
setOnError={setOnError} | ||
contextId={contextId} | ||
liftInstruction={liftInstruction} | ||
{...props} | ||
> | ||
{props.children} | ||
@@ -38,0 +47,0 @@ </App> |
@@ -235,18 +235,5 @@ // @flow | ||
} | ||
// const merge: ?CombineImpact = impact.merge; | ||
// const isCombinedWith: boolean = Boolean( | ||
// merge && merge.combine.draggableId === ownId, | ||
// ); | ||
const displaceBy: Position = impact.displacedBy.point; | ||
const offset: Position = memoizedOffset(displaceBy.x, displaceBy.y); | ||
// if (isCombinedWith) { | ||
// return getSecondaryProps( | ||
// displacement ? offset : origin, | ||
// draggingId, | ||
// displacement ? displacement.shouldAnimate : true, | ||
// ); | ||
// } | ||
return getMemoizedProps(offset, null, displacement.shouldAnimate); | ||
@@ -253,0 +240,0 @@ }; |
@@ -11,2 +11,3 @@ // @flow | ||
ContextId, | ||
ElementId, | ||
} from '../../types'; | ||
@@ -70,4 +71,4 @@ import { dropAnimationFinished } from '../../state/action-creators'; | ||
// Aria role (nicer screen reader text) | ||
'aria-roledescription': string, | ||
// id of drag handle aria description for screen readers | ||
'aria-labelledby': ElementId, | ||
@@ -74,0 +75,0 @@ // Allow tabbing to this element |
@@ -32,3 +32,3 @@ // @flow | ||
// context | ||
const { contextId } = useRequiredContext(AppContext); | ||
const { contextId, liftInstructionId } = useRequiredContext(AppContext); | ||
@@ -84,4 +84,3 @@ // props | ||
'data-rbd-drag-handle-context-id': contextId, | ||
// English default. Consumers are welcome to add their own start instruction | ||
'aria-roledescription': 'Draggable item. Press space bar to lift', | ||
'aria-labelledby': liftInstructionId, | ||
// Opting out of html5 drag and drops | ||
@@ -92,3 +91,3 @@ draggable: false, | ||
: null, | ||
[contextId, draggableId, isEnabled], | ||
[contextId, draggableId, isEnabled, liftInstructionId], | ||
); | ||
@@ -95,0 +94,0 @@ |
// @flow | ||
import invariant from 'tiny-invariant'; | ||
import type { Position } from 'css-box-model'; | ||
@@ -17,2 +18,3 @@ import rafSchd from 'raf-schd'; | ||
stop: () => void, | ||
isActive: () => boolean, | ||
|}; | ||
@@ -25,4 +27,2 @@ | ||
eventName: 'scroll', | ||
// TODO: should this be different for SNAP dragging? | ||
// ## Passive: true | ||
@@ -58,6 +58,12 @@ // Eventual consistency is fine because we use position: fixed on the item | ||
function isActive(): boolean { | ||
return unbind !== noop; | ||
} | ||
function start() { | ||
invariant(!isActive(), 'Cannot start scroll listener when already active'); | ||
unbind = bindEvents(window, [binding]); | ||
} | ||
function stop() { | ||
invariant(isActive(), 'Cannot stop scroll listener when not active'); | ||
scheduled.cancel(); | ||
@@ -68,3 +74,3 @@ unbind(); | ||
return { start, stop }; | ||
return { start, stop, isActive }; | ||
} |
@@ -8,18 +8,4 @@ // @flow | ||
import getBodyElement from '../get-body-element'; | ||
import visuallyHidden from '../visually-hidden-style'; | ||
// https://allyjs.io/tutorials/hiding-elements.html | ||
// Element is visually hidden but is readable by screen readers | ||
const visuallyHidden: Object = { | ||
position: 'absolute', | ||
width: '1px', | ||
height: '1px', | ||
margin: '-1px', | ||
border: '0', | ||
padding: '0', | ||
overflow: 'hidden', | ||
clip: 'rect(0 0 0 0)', | ||
// for if 'clip' is ever removed | ||
'clip-path': 'inset(100%)', | ||
}; | ||
export const getId = (contextId: ContextId): string => | ||
@@ -26,0 +12,0 @@ `rbd-announcement-${contextId}`; |
@@ -47,13 +47,7 @@ // @flow | ||
const idle: Idle = { type: 'IDLE' }; | ||
export const timeForLongPress: number = 150; | ||
// Decreased from 150 as a work around for an issue for forcepress on iOS | ||
// https://github.com/atlassian/react-beautiful-dnd/issues/1401 | ||
export const timeForLongPress: number = 120; | ||
export const forcePressThreshold: number = 0.15; | ||
// window.addEventListener( | ||
// 'touchmove', | ||
// (event: Event) => { | ||
// console.log('TOUCHMOVE. prevented?', event.defaultPrevented); | ||
// }, | ||
// { capture: false, passive: false }, | ||
// ); | ||
type GetBindingArgs = {| | ||
@@ -198,25 +192,42 @@ cancel: () => void, | ||
// Opting out of respecting force press interactions | ||
if (!phase.actions.shouldRespectForcePress()) { | ||
event.preventDefault(); | ||
// This is not fantastic logic, but it is done to account for | ||
// and issue with forcepress on iOS | ||
// Calling event.preventDefault() will currently opt out of scrolling and clicking | ||
// https://github.com/atlassian/react-beautiful-dnd/issues/1401 | ||
const touch: TouchWithForce = (event.touches[0]: any); | ||
const isForcePress: boolean = touch.force >= forcePressThreshold; | ||
if (!isForcePress) { | ||
return; | ||
} | ||
// A force push action will no longer fire after a touchmove | ||
// This is being super safe. While this situation should not occur we | ||
// are still expressing that we want to opt out of force pressing | ||
if (phase.type === 'DRAGGING' && phase.hasMoved) { | ||
event.preventDefault(); | ||
const shouldRespect: boolean = phase.actions.shouldRespectForcePress(); | ||
if (phase.type === 'PENDING') { | ||
if (shouldRespect) { | ||
cancel(); | ||
} | ||
// If not respecting we just let the event go through | ||
// It will not have an impact on the browser until | ||
// there has been a sufficient time ellapsed | ||
return; | ||
} | ||
// A drag could be pending or has already started but no movement has occurred | ||
// 'DRAGGING' | ||
const touch: TouchWithForce = (event.touches[0]: any); | ||
if (touch.force >= forcePressThreshold) { | ||
// this is an indirect cancel so we do not preventDefault | ||
// we also want to allow the force press to occur | ||
if (shouldRespect) { | ||
if (phase.hasMoved) { | ||
// After the user has moved we do not allow the dragging item to be force pressed | ||
// This prevents strange behaviour such as a link preview opening mid drag | ||
event.preventDefault(); | ||
return; | ||
} | ||
// indirect cancel | ||
cancel(); | ||
return; | ||
} | ||
// not respecting during a drag | ||
event.preventDefault(); | ||
}, | ||
@@ -451,3 +462,3 @@ }, | ||
return unbind; | ||
}); | ||
}, []); | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
243
1394087
73
38442
318
Updatedcss-box-model@^1.1.3
Updatedmemoize-one@^5.0.5
Updatedraf-schd@^4.0.2
Updatedredux@^4.0.2
Updatedtiny-invariant@^1.0.5
Updateduse-memo-one@^1.1.1