Skip to content

Commit ad6eafd

Browse files
update skeleton display and initial loading user interaction block
1 parent 8f32c85 commit ad6eafd

7 files changed

Lines changed: 79 additions & 18 deletions

File tree

editor/components/client-only.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from "react";
2+
3+
const ClientOnly = ({ children, ...delegated }) => {
4+
const [hasMounted, setHasMounted] = React.useState(false);
5+
6+
React.useEffect(() => {
7+
setHasMounted(true);
8+
}, []);
9+
10+
if (!hasMounted) return null;
11+
12+
return <React.Fragment {...delegated}>{children}</React.Fragment>;
13+
};
14+
15+
export default ClientOnly;

editor/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * as canvas from "./design-preview-as-is";
33
export * as code from "./code-editor";
44
export * as runner from "./app-runner";
55
export * as visualization from "../../editor-packages/editor-debugger/components/visualization";
6+
export * from "./client-only";

editor/hooks/use-design.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import { convert } from "@design-sdk/figma-node-conversion";
1515
import { mapFigmaRemoteToFigma } from "@design-sdk/figma-remote/lib/mapper";
1616
import { useFigmaAccessToken } from ".";
1717
import { FileResponse } from "@design-sdk/figma-remote-types";
18-
import { FigmaDesignRepository } from "repository/figma-design-repository";
18+
import {
19+
FigmaDesignRepository,
20+
TFetchFileForApp,
21+
} from "repository/figma-design-repository";
1922

2023
// globally configure auth credentials for interacting with `@design-sdk/figma-remote`
2124
configure_auth_credentials({
@@ -167,14 +170,14 @@ export function useDesign({
167170
}
168171

169172
export function useDesignFile({ file }: { file: string }) {
170-
const [designfile, setDesignFile] = useState<FileResponse>(null);
173+
const [designfile, setDesignFile] = useState<TFetchFileForApp>(null);
171174
const fat = useFigmaAccessToken();
172175
useEffect(() => {
173176
if (file && (fat.accessToken || fat.personalAccessToken)) {
174177
async function handle() {
175178
const repo = new FigmaDesignRepository(fat);
176179
const iterator = repo.fetchFile(file);
177-
let next: IteratorResult<FileResponse>;
180+
let next: IteratorResult<TFetchFileForApp>;
178181
while ((next = await iterator.next()).done === false) {
179182
setDesignFile(next.value);
180183
}

editor/pages/files/[key]/index.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useCallback, useReducer } from "react";
1+
import React, { useEffect, useCallback, useReducer, useState } from "react";
22
import { useRouter } from "next/router";
33
import { SigninToContinueBannerPrmoptProvider } from "components/prompt-banner-signin-to-continue";
44
import { Editor, EditorDefaultProviders } from "scaffolds/editor";
@@ -13,6 +13,8 @@ export default function FileEntryEditor() {
1313
const { key } = router.query;
1414
const filekey = key as string;
1515

16+
const [loading, setLoading] = useState<boolean>(true);
17+
1618
const [initialState, initialDispatcher] = useReducer(warmup.initialReducer, {
1719
type: "pending",
1820
});
@@ -28,6 +30,11 @@ export default function FileEntryEditor() {
2830

2931
useEffect(() => {
3032
if (file) {
33+
if (!file.__initial) {
34+
// when full file is loaded, allow editor with user interaction.
35+
setLoading(false);
36+
}
37+
3138
let val: EditorSnapshot;
3239

3340
// TODO: seed this as well
@@ -76,7 +83,7 @@ export default function FileEntryEditor() {
7683
<SigninToContinueBannerPrmoptProvider>
7784
<StateProvider state={safe_value} dispatch={handleDispatch}>
7885
<EditorDefaultProviders>
79-
<Editor />
86+
<Editor loading={loading} />
8087
</EditorDefaultProviders>
8188
</StateProvider>
8289
</SigninToContinueBannerPrmoptProvider>

editor/repository/figma-design-repository/index.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
import { fetch } from "@design-sdk/figma-remote";
22
import { FileResponse } from "@design-sdk/figma-remote-types";
3-
import { FigmaFileStore } from "store/fimga-file-store/figma-file-store";
3+
import {
4+
FigmaFileStore,
5+
FileResponseRecord,
6+
} from "store/fimga-file-store/figma-file-store";
7+
8+
export type TFetchFileForApp = (
9+
| fetch.FetchFileGeneratorReturnType
10+
| FileResponseRecord
11+
) & {
12+
/**
13+
* rather this fetch is a initail fetch. this is used when blocking the user interaction until first initial whole file fetching on first entry.
14+
*/
15+
__initial: boolean;
16+
};
417

518
export class FigmaDesignRepository {
619
constructor(
@@ -10,7 +23,7 @@ export class FigmaDesignRepository {
1023
const store = new FigmaFileStore(fileId);
1124
const existing = await store.get();
1225
if (existing) {
13-
yield existing;
26+
yield { ...existing, __initial: false } as TFetchFileForApp;
1427
}
1528

1629
const _iter = fetch.fetchFile({ file: fileId, auth: this.auth });
@@ -19,18 +32,18 @@ export class FigmaDesignRepository {
1932
switch (next.value.__response_type) {
2033
case "pages":
2134
if (!existing) {
22-
yield next.value;
35+
yield { ...next.value, __initial: true } as TFetchFileForApp;
2336
store.upsert(next.value);
2437
}
2538
break;
2639
case "roots":
2740
if (!existing) {
28-
yield next.value;
41+
yield { ...next.value, __initial: true } as TFetchFileForApp;
2942
store.upsert(next.value);
3043
}
3144
break;
3245
case "whole":
33-
yield next.value;
46+
yield { ...next.value, __initial: false } as TFetchFileForApp;
3447
store.upsert(next.value);
3548
break;
3649
}

editor/scaffolds/editor/editor.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,14 @@ import {
2222
} from "@design-sdk/core/assets-repository";
2323
import { useFigmaAccessToken } from "hooks";
2424

25-
export function Editor() {
25+
export function Editor({
26+
loading = false,
27+
}: {
28+
/**
29+
* explicitly set loading to block uesr interaction.
30+
*/
31+
loading?: boolean;
32+
}) {
2633
const wstate = useWorkspaceState();
2734
const [state] = useEditorState();
2835

@@ -51,13 +58,16 @@ export function Editor() {
5158

5259
const _initially_loaded = state.design?.pages?.length > 0;
5360
const _initial_load_progress =
54-
[!!state.design?.input, state.design?.pages?.length > 0].filter(Boolean)
55-
.length / 2;
61+
[!!state.design?.input, state.design?.pages?.length > 0, !loading].filter(
62+
Boolean
63+
).length /
64+
3 +
65+
0.2;
5666

5767
return (
5868
<>
59-
{!_initially_loaded && (
60-
<EditorSkeleton percent={_initial_load_progress + 0.2} />
69+
{(loading || !_initially_loaded) && (
70+
<EditorSkeleton percent={_initial_load_progress * 100} />
6171
)}
6272
<DefaultEditorWorkspaceLayout
6373
backgroundColor={colors.color_editor_bg_on_dark}

editor/scaffolds/editor/skeleton.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,24 @@ import { HomeLogo } from "icons/home-logo";
44
import { withStyles } from "@material-ui/core/styles";
55
import Box from "@material-ui/core/Box";
66
import LinearProgress from "@material-ui/core/LinearProgress";
7+
import ClientOnly from "components/client-only";
78

8-
export function EditorSkeleton({ percent = 0 }: { percent?: number }) {
9+
export function EditorSkeleton({
10+
percent = 0,
11+
}: {
12+
/**
13+
* loading progress to display on progress bar
14+
*/
15+
percent?: number;
16+
}) {
917
return (
1018
<SkeletonWrap>
1119
<LoadingIndicatorContainer>
1220
<LogoAndLoading>
1321
<HomeLogo />
14-
<ColoredLinearProgress />
22+
<ClientOnly>
23+
<ColoredLinearProgress value={percent} />
24+
</ClientOnly>
1525
</LogoAndLoading>
1626
<TipsContainer />
1727
</LoadingIndicatorContainer>
@@ -68,7 +78,9 @@ const styles = (props) => ({
6878
},
6979
});
7080

71-
const ColoredLinearProgress = withStyles(styles)(function (props) {
81+
const ColoredLinearProgress = withStyles(styles)(function (props: {
82+
value?: number;
83+
}) {
7284
//@ts-ignore
7385
const { classes } = props;
7486
return (

0 commit comments

Comments
 (0)