fix: should show/hide schema when enabled/disabled TabBar, Tabs, Header (#2428)

This commit is contained in:
Dunqing 2023-08-14 20:32:40 +08:00 committed by GitHub
parent b542802667
commit 26cd9e810c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 111 deletions

View File

@ -20,7 +20,8 @@
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-i18next": "^11.15.1",
"react-router-dom": "^6.11.2"
"react-router-dom": "^6.11.2",
"ahooks": "^3.7.2"
},
"peerDependencies": {
"@nocobase/client": "0.x",

View File

@ -6,20 +6,21 @@ import { Button } from 'antd';
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { generateNTemplate, useTranslation } from '../../../../locale';
import { PageSchema } from '../../common';
import { findSchema } from '../../helpers';
import { useSchemaPatch } from '../../hooks';
export const ContainerDesigner = () => {
const { t } = useTranslation();
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
const tabBarSchema = fieldSchema.reduceProperties(
(schema, next) => schema || (next['x-component'] === 'MTabBar' && next),
) as Schema;
const navigate = useNavigate();
const { onUpdateComponentProps } = useSchemaPatch();
const field = useField();
const { dn } = useDesignable();
const navigate = useNavigate();
const tabBarSchema = findSchema(fieldSchema, 'MTabBar');
const tabBarEnabled = tabBarSchema && field.componentProps.tabBarEnabled !== false;
const schemaSettingsProps = {
dn,
field,
@ -43,44 +44,41 @@ export const ContainerDesigner = () => {
{...schemaSettingsProps}
>
<SchemaSettings.SwitchItem
checked={!!tabBarSchema}
checked={tabBarEnabled}
title={t('Enable TabBar')}
onChange={async (v) => {
if (v) {
const pageSchema = findSchema(fieldSchema, 'MPage');
if (!pageSchema) return;
await dn.remove(pageSchema);
await dn.insertBeforeEnd({
type: 'void',
'x-component': 'MTabBar',
'x-component-props': {},
name: 'tabBar',
properties: {
[uid()]: {
type: 'void',
'x-component': 'MTabBar.Item',
'x-designer': 'MTabBar.Item.Designer',
'x-component-props': {
icon: 'HomeOutlined',
title: generateNTemplate('Untitled'),
},
properties: {
page: pageSchema.toJSON(),
if (!tabBarSchema) {
const pageSchema = findSchema(fieldSchema, 'MPage');
await dn.insertBeforeEnd({
type: 'void',
'x-component': 'MTabBar',
'x-component-props': {},
name: 'tabBar',
properties: {
[uid()]: {
type: 'void',
'x-component': 'MTabBar.Item',
'x-designer': 'MTabBar.Item.Designer',
'x-component-props': {
icon: 'HomeOutlined',
title: generateNTemplate('Untitled'),
},
properties: {
page: pageSchema.toJSON(),
},
},
},
},
});
} else {
const tabBarSchemaFirstKey = Object.keys(tabBarSchema.properties || {})?.[0];
const pageSchema = tabBarSchemaFirstKey
? findSchema(tabBarSchema.properties[tabBarSchemaFirstKey], 'MPage')
: null;
await dn.remove(tabBarSchema);
await dn.insertBeforeEnd(pageSchema || PageSchema, {
onSuccess() {
navigate('../');
},
});
});
}
}
await onUpdateComponentProps({
tabBarEnabled: v,
});
if (v === false) {
navigate('../');
}
}}
/>

View File

@ -1,4 +1,4 @@
import { useFieldSchema } from '@formily/react';
import { useField, useFieldSchema } from '@formily/react';
import { cx, SchemaComponent, SortableItem, useDesigner, useToken } from '@nocobase/client';
import React, { useEffect } from 'react';
import { Navigate, useLocation, useNavigate, useParams } from 'react-router-dom';
@ -36,6 +36,8 @@ const InternalContainer: React.FC = (props) => {
const navigate = useNavigate();
const params = useParams<{ name: string }>();
const location = useLocation();
const field = useField();
const isTabBarEnabled = field.componentProps.tabBarEnabled !== false;
const tabBarSchema = fieldSchema?.properties?.['tabBar'];
const tabBarCurrentFirstKey = tabBarSchema?.properties ? Object.keys(tabBarSchema.properties)[0] : null;
let redirectToUid = null;
@ -69,15 +71,17 @@ const InternalContainer: React.FC = (props) => {
/>
)}
</div>
<div className={cx('nb-mobile-container-tab-bar', styles.tabBar)}>
<SchemaComponent
onlyRenderProperties
filterProperties={(schema) => {
return schema['x-component'] === 'MTabBar';
}}
schema={fieldSchema}
></SchemaComponent>
</div>
{isTabBarEnabled && (
<div className={cx('nb-mobile-container-tab-bar', styles.tabBar)}>
<SchemaComponent
onlyRenderProperties
filterProperties={(schema) => {
return schema['x-component'] === 'MTabBar';
}}
schema={fieldSchema}
></SchemaComponent>
</div>
)}
</SortableItem>
);
};

View File

@ -6,15 +6,19 @@ import { Button } from 'antd';
import React from 'react';
import { generateNTemplate, useTranslation } from '../../../../locale';
import { findGridSchema } from '../../helpers';
import { useSchemaPatch } from '../../hooks';
export const PageDesigner = (props) => {
const { showBack } = props;
const { t } = useTranslation();
const field = useField();
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
const { onUpdateComponentProps } = useSchemaPatch();
const headerSchema = fieldSchema?.properties?.['header'];
const isHeaderEnabled = !!headerSchema && field.componentProps?.headerEnabled !== false;
const tabsSchema = fieldSchema?.properties?.['tabs'];
const field = useField();
const isTabsEnabled = !!tabsSchema && field.componentProps?.tabsEnabled !== false;
const schemaSettingsProps = {
dn,
field,
@ -39,10 +43,10 @@ export const PageDesigner = (props) => {
{...schemaSettingsProps}
>
<SchemaSettings.SwitchItem
checked={!!headerSchema}
checked={isHeaderEnabled}
title={t('Enable Header')}
onChange={async (v) => {
if (v) {
if (!headerSchema) {
await dn.insertAfterBegin({
type: 'void',
name: 'header',
@ -53,53 +57,49 @@ export const PageDesigner = (props) => {
showBack,
},
});
} else {
await dn.remove(headerSchema);
}
dn.refresh();
await onUpdateComponentProps({
headerEnabled: v,
});
}}
/>
<SchemaSettings.SwitchItem
checked={!!tabsSchema}
checked={isTabsEnabled}
title={t('Enable Tabs')}
onChange={async (v) => {
if (v) {
if (!tabsSchema) {
const gridSchema = findGridSchema(fieldSchema);
if (gridSchema) {
return dn.remove(gridSchema).then(() => {
return dn.insertBeforeEnd({
await dn.remove(gridSchema);
return dn.insertBeforeEnd({
type: 'void',
name: 'tabs',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'TabPaneInitializers',
'x-initializer-props': {
gridInitializer: 'MBlockInitializers',
},
properties: {
tab1: {
type: 'void',
name: 'tabs',
'x-component': 'Tabs',
title: generateNTemplate('Untitled'),
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
'x-initializer': 'TabPaneInitializers',
'x-initializer-props': {
gridInitializer: 'MBlockInitializers',
},
properties: {
tab1: {
type: 'void',
title: generateNTemplate('Untitled'),
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
...gridSchema,
'x-uid': uid(),
},
},
grid: {
...gridSchema,
'x-uid': uid(),
},
},
});
});
}
} else {
const gridSchema = findGridSchema(tabsSchema.properties[Object.keys(tabsSchema.properties)[0]]);
if (gridSchema) {
return dn.remove(tabsSchema).then(() => dn.insertBeforeEnd(gridSchema, {}));
}
},
},
});
}
await onUpdateComponentProps({
tabsEnabled: v,
});
}}
/>
</SchemaSettings>

View File

@ -1,18 +1,32 @@
import { RecursionField, useFieldSchema } from '@formily/react';
import { RecursionField, useField, useFieldSchema } from '@formily/react';
import { ActionBarProvider, SortableItem, TabsContextProvider, cx, useDesigner } from '@nocobase/client';
import { TabsProps } from 'antd';
import React, { useCallback } from 'react';
import { useSearchParams } from 'react-router-dom';
import { countGridCol } from '../../helpers';
import { countGridCol, findSchema } from '../../helpers';
import { PageDesigner } from './Page.Designer';
import useStyles from './style';
const InternalPage: React.FC = (props) => {
const { styles } = useStyles();
const Designer = useDesigner();
const field = useField();
const fieldSchema = useFieldSchema();
const [searchParams, setSearchParams] = useSearchParams();
const tabsSchema = fieldSchema.properties?.['tabs'];
const isHeaderEnabled = field.componentProps.headerEnabled !== false;
const isTabsEnabled = field.componentProps.tabsEnabled !== false;
let pageSchema = findSchema(fieldSchema, 'MPage');
if (!isTabsEnabled && !pageSchema && tabsSchema) {
const schemaArr = Object.values(tabsSchema.properties || {}).sort((k1, k2) => {
return k1['x-index'] - k2['x-index'];
});
if (schemaArr.length !== 0) {
pageSchema = Object.values(schemaArr[0].properties)?.[0];
}
}
// Only support globalActions in page
const onlyInPage = fieldSchema.root === fieldSchema.parent;
let hasGlobalActions = false;
@ -42,9 +56,9 @@ const InternalPage: React.FC = (props) => {
const GlobalActionProvider = useCallback(
(props) => {
if (hasGlobalActions) {
return (
<TabsContextProvider>
return (
<TabsContextProvider>
{hasGlobalActions ? (
<ActionBarProvider
container={
(typeof props.active !== 'undefined' ? props.active : true) && onlyInPage
@ -58,12 +72,13 @@ const InternalPage: React.FC = (props) => {
>
{props.children}
</ActionBarProvider>
</TabsContextProvider>
);
}
return <>{props.children}</>;
) : (
props.children
)}
</TabsContextProvider>
);
},
[hasGlobalActions, onlyInPage],
[hasGlobalActions, onlyInPage, styles.globalActionCSS],
);
return (
@ -75,21 +90,23 @@ const InternalPage: React.FC = (props) => {
}}
className={cx('nb-mobile-page-header', styles.mobilePageHeader)}
>
<RecursionField
schema={fieldSchema}
filterProperties={(s) => {
return 'MHeader' === s['x-component'];
}}
></RecursionField>
{isHeaderEnabled && (
<RecursionField
schema={fieldSchema}
filterProperties={(s) => {
return 'MHeader' === s['x-component'];
}}
></RecursionField>
)}
<TabsContextProvider
PaneRoot={GlobalActionProvider}
activeKey={searchParams.get('tab')}
onChange={onTabsChange}
>
<RecursionField
schema={fieldSchema}
schema={isTabsEnabled ? fieldSchema : pageSchema}
filterProperties={(s) => {
return 'Tabs' === s['x-component'];
return 'Tabs' === s['x-component'] || 'Grid.Row' === s['x-component'];
}}
></RecursionField>
</TabsContextProvider>

View File

@ -1,17 +1,17 @@
import { useField, useFieldSchema } from '@formily/react';
import { useDesignable } from '@nocobase/client';
import lodash from 'lodash';
import { useCallback } from 'react';
import { useMemoizedFn } from 'ahooks';
export const useSchemaPatch = () => {
const { dn } = useDesignable();
const fieldSchema = useFieldSchema();
const field = useField();
const onUpdateComponentProps = useCallback((data) => {
const onUpdateComponentProps = useMemoizedFn(async (data) => {
lodash.set(fieldSchema, 'x-component-props', data);
field.componentProps = { ...field.componentProps, ...data };
dn.emit('patch', {
await dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-component-props': fieldSchema['x-component-props'],
@ -23,8 +23,8 @@ export const useSchemaPatch = () => {
],
},
});
dn.refresh();
}, []);
await dn.refresh();
});
return { onUpdateComponentProps };
};