gwchq-textjam 0.5.2 → 0.5.4

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.
Files changed (2) hide show
  1. package/dist/index.js +41 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -382711,9 +382711,12 @@ const WebComponentLoader = (props) => {
382711
382711
  (0, react_1.useEffect)(() => {
382712
382712
  dispatch((0, EditorSlice_1.setReadOnly)(readOnly));
382713
382713
  }, [readOnly, dispatch]);
382714
+ // Depend on the mode value: the host rebuilds `curriculum` whenever its
382715
+ // content changes, and that must not reset a student's expanded view.
382716
+ const hostCurriculumDisplayMode = curriculum?.curriculumDisplayMode ?? types_1.CurriculumDisplayMode.HIDDEN;
382714
382717
  (0, react_1.useEffect)(() => {
382715
- dispatch((0, EditorSlice_1.setCurriculumDisplayMode)(curriculum?.curriculumDisplayMode ?? types_1.CurriculumDisplayMode.HIDDEN));
382716
- }, [curriculum, dispatch]);
382718
+ dispatch((0, EditorSlice_1.setCurriculumDisplayMode)(hostCurriculumDisplayMode));
382719
+ }, [hostCurriculumDisplayMode, dispatch]);
382717
382720
  (0, react_1.useEffect)(() => {
382718
382721
  if (isCodeVisible !== undefined) {
382719
382722
  dispatch((0, EditorSlice_1.setCodeVisibility)({ isVisible: isCodeVisible }));
@@ -383649,9 +383652,13 @@ const useProject = ({ projectData, projectContent = null, starterCodeContent = n
383649
383652
  const sourceComponents = incomingData?.components ?? defaultProject.components ?? [];
383650
383653
  // clone components before sorting to avoid mutating frozen/template objects
383651
383654
  const preparedComponents = prepareTemplateComponents(sourceComponents);
383655
+ // incomingData is assembled by the host from partially loaded state, so
383656
+ // it can carry undefined fields (e.g. name before the first save).
383657
+ // dropping them keeps the default template's values as the real fallback
383658
+ const definedIncomingData = Object.fromEntries(Object.entries(incomingData ?? {}).filter(([, value]) => value !== undefined));
383652
383659
  const projectToSet = {
383653
383660
  ...defaultProject,
383654
- ...incomingData,
383661
+ ...definedIncomingData,
383655
383662
  components: preparedComponents,
383656
383663
  commitId: null,
383657
383664
  };
@@ -383694,8 +383701,12 @@ const useProject = ({ projectData, projectContent = null, starterCodeContent = n
383694
383701
  }
383695
383702
  return;
383696
383703
  }
383697
- // if user has chosen start new for a draft, ignore cache completely
383698
- if (!projectData?.commitId && shouldBypassCachedDraft) {
383704
+ // if user has chosen start new for a draft, ignore cache completely.
383705
+ // starter code takes precedence over the project-type template: when an
383706
+ // archive is available useProjectStarterCode applies it instead.
383707
+ if (!projectData?.commitId &&
383708
+ shouldBypassCachedDraft &&
383709
+ !starterCodeContent) {
383699
383710
  if (loadTemplateProjectData && !isTemplateDataLoaded) {
383700
383711
  dispatch((0, EditorSlice_1.setLoading)(types_1.LoadingState.IDLE));
383701
383712
  loadTemplateProjectData();
@@ -384252,11 +384263,14 @@ const useIsMounted_1 = __webpack_require__(76314);
384252
384263
  const useProjectCache_1 = __webpack_require__(69557);
384253
384264
  const useUnsavedDraftResolution_1 = __webpack_require__(61171);
384254
384265
  const isFinalLoadingState = (state) => state === types_1.LoadingState.SUCCESS || state === types_1.LoadingState.FAILED;
384266
+ // distinguishes "not applied yet" from a project whose cache key is undefined
384267
+ const NOT_APPLIED = Symbol("starterCodeNotApplied");
384255
384268
  // unpacks a starter-code zip archive and applies it as the initial project
384256
384269
  const useProjectStarterCode = ({ projectData, starterCodeContent = null, isLoading = false, isPreviewMode = false, }) => {
384257
384270
  const dispatch = (0, react_redux_1.useDispatch)();
384258
384271
  const isMounted = (0, useIsMounted_1.useIsMounted)();
384259
384272
  const callIdRef = (0, react_1.useRef)(null);
384273
+ const appliedForCacheKeyRef = (0, react_1.useRef)(NOT_APPLIED);
384260
384274
  const loadingState = (0, stores_1.useAppSelector)((state) => state.editor.loading);
384261
384275
  const savingState = (0, stores_1.useAppSelector)((state) => state.editor.saving);
384262
384276
  const commitIdLoadTriggered = (0, stores_1.useAppSelector)((state) => state.editor.commitIdLoadTriggered);
@@ -384272,26 +384286,33 @@ const useProjectStarterCode = ({ projectData, starterCodeContent = null, isLoadi
384272
384286
  isCurrentOutdated,
384273
384287
  });
384274
384288
  (0, react_1.useEffect)(() => {
384289
+ // nothing to unpack, or nowhere to unpack it into
384275
384290
  if (!starterCodeContent || !projectData)
384276
384291
  return;
384277
- if (isLoading || isLoadingCache)
384278
- return;
384279
- if (!isCacheLoaded && cacheKey)
384280
- return;
384281
- if (commitIdLoadTriggered)
384282
- return;
384283
- if (projectData.commitId)
384284
- return;
384285
- if (cachedProject)
384286
- return;
384287
- if (isPreviewMode)
384288
- return;
384289
- if (saveTriggered || savingState === types_1.SavingState.PROCESS)
384290
- return;
384291
- if (isFinalLoadingState(loadingState) && !shouldBypassCachedDraft)
384292
+ // inputs are still settling
384293
+ const isCachePending = isLoading || isLoadingCache || (!isCacheLoaded && !!cacheKey);
384294
+ // another source of project content already owns this load
384295
+ const hasConflictingOperation = !!commitIdLoadTriggered ||
384296
+ !!projectData.commitId ||
384297
+ isPreviewMode ||
384298
+ saveTriggered ||
384299
+ savingState === types_1.SavingState.PROCESS;
384300
+ // a cached draft, or a project that already finished loading, must not be
384301
+ // overwritten - unless the student chose "Start new"
384302
+ const shouldPreserveExistingProject = (!!cachedProject || isFinalLoadingState(loadingState)) &&
384303
+ !shouldBypassCachedDraft;
384304
+ // the bypass flag stays set until the first save, and the fresh project
384305
+ // reaches the cache moments later: without this guard the archive would be
384306
+ // re-applied on top of the student's first edits
384307
+ const isAlreadyApplied = appliedForCacheKeyRef.current === cacheKey;
384308
+ if (isCachePending ||
384309
+ hasConflictingOperation ||
384310
+ shouldPreserveExistingProject ||
384311
+ isAlreadyApplied)
384292
384312
  return;
384293
384313
  const callId = Symbol("loadStarterCodeFromZip");
384294
384314
  callIdRef.current = callId;
384315
+ appliedForCacheKeyRef.current = cacheKey;
384295
384316
  (0, loadProjectFromZip_1.loadProjectFromZip)({
384296
384317
  zipBlob: starterCodeContent,
384297
384318
  identifier: projectData.identifier,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gwchq-textjam",
3
3
  "description": "Embeddable React editor used in Raspberry Pi text-based projects.",
4
- "version": "0.5.2",
4
+ "version": "0.5.4",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/GirlsFirst/gwchq-textjam",
7
7
  "author": "Girls Who Code HQ",