fix: should show/hide schema when enabled/disabled TabBar, Tabs, Header (#2428)
This commit is contained in:
parent
b542802667
commit
26cd9e810c
@ -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",
|
||||
|
@ -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('../');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 };
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user