UNPKG

@atlaskit/renderer

Version:
204 lines • 7.04 kB
import { useLayoutEffect, useMemo, useState } from 'react'; import { AnnotationUpdateEvent } from '@atlaskit/editor-common/types'; import { AnnotationTypes } from '@atlaskit/adf-schema'; import { ACTION, ACTION_SUBJECT, EVENT_TYPE, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics'; import { FabricChannel } from '@atlaskit/analytics-listeners/types'; import { useAnnotationManagerDispatch, useAnnotationManagerState } from '../contexts/AnnotationManagerContext'; export const useAnnotationStateByTypeEvent = ({ type, updateSubscriber }) => { const [states, setStates] = useState({}); const { annotationManager, dispatch } = useAnnotationManagerDispatch(); const { annotations } = useAnnotationManagerState(); const isAnnotationManagerEnabled = !!annotationManager; useLayoutEffect(() => { if (!updateSubscriber) { return; } const cb = payload => { if (!payload) { return; } const nextStates = Object.values(payload).reduce((acc, curr) => { if (curr.id && curr.annotationType === type) { // Check for empty state to prevent additional renders const isEmpty = curr.state === null || curr.state === undefined; return { ...acc, [curr.id]: !isEmpty ? curr.state : states[curr.id] }; } return acc; }, {}); setStates({ ...states, ...nextStates }); }; if (!isAnnotationManagerEnabled) { updateSubscriber.on(AnnotationUpdateEvent.SET_ANNOTATION_STATE, cb); return () => { updateSubscriber.off(AnnotationUpdateEvent.SET_ANNOTATION_STATE, cb); }; } }, [states, type, updateSubscriber, dispatch, isAnnotationManagerEnabled]); const annotationMarkStates = useMemo(() => { return Object.values(annotations).reduce((acc, curr) => { return { ...acc, [curr.id]: curr.markState }; }, {}); }, [annotations]); if (isAnnotationManagerEnabled) { return annotationMarkStates; } else { return states; } }; export const useHasFocusEvent = ({ id, updateSubscriber }) => { const [hasFocus, setHasFocus] = useState(false); const [isHovered, setIsHovered] = useState(false); const { currentSelectedAnnotationId, currentHoveredAnnotationId } = useAnnotationManagerState(); const { annotationManager } = useAnnotationManagerDispatch(); const isAnnotationManagerEnabled = !!annotationManager; useLayoutEffect(() => { if (!updateSubscriber) { return; } const cb = payload => { setHasFocus(payload && payload.annotationId === id); }; const callbackForHoveredAnnotation = payload => { setIsHovered(payload && payload.annotationId === id); }; const removeFocus = () => { setHasFocus(false); }; const removeHoverEffect = () => { setIsHovered(false); }; if (!isAnnotationManagerEnabled) { updateSubscriber.on(AnnotationUpdateEvent.SET_ANNOTATION_FOCUS, cb); updateSubscriber.on(AnnotationUpdateEvent.SET_ANNOTATION_HOVERED, callbackForHoveredAnnotation); updateSubscriber.on(AnnotationUpdateEvent.REMOVE_ANNOTATION_FOCUS, removeFocus); updateSubscriber.on(AnnotationUpdateEvent.REMOVE_ANNOTATION_HOVERED, removeHoverEffect); return () => { updateSubscriber.off(AnnotationUpdateEvent.SET_ANNOTATION_FOCUS, cb); updateSubscriber.off(AnnotationUpdateEvent.SET_ANNOTATION_HOVERED, callbackForHoveredAnnotation); updateSubscriber.off(AnnotationUpdateEvent.REMOVE_ANNOTATION_FOCUS, removeFocus); updateSubscriber.off(AnnotationUpdateEvent.SET_ANNOTATION_HOVERED, removeHoverEffect); }; } }, [id, updateSubscriber, isAnnotationManagerEnabled]); if (isAnnotationManagerEnabled) { return { hasFocus: currentSelectedAnnotationId === id, isHovered: currentHoveredAnnotationId === id }; } else { return { hasFocus, isHovered }; } }; const NO_ANNOTATION_SELECTED = { annotations: [], clickElementTarget: undefined }; export const useAnnotationClickEvent = props => { const [annotationClickEvent, setAnnotationClickEvent] = useState(null); const { updateSubscriber, createAnalyticsEvent, isNestedRender } = props; const { annotationManager } = useAnnotationManagerDispatch(); const isAnnotationManagerEnabled = !!annotationManager; const { currentSelectedAnnotationId, currentSelectedMarkRef } = useAnnotationManagerState(); const selectedAnnotation = useMemo(() => { return currentSelectedAnnotationId && currentSelectedMarkRef && currentSelectedMarkRef.id === currentSelectedAnnotationId ? { annotations: [{ id: currentSelectedAnnotationId, type: AnnotationTypes.INLINE_COMMENT }], clickElementTarget: currentSelectedMarkRef } : // This is a constant to represent the case when no annotation is selected. // When creating a new annotation, currentSelectedAnnotationId and currentSelectedMarkRef will be set one after another, // if this isn't a const, it will cause useMemo to return two different "empty" objects and causes infinite re-renders. NO_ANNOTATION_SELECTED; }, [currentSelectedAnnotationId, currentSelectedMarkRef]); useLayoutEffect(() => { if (!updateSubscriber || isNestedRender) { return; } const clickCb = ({ annotationIds, eventTarget, eventTargetType, viewMethod }) => { const annotationsByType = annotationIds.filter(id => !!id).map(id => ({ id, type: AnnotationTypes.INLINE_COMMENT })); if (createAnalyticsEvent) { createAnalyticsEvent({ action: ACTION.VIEWED, actionSubject: ACTION_SUBJECT.ANNOTATION, actionSubjectId: ACTION_SUBJECT_ID.INLINE_COMMENT, eventType: EVENT_TYPE.TRACK, attributes: { overlap: annotationsByType.length || 0, targetNodeType: eventTargetType, method: viewMethod } }).fire(FabricChannel.editor); } setAnnotationClickEvent({ annotations: annotationsByType, clickElementTarget: eventTarget }); }; const deselectCb = () => { setAnnotationClickEvent({ annotations: [], clickElementTarget: undefined }); }; if (!isAnnotationManagerEnabled) { updateSubscriber.on(AnnotationUpdateEvent.ON_ANNOTATION_CLICK, clickCb); updateSubscriber.on(AnnotationUpdateEvent.DESELECT_ANNOTATIONS, deselectCb); return () => { updateSubscriber.off(AnnotationUpdateEvent.ON_ANNOTATION_CLICK, clickCb); updateSubscriber.off(AnnotationUpdateEvent.DESELECT_ANNOTATIONS, deselectCb); }; } }, [updateSubscriber, createAnalyticsEvent, isNestedRender, isAnnotationManagerEnabled]); if (isAnnotationManagerEnabled) { return isNestedRender ? null : selectedAnnotation; } else { return annotationClickEvent; } };