mirror of
https://github.com/stan-smith/FossFLOW.git
synced 2025-12-25 23:49:10 -05:00
fix: fixes image export reading non-current scene
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
||||
VIEW_DEFAULTS
|
||||
} from 'src/config';
|
||||
import { createView } from 'src/stores/reducers';
|
||||
import { useView } from 'src/hooks/useView';
|
||||
import { useIconCategories } from './hooks/useIconCategories';
|
||||
|
||||
const App = ({
|
||||
@@ -53,6 +54,7 @@ const App = ({
|
||||
return state.actions;
|
||||
});
|
||||
const { setIconCategoriesState } = useIconCategories();
|
||||
const { changeView } = useView();
|
||||
|
||||
useEffect(() => {
|
||||
if (initialData?.zoom) {
|
||||
@@ -100,9 +102,10 @@ const App = ({
|
||||
|
||||
prevInitialData.current = fullInitialData;
|
||||
modelActions.set(fullInitialData);
|
||||
uiActions.setView(fullInitialData.views[0].id);
|
||||
|
||||
changeView(fullInitialData.views[0].id, fullInitialData);
|
||||
setIsReady(true);
|
||||
}, [initialData, modelActions, uiActions]);
|
||||
}, [initialData, modelActions, uiActions, changeView]);
|
||||
|
||||
useEffect(() => {
|
||||
setIconCategoriesState();
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
downloadFile as downloadFileUtil,
|
||||
getTileScrollPosition,
|
||||
base64ToBlob,
|
||||
generateGenericFilename
|
||||
generateGenericFilename,
|
||||
modelFromModelStore
|
||||
} from 'src/utils';
|
||||
import { ModelStore } from 'src/types';
|
||||
import { useDiagramUtils } from 'src/hooks/useDiagramUtils';
|
||||
@@ -36,14 +37,7 @@ export const ExportImageDialog = ({ onClose, quality = 4 }: Props) => {
|
||||
return state.actions;
|
||||
});
|
||||
const model = useModelStore((state): Omit<ModelStore, 'actions'> => {
|
||||
return {
|
||||
title: state.title,
|
||||
version: state.version,
|
||||
items: state.items,
|
||||
icons: state.icons,
|
||||
views: state.views,
|
||||
colors: state.colors
|
||||
};
|
||||
return modelFromModelStore(state);
|
||||
});
|
||||
|
||||
const unprojectedBounds = useMemo(() => {
|
||||
|
||||
@@ -9,12 +9,11 @@ import {
|
||||
FolderOpen as FolderOpenIcon,
|
||||
DeleteOutline as DeleteOutlineIcon
|
||||
} from '@mui/icons-material';
|
||||
import { Model } from 'src/types/model';
|
||||
import { UiElement } from 'src/components/UiElement/UiElement';
|
||||
import { IconButton } from 'src/components/IconButton/IconButton';
|
||||
import { useUiStateStore } from 'src/stores/uiStateStore';
|
||||
import { useModelStore } from 'src/stores/modelStore';
|
||||
import { exportAsJSON } from 'src/utils';
|
||||
import { exportAsJSON, modelFromModelStore } from 'src/utils';
|
||||
import { INITIAL_DATA } from 'src/config';
|
||||
import { MenuItem } from './MenuItem';
|
||||
|
||||
@@ -27,7 +26,7 @@ export const MainMenu = () => {
|
||||
return state.mainMenuOptions;
|
||||
});
|
||||
const model = useModelStore((state) => {
|
||||
return state;
|
||||
return modelFromModelStore(state);
|
||||
});
|
||||
const modelActions = useModelStore((state) => {
|
||||
return state.actions;
|
||||
@@ -76,17 +75,7 @@ export const MainMenu = () => {
|
||||
}, [uiStateActions, modelActions]);
|
||||
|
||||
const onExportAsJSON = useCallback(async () => {
|
||||
const payload: Model = {
|
||||
icons: model.icons,
|
||||
colors: model.colors,
|
||||
items: model.items,
|
||||
title: model.title,
|
||||
version: model.version,
|
||||
views: model.views,
|
||||
description: model.description
|
||||
};
|
||||
|
||||
exportAsJSON(payload);
|
||||
exportAsJSON(model);
|
||||
uiStateActions.setIsMainMenuOpen(false);
|
||||
}, [model, uiStateActions]);
|
||||
|
||||
|
||||
34
src/hooks/useView.ts
Normal file
34
src/hooks/useView.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useUiStateStore } from 'src/stores/uiStateStore';
|
||||
import { useModelStore } from 'src/stores/modelStore';
|
||||
import { useSceneStore } from 'src/stores/sceneStore';
|
||||
import { syncScene } from 'src/stores/reducers';
|
||||
import { Model } from 'src/types';
|
||||
|
||||
export const useView = () => {
|
||||
const modelActions = useModelStore((state) => {
|
||||
return state.actions;
|
||||
});
|
||||
|
||||
const uiStateActions = useUiStateStore((state) => {
|
||||
return state.actions;
|
||||
});
|
||||
|
||||
const sceneActions = useSceneStore((state) => {
|
||||
return state.actions;
|
||||
});
|
||||
|
||||
const changeView = useCallback(
|
||||
(viewId: string, model: Model) => {
|
||||
const newState = syncScene(viewId, model);
|
||||
sceneActions.set(newState.scene);
|
||||
modelActions.set(newState.model);
|
||||
uiStateActions.setView(viewId);
|
||||
},
|
||||
[uiStateActions, sceneActions, modelActions]
|
||||
);
|
||||
|
||||
return {
|
||||
changeView
|
||||
};
|
||||
};
|
||||
@@ -23,7 +23,10 @@ export const Connector: ModeActions = {
|
||||
)
|
||||
return;
|
||||
|
||||
const connector = getItemByIdOrThrow(scene.connectors, uiState.mode.id);
|
||||
const connector = getItemByIdOrThrow(
|
||||
scene.currentView.connectors ?? [],
|
||||
uiState.mode.id
|
||||
);
|
||||
|
||||
const itemAtTile = getItemAtTile({
|
||||
tile: uiState.mouse.position.tile,
|
||||
|
||||
@@ -54,9 +54,8 @@ export const updateConnector = (
|
||||
viewId: string,
|
||||
state: State
|
||||
): State => {
|
||||
const view = getItemByIdOrThrow(state.model.views, viewId);
|
||||
|
||||
const newState = produce(state, (draft) => {
|
||||
const view = getItemByIdOrThrow(draft.model.views, viewId);
|
||||
const { connectors } = draft.model.views[view.index];
|
||||
|
||||
if (!connectors) return;
|
||||
@@ -67,8 +66,8 @@ export const updateConnector = (
|
||||
|
||||
if (updates.anchors) {
|
||||
const stateAfterSync = syncConnector(id, viewId, draft);
|
||||
draft.scene = stateAfterSync.scene;
|
||||
draft.model = stateAfterSync.model;
|
||||
draft.scene = stateAfterSync.scene;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -80,9 +79,8 @@ export const createConnector = (
|
||||
viewId: string,
|
||||
state: State
|
||||
): State => {
|
||||
const view = getItemByIdOrThrow(state.model.views, viewId);
|
||||
|
||||
const newState = produce(state, (draft) => {
|
||||
const view = getItemByIdOrThrow(draft.model.views, viewId);
|
||||
const { connectors } = draft.model.views[view.index];
|
||||
|
||||
if (!connectors) {
|
||||
@@ -90,7 +88,11 @@ export const createConnector = (
|
||||
} else {
|
||||
draft.model.views[view.index].connectors?.unshift(newConnector);
|
||||
}
|
||||
|
||||
const stateAfterSync = syncConnector(newConnector.id, viewId, draft);
|
||||
draft.model = stateAfterSync.model;
|
||||
draft.scene = stateAfterSync.scene;
|
||||
});
|
||||
|
||||
return syncConnector(newConnector.id, viewId, newState);
|
||||
return newState;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,29 @@ import {
|
||||
} from 'src/config';
|
||||
import { State } from './types';
|
||||
|
||||
export const syncTextBox = (
|
||||
id: string,
|
||||
viewId: string,
|
||||
state: State
|
||||
): State => {
|
||||
const newState = produce(state, (draft) => {
|
||||
const view = getItemByIdOrThrow(draft.model.views, viewId);
|
||||
const textBox = getItemByIdOrThrow(view.value.textBoxes ?? [], id);
|
||||
|
||||
const width = getTextWidth(textBox.value.content, {
|
||||
fontSize: textBox.value.fontSize ?? TEXTBOX_DEFAULTS.fontSize,
|
||||
fontFamily: DEFAULT_FONT_FAMILY,
|
||||
fontWeight: TEXTBOX_FONT_WEIGHT
|
||||
});
|
||||
const height = 1;
|
||||
const size = { width, height };
|
||||
|
||||
draft.scene.textBoxes[textBox.value.id] = { size };
|
||||
});
|
||||
|
||||
return newState;
|
||||
};
|
||||
|
||||
export const updateTextBox = (
|
||||
id: string,
|
||||
updates: Partial<TextBox>,
|
||||
@@ -26,18 +49,9 @@ export const updateTextBox = (
|
||||
textBoxes[textBox.index] = newTextBox;
|
||||
|
||||
if (updates.content !== undefined || updates.fontSize !== undefined) {
|
||||
const width = getTextWidth(updates.content ?? textBox.value.content, {
|
||||
fontSize:
|
||||
updates.fontSize ??
|
||||
textBox.value.fontSize ??
|
||||
TEXTBOX_DEFAULTS.fontSize,
|
||||
fontFamily: DEFAULT_FONT_FAMILY,
|
||||
fontWeight: TEXTBOX_FONT_WEIGHT
|
||||
});
|
||||
const height = 1;
|
||||
const size = { width, height };
|
||||
|
||||
draft.scene.textBoxes[newTextBox.id] = { size };
|
||||
const stateAfterSync = syncTextBox(newTextBox.id, viewId, draft);
|
||||
draft.model = stateAfterSync.model;
|
||||
draft.scene = stateAfterSync.scene;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,35 @@
|
||||
import { produce } from 'immer';
|
||||
import { View } from 'src/types';
|
||||
import { getItemByIdOrThrow } from 'src/utils';
|
||||
import { State } from './types';
|
||||
import { syncConnector } from './connector';
|
||||
import { syncTextBox } from './textBox';
|
||||
|
||||
export const syncScene = (viewId: string, model: State['model']) => {
|
||||
const view = getItemByIdOrThrow(model.views, viewId);
|
||||
|
||||
const startingState: State = {
|
||||
model,
|
||||
scene: {
|
||||
connectors: {},
|
||||
textBoxes: {}
|
||||
}
|
||||
};
|
||||
|
||||
const stateAfterConnectorsSynced = [
|
||||
...(view.value.connectors ?? [])
|
||||
].reduce<State>((acc, connector) => {
|
||||
return syncConnector(connector.id, viewId, acc);
|
||||
}, startingState);
|
||||
|
||||
const stateAfterTextBoxesSynced = [
|
||||
...(view.value.textBoxes ?? [])
|
||||
].reduce<State>((acc, textBox) => {
|
||||
return syncTextBox(textBox.id, viewId, acc);
|
||||
}, stateAfterConnectorsSynced);
|
||||
|
||||
return stateAfterTextBoxesSynced;
|
||||
};
|
||||
|
||||
export const createView = (
|
||||
newView: View,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { produce } from 'immer';
|
||||
import { Model } from 'src/types';
|
||||
import { Model, ModelStore } from 'src/types';
|
||||
import { validateModel } from 'src/schemas/validation';
|
||||
import { getItemByIdOrThrow } from './common';
|
||||
|
||||
@@ -52,3 +52,15 @@ export const fixModel = (model: Model): Model => {
|
||||
return acc;
|
||||
}, model);
|
||||
};
|
||||
|
||||
export const modelFromModelStore = (modelStore: ModelStore): Model => {
|
||||
return {
|
||||
version: modelStore.version,
|
||||
title: modelStore.title,
|
||||
description: modelStore.description,
|
||||
colors: modelStore.colors,
|
||||
icons: modelStore.icons,
|
||||
items: modelStore.items,
|
||||
views: modelStore.views
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user