@pie-element/image-cloze-association 10.3.0 → 10.3.1-beta.2

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/lib/root.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"root.js","names":["_react","_interopRequireDefault","require","_propTypes","_core","_drag","_reactTransitionGroup","_renderUi","_styles","_NotInterested","_correctAnswerToggle","_translator","_lodashEs","_imageContainer","_interactiveSection","_possibleResponses2","_utilsCorrectness","_possibleResponse","_keyboardCoordinates","translator","Translator","generateId","Math","random","toString","substring","Date","getTime","CLICK_AFTER_DRAG_GUARD_MS","StyledUiLayout","styled","UiLayout","color","text","backgroundColor","background","position","maxWidth","height","StyledTeacherInstructions","Collapsible","theme","marginBottom","spacing","StyledRationale","marginTop","ImageClozeAssociationComponent","React","Component","constructor","props","_defineProperty2","default","event","active","data","current","setState","draggingElement","isValidDrop","selectedResponse","over","model","duplicateResponses","draggedItem","responseArea","containerIndex","undefined","shouldDisableAnimation","id","value","cancelSelection","lastDragEndAt","now","handleOnAnswerRemove","handleOnAnswerSelect","a","b","state","isSameResponse","document","dispatchEvent","KeyboardEvent","code","bubbles","cancelable","endAnyLiveKeyboardDrag","isClickSoonAfterDragEnd","toggleResponseSelection","placeSelectedResponse","imgRegex","containsImage","test","createElement","key","canDrag","onDragBegin","isOverlay","containerStyle","answerChoiceTransparency","opacity","padding","margin","possibleResponses","answer","filter","response","responseContainerIndex","updateAnswer","answers","maxResponsePerZone","answersToStore","answersInThisContainer","answersInOtherContainers","forEach","push","length","shiftedItem","shift","maxResponsePerZoneWarning","Array","isArray","filterPossibleAnswers","shouldNotPushInPossibleResponses","showCorrect","responseContainers","session","possibleResponsesWithIds","map","item","index","groupedAnswers","groupBy","limitedAnswers","flatMap","grp","slice","possibleResponsesFiltered","find","render","disabled","extraCSSRules","image","responseAreaFill","stimulus","responseCorrect","validation","teacherInstructions","prompt","autoplayAudioEnabled","showDashedBorder","mode","rationale","language","uiStyle","responseContainerPadding","imageDropTargetPadding","fontSizeFactor","customAudioButton","isEvaluateMode","showToggle","possibilityListPosition","isVertical","validResponse","correctAnswers","showRationale","hasText","hasMedia","showTeacherInstructions","container","i","images","v","isCorrect","warningMessage","t","lng","count","answersToShow","getAnswersCorrectness","getUnansweredAnswers","sharedImageProps","onAnswerSelect","onDragAnswerBegin","onDragStart","onDragAnswerEnd","onDragEnd","onSelectClick","onResponseClick","onPlacementClick","renderImage","_extends2","renderPossibleResponses","Fragment","WarningInfo","message","onAnswerRemove","customStyle","minWidth","width","minHeight","DragProvider","onDragCancel","keyboardCoordinateGetter","closestDroppableKeyboardCoordinates","keyboardCodes","start","cancel","end","labels","hidden","visible","PreviewPrompt","className","show","toggled","onToggle","toggleCorrect","DragOverlay","dropAnimation","renderDragOverlay","exports","WarningContainer","display","alignItems","WarningMessage","paddingLeft","userSelect","nodeRef","useRef","TransitionGroup","CSSTransition","classNames","timeout","ref","fontSize","dangerouslySetInnerHTML","__html","propTypes","PropTypes","string","object","isRequired","func","_default"],"sources":["../src/root.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { DragOverlay } from '@dnd-kit/core';\nimport { DragProvider } from '@pie-lib/drag';\nimport { CSSTransition, TransitionGroup } from 'react-transition-group';\nimport { color, Collapsible, PreviewPrompt, UiLayout, hasText, hasMedia } from '@pie-lib/render-ui';\nimport { styled } from '@mui/material/styles';\nimport NotInterestedIcon from '@mui/icons-material/NotInterested';\nimport CorrectAnswerToggle from '@pie-lib/correct-answer-toggle';\nimport Translator from '@pie-lib/translator';\nimport { flatMap, groupBy } from 'lodash-es';\n\nconst { translator } = Translator;\nimport Image from './image-container';\nimport InteractiveSection from './interactive-section';\nimport PossibleResponses from './possible-responses';\nimport { getUnansweredAnswers, getAnswersCorrectness } from './utils-correctness';\nimport PossibleResponse from './possible-response';\nimport { closestDroppableKeyboardCoordinates } from './keyboard-coordinates';\n\nconst generateId = () => Math.random().toString(36).substring(2) + new Date().getTime().toString(36);\n\n// A click that lands right after a real drag gesture ends (pointer drag-and-drop, or\n// the browser's own synthetic click for a keyboard Space/Enter) must be ignored by the\n// click-to-select/click-to-place handlers below, or it would immediately reopen or\n// re-trigger a selection for a drag that just completed.\nconst CLICK_AFTER_DRAG_GUARD_MS = 250;\n\nconst StyledUiLayout = styled(UiLayout)({\n color: color.text(),\n backgroundColor: color.background(),\n position: 'relative',\n '& img': {\n maxWidth: '100%',\n height: 'auto',\n },\n});\n\nconst StyledTeacherInstructions = styled(Collapsible)(({ theme }) => ({\n marginBottom: theme.spacing(2),\n}));\n\nconst StyledRationale = styled(Collapsible)(({ theme }) => ({\n marginTop: theme.spacing(2),\n}));\n\nexport class ImageClozeAssociationComponent extends React.Component {\n constructor(props) {\n super(props);\n const {\n model: { possibleResponses, responseContainers, duplicateResponses, maxResponsePerZone },\n session,\n } = props;\n let { answers } = session || {};\n // set id for each possible response\n const possibleResponsesWithIds = (possibleResponses || []).map((item, index) => ({\n value: item,\n id: `${index}`,\n }));\n\n let groupedAnswers = groupBy(answers || [], 'containerIndex');\n // keep only last maxResponsePerZone answers for each zone\n let limitedAnswers = flatMap(groupedAnswers, (grp) => grp.slice(-(maxResponsePerZone || 1)));\n answers = limitedAnswers\n // set id for each answer\n .map((answer, index) => ({ ...answer, id: `${index}` }))\n // return only answer which have a valid container index\n .filter((answer) => answer.containerIndex < responseContainers.length);\n\n const possibleResponsesFiltered = possibleResponsesWithIds.filter(\n (response) => !answers.find((answer) => answer.value === response.value),\n );\n this.state = {\n answers: answers || [],\n draggingElement: { id: '', value: '' },\n possibleResponses: duplicateResponses ? possibleResponsesWithIds : possibleResponsesFiltered,\n // set id for each response containers\n responseContainers: (responseContainers || []).map((item, index) => ({\n index,\n ...item,\n id: `${index}`,\n })),\n maxResponsePerZone: maxResponsePerZone || 1,\n showCorrect: false,\n isValidDrop: false,\n selectedResponse: null,\n };\n this.lastDragEndAt = 0;\n }\n\n onDragStart = (event) => {\n const { active } = event;\n\n if (active?.data?.current) {\n this.setState({\n draggingElement: active.data.current,\n isValidDrop: false,\n selectedResponse: active.data.current,\n });\n }\n };\n\n onDragEnd = (event) => {\n const { active, over } = event;\n const { model } = this.props;\n const { duplicateResponses } = model || {};\n\n // Check if drop is valid\n const draggedItem = active?.data?.current;\n const responseArea = over?.data?.current;\n const isValidDrop =\n over &&\n active &&\n draggedItem &&\n responseArea &&\n responseArea.containerIndex !== undefined;\n\n const shouldDisableAnimation = isValidDrop && duplicateResponses;\n\n this.setState({\n draggingElement: { id: '', value: '' },\n isValidDrop: shouldDisableAnimation,\n });\n\n this.cancelSelection();\n this.lastDragEndAt = Date.now();\n\n if (!over || !active) {\n return;\n }\n\n if (!draggedItem) {\n return;\n }\n\n if (over.id === 'ica-board') {\n if (draggedItem.containerIndex !== undefined) {\n this.handleOnAnswerRemove(draggedItem);\n }\n return;\n }\n\n if (responseArea) {\n this.handleOnAnswerSelect(draggedItem, responseArea.containerIndex);\n }\n };\n\n onDragCancel = () => {\n this.setState({ draggingElement: { id: '', value: '' } });\n this.cancelSelection();\n this.lastDragEndAt = Date.now();\n };\n\n isSameResponse = (a, b) => !!a && !!b && a.id === b.id && a.containerIndex === b.containerIndex;\n\n // Click-to-select semantics: selecting the currently-selected response again clears\n // the selection instead of re-selecting it.\n toggleResponseSelection = (data) => {\n this.setState((state) => ({\n selectedResponse: this.isSameResponse(state.selectedResponse, data) ? null : data,\n }));\n };\n\n cancelSelection = () => {\n this.setState({ selectedResponse: null });\n };\n\n // If a real dnd-kit drag (started via keyboard Space/Enter) is still live when a\n // click completes the placement below, it needs to be cleanly ended — otherwise\n // dnd-kit would still think a drag is in progress. Escape is already configured as\n // this sensor's cancel key (see the keyboardCodes passed to DragProvider below), and\n // dispatching it as a real DOM KeyboardEvent is how dnd-kit's own document-level\n // listener is reached from outside its sensor.\n //\n // Only dispatch when a drag is actually live (draggingElement.id is truthy) — this is\n // a synthetic Escape keydown on `document`, so an unconditional dispatch would also be\n // observed by any other document-level Escape listener (host player modals/dialogs,\n // or another mounted instance of this same component) even when nothing here actually\n // needed cancelling.\n endAnyLiveKeyboardDrag = () => {\n if (!this.state.draggingElement.id) {\n return;\n }\n\n document.dispatchEvent(new KeyboardEvent('keydown', { code: 'Escape', bubbles: true, cancelable: true }));\n };\n\n placeSelectedResponse = (containerIndex) => {\n const { selectedResponse } = this.state;\n\n if (!selectedResponse) {\n return;\n }\n\n if (containerIndex === undefined) {\n // Placing into the pool = removing it from wherever it currently is\n if (selectedResponse.containerIndex !== undefined) {\n this.handleOnAnswerRemove(selectedResponse);\n }\n } else {\n this.handleOnAnswerSelect(selectedResponse, containerIndex);\n }\n\n this.cancelSelection();\n this.endAnyLiveKeyboardDrag();\n this.lastDragEndAt = Date.now();\n };\n\n isClickSoonAfterDragEnd = () => Date.now() - this.lastDragEndAt < CLICK_AFTER_DRAG_GUARD_MS;\n\n onResponseClick = (data) => {\n if (this.isClickSoonAfterDragEnd()) {\n return;\n }\n\n // A click that selects/deselects/switches a tile must end any dnd-kit drag that's\n // still live from an earlier keyboard Space/Enter pick-up first — otherwise dnd-kit\n // keeps thinking that earlier item is being dragged (it ignores new sensor\n // activation while a drag is active) while selectedResponse visually points at\n // whatever this click just selected. Ending the stale drag first (rather than\n // after) matters: ending it also cancels the current selection as a side effect\n // (see onDragCancel above), so doing it before\n // toggleResponseSelection lets this click's own selection be the one that sticks.\n this.endAnyLiveKeyboardDrag();\n this.toggleResponseSelection(data);\n };\n\n onPlacementClick = (containerIndex) => {\n if (this.isClickSoonAfterDragEnd()) {\n return;\n }\n\n this.placeSelectedResponse(containerIndex);\n };\n\n renderDragOverlay = () => {\n const { draggingElement } = this.state;\n const { model } = this.props;\n\n if (!draggingElement.id) return null;\n\n // check if the response contains an image\n const imgRegex = /<img[^>]+src=\"([^\">]+)\"/;\n const containsImage = imgRegex.test(draggingElement.value);\n\n return (\n <PossibleResponse\n key={draggingElement.id}\n canDrag={false}\n data={draggingElement}\n onDragBegin={() => {}}\n isOverlay\n containerStyle={{\n ...(model.answerChoiceTransparency ? { opacity: '0.8' } : {}),\n ...(!containsImage ? { padding: '0 10px', margin: '4px 6px !important' } : {}),\n }}\n />\n );\n };\n\n filterPossibleAnswers = (possibleResponses, answer) =>\n possibleResponses.filter((response) => response.value !== answer.value);\n\n handleOnAnswerSelect = (answer, responseContainerIndex) => {\n const {\n model: { duplicateResponses },\n updateAnswer,\n } = this.props;\n const { answers, maxResponsePerZone } = this.state;\n let { possibleResponses } = this.state;\n let answersToStore;\n\n const answersInThisContainer = [];\n const answersInOtherContainers = [];\n\n answers.forEach((a) => {\n if (a.containerIndex === responseContainerIndex) {\n answersInThisContainer.push(a);\n } else {\n answersInOtherContainers.push(a);\n }\n });\n\n if (maxResponsePerZone === answersInThisContainer.length) {\n const shiftedItem = answersInThisContainer[0];\n if (maxResponsePerZone === 1) {\n answersInThisContainer.shift(); // FIFO\n } else {\n this.setState({ maxResponsePerZoneWarning: true });\n return;\n }\n\n // if duplicates are not allowed, make sure to put the shifted value back in possible responses\n if (!duplicateResponses) {\n possibleResponses = Array.isArray(possibleResponses) ? possibleResponses : [];\n\n possibleResponses.push({\n ...shiftedItem,\n containerIndex: undefined,\n id: shiftedItem.id || generateId(),\n });\n }\n\n // answers will be:\n // + shifted answers for the current container\n // + if duplicatesAllowed, all the other answers from other containers\n // else: all the answers from other containers that are not having the same value\n // + new answer\n answersToStore = [\n ...answersInThisContainer, // shifted\n // TODO allow duplicates case Question: should we remove answer from a container if dragged to another container?\n // if yes, this should do it: add a.id !== answer.id instead of 'true'\n ...answersInOtherContainers.filter((a) => (duplicateResponses ? true : a.value !== answer.value)), // un-shifted\n {\n ...answer,\n containerIndex: responseContainerIndex,\n ...(duplicateResponses ? { id: generateId() } : {}),\n },\n ];\n } else {\n // answers will be:\n // + if duplicatesAllowed, all the other answers, except the one that was dragged\n // else: all the answers that are not having the same value\n // + new answer\n answersToStore = [\n // TODO allow duplicates case Question: should we remove answer from a container if dragged to another container?\n // if yes, this should do it: add a.id !== answer.id instead of 'true'\n ...answers.filter((a) => (duplicateResponses ? a.id !== answer.id : a.value !== answer.value)),\n {\n ...answer,\n containerIndex: responseContainerIndex,\n ...(duplicateResponses ? { id: generateId() } : {}),\n },\n ];\n }\n this.setState({\n maxResponsePerZoneWarning: false,\n answers: answersToStore,\n possibleResponses:\n // for single response per container remove answer from possible responses\n duplicateResponses ? possibleResponses : this.filterPossibleAnswers(possibleResponses, answer),\n });\n updateAnswer(answersToStore);\n };\n\n handleOnAnswerRemove = (answer) => {\n const {\n model: { duplicateResponses },\n updateAnswer,\n } = this.props;\n const { answers, possibleResponses } = this.state;\n const answersToStore = answers.filter((a) => a.id !== answer.id);\n const shouldNotPushInPossibleResponses = answer.containerIndex === undefined; // don't duplicate possible responses\n\n this.setState({\n maxResponsePerZoneWarning: false,\n answers: answersToStore,\n // push back into possible responses the removed answer if responses cannot be duplicated\n possibleResponses:\n duplicateResponses || shouldNotPushInPossibleResponses\n ? possibleResponses\n : [\n ...possibleResponses,\n {\n ...answer,\n containerIndex: undefined,\n },\n ],\n });\n updateAnswer(answersToStore);\n };\n\n toggleCorrect = (showCorrect) => this.setState({ showCorrect });\n\n render() {\n const {\n model: {\n disabled,\n duplicateResponses,\n extraCSSRules,\n image,\n responseAreaFill,\n stimulus,\n responseCorrect,\n validation,\n teacherInstructions,\n prompt,\n autoplayAudioEnabled,\n showDashedBorder,\n mode,\n rationale,\n language,\n uiStyle = {},\n answerChoiceTransparency,\n responseContainerPadding,\n imageDropTargetPadding,\n fontSizeFactor,\n customAudioButton,\n },\n } = this.props;\n const {\n answers,\n draggingElement,\n possibleResponses,\n responseContainers,\n maxResponsePerZone,\n maxResponsePerZoneWarning,\n showCorrect,\n isValidDrop,\n } = this.state;\n const isEvaluateMode = mode === 'evaluate';\n const showToggle = isEvaluateMode && !responseCorrect;\n const { possibilityListPosition = 'bottom' } = uiStyle || {};\n const isVertical = possibilityListPosition === 'left' || possibilityListPosition === 'right';\n\n const { validResponse } = validation || {};\n const correctAnswers = [];\n const showRationale = rationale && (hasText(rationale) || hasMedia(rationale));\n const showTeacherInstructions =\n teacherInstructions && (hasText(teacherInstructions) || hasMedia(teacherInstructions));\n\n if (validResponse) {\n (validResponse.value || []).forEach((container, i) => {\n (container.images || []).forEach((v) => {\n correctAnswers.push({\n value: v,\n containerIndex: i,\n isCorrect: true,\n });\n });\n });\n }\n\n const warningMessage = translator.t('imageClozeAssociation.reachedLimit_other', {\n lng: language,\n count: maxResponsePerZone,\n });\n\n let answersToShow =\n responseCorrect !== undefined ? getAnswersCorrectness(answers, validation, duplicateResponses) : answers;\n\n if (responseCorrect === false && maxResponsePerZone === 1) {\n answersToShow = [...answersToShow, ...getUnansweredAnswers(answersToShow, validation)];\n }\n\n const sharedImageProps = {\n draggingElement,\n duplicateResponses,\n image,\n onAnswerSelect: this.handleOnAnswerSelect,\n onDragAnswerBegin: this.onDragStart,\n onDragAnswerEnd: this.onDragEnd,\n responseContainers,\n showDashedBorder,\n responseAreaFill,\n responseContainerPadding,\n imageDropTargetPadding,\n maxResponsePerZone,\n selectedResponse: this.state.selectedResponse,\n onSelectClick: this.onResponseClick,\n onPlacementClick: this.onPlacementClick,\n };\n\n const renderImage = () => (\n <Image\n {...sharedImageProps}\n canDrag={showCorrect && showToggle ? false : !disabled}\n answers={showCorrect && showToggle ? correctAnswers : answersToShow}\n answerChoiceTransparency={!(showCorrect && showToggle) ? answerChoiceTransparency : undefined}\n />\n );\n\n const renderPossibleResponses = () => {\n if (showCorrect && showToggle) return null;\n\n return (\n <React.Fragment>\n {maxResponsePerZoneWarning && <WarningInfo message={warningMessage} />}\n <PossibleResponses\n canDrag={!disabled}\n data={possibleResponses}\n onAnswerRemove={this.handleOnAnswerRemove}\n onDragBegin={this.onDragStart}\n answerChoiceTransparency={answerChoiceTransparency}\n customStyle={{\n minWidth: isVertical ? '130px' : image?.width || 'fit-content',\n }}\n isVertical={isVertical}\n minHeight={isVertical ? image?.height : undefined}\n selectedResponse={this.state.selectedResponse}\n onSelectClick={this.onResponseClick}\n onPlacementClick={this.onPlacementClick}\n />\n </React.Fragment>\n );\n };\n\n return (\n <DragProvider\n onDragStart={this.onDragStart}\n onDragEnd={this.onDragEnd}\n onDragCancel={this.onDragCancel}\n keyboardCoordinateGetter={closestDroppableKeyboardCoordinates}\n keyboardCodes={{ start: ['Space', 'Enter'], cancel: ['Escape'], end: ['Space', 'Enter'] }}\n >\n <StyledUiLayout extraCSSRules={extraCSSRules} id={'main-container'} fontSizeFactor={fontSizeFactor}>\n {showTeacherInstructions && (\n <StyledTeacherInstructions\n labels={{\n hidden: 'Show Teacher Instructions',\n visible: 'Hide Teacher Instructions',\n }}\n >\n <PreviewPrompt prompt={teacherInstructions} />\n </StyledTeacherInstructions>\n )}\n\n <PreviewPrompt\n className=\"prompt\"\n prompt={prompt}\n autoplayAudioEnabled={autoplayAudioEnabled}\n customAudioButton={customAudioButton}\n />\n\n <PreviewPrompt prompt={stimulus} />\n\n <CorrectAnswerToggle\n show={showToggle}\n toggled={showCorrect}\n onToggle={this.toggleCorrect}\n language={language}\n />\n\n <InteractiveSection responseCorrect={showCorrect && showToggle ? true : responseCorrect} uiStyle={uiStyle}>\n {renderImage()}\n {renderPossibleResponses()}\n </InteractiveSection>\n\n {showRationale && (\n <StyledRationale\n labels={{\n hidden: 'Show Rationale',\n visible: 'Hide Rationale',\n }}\n >\n <PreviewPrompt prompt={rationale} />\n </StyledRationale>\n )}\n </StyledUiLayout>\n {/* Disable drop animation for valid drops to prevent visual snap-back */}\n {/* Keep default animation for invalid drops to show visual feedback */}\n <DragOverlay dropAnimation={isValidDrop ? null : undefined}>\n {this.renderDragOverlay()}\n </DragOverlay>\n </DragProvider>\n );\n }\n}\n\nconst WarningContainer = styled('div')(({ theme }) => ({\n margin: `0 ${theme.spacing(2)}`,\n backgroundColor: '#dddddd',\n padding: theme.spacing(1),\n display: 'flex',\n alignItems: 'center',\n '& svg': {\n height: '30px',\n },\n '& h1': {\n padding: '0px',\n margin: '0px',\n },\n}));\n\nconst WarningMessage = styled('span')(({ theme }) => ({\n paddingLeft: theme.spacing(0.5),\n userSelect: 'none',\n}));\n\nconst WarningInfo = ({ message }) => {\n const nodeRef = React.useRef(null);\n\n return (\n <TransitionGroup>\n <CSSTransition classNames={'fb'} key=\"fb\" timeout={300} nodeRef={nodeRef}>\n <WarningContainer ref={nodeRef} key=\"panel\">\n <NotInterestedIcon color={'secondary'} fontSize={'small'} />\n <WarningMessage dangerouslySetInnerHTML={{ __html: message }} />\n </WarningContainer>\n </CSSTransition>\n </TransitionGroup>\n );\n};\n\nWarningInfo.propTypes = {\n message: PropTypes.string,\n};\n\nImageClozeAssociationComponent.propTypes = {\n model: PropTypes.object.isRequired,\n session: PropTypes.object,\n updateAnswer: PropTypes.func.isRequired,\n};\n\nexport default ImageClozeAssociationComponent;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"root.js","names":["_react","_interopRequireDefault","require","_propTypes","_core","_drag","_reactTransitionGroup","_renderUi","_styles","_NotInterested","_correctAnswerToggle","_translator","_lodashEs","_imageContainer","_interactiveSection","_possibleResponses2","_utilsCorrectness","_possibleResponse","translator","Translator","generateId","Math","random","toString","substring","Date","getTime","StyledUiLayout","styled","UiLayout","color","text","backgroundColor","background","position","maxWidth","height","StyledTeacherInstructions","Collapsible","theme","marginBottom","spacing","StyledRationale","marginTop","ImageClozeAssociationComponent","React","Component","constructor","props","_defineProperty2","default","event","active","data","current","setState","draggingElement","isValidDrop","over","model","duplicateResponses","draggedItem","responseArea","containerIndex","undefined","shouldDisableAnimation","id","value","handleOnAnswerRemove","handleOnAnswerSelect","state","imgRegex","containsImage","test","createElement","key","canDrag","onDragBegin","isOverlay","containerStyle","answerChoiceTransparency","opacity","padding","margin","possibleResponses","answer","filter","response","responseContainerIndex","updateAnswer","answers","maxResponsePerZone","answersToStore","answersInThisContainer","answersInOtherContainers","forEach","a","push","length","shiftedItem","shift","maxResponsePerZoneWarning","Array","isArray","filterPossibleAnswers","shouldNotPushInPossibleResponses","showCorrect","responseContainers","session","possibleResponsesWithIds","map","item","index","groupedAnswers","groupBy","limitedAnswers","flatMap","grp","slice","possibleResponsesFiltered","find","render","disabled","extraCSSRules","image","responseAreaFill","stimulus","responseCorrect","validation","teacherInstructions","prompt","autoplayAudioEnabled","showDashedBorder","mode","rationale","language","uiStyle","responseContainerPadding","imageDropTargetPadding","fontSizeFactor","customAudioButton","isEvaluateMode","showToggle","possibilityListPosition","isVertical","validResponse","correctAnswers","showRationale","hasText","hasMedia","showTeacherInstructions","container","i","images","v","isCorrect","warningMessage","t","lng","count","answersToShow","getAnswersCorrectness","getUnansweredAnswers","sharedImageProps","onAnswerSelect","onDragAnswerBegin","onDragStart","onDragAnswerEnd","onDragEnd","renderImage","_extends2","renderPossibleResponses","Fragment","WarningInfo","message","onAnswerRemove","customStyle","minWidth","width","minHeight","DragProvider","labels","hidden","visible","PreviewPrompt","className","show","toggled","onToggle","toggleCorrect","DragOverlay","dropAnimation","renderDragOverlay","exports","WarningContainer","display","alignItems","WarningMessage","paddingLeft","userSelect","nodeRef","useRef","TransitionGroup","CSSTransition","classNames","timeout","ref","fontSize","dangerouslySetInnerHTML","__html","propTypes","PropTypes","string","object","isRequired","func","_default"],"sources":["../src/root.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { DragOverlay } from '@dnd-kit/core';\nimport { DragProvider } from '@pie-lib/drag';\nimport { CSSTransition, TransitionGroup } from 'react-transition-group';\nimport { color, Collapsible, PreviewPrompt, UiLayout, hasText, hasMedia } from '@pie-lib/render-ui';\nimport { styled } from '@mui/material/styles';\nimport NotInterestedIcon from '@mui/icons-material/NotInterested';\nimport CorrectAnswerToggle from '@pie-lib/correct-answer-toggle';\nimport Translator from '@pie-lib/translator';\nimport { flatMap, groupBy } from 'lodash-es';\n\nconst { translator } = Translator;\nimport Image from './image-container';\nimport InteractiveSection from './interactive-section';\nimport PossibleResponses from './possible-responses';\nimport { getUnansweredAnswers, getAnswersCorrectness } from './utils-correctness';\nimport PossibleResponse from './possible-response';\n\nconst generateId = () => Math.random().toString(36).substring(2) + new Date().getTime().toString(36);\n\nconst StyledUiLayout = styled(UiLayout)({\n color: color.text(),\n backgroundColor: color.background(),\n position: 'relative',\n '& img': {\n maxWidth: '100%',\n height: 'auto',\n },\n});\n\nconst StyledTeacherInstructions = styled(Collapsible)(({ theme }) => ({\n marginBottom: theme.spacing(2),\n}));\n\nconst StyledRationale = styled(Collapsible)(({ theme }) => ({\n marginTop: theme.spacing(2),\n}));\n\nexport class ImageClozeAssociationComponent extends React.Component {\n constructor(props) {\n super(props);\n const {\n model: { possibleResponses, responseContainers, duplicateResponses, maxResponsePerZone },\n session,\n } = props;\n let { answers } = session || {};\n // set id for each possible response\n const possibleResponsesWithIds = (possibleResponses || []).map((item, index) => ({\n value: item,\n id: `${index}`,\n }));\n\n let groupedAnswers = groupBy(answers || [], 'containerIndex');\n // keep only last maxResponsePerZone answers for each zone\n let limitedAnswers = flatMap(groupedAnswers, (grp) => grp.slice(-(maxResponsePerZone || 1)));\n answers = limitedAnswers\n // set id for each answer\n .map((answer, index) => ({ ...answer, id: `${index}` }))\n // return only answer which have a valid container index\n .filter((answer) => answer.containerIndex < responseContainers.length);\n\n const possibleResponsesFiltered = possibleResponsesWithIds.filter(\n (response) => !answers.find((answer) => answer.value === response.value),\n );\n this.state = {\n answers: answers || [],\n draggingElement: { id: '', value: '' },\n possibleResponses: duplicateResponses ? possibleResponsesWithIds : possibleResponsesFiltered,\n // set id for each response containers\n responseContainers: (responseContainers || []).map((item, index) => ({\n index,\n ...item,\n id: `${index}`,\n })),\n maxResponsePerZone: maxResponsePerZone || 1,\n showCorrect: false,\n isValidDrop: false,\n };\n }\n\n onDragStart = (event) => {\n const { active } = event;\n\n if (active?.data?.current) {\n this.setState({\n draggingElement: active.data.current,\n isValidDrop: false,\n });\n }\n };\n\n onDragEnd = (event) => {\n const { active, over } = event;\n const { model } = this.props;\n const { duplicateResponses } = model || {};\n\n // Check if drop is valid\n const draggedItem = active?.data?.current;\n const responseArea = over?.data?.current;\n const isValidDrop =\n over &&\n active &&\n draggedItem &&\n responseArea &&\n responseArea.containerIndex !== undefined;\n\n const shouldDisableAnimation = isValidDrop && duplicateResponses;\n\n this.setState({\n draggingElement: { id: '', value: '' },\n isValidDrop: shouldDisableAnimation,\n });\n\n if (!over || !active) {\n return;\n }\n\n if (!draggedItem) {\n return;\n }\n\n if (over.id === 'ica-board') {\n this.handleOnAnswerRemove(draggedItem);\n return;\n }\n\n if (responseArea) {\n this.handleOnAnswerSelect(draggedItem, responseArea.containerIndex);\n }\n };\n\n renderDragOverlay = () => {\n const { draggingElement } = this.state;\n const { model } = this.props;\n\n if (!draggingElement.id) return null;\n\n // check if the response contains an image\n const imgRegex = /<img[^>]+src=\"([^\">]+)\"/;\n const containsImage = imgRegex.test(draggingElement.value);\n\n return (\n <PossibleResponse\n key={draggingElement.id}\n canDrag={false}\n data={draggingElement}\n onDragBegin={() => {}}\n isOverlay\n containerStyle={{\n ...(model.answerChoiceTransparency ? { opacity: '0.8' } : {}),\n ...(!containsImage ? { padding: '0 10px', margin: '4px 6px !important' } : {}),\n }}\n />\n );\n };\n\n filterPossibleAnswers = (possibleResponses, answer) =>\n possibleResponses.filter((response) => response.value !== answer.value);\n\n handleOnAnswerSelect = (answer, responseContainerIndex) => {\n const {\n model: { duplicateResponses },\n updateAnswer,\n } = this.props;\n const { answers, maxResponsePerZone } = this.state;\n let { possibleResponses } = this.state;\n let answersToStore;\n\n const answersInThisContainer = [];\n const answersInOtherContainers = [];\n\n answers.forEach((a) => {\n if (a.containerIndex === responseContainerIndex) {\n answersInThisContainer.push(a);\n } else {\n answersInOtherContainers.push(a);\n }\n });\n\n if (maxResponsePerZone === answersInThisContainer.length) {\n const shiftedItem = answersInThisContainer[0];\n if (maxResponsePerZone === 1) {\n answersInThisContainer.shift(); // FIFO\n } else {\n this.setState({ maxResponsePerZoneWarning: true });\n return;\n }\n\n // if duplicates are not allowed, make sure to put the shifted value back in possible responses\n if (!duplicateResponses) {\n possibleResponses = Array.isArray(possibleResponses) ? possibleResponses : [];\n\n possibleResponses.push({\n ...shiftedItem,\n containerIndex: undefined,\n id: shiftedItem.id || generateId(),\n });\n }\n\n // answers will be:\n // + shifted answers for the current container\n // + if duplicatesAllowed, all the other answers from other containers\n // else: all the answers from other containers that are not having the same value\n // + new answer\n answersToStore = [\n ...answersInThisContainer, // shifted\n // TODO allow duplicates case Question: should we remove answer from a container if dragged to another container?\n // if yes, this should do it: add a.id !== answer.id instead of 'true'\n ...answersInOtherContainers.filter((a) => (duplicateResponses ? true : a.value !== answer.value)), // un-shifted\n {\n ...answer,\n containerIndex: responseContainerIndex,\n ...(duplicateResponses ? { id: generateId() } : {}),\n },\n ];\n } else {\n // answers will be:\n // + if duplicatesAllowed, all the other answers, except the one that was dragged\n // else: all the answers that are not having the same value\n // + new answer\n answersToStore = [\n // TODO allow duplicates case Question: should we remove answer from a container if dragged to another container?\n // if yes, this should do it: add a.id !== answer.id instead of 'true'\n ...answers.filter((a) => (duplicateResponses ? a.id !== answer.id : a.value !== answer.value)),\n {\n ...answer,\n containerIndex: responseContainerIndex,\n ...(duplicateResponses ? { id: generateId() } : {}),\n },\n ];\n }\n this.setState({\n maxResponsePerZoneWarning: false,\n answers: answersToStore,\n possibleResponses:\n // for single response per container remove answer from possible responses\n duplicateResponses ? possibleResponses : this.filterPossibleAnswers(possibleResponses, answer),\n });\n updateAnswer(answersToStore);\n };\n\n handleOnAnswerRemove = (answer) => {\n const {\n model: { duplicateResponses },\n updateAnswer,\n } = this.props;\n const { answers, possibleResponses } = this.state;\n const answersToStore = answers.filter((a) => a.id !== answer.id);\n const shouldNotPushInPossibleResponses = answer.containerIndex === undefined; // don't duplicate possible responses\n\n this.setState({\n maxResponsePerZoneWarning: false,\n answers: answersToStore,\n // push back into possible responses the removed answer if responses cannot be duplicated\n possibleResponses:\n duplicateResponses || shouldNotPushInPossibleResponses\n ? possibleResponses\n : [\n ...possibleResponses,\n {\n ...answer,\n containerIndex: undefined,\n },\n ],\n });\n updateAnswer(answersToStore);\n };\n\n toggleCorrect = (showCorrect) => this.setState({ showCorrect });\n\n render() {\n const {\n model: {\n disabled,\n duplicateResponses,\n extraCSSRules,\n image,\n responseAreaFill,\n stimulus,\n responseCorrect,\n validation,\n teacherInstructions,\n prompt,\n autoplayAudioEnabled,\n showDashedBorder,\n mode,\n rationale,\n language,\n uiStyle = {},\n answerChoiceTransparency,\n responseContainerPadding,\n imageDropTargetPadding,\n fontSizeFactor,\n customAudioButton,\n },\n } = this.props;\n const {\n answers,\n draggingElement,\n possibleResponses,\n responseContainers,\n maxResponsePerZone,\n maxResponsePerZoneWarning,\n showCorrect,\n isValidDrop,\n } = this.state;\n const isEvaluateMode = mode === 'evaluate';\n const showToggle = isEvaluateMode && !responseCorrect;\n const { possibilityListPosition = 'bottom' } = uiStyle || {};\n const isVertical = possibilityListPosition === 'left' || possibilityListPosition === 'right';\n\n const { validResponse } = validation || {};\n const correctAnswers = [];\n const showRationale = rationale && (hasText(rationale) || hasMedia(rationale));\n const showTeacherInstructions =\n teacherInstructions && (hasText(teacherInstructions) || hasMedia(teacherInstructions));\n\n if (validResponse) {\n (validResponse.value || []).forEach((container, i) => {\n (container.images || []).forEach((v) => {\n correctAnswers.push({\n value: v,\n containerIndex: i,\n isCorrect: true,\n });\n });\n });\n }\n\n const warningMessage = translator.t('imageClozeAssociation.reachedLimit_other', {\n lng: language,\n count: maxResponsePerZone,\n });\n\n let answersToShow =\n responseCorrect !== undefined ? getAnswersCorrectness(answers, validation, duplicateResponses) : answers;\n\n if (responseCorrect === false && maxResponsePerZone === 1) {\n answersToShow = [...answersToShow, ...getUnansweredAnswers(answersToShow, validation)];\n }\n\n const sharedImageProps = {\n draggingElement,\n duplicateResponses,\n image,\n onAnswerSelect: this.handleOnAnswerSelect,\n onDragAnswerBegin: this.onDragStart,\n onDragAnswerEnd: this.onDragEnd,\n responseContainers,\n showDashedBorder,\n responseAreaFill,\n responseContainerPadding,\n imageDropTargetPadding,\n maxResponsePerZone,\n };\n\n const renderImage = () => (\n <Image\n {...sharedImageProps}\n canDrag={showCorrect && showToggle ? false : !disabled}\n answers={showCorrect && showToggle ? correctAnswers : answersToShow}\n answerChoiceTransparency={!(showCorrect && showToggle) ? answerChoiceTransparency : undefined}\n />\n );\n\n const renderPossibleResponses = () => {\n if (showCorrect && showToggle) return null;\n\n return (\n <React.Fragment>\n {maxResponsePerZoneWarning && <WarningInfo message={warningMessage} />}\n <PossibleResponses\n canDrag={!disabled}\n data={possibleResponses}\n onAnswerRemove={this.handleOnAnswerRemove}\n onDragBegin={this.onDragStart}\n answerChoiceTransparency={answerChoiceTransparency}\n customStyle={{\n minWidth: isVertical ? '130px' : image?.width || 'fit-content',\n }}\n isVertical={isVertical}\n minHeight={isVertical ? image?.height : undefined}\n />\n </React.Fragment>\n );\n };\n\n return (\n <DragProvider onDragStart={this.onDragStart} onDragEnd={this.onDragEnd}>\n <StyledUiLayout extraCSSRules={extraCSSRules} id={'main-container'} fontSizeFactor={fontSizeFactor}>\n {showTeacherInstructions && (\n <StyledTeacherInstructions\n labels={{\n hidden: 'Show Teacher Instructions',\n visible: 'Hide Teacher Instructions',\n }}\n >\n <PreviewPrompt prompt={teacherInstructions} />\n </StyledTeacherInstructions>\n )}\n\n <PreviewPrompt\n className=\"prompt\"\n prompt={prompt}\n autoplayAudioEnabled={autoplayAudioEnabled}\n customAudioButton={customAudioButton}\n />\n\n <PreviewPrompt prompt={stimulus} />\n\n <CorrectAnswerToggle\n show={showToggle}\n toggled={showCorrect}\n onToggle={this.toggleCorrect}\n language={language}\n />\n\n <InteractiveSection responseCorrect={showCorrect && showToggle ? true : responseCorrect} uiStyle={uiStyle}>\n {renderImage()}\n {renderPossibleResponses()}\n </InteractiveSection>\n\n {showRationale && (\n <StyledRationale\n labels={{\n hidden: 'Show Rationale',\n visible: 'Hide Rationale',\n }}\n >\n <PreviewPrompt prompt={rationale} />\n </StyledRationale>\n )}\n </StyledUiLayout>\n {/* Disable drop animation for valid drops to prevent visual snap-back */}\n {/* Keep default animation for invalid drops to show visual feedback */}\n <DragOverlay dropAnimation={isValidDrop ? null : undefined}>\n {this.renderDragOverlay()}\n </DragOverlay>\n </DragProvider>\n );\n }\n}\n\nconst WarningContainer = styled('div')(({ theme }) => ({\n margin: `0 ${theme.spacing(2)}`,\n backgroundColor: '#dddddd',\n padding: theme.spacing(1),\n display: 'flex',\n alignItems: 'center',\n '& svg': {\n height: '30px',\n },\n '& h1': {\n padding: '0px',\n margin: '0px',\n },\n}));\n\nconst WarningMessage = styled('span')(({ theme }) => ({\n paddingLeft: theme.spacing(0.5),\n userSelect: 'none',\n}));\n\nconst WarningInfo = ({ message }) => {\n const nodeRef = React.useRef(null);\n\n return (\n <TransitionGroup>\n <CSSTransition classNames={'fb'} key=\"fb\" timeout={300} nodeRef={nodeRef}>\n <WarningContainer ref={nodeRef} key=\"panel\">\n <NotInterestedIcon color={'secondary'} fontSize={'small'} />\n <WarningMessage dangerouslySetInnerHTML={{ __html: message }} />\n </WarningContainer>\n </CSSTransition>\n </TransitionGroup>\n );\n};\n\nWarningInfo.propTypes = {\n message: PropTypes.string,\n};\n\nImageClozeAssociationComponent.propTypes = {\n model: PropTypes.object.isRequired,\n session: PropTypes.object,\n updateAnswer: PropTypes.func.isRequired,\n};\n\nexport default ImageClozeAssociationComponent;\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pie-element/image-cloze-association",
3
3
  "repository": "pie-framework/pie-elements",
4
- "version": "10.3.0",
4
+ "version": "10.3.1-beta.2",
5
5
  "description": "",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -13,10 +13,10 @@
13
13
  "@mui/icons-material": "^7.3.4",
14
14
  "@mui/material": "^7.3.4",
15
15
  "@pie-framework/pie-player-events": "^0.1.0",
16
- "@pie-lib/correct-answer-toggle": "4.0.7",
17
- "@pie-lib/drag": "4.1.2",
16
+ "@pie-lib/correct-answer-toggle": "4.0.5",
17
+ "@pie-lib/drag": "4.0.6",
18
18
  "@pie-lib/math-rendering": "5.1.0",
19
- "@pie-lib/render-ui": "7.0.1",
19
+ "@pie-lib/render-ui": "6.1.3",
20
20
  "@pie-lib/translator": "4.0.2",
21
21
  "classnames": "^2.2.6",
22
22
  "humps": "^2.0.1",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "author": "pie framework developers",
29
29
  "license": "ISC",
30
- "gitHead": "5635523a84dd61f007275dcb853627b1ff0c6792",
30
+ "gitHead": "fcf6139719821e97ab40cb60e9a953fe427d86a4",
31
31
  "scripts": {
32
32
  "postpublish": "../../scripts/postpublish"
33
33
  },
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
- import { render, fireEvent } from '@testing-library/react';
2
+ import { render } from '@testing-library/react';
3
3
  import { ImageClozeAssociationComponent as Root } from '../root';
4
- import { closestDroppableKeyboardCoordinates } from '../keyboard-coordinates';
5
4
 
6
5
  jest.mock('@dnd-kit/core', () => ({
7
6
  DragOverlay: ({ children }) => <div>{children}</div>,
@@ -16,13 +15,8 @@ jest.mock('@dnd-kit/core', () => ({
16
15
  }),
17
16
  }));
18
17
 
19
- let capturedDragProviderProps;
20
-
21
18
  jest.mock('@pie-lib/drag', () => ({
22
- DragProvider: (props) => {
23
- capturedDragProviderProps = props;
24
- return <div>{props.children}</div>;
25
- },
19
+ DragProvider: ({ children }) => <div>{children}</div>,
26
20
  ICADroppablePlaceholder: ({ children }) => <div>{children}</div>,
27
21
  }));
28
22
 
@@ -40,18 +34,6 @@ const model = {
40
34
  describe('Root', () => {
41
35
  const updateAnswer = jest.fn();
42
36
 
43
- // Warm-up render: the very first `render(<Root .../>)` call in this file's jest
44
- // worker doesn't reliably invoke the mocked `DragProvider` (its assignment to
45
- // `capturedDragProviderProps` never runs, even though React reports the correct
46
- // component reference and the surrounding tree renders successfully) — a one-time
47
- // environment quirk, not anything about the mock or Root itself, since every
48
- // subsequent render works correctly. Priming it here, once, before any test's
49
- // assertions depend on it, avoids the tests that check `capturedDragProviderProps`
50
- // being order-dependent on some other, unrelated test happening to render first.
51
- beforeAll(() => {
52
- render(<Root model={model} session={{ answers: [] }} updateAnswer={jest.fn()} />).unmount();
53
- });
54
-
55
37
  const mkWrapper = (opts = {}) => {
56
38
  const props = {
57
39
  model,
@@ -114,245 +96,4 @@ describe('Root', () => {
114
96
  });
115
97
  });
116
98
 
117
- describe('selection state', () => {
118
- it('mirrors an active drag into selectedResponse on drag start', () => {
119
- const instance = createInstance();
120
- const data = { id: '3', value: 'X', containerIndex: 1 };
121
-
122
- instance.onDragStart({ active: { data: { current: data } } });
123
-
124
- expect(instance.state.selectedResponse).toEqual(data);
125
- });
126
-
127
- it('toggleResponseSelection selects, then deselects the same response', () => {
128
- const instance = createInstance();
129
- const data = { id: '3', value: 'X', containerIndex: undefined };
130
-
131
- instance.toggleResponseSelection(data);
132
- expect(instance.state.selectedResponse).toEqual(data);
133
-
134
- instance.toggleResponseSelection(data);
135
- expect(instance.state.selectedResponse).toBeNull();
136
- });
137
-
138
- it('toggleResponseSelection switches selection to a different response', () => {
139
- const instance = createInstance();
140
- const first = { id: '3', value: 'X', containerIndex: undefined };
141
- const second = { id: '4', value: 'Y', containerIndex: undefined };
142
-
143
- instance.toggleResponseSelection(first);
144
- instance.toggleResponseSelection(second);
145
-
146
- expect(instance.state.selectedResponse).toEqual(second);
147
- });
148
-
149
- it('placeSelectedResponse places the selection into a container via handleOnAnswerSelect', () => {
150
- const instance = createInstance();
151
- const data = { id: '0', value: 'firstImage', containerIndex: undefined };
152
-
153
- instance.toggleResponseSelection(data);
154
- instance.placeSelectedResponse(1);
155
-
156
- expect(instance.state.answers).toEqual([{ id: '0', value: 'firstImage', containerIndex: 1 }]);
157
- expect(instance.state.selectedResponse).toBeNull();
158
- });
159
-
160
- it('placeSelectedResponse with containerIndex undefined removes the placed response (returns it to the pool)', () => {
161
- const instance = createInstance();
162
- instance.handleOnAnswerSelect({ value: 'firstImage', id: '0' }, 0);
163
-
164
- instance.toggleResponseSelection({ id: '0', value: 'firstImage', containerIndex: 0 });
165
- instance.placeSelectedResponse(undefined);
166
-
167
- expect(instance.state.answers).toEqual([]);
168
- expect(instance.state.possibleResponses).toEqual([
169
- { value: 'secondImage', id: '1' },
170
- { value: 'firstImage', id: '0' },
171
- ]);
172
- });
173
-
174
- it('placeSelectedResponse does nothing when nothing is selected', () => {
175
- const instance = createInstance();
176
-
177
- instance.placeSelectedResponse(1);
178
-
179
- expect(instance.state.answers).toEqual([]);
180
- });
181
-
182
- it('placeSelectedResponse(undefined) is a no-op when the selection is already a pool item, even if its id collides with an unrelated placed answer (C1)', () => {
183
- // Pool items are indexed 0..n-1 over possibleResponses, and placed answers are
184
- // re-indexed 0..n-1 independently over the session's initial answers — so a pool
185
- // item's id can coincide with an unrelated placed answer's id purely from the
186
- // initial model/session, with no further user action required.
187
- const instance = createInstance({ session: { answers: [{ value: 'thirdImage', containerIndex: 1 }] } });
188
-
189
- const unrelatedPlacedAnswer = { value: 'thirdImage', containerIndex: 1, id: '0' };
190
- expect(instance.state.answers).toEqual([unrelatedPlacedAnswer]);
191
-
192
- // 'firstImage' is a pool item whose id ('0') collides with the unrelated placed
193
- // answer's id above, but it is NOT currently placed anywhere
194
- // (containerIndex undefined).
195
- const poolItem = { value: 'firstImage', id: '0' };
196
- instance.toggleResponseSelection(poolItem);
197
-
198
- instance.placeSelectedResponse(undefined);
199
-
200
- // The unrelated placed answer must survive untouched...
201
- expect(instance.state.answers).toEqual([unrelatedPlacedAnswer]);
202
- // ...and nothing should have been incorrectly pushed into possibleResponses either.
203
- expect(instance.state.possibleResponses).toEqual([
204
- { value: 'firstImage', id: '0' },
205
- { value: 'secondImage', id: '1' },
206
- ]);
207
- expect(instance.state.selectedResponse).toBeNull();
208
- });
209
-
210
- it('onDragEnd dropping a pool item back onto the pool ("ica-board") is a no-op, even if its id collides with an unrelated placed answer (C1, drag path)', () => {
211
- // Same hazard as the click-path C1 test above, but reached via a real
212
- // pointer/keyboard drag ending on the pool ('ica-board') instead of a click:
213
- // pool tiles are draggable too, and 'ica-board' is a valid Tab/Shift+Tab
214
- // keyboard-navigable drop target, so draggedItem can be a pool item
215
- // (containerIndex undefined) rather than a placed answer being moved back.
216
- const instance = createInstance({ session: { answers: [{ value: 'thirdImage', containerIndex: 1 }] } });
217
-
218
- const unrelatedPlacedAnswer = { value: 'thirdImage', containerIndex: 1, id: '0' };
219
- expect(instance.state.answers).toEqual([unrelatedPlacedAnswer]);
220
-
221
- // 'firstImage' is a pool item whose id ('0') collides with the unrelated placed
222
- // answer's id above, but it is NOT currently placed anywhere.
223
- const poolItem = { id: '0', value: 'firstImage', containerIndex: undefined };
224
-
225
- instance.onDragEnd({ active: { data: { current: poolItem } }, over: { id: 'ica-board' } });
226
-
227
- // The unrelated placed answer must survive untouched.
228
- expect(instance.state.answers).toEqual([unrelatedPlacedAnswer]);
229
- });
230
-
231
- it('onResponseClick and onPlacementClick are ignored for a short window right after a drag ends', () => {
232
- const instance = createInstance();
233
- const data = { id: '0', value: 'firstImage', containerIndex: undefined };
234
-
235
- instance.onDragEnd({ active: null, over: null });
236
- instance.onResponseClick(data);
237
-
238
- expect(instance.state.selectedResponse).toBeNull();
239
- });
240
-
241
- it('onPlacementClick is ignored for a short window right after a drag ends, even with an active selection', () => {
242
- const instance = createInstance();
243
- const data = { id: '0', value: 'firstImage', containerIndex: undefined };
244
-
245
- instance.toggleResponseSelection(data);
246
- instance.lastDragEndAt = Date.now(); // simulate the guard window without clearing selectedResponse
247
-
248
- instance.onPlacementClick(1);
249
-
250
- expect(instance.state.answers).toEqual([]);
251
- expect(instance.state.selectedResponse).toEqual(data); // still selected — the call was ignored, not processed
252
- });
253
-
254
- it('endAnyLiveKeyboardDrag does not dispatch a document Escape keydown when no drag is live (I4)', () => {
255
- const instance = createInstance();
256
- const dispatchSpy = jest.spyOn(document, 'dispatchEvent');
257
-
258
- // No onDragStart call happened, so draggingElement.id is falsy.
259
- instance.endAnyLiveKeyboardDrag();
260
-
261
- expect(dispatchSpy).not.toHaveBeenCalled();
262
- dispatchSpy.mockRestore();
263
- });
264
-
265
- it('endAnyLiveKeyboardDrag dispatches a document Escape keydown when a drag is live (I4)', () => {
266
- const instance = createInstance();
267
- const dispatchSpy = jest.spyOn(document, 'dispatchEvent');
268
-
269
- instance.onDragStart({ active: { data: { current: { id: '3', value: 'X', containerIndex: undefined } } } });
270
- instance.endAnyLiveKeyboardDrag();
271
-
272
- expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ type: 'keydown', code: 'Escape' }));
273
- dispatchSpy.mockRestore();
274
- });
275
-
276
- it('onResponseClick ends a still-live keyboard drag before applying the click selection, so the new selection sticks (I1)', () => {
277
- const instance = createInstance();
278
- const tileA = { id: '3', value: 'A', containerIndex: undefined };
279
- const tileB = { id: '4', value: 'B', containerIndex: undefined };
280
-
281
- // Pick up tile A via keyboard: starts a real dnd-kit drag and mirrors it into
282
- // selectedResponse.
283
- instance.onDragStart({ active: { data: { current: tileA } } });
284
- expect(instance.state.selectedResponse).toEqual(tileA);
285
- expect(instance.state.draggingElement).toEqual(tileA);
286
-
287
- // Now click tile B with the mouse. Real dnd-kit's own document Escape listener
288
- // would react to the synthetic Escape dispatched by endAnyLiveKeyboardDrag and
289
- // cancel the drag (calling onDragCancel) — simulate that here the same way,
290
- // since @dnd-kit/core itself is mocked out of this test file.
291
- const originalDispatch = document.dispatchEvent.bind(document);
292
- const dispatchSpy = jest.spyOn(document, 'dispatchEvent').mockImplementation((event) => {
293
- if (event.code === 'Escape') {
294
- instance.onDragCancel();
295
- }
296
-
297
- return originalDispatch(event);
298
- });
299
-
300
- instance.onResponseClick(tileB);
301
-
302
- expect(dispatchSpy).toHaveBeenCalled();
303
- expect(instance.state.draggingElement).toEqual({ id: '', value: '' });
304
- // B's selection must be the one that sticks, not wiped out by ending A's drag.
305
- expect(instance.state.selectedResponse).toEqual(tileB);
306
-
307
- dispatchSpy.mockRestore();
308
- });
309
-
310
- });
311
-
312
- describe('DragProvider wiring', () => {
313
- it('passes the Tab/Shift+Tab coordinate getter and keyboard codes to DragProvider', () => {
314
- mkWrapper();
315
-
316
- expect(capturedDragProviderProps.keyboardCoordinateGetter).toBe(closestDroppableKeyboardCoordinates);
317
- expect(capturedDragProviderProps.keyboardCodes).toEqual({
318
- start: ['Space', 'Enter'],
319
- cancel: ['Escape'],
320
- end: ['Space', 'Enter'],
321
- });
322
- });
323
-
324
- it('passes onDragCancel to DragProvider (forward-compatible with the pie-lib fix once bumped)', () => {
325
- mkWrapper();
326
-
327
- expect(typeof capturedDragProviderProps.onDragCancel).toBe('function');
328
- });
329
- });
330
-
331
- describe('full component tree (I5)', () => {
332
- // Only @dnd-kit/core and @pie-lib/drag are mocked in this file — everything else,
333
- // including image-container.jsx and image-drop-target.jsx, renders for real. This
334
- // proves the whole click-to-select/click-to-place prop chain works end to end,
335
- // rather than each component's own test mocking its immediate child.
336
- it('clicking a real pool tile then a real response container places the answer, exercising the full prop chain', () => {
337
- updateAnswer.mockClear();
338
-
339
- const { getByText, container } = mkWrapper();
340
-
341
- // Click a real pool tile (rendered by possible-responses.jsx -> possible-response.jsx).
342
- const poolTile = getByText('firstImage');
343
- fireEvent.click(poolTile);
344
-
345
- // Both response containers (rendered by image-container.jsx -> image-drop-target.jsx)
346
- // are still empty at this point, so both are native tab stops with role="button" —
347
- // this is the only role="button" element in the tree (pool tiles don't set one).
348
- const dropTargets = container.querySelectorAll('[role="button"]');
349
- expect(dropTargets.length).toBe(2);
350
-
351
- // Click the first response container to place the selected pool tile into it.
352
- fireEvent.click(dropTargets[0]);
353
-
354
- expect(updateAnswer).toHaveBeenCalledWith([{ value: 'firstImage', id: '0', containerIndex: 0 }]);
355
- });
356
- });
357
-
358
99
  });
@@ -27,9 +27,6 @@ class ImageContainer extends Component {
27
27
  responseContainerPadding,
28
28
  imageDropTargetPadding,
29
29
  maxResponsePerZone,
30
- selectedResponse,
31
- onSelectClick,
32
- onPlacementClick,
33
30
  } = this.props;
34
31
 
35
32
  return (
@@ -65,9 +62,6 @@ class ImageContainer extends Component {
65
62
  responseContainerPadding={responseContainerPadding}
66
63
  imageDropTargetPadding={imageDropTargetPadding}
67
64
  maxResponsePerZone={maxResponsePerZone}
68
- selectedResponse={selectedResponse}
69
- onSelectClick={onSelectClick}
70
- onPlacementClick={onPlacementClick}
71
65
  />
72
66
  );
73
67
  })}
@@ -91,9 +85,6 @@ ImageContainer.propTypes = {
91
85
  responseContainerPadding: PropTypes.string,
92
86
  imageDropTargetPadding: PropTypes.string,
93
87
  maxResponsePerZone: PropTypes.number,
94
- selectedResponse: PropTypes.object,
95
- onSelectClick: PropTypes.func,
96
- onPlacementClick: PropTypes.func,
97
88
  };
98
89
 
99
90
  export default ImageContainer;
@@ -43,11 +43,7 @@ const ImageDropTarget = ({
43
43
  maxResponsePerZone,
44
44
  onDrop,
45
45
  index,
46
- selectedResponse,
47
- onSelectClick,
48
- onPlacementClick,
49
46
  }) => {
50
- const [isHovered, setIsHovered] = useState(false);
51
47
  const [shouldHaveSmallPadding, setShouldHaveSmallPadding] = useState(false);
52
48
  const dropContainerRef = useRef(null);
53
49
  const dropContainerResponsesHeightRef = useRef(null);
@@ -77,11 +73,9 @@ const ImageDropTarget = ({
77
73
  }, []);
78
74
 
79
75
  const isDraggingElement = !!draggingElement.id;
80
- const hasSelection = !!selectedResponse;
81
- const showsHoverEffect = isOver || (hasSelection && isHovered && canDrag);
82
76
 
83
77
  const containerClasses = cx({
84
- 'is-over': showsHoverEffect,
78
+ 'is-over': isOver,
85
79
  dashed: showDashedBorder && !isDraggingElement,
86
80
  active: isDraggingElement,
87
81
  });
@@ -90,31 +84,6 @@ const ImageDropTarget = ({
90
84
  padding: maxResponsePerZone === 1 ? '0' : responseContainerPadding,
91
85
  ...containerStyle,
92
86
  ...(responseAreaFill && !isDraggingElement && { backgroundColor: responseAreaFill }),
93
- cursor: hasSelection && canDrag ? 'pointer' : undefined,
94
- };
95
-
96
- const handleContainerClick = () => {
97
- if (!canDrag) return;
98
-
99
- if (selectedResponse) {
100
- onPlacementClick?.(index);
101
- }
102
-
103
- // Empty background clicked with nothing selected: nothing to place.
104
- };
105
-
106
- // Only a native Tab stop when there's nothing else in this container to carry
107
- // tabbability — once it holds an answer, that answer's own tile (rendered by
108
- // PossibleResponse, via dnd-kit's `useDraggable`) is already independently tabbable,
109
- // and adding a second stop for the same visual container would add an extra stop to
110
- // the existing Tab order (match-list's equivalent)
111
- const isNativeTabStop = answers.length === 0 && canDrag;
112
-
113
- const handleContainerKeyDown = (e) => {
114
- if (e.code === 'Space' || e.code === 'Enter') {
115
- e.preventDefault();
116
- handleContainerClick();
117
- }
118
87
  };
119
88
 
120
89
  return (
@@ -125,12 +94,6 @@ const ImageDropTarget = ({
125
94
  }}
126
95
  className={containerClasses}
127
96
  style={updatedContainerStyle}
128
- role={isNativeTabStop ? 'button' : undefined}
129
- tabIndex={isNativeTabStop ? 0 : -1}
130
- onClick={handleContainerClick}
131
- onKeyDown={isNativeTabStop ? handleContainerKeyDown : undefined}
132
- onMouseEnter={() => setIsHovered(true)}
133
- onMouseLeave={() => setIsHovered(false)}
134
97
  >
135
98
  {answers.length ? (
136
99
  <AnswersContainer
@@ -149,9 +112,6 @@ const ImageDropTarget = ({
149
112
  containerStyle={{
150
113
  padding: imageDropTargetPadding ? imageDropTargetPadding : shouldHaveSmallPadding ? '2px' : '6px 10px',
151
114
  }}
152
- selectedResponse={selectedResponse}
153
- onSelectClick={onSelectClick}
154
- onPlacementClick={onPlacementClick}
155
115
  />
156
116
  ))}
157
117
  </AnswersContainer>
@@ -175,9 +135,6 @@ ImageDropTarget.propTypes = {
175
135
  responseContainerPadding: PropTypes.string,
176
136
  imageDropTargetPadding: PropTypes.string,
177
137
  maxResponsePerZone: PropTypes.number,
178
- selectedResponse: PropTypes.object,
179
- onSelectClick: PropTypes.func,
180
- onPlacementClick: PropTypes.func,
181
138
  };
182
139
 
183
140
  export default ImageDropTarget;
package/src/index.js CHANGED
@@ -35,7 +35,7 @@ export default class ImageClozeAssociation extends HTMLElement {
35
35
  if (autoplayAudioEnabled && completeAudioEnabled && !this.audioComplete) {
36
36
  if (elementContext) {
37
37
  const audio = elementContext.querySelector('audio');
38
- const isInsidePrompt = audio && audio.closest('.preview-prompt');
38
+ const isInsidePrompt = audio && audio.closest('#preview-prompt');
39
39
 
40
40
  // only require audio completion if audio exists and is inside the prompt
41
41
  if (audio && isInsidePrompt) {
@@ -144,7 +144,7 @@ export default class ImageClozeAssociation extends HTMLElement {
144
144
  mutationsList.forEach((mutation) => {
145
145
  if (mutation.type === 'childList') {
146
146
  const audio = this.querySelector('audio');
147
- const isInsidePrompt = audio && audio.closest('.preview-prompt');
147
+ const isInsidePrompt = audio && audio.closest('#preview-prompt');
148
148
 
149
149
  if (!this._model) return;
150
150
  if (!this._model.autoplayAudioEnabled) return;