Skip to content

Commit

Permalink
Settings -> LocalItemState
Browse files Browse the repository at this point in the history
  • Loading branch information
OAGr committed Sep 20, 2023
1 parent c3fd9fc commit c030b44
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 60 deletions.
11 changes: 6 additions & 5 deletions packages/components/src/components/Calculator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,20 @@ export const Calculator: FC<Props> = ({
valueWithContext,
}) => {
const { path } = valueWithContext.context;
const { getSettings, dispatch: viewerContextDispatch } = useViewerContext();
const itemSettings = getSettings({ path });
const { getLocalItemState, dispatch: viewerContextDispatch } =
useViewerContext();
const itemState = getLocalItemState({ path });
const [prevCalculator, setPrevCalculator] = useState<SqCalculator | null>(
null
);

const getCalculatorStateFromCache = () => {
const sameCalculatorCacheExists =
itemSettings.calculator &&
hasSameCalculator(itemSettings.calculator, calculator);
itemState.calculator &&
hasSameCalculator(itemState.calculator, calculator);

if (sameCalculatorCacheExists) {
return itemSettings.calculator!;
return itemState.calculator!;
} else {
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
import { PlaygroundContext } from "../SquigglePlayground/index.js";
import {
ViewerContext,
useSetSettings,
useSetLocalItemState,
useViewerContext,
useResetStateSettings,
} from "./ViewerProvider.js";
import { pathAsString } from "./utils.js";

Expand All @@ -36,8 +37,8 @@ const ItemSettingsModal: React.FC<
close,
resetScroll,
}) => {
const setSettings = useSetSettings();
const { getSettings, getMergedSettings } = useViewerContext();
const setLocalItemState = useSetLocalItemState();
const { getLocalItemState, getMergedSettings } = useViewerContext();

const { path } = value.context;

Expand All @@ -51,16 +52,16 @@ const ItemSettingsModal: React.FC<

useEffect(() => {
const submit = form.handleSubmit((data) => {
setSettings(path, {
setLocalItemState(path, {
collapsed: false,
...data,
settings: data,
});
onChange();
});

const subscription = form.watch(() => submit());
return () => subscription.unsubscribe();
}, [getSettings, setSettings, onChange, path, form]);
}, [getLocalItemState, setLocalItemState, onChange, path, form]);

const { getLeftPanelElement } = useContext(PlaygroundContext);

Expand Down Expand Up @@ -98,8 +99,8 @@ const ItemSettingsModal: React.FC<

export const ItemSettingsMenu: React.FC<Props> = (props) => {
const [isOpen, setIsOpen] = useState(false);
const setSettings = useSetSettings();
const { localSettingsEnabled, getSettings, dispatch } =
const resetStateSettings = useResetStateSettings();
const { localSettingsEnabled, getLocalItemState, dispatch } =
useContext(ViewerContext);

const ref = useRef<HTMLDivElement | null>(null);
Expand All @@ -110,7 +111,7 @@ export const ItemSettingsMenu: React.FC<Props> = (props) => {

const { path } = props.value.context;

const settings = getSettings({ path });
const localState = getLocalItemState({ path });

const resetScroll = () => {
dispatch({
Expand All @@ -127,12 +128,10 @@ export const ItemSettingsMenu: React.FC<Props> = (props) => {
onClick={() => setIsOpen(!isOpen)}
/>
</TextTooltip>
{settings.distributionChartSettings ? (
{localState.settings.distributionChartSettings ? (
<button
onClick={() => {
setSettings(path, {
collapsed: settings.collapsed,
});
resetStateSettings(path, localState);
props.onChange();
}}
className="text-xs px-1 py-0.5 rounded bg-stone-200 hover:bg-stone-400"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const VariableBox: FC<VariableBoxProps> = ({
const toggleCollapsed_ = useToggleCollapsed();
const collapseChildren = useCollapseChildren();
const focus = useFocus();
const { editor, getSettings, getMergedSettings, dispatch } =
const { editor, getLocalItemState, getMergedSettings, dispatch } =
useViewerContext();
const isFocused = useIsFocused(value.context.path);
const { tag } = value;
Expand Down Expand Up @@ -89,10 +89,11 @@ export const VariableBox: FC<VariableBoxProps> = ({
}
return {
collapsed: !isRoot && childrenElements.length > 5,
settings: {},
};
}, [value, collapseChildren, isRoot]);

const settings = getSettings({ path, defaults });
const settings = getLocalItemState({ path, defaults });

const getAdjustedMergedSettings = (path: SqValuePath) => {
const mergedSettings = getMergedSettings({ path });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { CalculatorState } from "../Calculator/calculatorReducer.js";

export type Action =
| {
type: "SET_SETTINGS";
type: "SET_LOCAL_ITEM_STATE";
payload: {
path: SqValuePath;
value: LocalItemState;
Expand Down Expand Up @@ -79,10 +79,10 @@ export type Action =
export type ViewProviderDispatch = (action: Action) => void;

type ViewerContextShape = {
// Note that we don't store settings themselves in the context (that would cause rerenders of the entire tree on each settings update).
// Instead, we keep settings in local state and notify the global context via setSettings to pass them down the component tree again if it got rebuilt from scratch.
// Note that we don't store localItemState themselves in the context (that would cause rerenders of the entire tree on each settings update).
// Instead, we keep localItemState in local state and notify the global context via setLocalItemState to pass them down the component tree again if it got rebuilt from scratch.
// See ./SquiggleViewer.tsx and ./VariableBox.tsx for other implementation details on this.
getSettings({
getLocalItemState({
path,
defaults,
}: {
Expand All @@ -104,7 +104,7 @@ type ViewerContextShape = {
};

export const ViewerContext = createContext<ViewerContextShape>({
getSettings: () => ({ collapsed: false }),
getLocalItemState: () => ({ collapsed: false, settings: {} }),
getCalculator: () => undefined,
getMergedSettings: () => defaultPlaygroundSettings,
localSettingsEnabled: false,
Expand All @@ -117,11 +117,11 @@ export function useViewerContext() {
return useContext(ViewerContext);
}

export function useSetSettings() {
export function useSetLocalItemState() {
const { dispatch } = useViewerContext();
return (path: SqValuePath, value: LocalItemState) => {
dispatch({
type: "SET_SETTINGS",
type: "SET_LOCAL_ITEM_STATE",
payload: { path, value },
});
};
Expand All @@ -136,6 +136,21 @@ export function useToggleCollapsed() {
});
};
}
export function useResetStateSettings() {
const { dispatch } = useViewerContext();
return (path: SqValuePath, value: LocalItemState) => {
dispatch({
type: "SET_LOCAL_ITEM_STATE",
payload: {
path,
value: {
...value,
settings: {},
},
},
});
};
}

export function useFocus() {
const { dispatch } = useViewerContext();
Expand Down Expand Up @@ -175,16 +190,17 @@ export function useIsFocused(location: SqValuePath) {
}
}

type SettingsStore = {
type LocalItemStateStore = {
[k: string]: LocalItemState;
};

const defaultLocalSettings: LocalItemState = {
const defaultLocalItemState: LocalItemState = {
collapsed: false,
settings: {},
};

const collapsedVariablesDefault: SettingsStore = {
[topLevelBindingsName]: { collapsed: true },
const collapsedVariablesDefault: LocalItemStateStore = {
[topLevelBindingsName]: { collapsed: true, settings: {} },
};

export const ViewerProvider: FC<
Expand All @@ -202,7 +218,7 @@ export const ViewerProvider: FC<
children,
}) => {
// can't store settings in the state because we don't want to rerender the entire tree on every change
const settingsStoreRef = useRef<SettingsStore>(
const localItemStateStoreRef = useRef<LocalItemStateStore>(
beginWithVariablesCollapsed ? collapsedVariablesDefault : {}
);

Expand All @@ -214,61 +230,63 @@ export const ViewerProvider: FC<
return merge({}, defaultPlaygroundSettings, partialPlaygroundSettings);
}, [partialPlaygroundSettings]);

// I'm not sure if we should use this, or getSettings(), which is similar.
const getSettingsRef = (path: SqValuePath): LocalItemState | undefined => {
return settingsStoreRef.current[pathAsString(path)];
// I'm not sure if we should use this, or getLocalItemState(), which is similar.
const getLocalItemStateRef = (
path: SqValuePath
): LocalItemState | undefined => {
return localItemStateStoreRef.current[pathAsString(path)];
};

const setSettings = (
const setLocalItemState = (
path: SqValuePath,
fn: (settings: LocalItemState) => LocalItemState
fn: (localItemState: LocalItemState) => LocalItemState
): void => {
const newSettings = fn(getSettingsRef(path) || defaultLocalSettings);
settingsStoreRef.current[pathAsString(path)] = newSettings;
const newSettings = fn(getLocalItemStateRef(path) || defaultLocalItemState);
localItemStateStoreRef.current[pathAsString(path)] = newSettings;
};

const getSettings = useCallback(
const getLocalItemState = useCallback(
({
path,
defaults = defaultLocalSettings,
defaults = defaultLocalItemState,
}: {
path: SqValuePath;
defaults?: LocalItemState;
}) => {
return settingsStoreRef.current[pathAsString(path)] || defaults;
return localItemStateStoreRef.current[pathAsString(path)] || defaults;
},
[settingsStoreRef]
[localItemStateStoreRef]
);

const getCalculator = useCallback(
({ path }: { path: SqValuePath }) => {
const response = settingsStoreRef.current[pathAsString(path)];
const response = localItemStateStoreRef.current[pathAsString(path)];
return response?.calculator;
},
[settingsStoreRef]
[localItemStateStoreRef]
);

const getMergedSettings = useCallback(
({
path,
defaults = defaultLocalSettings,
defaults = defaultLocalItemState,
}: {
path: SqValuePath;
defaults?: LocalItemState;
}) => {
const localSettings = getSettings({ path, defaults });
const localItemState = getLocalItemState({ path, defaults });
const result: MergedItemSettings = merge(
{},
globalSettings,
localSettings
localItemState.settings
);
return result;
},
[globalSettings, getSettings]
[globalSettings, getLocalItemState]
);

const setCollapsed = (path: SqValuePath, isCollapsed: boolean) => {
setSettings(path, (state) => ({
setLocalItemState(path, (state) => ({
...state,
collapsed: state?.collapsed ?? isCollapsed,
}));
Expand All @@ -277,8 +295,8 @@ export const ViewerProvider: FC<
const dispatch = useCallback(
(action: Action) => {
switch (action.type) {
case "SET_SETTINGS":
setSettings(action.payload.path, () => action.payload.value);
case "SET_LOCAL_ITEM_STATE":
setLocalItemState(action.payload.path, () => action.payload.value);
return;
case "FOCUS":
setFocused(action.payload);
Expand All @@ -287,7 +305,7 @@ export const ViewerProvider: FC<
setFocused(undefined);
return;
case "TOGGLE_COLLAPSED": {
setSettings(action.payload, (state) => ({
setLocalItemState(action.payload, (state) => ({
...state,
collapsed: !state?.collapsed,
}));
Expand All @@ -314,21 +332,21 @@ export const ViewerProvider: FC<
return;
case "CALCULATOR_UPDATE": {
const { calculator, path } = action.payload;
setSettings(path, (state) => ({
setLocalItemState(path, (state) => ({
...state,
calculator: calculator,
}));
return;
}
}
},
[settingsStoreRef]
[localItemStateStoreRef]

Check warning on line 343 in packages/components/src/components/SquiggleViewer/ViewerProvider.tsx

View workflow job for this annotation

GitHub Actions / Build, test, lint

React Hook useCallback has missing dependencies: 'setCollapsed' and 'setLocalItemState'. Either include them or remove the dependency array
);

return (
<ViewerContext.Provider
value={{
getSettings,
getLocalItemState,
getCalculator,
getMergedSettings,
localSettingsEnabled,
Expand Down
9 changes: 5 additions & 4 deletions packages/components/src/components/SquiggleViewer/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { CalculatorState } from "../Calculator/calculatorReducer.js";
export type LocalItemState = {
collapsed: boolean;
calculator?: CalculatorState;
} & Pick<
PartialPlaygroundSettings,
"distributionChartSettings" | "functionChartSettings"
>;
settings: Pick<
PartialPlaygroundSettings,
"distributionChartSettings" | "functionChartSettings"
>;
};

export type MergedItemSettings = PlaygroundSettings;

Expand Down

0 comments on commit c030b44

Please sign in to comment.