mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-02-11 14:20:07 +08:00
feat(server): Render loop for skeleton and loading.
This commit is contained in:
parent
b1d4212ddd
commit
3ec944b752
@ -33,7 +33,7 @@ function reducer(state, action) {
|
||||
}
|
||||
|
||||
// TODO: inc every second
|
||||
const ProgressBarController = ({ id, ProgressBar, children, lowdefy }) => {
|
||||
const ProgressBarController = ({ id, ProgressBar, content, lowdefy }) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
return (
|
||||
<ProgressBar
|
||||
@ -46,7 +46,7 @@ const ProgressBarController = ({ id, ProgressBar, children, lowdefy }) => {
|
||||
properties={{ ...state }}
|
||||
user={lowdefy.user}
|
||||
content={{
|
||||
content: () => children({ state, dispatch }),
|
||||
content: () => content.content({ state, dispatch }),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -21,7 +21,7 @@ import { ErrorBoundary } from '@lowdefy/block-utils';
|
||||
import CategorySwitch from './CategorySwitch.js';
|
||||
import MountEvents from '../MountEvents.js';
|
||||
|
||||
const Block = ({ block, Blocks, context, isRoot, lowdefy, parentLoading }) => {
|
||||
const Block = ({ block, Blocks, context, isRoot, loading, lowdefy, parentLoading }) => {
|
||||
const [updates, setUpdate] = useState(0);
|
||||
lowdefy._internal.updaters[block.id] = () => setUpdate(updates + 1);
|
||||
return (
|
||||
@ -36,13 +36,13 @@ const Block = ({ block, Blocks, context, isRoot, lowdefy, parentLoading }) => {
|
||||
block.triggerEvent({ name: 'onMount' });
|
||||
}}
|
||||
>
|
||||
{(loading) => (
|
||||
{(eventLoading) => (
|
||||
<CategorySwitch
|
||||
block={block}
|
||||
Blocks={Blocks}
|
||||
context={context}
|
||||
isRoot={isRoot}
|
||||
loading={loading}
|
||||
loading={eventLoading || loading || block.eval.loading}
|
||||
lowdefy={lowdefy}
|
||||
updates={updates}
|
||||
/>
|
||||
|
@ -17,15 +17,53 @@
|
||||
import React from 'react';
|
||||
import { BlockLayout } from '@lowdefy/layout';
|
||||
import { makeCssClass } from '@lowdefy/block-utils';
|
||||
import { type } from '@lowdefy/helpers';
|
||||
|
||||
import Container from './Container.js';
|
||||
import List from './List.js';
|
||||
import LoadingBlock from './LoadingBlock.js';
|
||||
|
||||
const CategorySwitch = ({ block, Blocks, context, lowdefy }) => {
|
||||
if (!block.eval) return null; // Renderer updates before eval is executed for the first time on lists. See #520
|
||||
const CategorySwitch = ({ block, Blocks, context, loading, lowdefy }) => {
|
||||
if (!block.eval) return null; // TODO: check Renderer updates before eval is executed for the first time on lists. See #520
|
||||
if (block.eval.visible === false)
|
||||
return <div id={`vs-${block.blockId}`} style={{ display: 'none' }} />;
|
||||
const Component = lowdefy._internal.blockComponents[block.type];
|
||||
let Component = lowdefy._internal.blockComponents[block.type];
|
||||
// block skeleton:
|
||||
// undefined, null, true - Try render component skeleton
|
||||
// object - Render skeleton
|
||||
// false - Render component
|
||||
if (loading && block.eval.skeleton !== false && !type.isNone(block.eval.skeleton)) {
|
||||
if (!type.isObject(block.eval.skeleton) && block.eval.skeleton !== true) {
|
||||
throw new Error(
|
||||
`Config Error: Invalid skeleton definition at block id ${block.blockId}. Skeleton config must be a boolean or an object.`
|
||||
);
|
||||
}
|
||||
return (
|
||||
<LoadingBlock
|
||||
blockLayout={block.eval.layout}
|
||||
context={context}
|
||||
lowdefy={lowdefy}
|
||||
skeleton={block.eval.skeleton}
|
||||
/>
|
||||
);
|
||||
}
|
||||
// component skeleton:
|
||||
// false - Render component
|
||||
// object - Render component skeleton
|
||||
if (loading && Component.meta.skeleton !== false && !type.isNone(Component.meta.skeleton)) {
|
||||
if (!type.isObject(Component.meta.skeleton) && Component.meta.skeleton !== true) {
|
||||
throw new Error(`Block Error: Block type ${block.type} has an invalid skeleton definition.`);
|
||||
}
|
||||
return (
|
||||
<LoadingBlock
|
||||
skeleton={Component.meta.skeleton}
|
||||
context={context}
|
||||
lowdefy={lowdefy}
|
||||
layout={block.eval.layout || {}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
switch (Component.meta.category) {
|
||||
case 'list':
|
||||
return (
|
||||
@ -34,6 +72,7 @@ const CategorySwitch = ({ block, Blocks, context, lowdefy }) => {
|
||||
Blocks={Blocks}
|
||||
Component={Component}
|
||||
context={context}
|
||||
loading={loading}
|
||||
lowdefy={lowdefy}
|
||||
/>
|
||||
);
|
||||
@ -44,6 +83,7 @@ const CategorySwitch = ({ block, Blocks, context, lowdefy }) => {
|
||||
Blocks={Blocks}
|
||||
Component={Component}
|
||||
context={context}
|
||||
loading={loading}
|
||||
lowdefy={lowdefy}
|
||||
/>
|
||||
);
|
||||
@ -69,6 +109,7 @@ const CategorySwitch = ({ block, Blocks, context, lowdefy }) => {
|
||||
components={lowdefy._internal.components}
|
||||
events={block.eval.events}
|
||||
key={block.blockId}
|
||||
loading={loading}
|
||||
menus={lowdefy.menus}
|
||||
pageId={lowdefy.pageId}
|
||||
properties={block.eval.properties}
|
||||
@ -100,6 +141,7 @@ const CategorySwitch = ({ block, Blocks, context, lowdefy }) => {
|
||||
components={lowdefy._internal.components}
|
||||
events={block.eval.events}
|
||||
key={block.blockId}
|
||||
loading={loading}
|
||||
menus={lowdefy.menus}
|
||||
pageId={lowdefy.pageId}
|
||||
properties={block.eval.properties}
|
||||
|
@ -20,7 +20,7 @@ import { makeCssClass } from '@lowdefy/block-utils';
|
||||
|
||||
import Block from './Block.js';
|
||||
|
||||
const Container = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
const Container = ({ block, Blocks, Component, context, loading, lowdefy }) => {
|
||||
const content = {};
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
const areas = Blocks.subBlocks[block.id][0].areas;
|
||||
@ -44,6 +44,7 @@ const Container = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
Blocks={Blocks.subBlocks[block.id][0]}
|
||||
block={bl}
|
||||
context={context}
|
||||
loading={loading}
|
||||
lowdefy={lowdefy}
|
||||
/>
|
||||
))}
|
||||
@ -71,6 +72,7 @@ const Container = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
content={content}
|
||||
events={block.eval.events}
|
||||
key={block.blockId}
|
||||
loading={loading}
|
||||
menus={lowdefy.menus}
|
||||
pageId={lowdefy.pageId}
|
||||
properties={block.eval.properties}
|
||||
|
@ -20,7 +20,7 @@ import { makeCssClass } from '@lowdefy/block-utils';
|
||||
|
||||
import Block from './Block.js';
|
||||
|
||||
const List = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
const List = ({ block, Blocks, Component, context, loading, lowdefy }) => {
|
||||
const content = {};
|
||||
const contentList = [];
|
||||
Blocks.subBlocks[block.id].forEach((SBlock) => {
|
||||
@ -44,6 +44,7 @@ const List = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
Blocks={SBlock}
|
||||
block={bl}
|
||||
context={context}
|
||||
loading={loading}
|
||||
lowdefy={lowdefy}
|
||||
/>
|
||||
))}
|
||||
@ -78,6 +79,7 @@ const List = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
events={block.eval.events}
|
||||
key={block.blockId}
|
||||
list={contentList}
|
||||
loading={loading}
|
||||
menus={lowdefy.menus}
|
||||
pageId={lowdefy.pageId}
|
||||
properties={block.eval.properties}
|
||||
|
@ -1,22 +1,79 @@
|
||||
import React from 'react';
|
||||
// import { Loading, makeCssClass } from '@lowdefy/block-utils';
|
||||
// import { get } from '@lowdefy/helpers';
|
||||
// import { BlockLayout } from '@lowdefy/layout';
|
||||
/*
|
||||
Copyright 2020-2022 Lowdefy, Inc
|
||||
|
||||
const LoadingBlock = ({ block, lowdefy }) => (
|
||||
<div>LoadingBlock</div>
|
||||
// <BlockLayout
|
||||
// id={`bl-loading-${block.blockId}`}
|
||||
// blockStyle={get(block, 'eval.style') || get(block, 'meta.loading.style', { default: {} })}
|
||||
// highlightBorders={lowdefy.lowdefyGlobal.highlightBorders}
|
||||
// layout={get(block, 'eval.layout') || get(block, 'meta.loading.layout', { default: {} })}
|
||||
// makeCssClass={makeCssClass}
|
||||
// >
|
||||
// <Loading
|
||||
// properties={get(block, 'meta.loading.properties')}
|
||||
// type={get(block, 'meta.loading.type')}
|
||||
// />
|
||||
// </BlockLayout>
|
||||
);
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { BlockLayout } from '@lowdefy/layout';
|
||||
import { makeCssClass } from '@lowdefy/block-utils';
|
||||
|
||||
import LoadingContainer from './LoadingContainer.js';
|
||||
import LoadingList from './LoadingList.js';
|
||||
|
||||
const LoadingBlock = ({ blockLayout, blockId, context, lowdefy, skeleton }) => {
|
||||
let Component = lowdefy._internal.blockComponents[skeleton.type];
|
||||
if (!Component) {
|
||||
// default to box when a skeleton block is not found - should be a basic or loader block.
|
||||
// TODO: Always throw a warning if blocks other than basic or loader are used in a skeleton.
|
||||
Component = lowdefy._internal.blockComponents.Box;
|
||||
}
|
||||
const layout = skeleton.layout || blockLayout || {};
|
||||
switch (Component.meta.category) {
|
||||
case 'list':
|
||||
return (
|
||||
<LoadingList
|
||||
blockId={blockId}
|
||||
Component={Component}
|
||||
context={context}
|
||||
layout={layout}
|
||||
lowdefy={lowdefy}
|
||||
skeleton={skeleton}
|
||||
/>
|
||||
);
|
||||
case 'container':
|
||||
return (
|
||||
<LoadingContainer
|
||||
blockId={blockId}
|
||||
Component={Component}
|
||||
context={context}
|
||||
layout={layout}
|
||||
lowdefy={lowdefy}
|
||||
skeleton={skeleton}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<BlockLayout
|
||||
blockStyle={skeleton.style}
|
||||
highlightBorders={lowdefy.lowdefyGlobal.highlightBorders}
|
||||
id={`s-bl-${blockId}-${skeleton.id}`}
|
||||
layout={layout}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
<Component
|
||||
basePath={lowdefy.basePath}
|
||||
blockId={blockId}
|
||||
components={lowdefy._internal.components}
|
||||
key={`s-${blockId}-${skeleton.id}`}
|
||||
menus={lowdefy.menus}
|
||||
methods={{ makeCssClass }}
|
||||
pageId={lowdefy.pageId}
|
||||
properties={skeleton.properties}
|
||||
user={lowdefy.user}
|
||||
/>
|
||||
</BlockLayout>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default LoadingBlock;
|
||||
|
76
packages/server/lib/components/block/LoadingContainer.js
Normal file
76
packages/server/lib/components/block/LoadingContainer.js
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2020-2022 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Area, BlockLayout, layoutParamsToArea } from '@lowdefy/layout';
|
||||
import { makeCssClass } from '@lowdefy/block-utils';
|
||||
|
||||
import LoadingBlock from './LoadingBlock.js';
|
||||
|
||||
const LoadingContainer = ({ blockId, Component, context, layout, lowdefy, skeleton }) => {
|
||||
const content = {};
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
Object.keys(skeleton.areas).forEach((areaKey, i) => {
|
||||
content[areaKey] = (areaStyle) => (
|
||||
<Area
|
||||
area={layoutParamsToArea({
|
||||
area: skeleton.areas[areaKey] || {},
|
||||
areaKey,
|
||||
layout,
|
||||
})}
|
||||
areaStyle={[areaStyle, skeleton.areas[areaKey] && skeleton.areas[areaKey].style]}
|
||||
highlightBorders={lowdefy.lowdefyGlobal.highlightBorders}
|
||||
id={`s-ar-${blockId}-${skeleton.id}-${areaKey}`}
|
||||
key={`s-ar-${blockId}-${skeleton.id}-${areaKey}-${i}`}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
{skeleton.areas[areaKey].blocks.map((skl, k) => (
|
||||
<LoadingBlock
|
||||
blockId={blockId}
|
||||
context={context}
|
||||
key={`s-co-${skl.id}-${k}`}
|
||||
lowdefy={lowdefy}
|
||||
skeleton={skl}
|
||||
/>
|
||||
))}
|
||||
</Area>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<BlockLayout
|
||||
blockStyle={skeleton.style}
|
||||
highlightBorders={lowdefy.lowdefyGlobal.highlightBorders}
|
||||
id={`s-bl-${blockId}-${skeleton.id}`}
|
||||
layout={layout}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
<Component
|
||||
basePath={lowdefy.basePath}
|
||||
blockId={blockId}
|
||||
components={lowdefy._internal.components}
|
||||
content={content}
|
||||
key={skeleton.id}
|
||||
menus={lowdefy.menus}
|
||||
methods={{ makeCssClass }}
|
||||
pageId={lowdefy.pageId}
|
||||
properties={skeleton.properties}
|
||||
user={lowdefy.user}
|
||||
/>
|
||||
</BlockLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingContainer;
|
78
packages/server/lib/components/block/LoadingList.js
Normal file
78
packages/server/lib/components/block/LoadingList.js
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2020-2022 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Area, BlockLayout, layoutParamsToArea } from '@lowdefy/layout';
|
||||
import { makeCssClass } from '@lowdefy/block-utils';
|
||||
|
||||
import LoadingBlock from './LoadingBlock.js';
|
||||
|
||||
const LoadingList = ({ blockId, Component, context, layout, lowdefy, skeleton }) => {
|
||||
const content = {};
|
||||
const contentList = [];
|
||||
new Array(3).forEach(() => {
|
||||
Object.keys(skeleton.areas).forEach((areaKey, i) => {
|
||||
content[areaKey] = (areaStyle) => (
|
||||
<Area
|
||||
area={layoutParamsToArea({
|
||||
area: skeleton.areas[areaKey] || {},
|
||||
areaKey,
|
||||
layout,
|
||||
})}
|
||||
areaStyle={[areaStyle, skeleton.areas[areaKey] && skeleton.areas[areaKey].style]}
|
||||
highlightBorders={lowdefy.lowdefyGlobal.highlightBorders}
|
||||
id={`s-ar-${blockId}-${skeleton.id}-${areaKey}`}
|
||||
key={`s-ar-${blockId}-${skeleton.id}-${areaKey}-${i}`}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
{skeleton.areas[areaKey].blocks.map((skl, k) => (
|
||||
<LoadingBlock
|
||||
blockId={blockId}
|
||||
context={context}
|
||||
key={`s-co-${skl.id}-${k}`}
|
||||
lowdefy={lowdefy}
|
||||
skeleton={skl}
|
||||
/>
|
||||
))}
|
||||
</Area>
|
||||
);
|
||||
});
|
||||
contentList.push({ ...content });
|
||||
});
|
||||
return (
|
||||
<BlockLayout
|
||||
blockStyle={skeleton.style}
|
||||
highlightBorders={lowdefy.lowdefyGlobal.highlightBorders}
|
||||
id={`s-bl-${blockId}-${skeleton.id}`}
|
||||
layout={layout}
|
||||
makeCssClass={makeCssClass}
|
||||
>
|
||||
<Component
|
||||
basePath={lowdefy.basePath}
|
||||
blockId={blockId}
|
||||
components={lowdefy._internal.components}
|
||||
list={contentList}
|
||||
menus={lowdefy.menus}
|
||||
methods={{ makeCssClass }}
|
||||
pageId={lowdefy.pageId}
|
||||
properties={skeleton.properties}
|
||||
user={lowdefy.user}
|
||||
/>
|
||||
</BlockLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingList;
|
Loading…
Reference in New Issue
Block a user