mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2024-11-27 08:39:59 +08:00
Merge branch 'main' into publish
* main: chore: remove `renderField` fix: show the state type by real initial value feat: improve the trait form fix: change the expression styles fix: fix no event type in the event widget adjust the editor area feat(table): add row click feat: add the TableColumn widget # Conflicts: # packages/chakra-ui-lib/package.json
This commit is contained in:
commit
d7f3b7f11a
@ -10,7 +10,13 @@ import { css } from '@emotion/css';
|
||||
import { Type, Static } from '@sinclair/typebox';
|
||||
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
|
||||
import { TablePropsSchema, ColumnSchema } from '../generated/types/Table';
|
||||
import { ReactNode, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, {
|
||||
ReactNode,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { sortBy } from 'lodash-es';
|
||||
import {
|
||||
LIST_ITEM_EXP,
|
||||
@ -21,6 +27,7 @@ import {
|
||||
import { TableInstance } from '@arco-design/web-react/es/Table/table';
|
||||
|
||||
const TableStateSchema = Type.Object({
|
||||
clickedRow:Type.Optional(Type.Any()),
|
||||
selectedRows: Type.Array(Type.Any()),
|
||||
selectedRow: Type.Optional(Type.Any()),
|
||||
selectedRowKeys: Type.Array(Type.String()),
|
||||
@ -52,6 +59,16 @@ const rowSelectionTypeMap: Record<string, 'checkbox' | 'radio' | undefined> = {
|
||||
disable: undefined,
|
||||
};
|
||||
|
||||
const rowClickStyle = css`
|
||||
cursor: pointer;
|
||||
& tr.selected td {
|
||||
background-color: rgb(235, 244, 251);
|
||||
}
|
||||
& tr.selected:hover > td {
|
||||
background-color: rgb(228, 236, 243) !important;
|
||||
}
|
||||
`;
|
||||
|
||||
export const exampleProperties: Static<typeof TablePropsSchema> = {
|
||||
columns: [
|
||||
{
|
||||
@ -116,6 +133,7 @@ export const exampleProperties: Static<typeof TablePropsSchema> = {
|
||||
pagination: {
|
||||
pageSize: 6,
|
||||
},
|
||||
rowClick:false,
|
||||
tableLayoutFixed: false,
|
||||
borderCell: false,
|
||||
stripe: false,
|
||||
@ -149,7 +167,7 @@ export const Table = implementRuntimeComponent({
|
||||
const { getElement, app, mergeState, customStyle, services, data, component } = props;
|
||||
|
||||
const ref = useRef<TableInstance | null>(null);
|
||||
const { pagination, ...cProps } = getComponentProps(props);
|
||||
const { pagination, rowClick, ...cProps } = getComponentProps(props);
|
||||
|
||||
const rowSelectionType = rowSelectionTypeMap[cProps.rowSelectionType];
|
||||
|
||||
@ -317,7 +335,10 @@ export const Table = implementRuntimeComponent({
|
||||
return (
|
||||
<BaseTable
|
||||
ref={ref}
|
||||
className={css(customStyle?.content)}
|
||||
className={css`
|
||||
${customStyle?.content}
|
||||
${rowClick ? rowClickStyle : ''}
|
||||
`}
|
||||
{...cProps}
|
||||
columns={columns}
|
||||
pagination={{
|
||||
@ -342,6 +363,24 @@ export const Table = implementRuntimeComponent({
|
||||
mergeState({ selectedRows });
|
||||
},
|
||||
}}
|
||||
onRow={
|
||||
rowClick
|
||||
? record => {
|
||||
return {
|
||||
onClick(event: React.ChangeEvent<HTMLButtonElement>) {
|
||||
const tr = event.target.closest('tr');
|
||||
const tbody = tr?.parentNode;
|
||||
if (tbody) {
|
||||
const prevSelectedEl = tbody.querySelector('.selected');
|
||||
prevSelectedEl?.classList.remove('selected');
|
||||
}
|
||||
tr?.classList.add('selected');
|
||||
mergeState({ clickedRow: record });
|
||||
},
|
||||
};
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
@ -107,6 +107,11 @@ export const TablePropsSchema = Type.Object({
|
||||
category: Category.Layout,
|
||||
weight: 10,
|
||||
}),
|
||||
rowClick:Type.Boolean({
|
||||
title: 'Row Click',
|
||||
category: Category.Basic,
|
||||
description:'If on, the table can be selected without setting the rowSelectionType'
|
||||
}),
|
||||
loading: Type.Boolean({
|
||||
title: 'Show Loading',
|
||||
category: Category.Basic,
|
||||
|
@ -23,7 +23,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"test": "jest",
|
||||
"build": "tsup src/index.ts --format cjs,esm,iife --legacy-output --inject ./react-import.js --clean --no-splitting --sourcemap",
|
||||
"build": "tsup src/index.ts src/widgets/index.ts --format cjs,esm,iife --legacy-output --inject ./react-import.js --clean --no-splitting --sourcemap",
|
||||
"typings": "tsc --emitDeclarationOnly",
|
||||
"lint": "eslint src --ext .ts",
|
||||
"prepublish": "npm run build && npm run typings"
|
||||
@ -35,6 +35,7 @@
|
||||
"@sinclair/typebox": "^0.21.2",
|
||||
"@sunmao-ui/core": "^0.5.3",
|
||||
"@sunmao-ui/runtime": "^0.5.3",
|
||||
"@sunmao-ui/editor-sdk": "^0.1.3",
|
||||
"chakra-react-select": "^1.3.2",
|
||||
"framer-motion": "^4",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Type } from '@sinclair/typebox';
|
||||
import { ModuleSchema, EventHandlerSchema } from '@sunmao-ui/runtime';
|
||||
import { ModuleSchema, BaseEventSchema } from '@sunmao-ui/runtime';
|
||||
import { BASIC, APPEARANCE, BEHAVIOR } from '../constants/category';
|
||||
|
||||
export const MajorKeyPropertySchema = Type.String({
|
||||
@ -57,7 +57,7 @@ export const ColumnSchema = Type.Object(
|
||||
text: Type.String({
|
||||
title: 'Button Text',
|
||||
}),
|
||||
handlers: Type.Array(EventHandlerSchema, {
|
||||
handlers: Type.Array(Type.Object(BaseEventSchema, { widget: 'core/v1/Event' }), {
|
||||
title: 'Button Handlers',
|
||||
}),
|
||||
},
|
||||
@ -69,6 +69,7 @@ export const ColumnSchema = Type.Object(
|
||||
},
|
||||
{
|
||||
title: 'Column',
|
||||
widget: 'chakra_ui/v1/TableColumn'
|
||||
}
|
||||
);
|
||||
|
||||
|
50
packages/chakra-ui-lib/src/widgets/TableColumn.tsx
Normal file
50
packages/chakra-ui-lib/src/widgets/TableColumn.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { implementWidget, WidgetProps, SchemaField } from '@sunmao-ui/editor-sdk';
|
||||
|
||||
export const TableColumnWidget: React.FC<WidgetProps> = props => {
|
||||
const { value, level, path, schema, component, services, onChange } = props;
|
||||
const { type } = value;
|
||||
const properties = schema.properties || {};
|
||||
const TYPE_MAP: Record<string, boolean> = {
|
||||
buttonConfig: type === 'button',
|
||||
module: type === 'module',
|
||||
};
|
||||
const propertyKeys = Object.keys(properties).filter(key => TYPE_MAP[key] !== false);
|
||||
const schemas: JSONSchema7[] = propertyKeys.map(key => properties[key] as JSONSchema7);
|
||||
|
||||
return (
|
||||
<>
|
||||
{schemas.map((propertySchema, index) => {
|
||||
const key = propertyKeys[index];
|
||||
|
||||
return (
|
||||
<SchemaField
|
||||
key={key}
|
||||
component={component}
|
||||
services={services}
|
||||
schema={propertySchema}
|
||||
value={value[key]}
|
||||
level={level + 1}
|
||||
path={path.concat(key)}
|
||||
onChange={propertyValue => {
|
||||
const result = {
|
||||
...value,
|
||||
[key]: propertyValue,
|
||||
};
|
||||
|
||||
onChange(result);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default implementWidget({
|
||||
version: 'chakra_ui/v1',
|
||||
metadata: {
|
||||
name: 'TableColumn',
|
||||
},
|
||||
})(TableColumnWidget);
|
5
packages/chakra-ui-lib/src/widgets/index.ts
Normal file
5
packages/chakra-ui-lib/src/widgets/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import tableColumnWidget from './TableColumn';
|
||||
|
||||
export * from './TableColumn';
|
||||
|
||||
export const widgets = [tableColumnWidget];
|
@ -252,7 +252,7 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
|
||||
return (
|
||||
<>
|
||||
{schema.properties?.type ? null : typeField}
|
||||
{schema.properties?.type ? typeField : null}
|
||||
{targetField}
|
||||
{methodField}
|
||||
{hasParams ? parametersField : null}
|
||||
|
@ -153,7 +153,7 @@ export const ExpressionWidget: React.FC<
|
||||
|
||||
return (
|
||||
<ExpressionEditor
|
||||
{...{
|
||||
compactOptions={{
|
||||
maxHeight: '125px',
|
||||
...(widgetOptions?.compactOptions || {}),
|
||||
}}
|
||||
|
@ -120,9 +120,11 @@ export const SchemaFieldWidgetOptions = Type.Object({
|
||||
|
||||
type SchemaFieldWidgetOptionsType = Static<typeof SchemaFieldWidgetOptions>;
|
||||
type Props = WidgetProps<SchemaFieldWidgetOptionsType> & {
|
||||
children?: React.ReactNode & {
|
||||
title?: any;
|
||||
} | null;
|
||||
children?:
|
||||
| (React.ReactNode & {
|
||||
title?: any;
|
||||
})
|
||||
| null;
|
||||
};
|
||||
|
||||
export const SchemaField: React.FC<Props> = props => {
|
||||
@ -192,7 +194,10 @@ export const SchemaField: React.FC<Props> = props => {
|
||||
title: children instanceof Object ? children.title : null,
|
||||
content: (
|
||||
<HStack>
|
||||
<Box flex={schema.type === 'boolean' && isExpression === false ? '' : 1}>
|
||||
<Box
|
||||
flex={schema.type === 'boolean' && isExpression === false ? '' : 1}
|
||||
maxWidth="100%"
|
||||
>
|
||||
<Component
|
||||
component={component}
|
||||
schema={
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { flatten } from 'lodash-es';
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FormControl, FormLabel, Input, Textarea, Text, VStack } from '@chakra-ui/react';
|
||||
import { FormControl, FormLabel, Input, Text, VStack } from '@chakra-ui/react';
|
||||
import { SchemaField } from '@sunmao-ui/editor-sdk';
|
||||
import { TSchema } from '@sinclair/typebox';
|
||||
import { parseType } from '@sunmao-ui/core';
|
||||
@ -18,75 +17,6 @@ type Props = {
|
||||
services: EditorServices;
|
||||
};
|
||||
|
||||
export const renderField = (properties: {
|
||||
key: string;
|
||||
value: unknown;
|
||||
type?: string;
|
||||
fullKey: string;
|
||||
selectedComponentId: string;
|
||||
index: number;
|
||||
services: EditorServices;
|
||||
}) => {
|
||||
const { value, type, fullKey, selectedComponentId, index, services } = properties;
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const [textareaValue, setTextareaValue] = useState(value as string);
|
||||
const { eventBus, registry } = services;
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useEffect(() => {
|
||||
if (typeof value !== 'object') {
|
||||
setTextareaValue(value as string);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
if (typeof value !== 'object') {
|
||||
const ref = React.createRef<HTMLTextAreaElement>();
|
||||
const onBlur = () => {
|
||||
const operation = type
|
||||
? genOperation(registry, 'modifyTraitProperty', {
|
||||
componentId: selectedComponentId,
|
||||
traitIndex: index,
|
||||
properties: {
|
||||
[fullKey]: ref.current?.value,
|
||||
},
|
||||
})
|
||||
: genOperation(registry, 'modifyComponentProperty', {
|
||||
componentId: selectedComponentId,
|
||||
properties: {
|
||||
[fullKey]: ref.current?.value,
|
||||
},
|
||||
});
|
||||
eventBus.send('operation', operation);
|
||||
};
|
||||
const onChange = (event: any) => {
|
||||
setTextareaValue(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl key={`${selectedComponentId}-${fullKey}`}>
|
||||
<FormLabel>{fullKey}</FormLabel>
|
||||
<Textarea ref={ref} onChange={onChange} onBlur={onBlur} value={textareaValue} />
|
||||
</FormControl>
|
||||
);
|
||||
} else {
|
||||
const fieldArray: React.ReactElement[] = flatten(
|
||||
Object.keys(value || []).map((childKey, index) => {
|
||||
const childValue = (value as any)[childKey];
|
||||
return renderField({
|
||||
index,
|
||||
key: childKey,
|
||||
value: childValue,
|
||||
type: type,
|
||||
fullKey: `${fullKey}.${childKey}`,
|
||||
selectedComponentId,
|
||||
services,
|
||||
});
|
||||
})
|
||||
);
|
||||
return fieldArray;
|
||||
}
|
||||
};
|
||||
|
||||
export const ComponentForm: React.FC<Props> = observer(props => {
|
||||
const { services } = props;
|
||||
const { editorStore, registry, eventBus } = services;
|
||||
|
@ -55,7 +55,7 @@ export const AddTraitButton: React.FC<Props> = props => {
|
||||
icon={<AddIcon />}
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
/>
|
||||
<MenuList>{menuItems}</MenuList>
|
||||
<MenuList zIndex={2}>{menuItems}</MenuList>
|
||||
</Menu>
|
||||
</Box>
|
||||
);
|
||||
|
@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
import { ComponentSchema, TraitSchema } from '@sunmao-ui/core';
|
||||
import { HStack, IconButton, VStack } from '@chakra-ui/react';
|
||||
import { parseTypeBox } from '@sunmao-ui/runtime';
|
||||
import { CloseIcon } from '@chakra-ui/icons';
|
||||
import { TSchema } from '@sinclair/typebox';
|
||||
import { renderField } from '../ComponentForm';
|
||||
import { formWrapperCSS } from '../style';
|
||||
import { EditorServices } from '../../../types';
|
||||
import { SchemaField } from '@sunmao-ui/editor-sdk';
|
||||
import { genOperation } from '../../../operations';
|
||||
|
||||
type Props = {
|
||||
component: ComponentSchema;
|
||||
@ -17,7 +19,7 @@ type Props = {
|
||||
|
||||
export const GeneralTraitForm: React.FC<Props> = props => {
|
||||
const { trait, traitIndex, component, onRemove, services } = props;
|
||||
const { registry } = services;
|
||||
const { registry, eventBus } = services;
|
||||
|
||||
const tImpl = registry.getTraitByType(trait.type);
|
||||
const properties = Object.assign(
|
||||
@ -26,16 +28,36 @@ export const GeneralTraitForm: React.FC<Props> = props => {
|
||||
);
|
||||
const fields = Object.keys(properties || []).map((key: string) => {
|
||||
const value = trait.properties[key];
|
||||
return renderField({
|
||||
index: traitIndex,
|
||||
key,
|
||||
value,
|
||||
fullKey: key,
|
||||
type: trait.type,
|
||||
selectedComponentId: component.id,
|
||||
services,
|
||||
});
|
||||
const propertySchema = (tImpl.spec.properties as TSchema).properties?.[key];
|
||||
const onChange = (newValue: any)=> {
|
||||
const operation = genOperation(registry, 'modifyTraitProperty', {
|
||||
componentId: component.id,
|
||||
traitIndex: traitIndex,
|
||||
properties: {
|
||||
[key]: newValue,
|
||||
},
|
||||
});
|
||||
|
||||
eventBus.send('operation', operation);
|
||||
};
|
||||
|
||||
return (
|
||||
<SchemaField
|
||||
key={key}
|
||||
level={1}
|
||||
path={[key]}
|
||||
schema={{
|
||||
...propertySchema,
|
||||
title: propertySchema.title || key
|
||||
}}
|
||||
value={value}
|
||||
services={services}
|
||||
component={component}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<VStack key={trait.type} className={formWrapperCSS}>
|
||||
<HStack width="full" justifyContent="space-between">
|
||||
|
@ -111,6 +111,7 @@ export const DataSource: React.FC<Props> = props => {
|
||||
emptyPlaceholder="No States."
|
||||
states={states}
|
||||
active={active}
|
||||
services={services}
|
||||
traitType="core/v1/state"
|
||||
onItemClick={onStateItemClick}
|
||||
onItemRemove={onStateItemRemove}
|
||||
@ -122,6 +123,7 @@ export const DataSource: React.FC<Props> = props => {
|
||||
emptyPlaceholder="No LocalStorages."
|
||||
states={localStorages}
|
||||
active={active}
|
||||
services={services}
|
||||
onItemClick={onLocalStorageItemClick}
|
||||
onItemRemove={onStateItemRemove}
|
||||
/>
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
AccordionPanel,
|
||||
} from '@chakra-ui/react';
|
||||
import { DataSourceItem } from './DataSourceItem';
|
||||
import { EditorServices } from '../../types';
|
||||
import { ComponentSchema } from '@sunmao-ui/core';
|
||||
|
||||
interface Props {
|
||||
@ -18,6 +19,7 @@ interface Props {
|
||||
traitType: string;
|
||||
filterPlaceholder: string;
|
||||
emptyPlaceholder: string;
|
||||
services: EditorServices;
|
||||
onItemClick: (state: ComponentSchema) => void;
|
||||
onItemRemove: (state: ComponentSchema) => void;
|
||||
}
|
||||
@ -40,27 +42,26 @@ export const State: React.FC<Props> = props => {
|
||||
filterPlaceholder,
|
||||
emptyPlaceholder,
|
||||
title,
|
||||
traitType,
|
||||
services,
|
||||
} = props;
|
||||
const { stateManager } = services;
|
||||
const { store } = stateManager;
|
||||
const list = useMemo(
|
||||
() => states.filter(({ id }) => id.includes(search)),
|
||||
[search, states]
|
||||
);
|
||||
|
||||
|
||||
const StateItems = () => (
|
||||
<>
|
||||
{list.map(state => {
|
||||
const trait = state.traits.find(({ type }) => type === traitType);
|
||||
const properties = trait!.properties;
|
||||
|
||||
return (
|
||||
<DataSourceItem
|
||||
key={state.id}
|
||||
dataSource={state}
|
||||
tag={
|
||||
Array.isArray(properties.initialValue)
|
||||
Array.isArray(store[state.id]?.value)
|
||||
? 'Array'
|
||||
: STATE_MAP[typeof properties.initialValue] ?? 'Any'
|
||||
: STATE_MAP[typeof store[state.id]?.value] ?? 'Any'
|
||||
}
|
||||
name={state.id}
|
||||
active={active === state.id}
|
||||
|
@ -4,6 +4,8 @@ import { useFormik } from 'formik';
|
||||
import { ComponentSchema } from '@sunmao-ui/core';
|
||||
import { EditorServices } from '../../../types';
|
||||
import { genOperation } from '../../../operations';
|
||||
import { SchemaField } from '@sunmao-ui/editor-sdk';
|
||||
import { Type } from '@sinclair/typebox';
|
||||
|
||||
interface Values {
|
||||
key: string;
|
||||
@ -67,7 +69,7 @@ export const StateForm: React.FC<Props> = props => {
|
||||
return (
|
||||
<VStack p="2" spacing="2" background="gray.50" onKeyDown={onKeyDown}>
|
||||
<FormControl>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>State Name</FormLabel>
|
||||
<Input
|
||||
value={name}
|
||||
onChange={e => {
|
||||
@ -78,12 +80,18 @@ export const StateForm: React.FC<Props> = props => {
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>Initial Value</FormLabel>
|
||||
<Input
|
||||
name="initialValue"
|
||||
<SchemaField
|
||||
schema={Type.Any()}
|
||||
value={values.initialValue}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={() => formik.handleSubmit()}
|
||||
/>
|
||||
component={state}
|
||||
level={1}
|
||||
path={['initialValue']}
|
||||
services={services}
|
||||
onChange={(value)=> {
|
||||
formik.setFieldValue('initialValue', value);
|
||||
formik.handleSubmit();
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
</VStack>
|
||||
);
|
||||
|
@ -158,7 +158,7 @@ export const Editor: React.FC<Props> = observer(
|
||||
|
||||
const renderMain = () => {
|
||||
const appBox = (
|
||||
<Flex flexDirection="column" width="full" height="full">
|
||||
<Flex flexDirection="column" width="full" height="full" overflow='hidden'>
|
||||
<Box
|
||||
id="editor-main"
|
||||
display="flex"
|
||||
@ -244,7 +244,7 @@ export const Editor: React.FC<Props> = observer(
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</Box>
|
||||
<Flex flex={1} position="relative">
|
||||
<Flex flex={1} position="relative" overflow='hidden'>
|
||||
{appBox}
|
||||
<Box
|
||||
width="320px"
|
||||
|
@ -2,6 +2,7 @@ import { StrictMode } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Registry } from '@sunmao-ui/runtime';
|
||||
import { sunmaoChakraUILib } from '@sunmao-ui/chakra-ui-lib';
|
||||
import { widgets as chakraWidgets } from '@sunmao-ui/chakra-ui-lib/dist/esm/widgets/index';
|
||||
import { ArcoDesignLib } from '@sunmao-ui/arco-lib';
|
||||
import { initSunmaoUIEditor } from './init';
|
||||
import { LocalStorageManager } from './LocalStorageManager';
|
||||
@ -16,6 +17,7 @@ type Options = Partial<{
|
||||
const lsManager = new LocalStorageManager();
|
||||
const { Editor, registry } = initSunmaoUIEditor({
|
||||
libs: [sunmaoChakraUILib, ArcoDesignLib],
|
||||
widgets: [...chakraWidgets],
|
||||
storageHandler: {
|
||||
onSaveApp(app) {
|
||||
lsManager.saveAppInLS(app);
|
||||
|
@ -24,5 +24,5 @@
|
||||
"declaration": true,
|
||||
"declarationDir": "lib"
|
||||
},
|
||||
"include": ["./src"]
|
||||
"include": ["./src", "./types"]
|
||||
}
|
||||
|
3
packages/editor/types/widgets.d.ts
vendored
Normal file
3
packages/editor/types/widgets.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
declare module '@sunmao-ui/chakra-ui-lib/dist/esm/widgets/index' {
|
||||
export * from '@sunmao-ui/chakra-ui-lib/lib/widgets/index';
|
||||
}
|
Loading…
Reference in New Issue
Block a user