@measured/dnd
Advanced tools
Comparing version 16.6.0-canary.7ed6934 to 16.6.0-canary.a2766de
@@ -224,2 +224,3 @@ import { Position } from 'css-box-model'; | ||
shouldRespectForcePress?: boolean; | ||
disableSecondaryAnimation?: boolean; | ||
} | ||
@@ -226,0 +227,0 @@ |
{ | ||
"name": "@measured/dnd", | ||
"version": "16.6.0-canary.7ed6934", | ||
"version": "16.6.0-canary.a2766de", | ||
"private": false, | ||
"description": "Beautiful and accessible drag and drop for lists with React", | ||
"author": "Alex Reardon <areardon@atlassian.com>", | ||
"description": "Beautiful and accessible drag and drop for lists with React, with iframe and CSS transform support", | ||
"author": "Measured Corporation Ltd <hello@measured.co>", | ||
"maintainers": [ | ||
"Gabriel Santerre <gab@100terres.com>", | ||
"Reece Carolan <reece@hellopangea.com>" | ||
"Measured Corporation Ltd <hello@measured.co>" | ||
], | ||
@@ -25,6 +24,6 @@ "keywords": [ | ||
"type": "git", | ||
"url": "https://github.com/hello-pangea/dnd.git" | ||
"url": "https://github.com/measuredco/dnd.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/hello-pangea/dnd/issues" | ||
"url": "https://github.com/measuredco/dnd/issues" | ||
}, | ||
@@ -80,2 +79,3 @@ "main": "dist/dnd.cjs.js", | ||
"css-box-model": "^1.2.1", | ||
"lru-cache": "^10.2.0", | ||
"memoize-one": "^6.0.0", | ||
@@ -108,4 +108,4 @@ "raf-schd": "^4.0.3", | ||
"@emotion/styled": "11.11.0", | ||
"@jest/environment": "29.7.0", | ||
"@measured/auto-frame-component": "0.1.0-canary.4686711", | ||
"@jest/environment": "29.7.0", | ||
"@release-it/conventional-changelog": "8.0.1", | ||
@@ -112,0 +112,0 @@ "@rollup/plugin-babel": "6.0.4", |
@@ -11,3 +11,3 @@ import rafSchd from 'raf-schd'; | ||
export interface PublicArgs { | ||
scrollWindow: (change: Position) => void; | ||
scrollWindow: (change: Position, win?: Window) => void; | ||
scrollDroppable: (id: DroppableId, change: Position) => void; | ||
@@ -14,0 +14,0 @@ getAutoScrollerOptions?: () => AutoScrollerOptions; |
@@ -14,2 +14,3 @@ import type { Position, Rect } from 'css-box-model'; | ||
import { AutoScrollerOptions } from './auto-scroller-options-types'; | ||
import getIframeScroll from './get-iframe-scroll'; | ||
@@ -20,3 +21,3 @@ interface Args { | ||
shouldUseTimeDampening: boolean; | ||
scrollWindow: (scroll: Position) => void; | ||
scrollWindow: (scroll: Position, win?: Window) => void; | ||
scrollDroppable: (id: DroppableId, scroll: Position) => void; | ||
@@ -56,2 +57,16 @@ getAutoScrollerOptions: () => AutoScrollerOptions; | ||
const iframeScroll = getIframeScroll({ | ||
state, | ||
dragStartTime, | ||
shouldUseTimeDampening, | ||
getAutoScrollerOptions, | ||
draggable, | ||
}); | ||
if (iframeScroll?.change) { | ||
scrollWindow(iframeScroll.change, iframeScroll.window); | ||
return; | ||
} | ||
const droppable: DroppableDimension | null = getBestScrollableDroppable({ | ||
@@ -58,0 +73,0 @@ center, |
@@ -14,2 +14,3 @@ import type { BoxModel, Position } from 'css-box-model'; | ||
import getSubject from './util/get-subject'; | ||
import { Transform } from '../../view/transform'; | ||
@@ -34,2 +35,3 @@ export interface Closest { | ||
closest?: Closest | null; | ||
transform: Transform | null; | ||
} | ||
@@ -46,2 +48,3 @@ | ||
closest, | ||
transform, | ||
}: Args): DroppableDimension => { | ||
@@ -100,2 +103,3 @@ const frame: Scrollable | null = (() => { | ||
subject, | ||
transform, | ||
}; | ||
@@ -102,0 +106,0 @@ |
@@ -156,2 +156,3 @@ import type { BoxModel, Rect, Position } from 'css-box-model'; | ||
subject: DroppableSubject; | ||
transform: Transform | null; | ||
} | ||
@@ -158,0 +159,0 @@ export interface DraggableLocation { |
@@ -23,2 +23,3 @@ import type { Position } from 'css-box-model'; | ||
Combine, | ||
DroppableDimension, | ||
} from '../../types'; | ||
@@ -218,2 +219,3 @@ import type { | ||
snapshot: getSecondarySnapshot(null), | ||
sourceDroppable: null, | ||
}, | ||
@@ -239,2 +241,3 @@ }; | ||
dimension?: DraggableDimension, | ||
sourceDroppable?: DroppableDimension | null, | ||
): MapProps => ({ | ||
@@ -248,2 +251,3 @@ mapped: { | ||
dimension, | ||
sourceDroppable: sourceDroppable || null, | ||
}, | ||
@@ -257,5 +261,6 @@ }), | ||
combineTargetFor?: DraggableId | null, | ||
disableSecondaryAnimation?: boolean, | ||
): MapProps | null => { | ||
return combineTargetFor | ||
? getMemoizedProps(origin, combineTargetFor, true) | ||
? getMemoizedProps(origin, combineTargetFor, !disableSecondaryAnimation) | ||
: null; | ||
@@ -270,2 +275,4 @@ }; | ||
dimension?: DraggableDimension, | ||
sourceDroppable?: DroppableDimension | null, | ||
disableSecondaryAnimation?: boolean, | ||
): MapProps | null => { | ||
@@ -284,3 +291,3 @@ const visualDisplacement: Displacement | null = | ||
if (!isAfterCriticalInVirtualList) { | ||
return getFallback(combineTargetFor); | ||
return getFallback(combineTargetFor, disableSecondaryAnimation); | ||
} | ||
@@ -302,3 +309,9 @@ | ||
const offset: Position = memoizedOffset(change.x, change.y); | ||
return getMemoizedProps(offset, combineTargetFor, true, dimension); | ||
return getMemoizedProps( | ||
offset, | ||
combineTargetFor, | ||
!disableSecondaryAnimation, | ||
dimension, | ||
sourceDroppable, | ||
); | ||
} | ||
@@ -318,4 +331,5 @@ | ||
combineTargetFor, | ||
visualDisplacement.shouldAnimate, | ||
disableSecondaryAnimation ? false : visualDisplacement.shouldAnimate, | ||
dimension, | ||
sourceDroppable, | ||
); | ||
@@ -337,2 +351,6 @@ }; | ||
const sourceDroppable = state.critical.droppable.id | ||
? state.dimensions.droppables[state.critical.droppable.id] | ||
: null; | ||
return getProps( | ||
@@ -344,2 +362,4 @@ ownProps.draggableId, | ||
dimension, | ||
sourceDroppable, | ||
ownProps.disableSecondaryAnimation, | ||
); | ||
@@ -357,2 +377,6 @@ } | ||
const sourceDroppable = completed.critical.droppable.id | ||
? state.dimensions.droppables[completed.critical.droppable.id] | ||
: null; | ||
return getProps( | ||
@@ -364,2 +388,4 @@ ownProps.draggableId, | ||
dimension, | ||
sourceDroppable, | ||
ownProps.disableSecondaryAnimation, | ||
); | ||
@@ -381,7 +407,24 @@ } | ||
const selector = (state: State, ownProps: OwnProps): MapProps => | ||
draggingSelector(state, ownProps) || | ||
secondarySelector(state, ownProps) || | ||
atRest; | ||
const selector = (state: State, ownProps: OwnProps): MapProps => { | ||
// Modify atRest based on props | ||
const atRestLocal = | ||
atRest.mapped.type === 'DRAGGING' | ||
? atRest | ||
: { | ||
...atRest, | ||
mapped: { | ||
...atRest.mapped, | ||
shouldAnimateDisplacement: ownProps.disableSecondaryAnimation | ||
? false | ||
: atRest.mapped.shouldAnimateDisplacement, | ||
}, | ||
}; | ||
return ( | ||
draggingSelector(state, ownProps) || | ||
secondarySelector(state, ownProps) || | ||
atRestLocal | ||
); | ||
}; | ||
return selector; | ||
@@ -388,0 +431,0 @@ }; |
@@ -16,2 +16,3 @@ import type { Position } from 'css-box-model'; | ||
DraggableRubric, | ||
DroppableDimension, | ||
} from '../../types'; | ||
@@ -144,2 +145,3 @@ import { dropAnimationFinished } from '../../state/action-creators'; | ||
dimension?: DraggableDimension; | ||
sourceDroppable: DroppableDimension | null; | ||
} | ||
@@ -171,2 +173,3 @@ | ||
shouldRespectForcePress?: boolean; | ||
disableSecondaryAnimation?: boolean; | ||
} | ||
@@ -173,0 +176,0 @@ |
@@ -14,3 +14,2 @@ import type { BoxModel } from 'css-box-model'; | ||
} from './draggable-types'; | ||
import { applyTransformPoint } from '../transform'; | ||
@@ -64,18 +63,10 @@ export const zIndexOptions: ZIndexOptions = { | ||
const transformedOffset = dimension.transform | ||
? applyTransformPoint( | ||
offset.x, | ||
offset.y, | ||
{ | ||
...dimension.transform.matrix, | ||
scaleX: 1 / dimension.transform.matrix.scaleX, | ||
scaleY: 1 / dimension.transform.matrix.scaleY, | ||
}, | ||
{ ...dimension.transform.origin }, | ||
) | ||
: offset; | ||
const untransformedOffset = { | ||
x: offset.x / (dimension?.transform?.matrix.scaleX || 1), | ||
y: offset.y / (dimension?.transform?.matrix.scaleY || 1), | ||
}; | ||
const transform: string | undefined = isDropAnimating | ||
? transforms.drop(transformedOffset, isCombining) | ||
: transforms.moveTo(transformedOffset); | ||
? transforms.drop(untransformedOffset, isCombining) | ||
: transforms.moveTo(untransformedOffset); | ||
@@ -113,10 +104,8 @@ const style: DraggingStyle = { | ||
function getSecondaryStyle(secondary: SecondaryMapProps): NotDraggingStyle { | ||
const { offset, sourceDroppable } = secondary; | ||
return { | ||
transform: transforms.moveTo({ | ||
x: | ||
secondary.offset.x / | ||
(secondary.dimension?.transform?.matrix.scaleX || 1), | ||
y: | ||
secondary.offset.y / | ||
(secondary.dimension?.transform?.matrix.scaleY || 1), | ||
x: offset.x / (sourceDroppable?.transform?.matrix.scaleX || 1), | ||
y: offset.y / (sourceDroppable?.transform?.matrix.scaleY || 1), | ||
}), | ||
@@ -123,0 +112,0 @@ // transition style is applied in the head |
@@ -1,2 +0,1 @@ | ||
import { IframeHTMLAttributes } from 'react'; | ||
import { querySelectorAll } from '../../query-selector-all'; | ||
@@ -21,2 +20,22 @@ import type { | ||
let loaded = false; | ||
function bindEvent(win: Window, binding: EventBinding, options: EventOptions) { | ||
let timer: number | undefined; | ||
if (!loaded) { | ||
// Some browsers require us to defer binding events, i.e. Safari | ||
timer = setInterval(() => { | ||
if ((win as Window).document.readyState === 'complete') { | ||
win.addEventListener(binding.eventName, binding.fn, options); | ||
loaded = true; | ||
} | ||
}, 100); | ||
} else { | ||
win.addEventListener(binding.eventName, binding.fn, options); | ||
} | ||
return timer; | ||
} | ||
export default function bindEvents( | ||
@@ -31,3 +50,3 @@ el: HTMLElement | Window, | ||
window.document, | ||
'iframe', | ||
'[data-rfd-iframe]', | ||
) as HTMLIFrameElement[]; | ||
@@ -42,5 +61,6 @@ | ||
win.addEventListener(binding.eventName, binding.fn, options); | ||
const timer = bindEvent(win as Window, binding, options); | ||
return function unbind() { | ||
clearInterval(timer); | ||
win.removeEventListener(binding.eventName, binding.fn, options); | ||
@@ -47,0 +67,0 @@ }; |
@@ -0,1 +1,2 @@ | ||
import { LRUCache } from 'lru-cache'; | ||
import type { DraggableId, ContextId } from '../../types'; | ||
@@ -7,2 +8,7 @@ import { dragHandle as dragHandleAttr } from '../data-attributes'; | ||
const dragHandleCache = new LRUCache<string, HTMLElement>({ | ||
max: 5000, | ||
ttl: 1000, | ||
}); | ||
export default function findDragHandle( | ||
@@ -15,2 +21,8 @@ contextId: ContextId, | ||
const cachedHandle = dragHandleCache.get(selector); | ||
if (cachedHandle) { | ||
return cachedHandle; | ||
} | ||
const possible = querySelectorAllIframe(selector); | ||
@@ -41,3 +53,5 @@ | ||
dragHandleCache.set(selector, handle); | ||
return handle; | ||
} |
@@ -0,1 +1,9 @@ | ||
import { LRUCache } from 'lru-cache'; | ||
import { querySelectorAll } from '../../query-selector-all'; | ||
const iframeCache = new LRUCache<string, HTMLIFrameElement[]>({ | ||
max: 1, | ||
ttl: 1000, | ||
}); | ||
/** | ||
@@ -6,8 +14,16 @@ * querySelectorAllIframe | ||
*/ | ||
export default function querySelectorAllIframe(selector: string) { | ||
let iframes = iframeCache.get('iframes'); | ||
import { querySelectorAll } from '../../query-selector-all'; | ||
if (!iframes) { | ||
iframes = querySelectorAll(document, 'iframe') as HTMLIFrameElement[]; | ||
export default function querySelectorAllIframe(selector: string) { | ||
const iframes = querySelectorAll(document, 'iframe') as HTMLIFrameElement[]; | ||
// Quicker than running the [data-rbd-frame] query | ||
iframes = iframes.filter((iframe) => | ||
iframe.hasAttribute('data-rfd-iframe'), | ||
); | ||
iframeCache.set('iframes', iframes); | ||
} | ||
const iframePossible = iframes.reduce<HTMLElement[]>( | ||
@@ -14,0 +30,0 @@ (acc, iframe) => [ |
@@ -101,2 +101,14 @@ import { BoxModel, Rect, Spacing } from 'css-box-model'; | ||
const defaultTransform = { | ||
matrix: { | ||
scaleX: 1, | ||
scaleY: 1, | ||
skewX: 0, | ||
skewY: 0, | ||
translateX: 0, | ||
translateY: 0, | ||
}, | ||
origin: { x: 0, y: 0 }, | ||
}; | ||
/** | ||
@@ -117,3 +129,3 @@ * Gets the transform of the element based on transform styles | ||
if (!transformEl) return null; | ||
if (!transformEl) return defaultTransform; | ||
@@ -132,3 +144,3 @@ const styles = window.getComputedStyle(transformEl); | ||
return null; | ||
return defaultTransform; | ||
}; | ||
@@ -135,0 +147,0 @@ |
import { calculateBox, withScroll } from 'css-box-model'; | ||
import type { BoxModel, Position } from 'css-box-model'; | ||
import type { Position } from 'css-box-model'; | ||
import type { | ||
@@ -20,3 +20,7 @@ DraggableDescriptor, | ||
let client = calculateBox(el.getBoundingClientRect(), computedStyles); | ||
const originalClient = calculateBox( | ||
el.getBoundingClientRect(), | ||
computedStyles, | ||
); | ||
let client = { ...originalClient }; | ||
let page = withScroll( | ||
@@ -41,3 +45,3 @@ calculateBox(el.getBoundingClientRect(), computedStyles), | ||
const placeholder: Placeholder = { | ||
client, | ||
client: originalClient, | ||
tagName: el.tagName.toLowerCase(), | ||
@@ -44,0 +48,0 @@ display: computedStyles.display, |
@@ -13,3 +13,6 @@ import { getBox, withScroll, createBox, expand } from 'css-box-model'; | ||
import getScroll from './get-scroll'; | ||
import getOffsettedBox from '../iframe/get-offsetted-box'; | ||
import getIframeOffset from '../iframe/get-iframe-offset'; | ||
import { applyOffsetBox } from '../iframe/apply-offset'; | ||
import { Transform, applyTransformBox, getTransform } from '../transform'; | ||
import { Offset } from '../iframe/offset-types'; | ||
@@ -19,5 +22,15 @@ const getClient = ( | ||
closestScrollable?: Element | null, | ||
offset?: Offset | null, | ||
transform?: Transform | null, | ||
): BoxModel => { | ||
const base: BoxModel = getOffsettedBox(targetRef); | ||
let base: BoxModel = getBox(targetRef); | ||
if (transform) { | ||
base = applyTransformBox(base, transform); | ||
} | ||
if (offset) { | ||
base = applyOffsetBox(base, offset); | ||
} | ||
// Droppable has no scroll parent | ||
@@ -85,2 +98,3 @@ if (!closestScrollable) { | ||
shouldClipSubject: boolean; | ||
transform: Transform | null; | ||
} | ||
@@ -99,3 +113,5 @@ | ||
const closestScrollable: Element | null = env.closestScrollable; | ||
const client: BoxModel = getClient(ref, closestScrollable); | ||
const offset = getIframeOffset(ref); | ||
const transform = getTransform(ref, { x: 0, y: 0 }); | ||
const client: BoxModel = getClient(ref, closestScrollable, offset, transform); | ||
const page: BoxModel = withScroll(client, windowScroll); | ||
@@ -132,2 +148,3 @@ | ||
closest, | ||
transform, | ||
}); | ||
@@ -134,0 +151,0 @@ |
import type { Position } from 'css-box-model'; | ||
import { getTransform } from '../transform'; | ||
@@ -7,5 +8,10 @@ export default (el: Element): Position => { | ||
if (isIframe) { | ||
const targetEl = (el as HTMLIFrameElement).contentWindow!; | ||
const win = (el as HTMLIFrameElement).contentWindow!; | ||
return { x: targetEl.scrollX, y: targetEl.scrollY }; | ||
const transform = getTransform(el as HTMLElement); | ||
return { | ||
x: win.scrollX * (transform?.matrix.scaleX || 1), | ||
y: win.scrollY * (transform?.matrix.scaleY || 1), | ||
}; | ||
} | ||
@@ -12,0 +18,0 @@ |
@@ -7,3 +7,3 @@ import { useRef } from 'react'; | ||
import { invariant } from '../../invariant'; | ||
import checkForNestedScrollContainers from './check-for-nested-scroll-container'; | ||
// import checkForNestedScrollContainers from './check-for-nested-scroll-container'; | ||
import * as dataAttr from '../data-attributes'; | ||
@@ -173,5 +173,5 @@ import { origin } from '../../state/position'; | ||
// print a debug warning if using an unsupported nested scroll container setup | ||
if (process.env.NODE_ENV !== 'production') { | ||
checkForNestedScrollContainers(scrollable); | ||
} | ||
// if (process.env.NODE_ENV !== 'production') { | ||
// checkForNestedScrollContainers(scrollable); | ||
// } | ||
} | ||
@@ -178,0 +178,0 @@ |
import { Position } from 'css-box-model'; | ||
import { applyTransformPoint, getMatrix, getOrigin } from '../../../transform'; | ||
import { applyTransformPoint, getTransform } from '../../../transform'; | ||
@@ -16,7 +16,4 @@ export default function offsetPoint( | ||
const iframeStyles = window.getComputedStyle(iframe); | ||
const transform = getTransform(iframe); | ||
const transform = getMatrix(iframeStyles.transform); | ||
const origin = getOrigin(iframeStyles.transformOrigin) || { x: 0, y: 0 }; | ||
offsetX = rect.left; | ||
@@ -29,4 +26,4 @@ offsetY = rect.top; | ||
y, | ||
transform, | ||
origin, | ||
transform.matrix, | ||
transform.origin, | ||
); | ||
@@ -33,0 +30,0 @@ |
@@ -1,2 +0,1 @@ | ||
import { useRef, MutableRefObject } from 'react'; | ||
import memoizeOne from 'memoize-one'; | ||
@@ -11,6 +10,7 @@ import { useMemo, useCallback } from 'use-memo-one'; | ||
import useLayoutEffect from '../use-isomorphic-layout-effect'; | ||
import { querySelectorAll } from '../../query-selector-all'; | ||
import querySelectorAllIframe from '../iframe/query-selector-all-iframe'; | ||
const getHead = (): HTMLHeadElement => { | ||
const head: HTMLHeadElement | null = document.querySelector('head'); | ||
invariant(head, 'Cannot find the head to append a style to'); | ||
const getHead = (doc: Document): HTMLHeadElement | null => { | ||
const head: HTMLHeadElement | null = doc.querySelector('head'); | ||
return head; | ||
@@ -28,6 +28,7 @@ }; | ||
const alwaysDataAttr = `${prefix}-always`; | ||
const dynamicDataAttr = `${prefix}-dynamic`; | ||
export default function useStyleMarshal(contextId: ContextId, nonce?: string) { | ||
const styles: Styles = useMemo(() => getStyles(contextId), [contextId]); | ||
const alwaysRef = useRef<HTMLStyleElement | null>(null); | ||
const dynamicRef = useRef<HTMLStyleElement | null>(null); | ||
@@ -38,51 +39,83 @@ // eslint-disable-next-line react-hooks/exhaustive-deps | ||
memoizeOne((proposed: string) => { | ||
const el: HTMLStyleElement | null = dynamicRef.current; | ||
invariant(el, 'Cannot set dynamic style element if it is not set'); | ||
el.textContent = proposed; | ||
const selector = `[${dynamicDataAttr}="${contextId}"]`; | ||
querySelectorAllIframe(selector).forEach((el) => { | ||
invariant(el, 'Cannot set dynamic style element if it is not set'); | ||
el.textContent = proposed; | ||
}); | ||
}), | ||
[], | ||
[contextId], | ||
); | ||
const setAlwaysStyle = useCallback((proposed: string) => { | ||
const el: HTMLStyleElement | null = alwaysRef.current; | ||
invariant(el, 'Cannot set dynamic style element if it is not set'); | ||
el.textContent = proposed; | ||
}, []); | ||
const setAlwaysStyle = useCallback( | ||
(proposed: string) => { | ||
const selector = `[${alwaysDataAttr}="${contextId}"]`; | ||
querySelectorAllIframe(selector).forEach((el) => { | ||
invariant(el, 'Cannot set dynamic style element if it is not set'); | ||
el.textContent = proposed; | ||
}); | ||
}, | ||
[contextId], | ||
); | ||
// using layout effect as programatic dragging might start straight away (such as for cypress) | ||
useLayoutEffect(() => { | ||
invariant( | ||
!alwaysRef.current && !dynamicRef.current, | ||
'style elements already mounted', | ||
); | ||
const alwaysSelector = `[${alwaysDataAttr}="${contextId}"]`; | ||
const dynamicSelector = `[${dynamicDataAttr}="${contextId}"]`; | ||
const always: HTMLStyleElement = createStyleEl(nonce); | ||
const dynamic: HTMLStyleElement = createStyleEl(nonce); | ||
const heads = [ | ||
getHead(document), | ||
...( | ||
querySelectorAll(document, `[${prefix}-iframe]`) as HTMLIFrameElement[] | ||
).map((iframe) => getHead(iframe.contentWindow!.document)), | ||
]; | ||
// store their refs | ||
alwaysRef.current = always; | ||
dynamicRef.current = dynamic; | ||
// Create initial style elements | ||
heads.forEach((head) => { | ||
if (!head) return; | ||
// for easy identification | ||
always.setAttribute(`${prefix}-always`, contextId); | ||
dynamic.setAttribute(`${prefix}-dynamic`, contextId); | ||
const alwaysElements = querySelectorAll( | ||
head.ownerDocument, | ||
alwaysSelector, | ||
); | ||
const dynamicElements = querySelectorAll( | ||
head.ownerDocument, | ||
dynamicSelector, | ||
); | ||
// add style tags to head | ||
getHead().appendChild(always); | ||
getHead().appendChild(dynamic); | ||
if ( | ||
alwaysElements.length >= heads.length || | ||
dynamicElements.length >= heads.length | ||
) { | ||
return; | ||
} | ||
// set initial style | ||
setAlwaysStyle(styles.always); | ||
setDynamicStyle(styles.resting); | ||
const always: HTMLStyleElement = createStyleEl(nonce); | ||
const dynamic: HTMLStyleElement = createStyleEl(nonce); | ||
// for easy identification | ||
always.setAttribute(alwaysDataAttr, contextId); | ||
dynamic.setAttribute(dynamicDataAttr, contextId); | ||
head.appendChild(always); | ||
head.appendChild(dynamic); | ||
// set initial style | ||
setAlwaysStyle(styles.always); | ||
setDynamicStyle(styles.resting); | ||
}); | ||
return () => { | ||
const remove = (ref: MutableRefObject<HTMLStyleElement | null>) => { | ||
const current: HTMLStyleElement | null = ref.current; | ||
invariant(current, 'Cannot unmount ref as it is not set'); | ||
getHead().removeChild(current); | ||
ref.current = null; | ||
const remove = (selector: string) => { | ||
const elements = querySelectorAllIframe(selector); | ||
elements.forEach((el) => { | ||
invariant(el, 'Cannot unmount element as it is not set'); | ||
el.ownerDocument.head.removeChild(el); | ||
}); | ||
}; | ||
remove(alwaysRef); | ||
remove(dynamicRef); | ||
remove(alwaysSelector); | ||
remove(dynamicSelector); | ||
}; | ||
@@ -113,6 +146,2 @@ }, [ | ||
const resting = useCallback(() => { | ||
// Can be called defensively | ||
if (!dynamicRef.current) { | ||
return; | ||
} | ||
setDynamicStyle(styles.resting); | ||
@@ -119,0 +148,0 @@ }, [setDynamicStyle, styles.resting]); |
import type { Position } from 'css-box-model'; | ||
// Not guarenteed to scroll by the entire amount | ||
export default (change: Position): void => { | ||
window.scrollBy(change.x, change.y); | ||
// Not guaranteed to scroll by the entire amount | ||
export default (change: Position, win: Window = window): void => { | ||
win.scrollBy(change.x, change.y); | ||
}; |
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
1423380
41501
270
10
252
+ Addedlru-cache@^10.2.0
+ Addedlru-cache@10.4.3(transitive)