Converted Talking Book Tool to React (BL-16410)#8075
Conversation
A design/hand-off document (Steps 0-5) describing how to convert the last non-React toolbox tool to React: move the AudioRecording engine to the page iframe, turn the button-state machine and controls into a React component in the toolbox, and stop audioRecording.ts from being duplicated into the page bundle. Step 6 (retiring the legacy non-React toolbox framework) is documented as a deferred follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…BloomDesktop into talkingBookToolReact
|
| Filename | Overview |
|---|---|
| src/BloomBrowserUI/bookEdit/toolbox/talkingBook/TalkingBookToolControls.tsx | New React component rendering the full talking book UI; correctly uses useMountEffect for canvas setup; TalkingBookButton destructures props in violation of the repo style guide. |
| src/BloomBrowserUI/bookEdit/toolbox/talkingBook/audioRecording.ts | Core engine refactored from DOM-manipulation to a uiState/observer pattern; delegated handlers removed in favor of public methods called directly by React; setStatus now mutates uiState and calls notifyStateChanged; getOrCreateAudioRecorder added for lazy initialization. |
| src/BloomBrowserUI/bookEdit/toolbox/talkingBook/talkingBookTool.tsx | New React adaptor replacing the old talkingBook.ts; delegates lifecycle events to the audioRecording engine cleanly; makeRootElement wires TalkingBookToolControls with getOrCreateAudioRecorder. |
| src/BloomBrowserUI/bookEdit/js/talkingBookChecksum.ts | Extracted checksum helper; the replace call only strips the first ' |
| src/BloomBrowserUI/bookEdit/toolbox/toolbox.ts | Removed the old pug-based HTML fetch path from beginAddTool; code is correct, but a stray //} comment left over from the refactoring remains. |
| src/BloomBrowserUI/bookEdit/toolbox/talkingBook/audioRecordingSpec.ts | Tests updated to check uiState directly instead of DOM classes; DOM button setup removed since player is now created lazily; setupForListen call added to force player element creation before tests that need it. |
Reviews (10): Last reviewed commit: "Converted Talking Book Tool to React (BL..." | Re-trigger Greptile
12cc862 to
05064c7
Compare
| // However, we don't want the sentence markup to be updated because the checksums differ (since a character was deleted). | ||
| // | ||
| // Thus, our checksum function needs to ignore the vertical line character when computing the checksum. | ||
| const adjustedMessage = message.replace("|", ""); |
There was a problem hiding this comment.
Only the first
| is stripped. String.prototype.replace with a plain string argument stops after the first match, so a sentence like "Hello | World | test" produces checksum "Hello World | test" — the second pipe is retained. After the user deletes all delimiter characters the actual text becomes "Hello World test", so the checksums never agree and the audio markup is unnecessarily regenerated every session. Use a global regex to remove all occurrences.
| const adjustedMessage = message.replace("|", ""); | |
| const adjustedMessage = message.replace(/\|/g, ""); |
24bcd41 to
19b45f5
Compare
| if (this.uiState.shouldShowDeviceMenu) { | ||
| this.uiState.shouldShowDeviceMenu = false; | ||
| this.notifyStateChanged(); | ||
| } |
There was a problem hiding this comment.
Device menu anchor lost on tool remount
shouldShowDeviceMenu is never reset to false in handleToolHiding() or setupForRecordingAsync(). If the user opens the device menu and then hides/reshows the tool, the React component remounts with menuAnchor reset to undefined (local useState), but uiState.shouldShowDeviceMenu is still true from the engine. The MUI Menu then renders with open={true} and anchorEl={undefined}, which causes it to appear at the wrong position (body top-left corner) rather than below the device icon.
Adding this.uiState.shouldShowDeviceMenu = false; inside handleToolHiding() would prevent the stale-open state from being carried over to the next mount.
19b45f5 to
5191780
Compare
Devin review
This change is