mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-04-06 21:40:23 +08:00
Merge branch 'main' into feat/style-trait-widget
* main: feat(widget): add the color widget fix: fix the type errors fix(widget): fix the crash problem when opening the event tab refactor(slot): slotSchema -> SlotSpec chore(examples): change the util method's examples refactor(arco): fix type update the collapse component impl refine slotElements interface to avoid re-mount memomize slotElements to avoid extra re-mount adapt new slots spec in editor migrate all in-tree components to the new slot spec impl #388, support slot props and apply to tabs component # Conflicts: # packages/editor-sdk/src/components/Widgets/StyleWidgets/SizeWidget.tsx # packages/editor-sdk/src/components/Widgets/index.ts # packages/editor/src/components/ComponentForm/StyleTraitForm/StyleTraitForm.tsx
This commit is contained in:
commit
61731f998e
@ -43,7 +43,7 @@
|
||||
{
|
||||
"componentId": "$utils",
|
||||
"method": {
|
||||
"name": "toast.open",
|
||||
"name": "chakra_ui/v1/openToast",
|
||||
"parameters": {
|
||||
"id": "createSuccessToast",
|
||||
"title": "恭喜",
|
||||
|
@ -43,7 +43,7 @@
|
||||
{
|
||||
"componentId": "$utils",
|
||||
"method": {
|
||||
"name": "toast.open",
|
||||
"name": "chakra_ui/v1/openToast",
|
||||
"parameters": {
|
||||
"id": "createSuccessToast",
|
||||
"title": "恭喜",
|
||||
|
@ -37,7 +37,7 @@
|
||||
"type": "chakra_ui/v1/button",
|
||||
"properties": {
|
||||
"text": {
|
||||
"raw": "in tab1",
|
||||
"raw": "only in tab {{ $slot.tabIndex + 1 }}",
|
||||
"format": "plain"
|
||||
}
|
||||
},
|
||||
@ -48,7 +48,8 @@
|
||||
"container": {
|
||||
"id": "tabs",
|
||||
"slot": "content"
|
||||
}
|
||||
},
|
||||
"ifCondition": "{{ $slot.tabIndex === 0 }}"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -59,7 +59,7 @@
|
||||
"type": "onClick",
|
||||
"componentId": "$utils",
|
||||
"method": {
|
||||
"name": "toast.open",
|
||||
"name": "chakra_ui/v1/openToast",
|
||||
"parameters": {
|
||||
"id": "{{open_button.lastToast}}",
|
||||
"title": "i am a title",
|
||||
@ -103,7 +103,7 @@
|
||||
"type": "onClick",
|
||||
"componentId": "$utils",
|
||||
"method": {
|
||||
"name": "toast.close",
|
||||
"name": "chakra_ui/v1/closeToast",
|
||||
"parameters": {
|
||||
"id": "{{open_button.lastToast}}"
|
||||
}
|
||||
@ -156,7 +156,7 @@
|
||||
"type": "onClick",
|
||||
"componentId": "$utils",
|
||||
"method": {
|
||||
"name": "toast.close"
|
||||
"name": "chakra_ui/v1/closeToast"
|
||||
},
|
||||
"wait": {}
|
||||
}
|
||||
|
@ -32,7 +32,10 @@ export const Alert = implementRuntimeComponent({
|
||||
properties: AlertPropsSpec,
|
||||
state: AlertStateSpec,
|
||||
methods: {},
|
||||
slots: ['action', 'icon'],
|
||||
slots: {
|
||||
action: { slotProps: Type.Object({}) },
|
||||
icon: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onClose', 'afterClose'],
|
||||
},
|
||||
@ -43,8 +46,8 @@ export const Alert = implementRuntimeComponent({
|
||||
return (
|
||||
<BaseAlert
|
||||
ref={elementRef}
|
||||
action={slotsElements.action}
|
||||
icon={slotsElements.icon}
|
||||
action={slotsElements.action ? slotsElements.action({}) : null}
|
||||
icon={slotsElements.icon ? slotsElements.icon({}) : null}
|
||||
onClose={_e => {
|
||||
callbackMap?.onClose?.();
|
||||
}}
|
||||
|
@ -34,7 +34,9 @@ export const Avatar = implementRuntimeComponent({
|
||||
properties: AvatarPropsSpec,
|
||||
state: AvatarStateSpec,
|
||||
methods: {},
|
||||
slots: ['triggerIcon'],
|
||||
slots: {
|
||||
triggerIcon: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onClick'],
|
||||
},
|
||||
@ -47,7 +49,7 @@ export const Avatar = implementRuntimeComponent({
|
||||
ref={elementRef}
|
||||
className={css(customStyle?.content)}
|
||||
{...cProps}
|
||||
triggerIcon={slotsElements.triggerIcon}
|
||||
triggerIcon={slotsElements.triggerIcon ? slotsElements.triggerIcon({}) : null}
|
||||
onClick={_e => {
|
||||
callbackMap?.onClick?.();
|
||||
}}
|
||||
|
@ -31,7 +31,9 @@ export const Badge = implementRuntimeComponent({
|
||||
properties: BadgePropsSpec,
|
||||
state: BadgeStateSpec,
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -55,7 +57,7 @@ export const Badge = implementRuntimeComponent({
|
||||
{...cProps}
|
||||
color={cProps.dotColor}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseBadge>
|
||||
);
|
||||
});
|
||||
|
@ -36,7 +36,9 @@ export const Button = implementRuntimeComponent({
|
||||
properties: ButtonPropsSpec,
|
||||
state: ButtonStateSpec,
|
||||
methods: {},
|
||||
slots: ['icon'],
|
||||
slots: {
|
||||
icon: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onClick'],
|
||||
},
|
||||
@ -49,7 +51,7 @@ export const Button = implementRuntimeComponent({
|
||||
ref={elementRef}
|
||||
className={css(customStyle?.content)}
|
||||
onClick={callbackMap?.onClick}
|
||||
icon={slotsElements.icon}
|
||||
icon={slotsElements.icon ? slotsElements.icon({}) : null}
|
||||
{...cProps}
|
||||
loadingFixedWidth
|
||||
>
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
CascaderValueSpec,
|
||||
} from '../generated/types/Cascader';
|
||||
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
||||
import { isArray } from 'lodash-es';
|
||||
import { SelectViewHandle } from '@arco-design/web-react/es/_class/select-view';
|
||||
|
||||
const CascaderPropsSpec = Type.Object(BaseCascaderPropsSpec);
|
||||
@ -96,7 +95,9 @@ export const Cascader = implementRuntimeComponent({
|
||||
properties: CascaderPropsSpec,
|
||||
state: CascaderStateSpec,
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange'],
|
||||
},
|
||||
@ -106,9 +107,7 @@ export const Cascader = implementRuntimeComponent({
|
||||
const { multiple, options, placeholder, ...cProps } = getComponentProps(props);
|
||||
const ref = useRef<SelectViewHandle | null>(null);
|
||||
|
||||
const content = isArray(slotsElements.content)
|
||||
? slotsElements.content[0]
|
||||
: slotsElements.content;
|
||||
const content = slotsElements.content ? slotsElements.content({}) : null;
|
||||
|
||||
const mode = multiple ? 'multiple' : undefined;
|
||||
|
||||
|
@ -65,7 +65,7 @@ export const Checkbox = implementRuntimeComponent({
|
||||
}),
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
slots: [],
|
||||
slots: {},
|
||||
events: ['onChange'],
|
||||
},
|
||||
})(props => {
|
||||
@ -79,7 +79,7 @@ export const Checkbox = implementRuntimeComponent({
|
||||
...checkboxProps
|
||||
} = getComponentProps(props);
|
||||
|
||||
const [checkedValues, setCheckedValues] = useStateValue<string[]>(
|
||||
const [checkedValues, setCheckedValues] = useStateValue(
|
||||
defaultCheckedValues,
|
||||
mergeState,
|
||||
updateWhenDefaultValueChanges,
|
||||
|
@ -51,7 +51,14 @@ export const Collapse = implementRuntimeComponent({
|
||||
methods: {
|
||||
setActiveKey: Type.String(),
|
||||
},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: {
|
||||
slotProps: Type.Object({
|
||||
activeKey: Type.Array(Type.String()),
|
||||
index: Type.Number(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange'],
|
||||
},
|
||||
@ -60,7 +67,7 @@ export const Collapse = implementRuntimeComponent({
|
||||
getComponentProps(props);
|
||||
const { elementRef, mergeState, slotsElements, customStyle, callbackMap } = props;
|
||||
|
||||
const [activeKey, setActiveKey] = useStateValue<string[]>(
|
||||
const [activeKey, setActiveKey] = useStateValue(
|
||||
defaultActiveKey.map(String),
|
||||
mergeState,
|
||||
updateWhenDefaultValueChanges,
|
||||
@ -76,10 +83,6 @@ export const Collapse = implementRuntimeComponent({
|
||||
[callbackMap, mergeState]
|
||||
);
|
||||
|
||||
const collapseItems = slotsElements.content
|
||||
? ([] as React.ReactElement[]).concat(slotsElements.content)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<BaseCollapse
|
||||
ref={elementRef}
|
||||
@ -88,12 +91,12 @@ export const Collapse = implementRuntimeComponent({
|
||||
activeKey={activeKey}
|
||||
onChange={onChange}
|
||||
>
|
||||
{options.map((o, idx) => {
|
||||
{options.map((o, index) => {
|
||||
const { key, ...props } = o;
|
||||
return (
|
||||
<BaseCollapse.Item key={key} name={String(key)} {...props}>
|
||||
{collapseItems.length ? (
|
||||
collapseItems[idx]
|
||||
{slotsElements?.content ? (
|
||||
slotsElements.content({ activeKey, index })
|
||||
) : (
|
||||
<EmptyPlaceholder componentName="" />
|
||||
)}
|
||||
|
@ -77,7 +77,14 @@ export const DatePicker = implementRuntimeComponent({
|
||||
properties: DatePickerPropsSpec,
|
||||
state: DatePickerStateSpec,
|
||||
methods: {},
|
||||
slots: ['footer', 'triggerElement'],
|
||||
slots: {
|
||||
footer: {
|
||||
slotProps: Type.Object({}),
|
||||
},
|
||||
triggerElement: {
|
||||
slotProps: Type.Object({}),
|
||||
},
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange', 'onClear', 'onVisibleChange'],
|
||||
},
|
||||
|
@ -60,7 +60,7 @@ export const Descriptions = implementRuntimeComponent({
|
||||
properties: DescriptionPropsSpec,
|
||||
state: DescriptionStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -30,7 +30,7 @@ export const Divider = implementRuntimeComponent({
|
||||
properties: DividerPropsSpec,
|
||||
state: DividerStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -44,7 +44,9 @@ export const Dropdown = implementRuntimeComponent({
|
||||
properties: DropdownPropsSpec,
|
||||
state: DropdownStateSpec,
|
||||
methods: {},
|
||||
slots: ['trigger'],
|
||||
slots: {
|
||||
trigger: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: [],
|
||||
events: ['onClickMenuItem', 'onVisibleChange', 'onButtonClick'],
|
||||
},
|
||||
@ -87,7 +89,9 @@ export const Dropdown = implementRuntimeComponent({
|
||||
onClick={callbackMap?.onButtonClick}
|
||||
triggerProps={{ autoAlignPopupMinWidth: autoAlignPopupWidth }}
|
||||
>
|
||||
<div ref={elementRef}>{slotsElements.trigger || <Button>Click</Button>}</div>
|
||||
<div ref={elementRef}>
|
||||
{slotsElements.trigger ? slotsElements.trigger({}) : <Button>Click</Button>}
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
});
|
||||
|
@ -60,7 +60,9 @@ export const FormControl = implementRuntimeComponent({
|
||||
properties: FormControlPropsSpec,
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -81,7 +83,7 @@ export const FormControl = implementRuntimeComponent({
|
||||
{...cProps}
|
||||
>
|
||||
{slotsElements.content ? (
|
||||
slotsElements.content
|
||||
slotsElements.content({})
|
||||
) : (
|
||||
<EmptyPlaceholder componentName="Input" />
|
||||
)}
|
||||
|
@ -28,7 +28,9 @@ export const Row = implementRuntimeComponent({
|
||||
properties: Type.Object(RowPropsSpec),
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['wrapper'],
|
||||
events: [],
|
||||
},
|
||||
@ -38,7 +40,11 @@ export const Row = implementRuntimeComponent({
|
||||
|
||||
return (
|
||||
<Grid.Row className={css(customStyle?.wrapper)} ref={elementRef} {...cProps}>
|
||||
{slotsElements.content || <EmptyPlaceholder componentName="" />}
|
||||
{slotsElements.content ? (
|
||||
slotsElements.content({})
|
||||
) : (
|
||||
<EmptyPlaceholder componentName="" />
|
||||
)}
|
||||
</Grid.Row>
|
||||
);
|
||||
});
|
||||
@ -67,7 +73,9 @@ export const Col = implementRuntimeComponent({
|
||||
properties: Type.Object(ColPropsSpec),
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['wrapper'],
|
||||
events: [],
|
||||
},
|
||||
@ -76,7 +84,11 @@ export const Col = implementRuntimeComponent({
|
||||
const { ...cProps } = getComponentProps(props);
|
||||
return (
|
||||
<Grid.Col className={css(customStyle?.wrapper)} ref={elementRef} {...cProps}>
|
||||
{slotsElements.content || <EmptyPlaceholder componentName="" />}
|
||||
{slotsElements.content ? (
|
||||
slotsElements.content({})
|
||||
) : (
|
||||
<EmptyPlaceholder componentName="" />
|
||||
)}
|
||||
</Grid.Col>
|
||||
);
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ export const Icon = implementRuntimeComponent({
|
||||
properties: IconPropsSpec,
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['slot'],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['event'],
|
||||
},
|
||||
|
@ -20,7 +20,7 @@ const exampleProperties: Static<typeof ImagePropsSpec> = {
|
||||
preview: false,
|
||||
width: 200,
|
||||
height: 200,
|
||||
error:''
|
||||
error: '',
|
||||
};
|
||||
|
||||
const options = {
|
||||
@ -38,7 +38,7 @@ const options = {
|
||||
properties: ImagePropsSpec,
|
||||
state: ImageStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onClick'],
|
||||
},
|
||||
@ -101,7 +101,7 @@ export const ImageGroup = implementRuntimeComponent({
|
||||
current: Type.Number(),
|
||||
}),
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange'],
|
||||
},
|
||||
|
@ -41,7 +41,12 @@ const options = {
|
||||
properties: InputPropsSpec,
|
||||
state: InputStateSpec,
|
||||
methods: {},
|
||||
slots: ['addAfter', 'prefix', 'suffix', 'addBefore'],
|
||||
slots: {
|
||||
addAfter: { slotProps: Type.Object({}) },
|
||||
prefix: { slotProps: Type.Object({}) },
|
||||
suffix: { slotProps: Type.Object({}) },
|
||||
addBefore: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['input'],
|
||||
events: ['onChange', 'onBlur', 'onFocus', 'onClear', 'onPressEnter'],
|
||||
},
|
||||
@ -79,10 +84,10 @@ export const Input = implementRuntimeComponent(options)(props => {
|
||||
<BaseInput
|
||||
className={css(customStyle?.input)}
|
||||
ref={ref}
|
||||
addAfter={slotsElements.addAfter}
|
||||
addBefore={slotsElements.addBefore}
|
||||
prefix={slotsElements.prefix}
|
||||
suffix={slotsElements.suffix}
|
||||
addAfter={slotsElements.addAfter ? slotsElements.addAfter({}) : null}
|
||||
addBefore={slotsElements.addBefore ? slotsElements.addBefore({}) : null}
|
||||
prefix={slotsElements.prefix ? slotsElements.prefix({}) : null}
|
||||
suffix={slotsElements.suffix ? slotsElements.suffix({}) : null}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onClear={() => {
|
||||
|
@ -48,7 +48,12 @@ export const Layout = implementRuntimeComponent({
|
||||
}),
|
||||
state: LayoutStateSpec,
|
||||
methods: {},
|
||||
slots: ['header', 'content', 'sidebar', 'footer'],
|
||||
slots: {
|
||||
header: { slotProps: Type.Object({}) },
|
||||
content: { slotProps: Type.Object({}) },
|
||||
sidebar: { slotProps: Type.Object({}) },
|
||||
footer: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['layout', 'header', 'content', 'sidebar', 'footer'],
|
||||
events: [],
|
||||
},
|
||||
@ -99,16 +104,24 @@ export const Layout = implementRuntimeComponent({
|
||||
return (
|
||||
<BaseLayout {...baseProps}>
|
||||
{showHeader && (
|
||||
<BaseLayout.Header {...headerProps}>{slotsElements.header}</BaseLayout.Header>
|
||||
<BaseLayout.Header {...headerProps}>
|
||||
{slotsElements.header ? slotsElements.header({}) : null}
|
||||
</BaseLayout.Header>
|
||||
)}
|
||||
<BaseLayout>
|
||||
{showSideBar && (
|
||||
<BaseLayout.Sider {...siderProps}>{slotsElements.sidebar}</BaseLayout.Sider>
|
||||
<BaseLayout.Sider {...siderProps}>
|
||||
{slotsElements.sidebar ? slotsElements.sidebar({}) : null}
|
||||
</BaseLayout.Sider>
|
||||
)}
|
||||
<BaseLayout.Content {...contentProps}>{slotsElements.content}</BaseLayout.Content>
|
||||
<BaseLayout.Content {...contentProps}>
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseLayout.Content>
|
||||
</BaseLayout>
|
||||
{showFooter && (
|
||||
<BaseLayout.Footer {...footerProps}>{slotsElements.footer}</BaseLayout.Footer>
|
||||
<BaseLayout.Footer {...footerProps}>
|
||||
{slotsElements.footer ? slotsElements.footer({}) : null}
|
||||
</BaseLayout.Footer>
|
||||
)}
|
||||
</BaseLayout>
|
||||
);
|
||||
|
@ -16,7 +16,6 @@ const exampleProperties: Static<typeof LinkPropsSpec> = {
|
||||
content: 'Link',
|
||||
};
|
||||
|
||||
|
||||
const statusMap = {
|
||||
default: undefined,
|
||||
success: 'success',
|
||||
@ -39,7 +38,7 @@ export const Link = implementRuntimeComponent({
|
||||
properties: LinkPropsSpec,
|
||||
state: LinkStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -37,7 +37,7 @@ export const Mentions = implementRuntimeComponent({
|
||||
properties: MentionsPropsSpec,
|
||||
state: MentionsStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange', 'onClear', 'onPressEnter', 'onFocus', 'onBlur'],
|
||||
},
|
||||
|
@ -45,7 +45,7 @@ export const Menu = implementRuntimeComponent({
|
||||
active: Type.String(),
|
||||
}),
|
||||
},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onClick'],
|
||||
},
|
||||
|
@ -39,7 +39,10 @@ export const Modal = implementRuntimeComponent({
|
||||
openModal: Type.String(),
|
||||
closeModal: Type.String(),
|
||||
},
|
||||
slots: ['content', 'footer'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
footer: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['afterOpen', 'afterClose', 'onCancel', 'onOk'],
|
||||
},
|
||||
@ -87,12 +90,14 @@ export const Modal = implementRuntimeComponent({
|
||||
}}
|
||||
afterClose={afterClose}
|
||||
afterOpen={afterOpen}
|
||||
footer={slotsElements.footer}
|
||||
footer={slotsElements.footer ? slotsElements.footer({}) : null}
|
||||
className={css(customStyle?.content)}
|
||||
mountOnEnter={true}
|
||||
{...cProps}
|
||||
>
|
||||
<div ref={contentRef}>{slotsElements.content}</div>
|
||||
<div ref={contentRef}>
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</div>
|
||||
</BaseModal>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
@ -40,7 +40,7 @@ export const Pagination = implementRuntimeComponent({
|
||||
properties: PaginationPropsSpec,
|
||||
state: PaginationStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange'],
|
||||
},
|
||||
@ -49,7 +49,7 @@ export const Pagination = implementRuntimeComponent({
|
||||
getComponentProps(props);
|
||||
const { elementRef, customStyle, mergeState, callbackMap } = props;
|
||||
|
||||
const [current, setCurrent] = useStateValue<number>(
|
||||
const [current, setCurrent] = useStateValue(
|
||||
defaultCurrent || 0,
|
||||
mergeState,
|
||||
updateWhenDefaultValueChanges,
|
||||
|
@ -39,7 +39,7 @@ export const PasswordInput = implementRuntimeComponent({
|
||||
properties: InputPropsSpec,
|
||||
state: InputStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['input'],
|
||||
events: ['onChange', 'onBlur', 'onFocus', 'onPressEnter'],
|
||||
},
|
||||
|
@ -37,7 +37,10 @@ export const Popover = implementRuntimeComponent({
|
||||
openPopover: Type.String(),
|
||||
closePopover: Type.String(),
|
||||
},
|
||||
slots: ['popupContent', 'content'],
|
||||
slots: {
|
||||
popupContent: { slotProps: Type.Object({}) },
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -62,21 +65,25 @@ export const Popover = implementRuntimeComponent({
|
||||
<BasePopover
|
||||
className={css(customStyle?.content)}
|
||||
{...cProps}
|
||||
content={slotsElements.popupContent}
|
||||
content={slotsElements.popupContent ? slotsElements.popupContent({}) : null}
|
||||
>
|
||||
<span ref={elementRef}>{slotsElements.content || <Button>Hover Me</Button>}</span>
|
||||
<span ref={elementRef}>
|
||||
{slotsElements.content ? slotsElements.content({}) : <Button>Hover Me</Button>}
|
||||
</span>
|
||||
</BasePopover>
|
||||
) : (
|
||||
<BasePopover
|
||||
className={css(customStyle?.content)}
|
||||
{...cProps}
|
||||
content={slotsElements.popupContent}
|
||||
content={slotsElements.popupContent ? slotsElements.popupContent({}) : null}
|
||||
popupVisible={popupVisible}
|
||||
onVisibleChange={visible => {
|
||||
setPopupVisible(visible);
|
||||
}}
|
||||
>
|
||||
<span ref={elementRef}>{slotsElements.content || <Button>Hover Me</Button>}</span>
|
||||
<span ref={elementRef}>
|
||||
{slotsElements.content ? slotsElements.content({}) : <Button>Hover Me</Button>}
|
||||
</span>
|
||||
</BasePopover>
|
||||
);
|
||||
});
|
||||
|
@ -35,7 +35,7 @@ export const Progress = implementRuntimeComponent({
|
||||
properties: ProgressPropsSpec,
|
||||
state: ProgressStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -46,7 +46,7 @@ export const Radio = implementRuntimeComponent({
|
||||
value: Type.String(),
|
||||
}),
|
||||
},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['group'],
|
||||
events: ['onChange'],
|
||||
},
|
||||
@ -54,7 +54,7 @@ export const Radio = implementRuntimeComponent({
|
||||
const { customStyle, callbackMap, mergeState, subscribeMethods, elementRef } = props;
|
||||
const { defaultCheckedValue, updateWhenDefaultValueChanges, ...cProps } =
|
||||
getComponentProps(props);
|
||||
const [checkedValue, setCheckedValue] = useStateValue<string>(
|
||||
const [checkedValue, setCheckedValue] = useStateValue(
|
||||
defaultCheckedValue,
|
||||
mergeState,
|
||||
updateWhenDefaultValueChanges,
|
||||
|
@ -52,7 +52,9 @@ export const Select = implementRuntimeComponent({
|
||||
properties: SelectPropsSpec,
|
||||
state: SelectStateSpec,
|
||||
methods: {},
|
||||
slots: ['dropdownRenderSlot'],
|
||||
slots: {
|
||||
dropdownRenderSlot: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content', 'dropdownRenderWrap'],
|
||||
events: ['onChange', 'onClear', 'onBlur', 'onFocus'],
|
||||
},
|
||||
@ -112,7 +114,9 @@ export const Select = implementRuntimeComponent({
|
||||
return (
|
||||
<div className={css(customStyle?.dropdownRenderWrap)}>
|
||||
{menu}
|
||||
{slotsElements.dropdownRenderSlot}
|
||||
{slotsElements.dropdownRenderSlot
|
||||
? slotsElements.dropdownRenderSlot({})
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
@ -30,7 +30,9 @@ export const Skeleton = implementRuntimeComponent({
|
||||
properties: SkeletonPropsSpec,
|
||||
state: SkeletonStateSpec,
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -40,7 +42,7 @@ export const Skeleton = implementRuntimeComponent({
|
||||
|
||||
return (
|
||||
<BaseSkeleton ref={elementRef} className={css(customStyle?.content)} {...cProps}>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseSkeleton>
|
||||
);
|
||||
});
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Slider as BaseSlider } from "@arco-design/web-react";
|
||||
import { implementRuntimeComponent } from "@sunmao-ui/runtime";
|
||||
import { css } from "@emotion/css";
|
||||
import { Type, Static } from "@sinclair/typebox";
|
||||
import { FALLBACK_METADATA, getComponentProps } from "../sunmao-helper";
|
||||
import { SliderPropsSpec as BaseSliderPropsSpec } from "../generated/types/Slider";
|
||||
import { Slider as BaseSlider } from '@arco-design/web-react';
|
||||
import { implementRuntimeComponent } from '@sunmao-ui/runtime';
|
||||
import { css } from '@emotion/css';
|
||||
import { Type, Static } from '@sinclair/typebox';
|
||||
import { FALLBACK_METADATA, getComponentProps } from '../sunmao-helper';
|
||||
import { SliderPropsSpec as BaseSliderPropsSpec } from '../generated/types/Slider';
|
||||
|
||||
const SliderPropsSpec = Type.Object(BaseSliderPropsSpec);
|
||||
const SliderStateSpec = Type.Object({});
|
||||
@ -18,41 +18,41 @@ const exampleProperties: Static<typeof SliderPropsSpec> = {
|
||||
marks: {},
|
||||
onlyMarkValue: false,
|
||||
reverse: false,
|
||||
step:1,
|
||||
showTicks:false
|
||||
step: 1,
|
||||
showTicks: false,
|
||||
};
|
||||
|
||||
export const Slider = implementRuntimeComponent({
|
||||
version: "arco/v1",
|
||||
version: 'arco/v1',
|
||||
metadata: {
|
||||
...FALLBACK_METADATA,
|
||||
name: "slider",
|
||||
displayName: "Slider",
|
||||
name: 'slider',
|
||||
displayName: 'Slider',
|
||||
exampleProperties,
|
||||
annotations: {
|
||||
category: "Display",
|
||||
category: 'Display',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
properties: SliderPropsSpec,
|
||||
state: SliderStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
styleSlots: ["content"],
|
||||
events: ["onChange", "onAfterChange"],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange', 'onAfterChange'],
|
||||
},
|
||||
})((props) => {
|
||||
})(props => {
|
||||
const { ...cProps } = getComponentProps(props);
|
||||
const { customStyle, elementRef, callbackMap, mergeState } = props;
|
||||
|
||||
return (
|
||||
<BaseSlider
|
||||
ref={elementRef}
|
||||
onChange={(val) => {
|
||||
onChange={val => {
|
||||
mergeState({ value: val });
|
||||
callbackMap?.onChange?.();
|
||||
}}
|
||||
onAfterChange={(val) => {
|
||||
onAfterChange={val => {
|
||||
mergeState({ value: val });
|
||||
callbackMap?.onAfterChange?.();
|
||||
}}
|
||||
|
@ -31,7 +31,9 @@ export const Space = implementRuntimeComponent({
|
||||
properties: SpacePropsSpec,
|
||||
state: SpaceStateSpec,
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onClick'],
|
||||
},
|
||||
@ -41,7 +43,7 @@ export const Space = implementRuntimeComponent({
|
||||
|
||||
return (
|
||||
<BaseSpace ref={elementRef} className={css(customStyle?.content)} {...cProps}>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseSpace>
|
||||
);
|
||||
});
|
||||
|
@ -42,7 +42,9 @@ export const Steps = implementRuntimeComponent({
|
||||
properties: StepsPropsSpec,
|
||||
state: StepsStateSpec,
|
||||
methods: {},
|
||||
slots: ['icons'],
|
||||
slots: {
|
||||
icons: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -63,7 +65,7 @@ export const Steps = implementRuntimeComponent({
|
||||
items.map((stepItem: StepItem, idx: number) => {
|
||||
return (
|
||||
<BaseSteps.Step
|
||||
icon={slotsElements.icons}
|
||||
icon={slotsElements.icons ? slotsElements.icons({}) : null}
|
||||
key={idx}
|
||||
title={stepItem.title}
|
||||
description={stepItem.description}
|
||||
|
@ -37,7 +37,7 @@ export const Switch = implementRuntimeComponent({
|
||||
properties: SwitchPropsSpec,
|
||||
state: SwitchStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange'],
|
||||
},
|
||||
@ -45,7 +45,7 @@ export const Switch = implementRuntimeComponent({
|
||||
const { elementRef, customStyle, mergeState, callbackMap } = props;
|
||||
const { defaultChecked, updateWhenDefaultValueChanges, ...cProps } =
|
||||
getComponentProps(props);
|
||||
const [value, setValue] = useStateValue<boolean>(
|
||||
const [value, setValue] = useStateValue(
|
||||
defaultChecked,
|
||||
mergeState,
|
||||
updateWhenDefaultValueChanges
|
||||
|
@ -155,7 +155,7 @@ export const Table = implementRuntimeComponent({
|
||||
properties: TablePropsSpec,
|
||||
state: TableStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [
|
||||
'onRowClick',
|
||||
|
@ -57,7 +57,13 @@ export const Tabs = implementRuntimeComponent({
|
||||
activeTab: Type.Number(),
|
||||
}),
|
||||
},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: {
|
||||
slotProps: Type.Object({
|
||||
tabIndex: Type.Number(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange', 'onClickTab'],
|
||||
},
|
||||
@ -73,7 +79,7 @@ export const Tabs = implementRuntimeComponent({
|
||||
slotsElements,
|
||||
} = props;
|
||||
const ref = useRef<{ current: HTMLDivElement }>(null);
|
||||
const [activeTab, setActiveTab] = useStateValue<number>(
|
||||
const [activeTab, setActiveTab] = useStateValue(
|
||||
defaultActiveTab ?? 0,
|
||||
mergeState,
|
||||
updateWhenDefaultValueChanges,
|
||||
@ -87,10 +93,6 @@ export const Tabs = implementRuntimeComponent({
|
||||
}
|
||||
}, [getElement, ref]);
|
||||
|
||||
const slots = Array.isArray(slotsElements.content)
|
||||
? slotsElements.content
|
||||
: [slotsElements.content];
|
||||
|
||||
useEffect(() => {
|
||||
subscribeMethods({
|
||||
setActiveTab: ({ activeTab }) => {
|
||||
@ -117,13 +119,15 @@ export const Tabs = implementRuntimeComponent({
|
||||
activeTab={String(activeTab)}
|
||||
ref={ref}
|
||||
>
|
||||
{tabs.map((tab, idx) =>
|
||||
tab.hidden ? null : (
|
||||
<TabPane key={idx} title={tab.title} destroyOnHide={tab.destroyOnHide}>
|
||||
{slots[idx]}
|
||||
</TabPane>
|
||||
)
|
||||
)}
|
||||
{tabs.map((tabName, idx) => (
|
||||
<TabPane key={String(idx)} title={tabName}>
|
||||
{slotsElements?.content
|
||||
? slotsElements.content({
|
||||
tabIndex: idx,
|
||||
})
|
||||
: null}
|
||||
</TabPane>
|
||||
))}
|
||||
</BaseTabs>
|
||||
);
|
||||
});
|
||||
|
@ -43,7 +43,7 @@ export const TextArea = implementRuntimeComponent({
|
||||
properties: TextAreaPropsSpec,
|
||||
state: TextAreaStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['TextArea'],
|
||||
events: ['onChange', 'onBlur', 'onFocus', 'onClear', 'onPressEnter'],
|
||||
},
|
||||
|
@ -61,7 +61,7 @@ export const Timeline = implementRuntimeComponent({
|
||||
properties: TimelinePropsSpec,
|
||||
state: TimelineStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -35,7 +35,9 @@ export const Tooltip = implementRuntimeComponent({
|
||||
openTooltip: Type.String(),
|
||||
closeTooltip: Type.String(),
|
||||
},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -65,13 +67,17 @@ export const Tooltip = implementRuntimeComponent({
|
||||
popupVisible={popupVisible}
|
||||
>
|
||||
{/* need the child node of Tooltip accepts onMouseEnter, onMouseLeave, onFocus, onClick events */}
|
||||
<span ref={elementRef}>{slotsElements.content || <Button>Hover Me</Button>}</span>
|
||||
<span ref={elementRef}>
|
||||
{slotsElements.content ? slotsElements.content({}) : <Button>Hover Me</Button>}
|
||||
</span>
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<BaseTooltip className={css(customStyle?.content)} {...cProps}>
|
||||
<span ref={elementRef}>{slotsElements.content || <Button>Hover Me</Button>}</span>
|
||||
<span ref={elementRef}>
|
||||
{slotsElements.content ? slotsElements.content({}) : <Button>Hover Me</Button>}
|
||||
</span>
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
);
|
||||
|
@ -87,7 +87,7 @@ export const Tree = implementRuntimeComponent({
|
||||
properties: TreePropsSpec,
|
||||
state: TreeStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onSelect'],
|
||||
},
|
||||
|
@ -71,7 +71,7 @@ export const TreeSelect = implementRuntimeComponent({
|
||||
properties: TreeSelectPropsSpec,
|
||||
state: TreeSelectStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onChange'],
|
||||
},
|
||||
@ -81,7 +81,7 @@ export const TreeSelect = implementRuntimeComponent({
|
||||
const { getElement, customStyle, mergeState, callbackMap } = props;
|
||||
const ref = useRef<RefTreeSelectType | null>(null);
|
||||
|
||||
const [selectedOptions, setSelectedOptions] = useStateValue<string[]>(
|
||||
const [selectedOptions, setSelectedOptions] = useStateValue(
|
||||
defaultValue!,
|
||||
mergeState,
|
||||
updateWhenDefaultValueChanges,
|
||||
|
@ -16,9 +16,9 @@ export const LinkPropsSpec = {
|
||||
hoverable: Type.Boolean({
|
||||
title: 'Hoverable',
|
||||
category: Category.Style,
|
||||
description: 'Whether to hide background when hover'
|
||||
description: 'Whether to hide background when hover',
|
||||
}),
|
||||
status: StringUnion(['default','success', 'warning', 'error'], {
|
||||
status: StringUnion(['default', 'success', 'warning', 'error'], {
|
||||
title: 'Status',
|
||||
category: Category.Style,
|
||||
}),
|
||||
|
@ -4,53 +4,61 @@ import { Category } from '../../constants/category';
|
||||
import { CORE_VERSION, CoreWidgetName } from '@sunmao-ui/editor-sdk';
|
||||
|
||||
export const SliderPropsSpec = {
|
||||
min: Type.Number({
|
||||
title: 'Min',
|
||||
category: Category.Basic
|
||||
}),
|
||||
max: Type.Number({
|
||||
title: 'Max',
|
||||
category: Category.Basic
|
||||
}),
|
||||
disabled: Type.Boolean({
|
||||
title: 'Disabled',
|
||||
category: Category.Basic
|
||||
}),
|
||||
toolTipPosition: Type.Optional(StringUnion(['top', 'tl', 'tr', 'bottom', 'bl', 'br', 'left', 'lt', 'lb', 'right', 'rt', 'rb'], {
|
||||
min: Type.Number({
|
||||
title: 'Min',
|
||||
category: Category.Basic,
|
||||
}),
|
||||
max: Type.Number({
|
||||
title: 'Max',
|
||||
category: Category.Basic,
|
||||
}),
|
||||
disabled: Type.Boolean({
|
||||
title: 'Disabled',
|
||||
category: Category.Basic,
|
||||
}),
|
||||
toolTipPosition: Type.Optional(
|
||||
StringUnion(
|
||||
['top', 'tl', 'tr', 'bottom', 'bl', 'br', 'left', 'lt', 'lb', 'right', 'rt', 'rb'],
|
||||
{
|
||||
category: Category.Layout,
|
||||
title: 'Tooltip Position'
|
||||
})),
|
||||
vertical: Type.Boolean({
|
||||
title: 'Vertical',
|
||||
category: Category.Layout,
|
||||
}),
|
||||
tooltipVisible: Type.Boolean({
|
||||
title: 'Show Tooltip',
|
||||
category: Category.Behavior
|
||||
}),
|
||||
range: Type.Boolean({
|
||||
title: 'Enable Range',
|
||||
category: Category.Behavior
|
||||
}),
|
||||
step: Type.Number({
|
||||
title: 'Step',
|
||||
category: Category.Behavior
|
||||
}),
|
||||
showTicks: Type.Boolean({
|
||||
title: 'Show Ticks',
|
||||
category: Category.Behavior
|
||||
}),
|
||||
marks: Type.Object({}, {
|
||||
title: 'Marks',
|
||||
widget: `${CORE_VERSION}/${CoreWidgetName.RecordField}`,
|
||||
category: Category.Behavior
|
||||
}),
|
||||
onlyMarkValue: Type.Boolean({
|
||||
title: 'Only Mark Value',
|
||||
category: Category.Behavior
|
||||
}),
|
||||
reverse: Type.Boolean({
|
||||
title: 'Reverse',
|
||||
category: Category.Behavior
|
||||
})
|
||||
};
|
||||
title: 'Tooltip Position',
|
||||
}
|
||||
)
|
||||
),
|
||||
vertical: Type.Boolean({
|
||||
title: 'Vertical',
|
||||
category: Category.Layout,
|
||||
}),
|
||||
tooltipVisible: Type.Boolean({
|
||||
title: 'Show Tooltip',
|
||||
category: Category.Behavior,
|
||||
}),
|
||||
range: Type.Boolean({
|
||||
title: 'Enable Range',
|
||||
category: Category.Behavior,
|
||||
}),
|
||||
step: Type.Number({
|
||||
title: 'Step',
|
||||
category: Category.Behavior,
|
||||
}),
|
||||
showTicks: Type.Boolean({
|
||||
title: 'Show Ticks',
|
||||
category: Category.Behavior,
|
||||
}),
|
||||
marks: Type.Object(
|
||||
{},
|
||||
{
|
||||
title: 'Marks',
|
||||
widget: `${CORE_VERSION}/${CoreWidgetName.RecordField}`,
|
||||
category: Category.Behavior,
|
||||
}
|
||||
),
|
||||
onlyMarkValue: Type.Boolean({
|
||||
title: 'Only Mark Value',
|
||||
category: Category.Behavior,
|
||||
}),
|
||||
reverse: Type.Boolean({
|
||||
title: 'Reverse',
|
||||
category: Category.Behavior,
|
||||
}),
|
||||
};
|
||||
|
@ -1,9 +1,14 @@
|
||||
import { RuntimeFunctions } from '@sunmao-ui/runtime';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { SlotSpec } from '@sunmao-ui/core';
|
||||
|
||||
export const useStateValue = <T>(
|
||||
export const useStateValue = <
|
||||
T,
|
||||
TMethods = any,
|
||||
TSlots extends Record<string, SlotSpec> = Record<string, SlotSpec>
|
||||
>(
|
||||
defaultValue: T,
|
||||
mergeState?: RuntimeFunctions<Record<string, T>, any>['mergeState'],
|
||||
mergeState?: RuntimeFunctions<Record<string, T>, TMethods, TSlots>['mergeState'],
|
||||
updateWhenDefaultValueChanges?: boolean,
|
||||
key = 'value'
|
||||
): [T, React.Dispatch<React.SetStateAction<T>>] => {
|
||||
@ -13,6 +18,7 @@ export const useStateValue = <T>(
|
||||
if (mergeState) {
|
||||
mergeState({ [key]: defaultValue });
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@ -20,7 +26,7 @@ export const useStateValue = <T>(
|
||||
setValue(defaultValue);
|
||||
mergeState({ [key]: defaultValue });
|
||||
}
|
||||
}, [defaultValue, updateWhenDefaultValueChanges, mergeState]);
|
||||
}, [defaultValue, updateWhenDefaultValueChanges, mergeState, key]);
|
||||
|
||||
return [value, setValue];
|
||||
};
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { ComponentMetadata } from '@sunmao-ui/core/lib/metadata';
|
||||
import { ComponentImplProps } from '@sunmao-ui/runtime';
|
||||
import { TLiteral, Type } from '@sinclair/typebox';
|
||||
import { SlotSpec } from '@sunmao-ui/core';
|
||||
|
||||
export type IntoStringUnion<T> = {
|
||||
[K in keyof T]: T[K] extends string ? TLiteral<T[K]> : never;
|
||||
@ -37,11 +38,11 @@ export const getComponentProps = <
|
||||
T,
|
||||
TState,
|
||||
TMethods,
|
||||
KSlot extends string,
|
||||
TSlots extends Record<string, SlotSpec>,
|
||||
KStyleSlot extends string,
|
||||
KEvent extends string
|
||||
>(
|
||||
props: T & ComponentImplProps<TState, TMethods, KSlot, KStyleSlot, KEvent>
|
||||
props: T & ComponentImplProps<TState, TMethods, TSlots, KStyleSlot, KEvent>
|
||||
) => {
|
||||
const {
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
@ -144,7 +144,9 @@ export default implementRuntimeComponent({
|
||||
properties: StyleSpec,
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -164,7 +166,7 @@ export default implementRuntimeComponent({
|
||||
`}
|
||||
ref={elementRef}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseBox>
|
||||
);
|
||||
});
|
||||
|
@ -50,7 +50,7 @@ export default implementRuntimeComponent({
|
||||
methods: {
|
||||
click: undefined,
|
||||
},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onClick'],
|
||||
},
|
||||
|
@ -100,7 +100,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: CheckboxStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -43,7 +43,9 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
@ -61,7 +63,7 @@ export default implementRuntimeComponent({
|
||||
isDisabled={isDisabled}
|
||||
onChange={val => setValue(val)}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseCheckboxGroup>
|
||||
</Box>
|
||||
);
|
||||
|
@ -76,7 +76,9 @@ export default implementRuntimeComponent({
|
||||
confirmDialog: undefined,
|
||||
cancelDialog: undefined,
|
||||
},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['cancelDialog', 'confirmDialog'],
|
||||
},
|
||||
@ -160,7 +162,9 @@ export default implementRuntimeComponent({
|
||||
ref={contentRef}
|
||||
>
|
||||
<AlertDialogHeader>{title}</AlertDialogHeader>
|
||||
<AlertDialogBody>{slotsElements.content}</AlertDialogBody>
|
||||
<AlertDialogBody>
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</AlertDialogBody>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<Button
|
||||
|
@ -21,7 +21,7 @@ export default implementRuntimeComponent({
|
||||
properties: Type.Object({}),
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -37,7 +37,9 @@ export default implementRuntimeComponent({
|
||||
methods: {
|
||||
resetForm: undefined,
|
||||
},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: ['onSubmit'],
|
||||
},
|
||||
@ -158,7 +160,7 @@ export default implementRuntimeComponent({
|
||||
`}
|
||||
ref={elementRef}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
{hideSubmit ? undefined : (
|
||||
<Button
|
||||
marginInlineStart="auto !important"
|
||||
|
@ -66,7 +66,9 @@ export default implementRuntimeComponent({
|
||||
value: Type.Any(),
|
||||
}),
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -149,7 +151,7 @@ export default implementRuntimeComponent({
|
||||
}, [inputId, fieldName, isInvalid, isRequired, inputValue, mergeState]);
|
||||
|
||||
const placeholder = <Text color="gray.200">Please Add Input Here</Text>;
|
||||
const slotView = slotsElements.content;
|
||||
const slotView = slotsElements.content ? slotsElements.content({}) : null;
|
||||
|
||||
return (
|
||||
<FormControl
|
||||
|
@ -41,7 +41,9 @@ export default implementRuntimeComponent({
|
||||
spec: {
|
||||
properties: PropsSpec,
|
||||
state: Type.Object({}),
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
methods: {},
|
||||
events: [],
|
||||
@ -72,7 +74,7 @@ export default implementRuntimeComponent({
|
||||
ref={elementRef}
|
||||
{...{ direction, wrap, align, justify, spacing }}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseHStack>
|
||||
);
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: ['onLoad', 'onError'],
|
||||
},
|
||||
|
@ -133,7 +133,7 @@ export default implementRuntimeComponent({
|
||||
}),
|
||||
resetInputValue: undefined,
|
||||
},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -35,7 +35,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -43,7 +43,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -50,7 +50,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
methods: {},
|
||||
state: Type.Object({}),
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -115,7 +115,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -54,51 +54,58 @@ const PropsSpec = Type.Object({
|
||||
category: APPEARANCE,
|
||||
}
|
||||
),
|
||||
customerIncrement: Type.Optional(Type.Object(
|
||||
{
|
||||
bg: Type.String({
|
||||
title: 'Background',
|
||||
}),
|
||||
children: Type.String({
|
||||
title: 'Text',
|
||||
}),
|
||||
_active: Type.Object({
|
||||
customerIncrement: Type.Optional(
|
||||
Type.Object(
|
||||
{
|
||||
bg: Type.String({
|
||||
title: 'Active Background',
|
||||
title: 'Background',
|
||||
}),
|
||||
}, {
|
||||
title: 'Active',
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: 'Increment Button',
|
||||
category: APPEARANCE,
|
||||
}
|
||||
)),
|
||||
customerDecrement: Type.Optional(Type.Object(
|
||||
{
|
||||
bg: Type.String({
|
||||
title: 'Background',
|
||||
}),
|
||||
children: Type.String({
|
||||
title: 'Text',
|
||||
}),
|
||||
_active: Type.Object(
|
||||
{
|
||||
bg: Type.String({
|
||||
title: 'Active Background',
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: 'Active',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Decrement Button',
|
||||
category: APPEARANCE,
|
||||
}
|
||||
)),
|
||||
children: Type.String({
|
||||
title: 'Text',
|
||||
}),
|
||||
_active: Type.Object(
|
||||
{
|
||||
bg: Type.String({
|
||||
title: 'Active Background',
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: 'Active',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Increment Button',
|
||||
category: APPEARANCE,
|
||||
}
|
||||
)
|
||||
),
|
||||
customerDecrement: Type.Optional(
|
||||
Type.Object(
|
||||
{
|
||||
bg: Type.String({
|
||||
title: 'Background',
|
||||
}),
|
||||
children: Type.String({
|
||||
title: 'Text',
|
||||
}),
|
||||
_active: Type.Object(
|
||||
{
|
||||
bg: Type.String({
|
||||
title: 'Active Background',
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: 'Active',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Decrement Button',
|
||||
category: APPEARANCE,
|
||||
}
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
const StateSpec = Type.Object({
|
||||
@ -137,7 +144,7 @@ export default implementRuntimeComponent({
|
||||
}),
|
||||
resetInputValue: undefined,
|
||||
},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -87,7 +87,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -42,7 +42,9 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -67,7 +69,7 @@ export default implementRuntimeComponent({
|
||||
`}
|
||||
ref={elementRef}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseRadioGroup>
|
||||
);
|
||||
}
|
||||
|
@ -20,7 +20,11 @@ export default implementRuntimeComponent({
|
||||
properties: Type.Object({}),
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['root'],
|
||||
slots: {
|
||||
root: {
|
||||
slotProps: Type.Object({}),
|
||||
},
|
||||
},
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
@ -32,7 +36,7 @@ export default implementRuntimeComponent({
|
||||
useSystemColorMode: false,
|
||||
})}
|
||||
>
|
||||
<div ref={elementRef}>{slotsElements.root}</div>
|
||||
<div ref={elementRef}>{slotsElements.root ? slotsElements.root({}) : null}</div>
|
||||
</ChakraProvider>
|
||||
);
|
||||
});
|
||||
|
@ -127,7 +127,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -82,14 +82,16 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
})(({ direction, wrap, align, justify, spacing, slotsElements, elementRef }) => {
|
||||
return (
|
||||
<BaseStack {...{ direction, wrap, align, justify, spacing }} ref={elementRef}>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseStack>
|
||||
);
|
||||
});
|
||||
|
@ -48,7 +48,7 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
|
@ -33,8 +33,8 @@ const exampleProperties = {
|
||||
type: 'text',
|
||||
displayValue: '',
|
||||
buttonConfig: {
|
||||
handlers: []
|
||||
}
|
||||
handlers: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
majorKey: 'id',
|
||||
@ -62,7 +62,7 @@ export const implementTable = implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: TableStateSpec,
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { css } from '@emotion/css';
|
||||
import {
|
||||
Tabs as BaseTabs,
|
||||
@ -49,7 +49,13 @@ export default implementRuntimeComponent({
|
||||
state: StateSpec,
|
||||
methods: {},
|
||||
// tab slot is dynamic
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: {
|
||||
slotProps: Type.Object({
|
||||
tabIndex: Type.Number(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
styleSlots: ['tabItem', 'tabContent'],
|
||||
events: [],
|
||||
},
|
||||
@ -91,9 +97,6 @@ export default implementRuntimeComponent({
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
{tabNames.map((_, idx) => {
|
||||
const ele = slotsElements.content
|
||||
? ([] as React.ReactElement[]).concat(slotsElements.content)[idx]
|
||||
: placeholder;
|
||||
return (
|
||||
<TabPanel
|
||||
key={idx}
|
||||
@ -101,7 +104,9 @@ export default implementRuntimeComponent({
|
||||
${customStyle?.tabContent}
|
||||
`}
|
||||
>
|
||||
{ele}
|
||||
{slotsElements?.content
|
||||
? slotsElements.content({ tabIndex: idx })
|
||||
: placeholder}
|
||||
</TabPanel>
|
||||
);
|
||||
})}
|
||||
|
@ -82,7 +82,9 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
@ -113,7 +115,7 @@ export default implementRuntimeComponent({
|
||||
shouldWrapChildren={shouldWrapChildren}
|
||||
ref={elementRef}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
@ -41,7 +41,9 @@ export default implementRuntimeComponent({
|
||||
spec: {
|
||||
properties: PropsSpec,
|
||||
state: Type.Object({}),
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
methods: {},
|
||||
events: [],
|
||||
@ -72,7 +74,7 @@ export default implementRuntimeComponent({
|
||||
ref={elementRef}
|
||||
{...{ direction, wrap, align, justify, spacing }}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseVStack>
|
||||
);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ describe('component', () => {
|
||||
},
|
||||
],
|
||||
styleSlots: ['content'],
|
||||
slots: [],
|
||||
slots: {},
|
||||
events: [],
|
||||
},
|
||||
});
|
||||
|
@ -2,6 +2,7 @@ import { JSONSchema7 } from 'json-schema';
|
||||
import { parseVersion, Version } from './version';
|
||||
import { ComponentMetadata } from './metadata';
|
||||
import { MethodSchema } from './method';
|
||||
import { SlotSpec } from './slot';
|
||||
|
||||
type ComponentSpec<
|
||||
KMethodName extends string,
|
||||
@ -13,7 +14,7 @@ type ComponentSpec<
|
||||
state: JSONSchema7;
|
||||
methods: Record<KMethodName, MethodSchema['parameters']>;
|
||||
styleSlots: ReadonlyArray<KStyleSlot>;
|
||||
slots: ReadonlyArray<KSlot>;
|
||||
slots: Record<KSlot, SlotSpec>;
|
||||
events: ReadonlyArray<KEvent>;
|
||||
};
|
||||
|
||||
|
@ -5,4 +5,5 @@ export * from './application';
|
||||
export * from './method';
|
||||
export * from './module';
|
||||
export * from './version';
|
||||
export * from './slot';
|
||||
export * from './utilMethod';
|
||||
|
5
packages/core/src/slot.ts
Normal file
5
packages/core/src/slot.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
|
||||
export type SlotSpec = {
|
||||
slotProps?: JSONSchema7;
|
||||
};
|
@ -39,6 +39,7 @@
|
||||
"mitt": "^3.0.0",
|
||||
"mobx-react-lite": "^3.2.2",
|
||||
"react": "^17.0.2",
|
||||
"react-color": "^2.19.3",
|
||||
"react-dom": "^17.0.2",
|
||||
"tern": "^0.24.3"
|
||||
},
|
||||
|
@ -156,6 +156,7 @@ type ExpressionEditorStyleProps = {
|
||||
height?: string;
|
||||
maxHeight?: string;
|
||||
paddingY?: string;
|
||||
isHiddenExpand?: boolean;
|
||||
};
|
||||
type BaseExpressionEditorProps = CommonExpressionEditorProps &
|
||||
ExpressionEditorStyleProps & {
|
||||
@ -377,20 +378,22 @@ export const ExpressionEditor = React.forwardRef<
|
||||
onFocus={onExpressionFocus}
|
||||
onBlur={onExpressionBlur}
|
||||
/>
|
||||
<IconButton
|
||||
aria-label="expand editor"
|
||||
position="absolute"
|
||||
right="0"
|
||||
bottom="0"
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
colorScheme="blue"
|
||||
zIndex="9"
|
||||
className="expand-icon"
|
||||
onClick={onExpand}
|
||||
>
|
||||
<ExternalLinkIcon />
|
||||
</IconButton>
|
||||
{compactOptions.isHiddenExpand ? null : (
|
||||
<IconButton
|
||||
aria-label="expand editor"
|
||||
position="absolute"
|
||||
right="0"
|
||||
bottom="0"
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
colorScheme="blue"
|
||||
zIndex="9"
|
||||
className="expand-icon"
|
||||
onClick={onExpand}
|
||||
>
|
||||
<ExternalLinkIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
{isFocus ? (
|
||||
<Box
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import { FormControl, FormLabel, Input, Select } from '@chakra-ui/react';
|
||||
import { Type, Static } from '@sinclair/typebox';
|
||||
import { Type, Static, TSchema } from '@sinclair/typebox';
|
||||
import { useFormik } from 'formik';
|
||||
import { GLOBAL_UTIL_METHOD_ID } from '@sunmao-ui/runtime';
|
||||
import { ComponentSchema } from '@sunmao-ui/core';
|
||||
@ -9,7 +9,7 @@ import { implementWidget, mergeWidgetOptionsIntoSpec } from '../../utils/widget'
|
||||
import { RecordWidget } from './RecordField';
|
||||
import { SpecWidget } from './SpecWidget';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { CORE_VERSION, CoreWidgetName } from '@sunmao-ui/shared';
|
||||
import { CORE_VERSION, CoreWidgetName, parseTypeBox } from '@sunmao-ui/shared';
|
||||
|
||||
const EventWidgetOptions = Type.Object({});
|
||||
|
||||
@ -90,13 +90,12 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
]);
|
||||
const params = useMemo(() => {
|
||||
const params: Record<string, string> = {};
|
||||
const parameters = formik.values.method.parameters;
|
||||
|
||||
for (const key in paramsSpec?.properties ?? {}) {
|
||||
const defaultValue = (paramsSpec?.properties?.[key] as WidgetProps['spec'])
|
||||
.defaultValue;
|
||||
const spec = paramsSpec!.properties![key] as TSchema;
|
||||
const defaultValue = spec.defaultValue;
|
||||
|
||||
params[key] = parameters?.[key] ?? defaultValue ?? '';
|
||||
params[key] = defaultValue ?? parseTypeBox(spec);
|
||||
}
|
||||
|
||||
return params;
|
||||
@ -177,7 +176,9 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
|
||||
const typeField = (
|
||||
<FormControl>
|
||||
<FormLabel fontSize='14px' fontWeight='normal'>Event Type</FormLabel>
|
||||
<FormLabel fontSize="14px" fontWeight="normal">
|
||||
Event Type
|
||||
</FormLabel>
|
||||
<Select
|
||||
name="type"
|
||||
onBlur={onSubmit}
|
||||
@ -195,7 +196,9 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
);
|
||||
const targetField = (
|
||||
<FormControl>
|
||||
<FormLabel fontSize='14px' fontWeight='normal'>Target Component</FormLabel>
|
||||
<FormLabel fontSize="14px" fontWeight="normal">
|
||||
Target Component
|
||||
</FormLabel>
|
||||
<Select
|
||||
name="componentId"
|
||||
onBlur={onSubmit}
|
||||
@ -213,7 +216,9 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
);
|
||||
const methodField = (
|
||||
<FormControl>
|
||||
<FormLabel fontSize='14px' fontWeight='normal'>Method</FormLabel>
|
||||
<FormLabel fontSize="14px" fontWeight="normal">
|
||||
Method
|
||||
</FormLabel>
|
||||
<Select
|
||||
name="method.name"
|
||||
onBlur={onSubmit}
|
||||
@ -232,7 +237,9 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
|
||||
const parametersField = (
|
||||
<FormControl>
|
||||
<FormLabel fontSize='14px' fontWeight='normal'>Parameters</FormLabel>
|
||||
<FormLabel fontSize="14px" fontWeight="normal">
|
||||
Parameters
|
||||
</FormLabel>
|
||||
<RecordWidget
|
||||
component={component}
|
||||
path={parametersPath}
|
||||
@ -247,7 +254,9 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
|
||||
const waitTypeField = (
|
||||
<FormControl>
|
||||
<FormLabel fontSize='14px' fontWeight='normal'>Wait Type</FormLabel>
|
||||
<FormLabel fontSize="14px" fontWeight="normal">
|
||||
Wait Type
|
||||
</FormLabel>
|
||||
<Select
|
||||
name="wait.type"
|
||||
onBlur={onSubmit}
|
||||
@ -263,7 +272,9 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
|
||||
const waitTimeField = (
|
||||
<FormControl>
|
||||
<FormLabel fontSize='14px' fontWeight='normal'>Wait Time</FormLabel>
|
||||
<FormLabel fontSize="14px" fontWeight="normal">
|
||||
Wait Time
|
||||
</FormLabel>
|
||||
<Input
|
||||
name="wait.time"
|
||||
onBlur={onSubmit}
|
||||
@ -275,7 +286,9 @@ export const EventWidget: React.FC<WidgetProps<EventWidgetOptionsType>> = observ
|
||||
|
||||
const disabledField = (
|
||||
<FormControl>
|
||||
<FormLabel fontSize='14px' fontWeight='normal'>Disabled</FormLabel>
|
||||
<FormLabel fontSize="14px" fontWeight="normal">
|
||||
Disabled
|
||||
</FormLabel>
|
||||
<SpecWidget
|
||||
{...props}
|
||||
spec={disabledSpec}
|
||||
|
@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import { CORE_VERSION, StyleWidgetName } from '@sunmao-ui/shared';
|
||||
import { WidgetProps } from '../../../types/widget';
|
||||
import { implementWidget, mergeWidgetOptionsIntoSpec } from '../../../utils/widget';
|
||||
import { ExpressionWidget } from '../ExpressionWidget';
|
||||
import {
|
||||
Box,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Popover,
|
||||
PopoverTrigger,
|
||||
PopoverContent,
|
||||
PopoverArrow,
|
||||
PopoverBody,
|
||||
Portal,
|
||||
} from '@chakra-ui/react';
|
||||
import { SketchPicker } from 'react-color';
|
||||
|
||||
export const ColorWidget: React.FC<WidgetProps<{}, string>> = props => {
|
||||
const { value, onChange } = props;
|
||||
const onColorChange = ({ rgb }: any) => {
|
||||
onChange(`rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`);
|
||||
};
|
||||
const onInputChange = (value: string) => {
|
||||
onChange(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<InputGroup>
|
||||
<ExpressionWidget
|
||||
{...props}
|
||||
spec={mergeWidgetOptionsIntoSpec(props.spec, {
|
||||
compactOptions: { isHiddenExpand: true, height: '32px' },
|
||||
})}
|
||||
value={value}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
<InputRightElement>
|
||||
<Popover arrowSize={8} placement="left" matchWidth>
|
||||
<PopoverTrigger>
|
||||
<Box
|
||||
cursor="pointer"
|
||||
backgroundColor={value || '#fff'}
|
||||
borderRadius="3px"
|
||||
border="1px solid #eee"
|
||||
width="20px"
|
||||
height="20px"
|
||||
boxShadow="rgba(149, 157, 165, 0.2) 0px 8px 24px"
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
<Portal>
|
||||
<PopoverContent w="auto">
|
||||
<PopoverArrow />
|
||||
<PopoverBody padding={0}>
|
||||
<SketchPicker
|
||||
width="250px"
|
||||
color={value || '#fff'}
|
||||
onChangeComplete={onColorChange}
|
||||
/>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Portal>
|
||||
</Popover>
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export default implementWidget({
|
||||
version: CORE_VERSION,
|
||||
metadata: {
|
||||
name: StyleWidgetName.Color,
|
||||
},
|
||||
})(ColorWidget);
|
@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { HStack, Text } from '@chakra-ui/react';
|
||||
import { HStack, Text, Box } from '@chakra-ui/react';
|
||||
import { CORE_VERSION, StyleWidgetName } from '@sunmao-ui/shared';
|
||||
import { WidgetProps } from '../../../types/widget';
|
||||
import { implementWidget } from '../../../utils/widget';
|
||||
import { ExpressionEditor } from '../../Form';
|
||||
import { implementWidget, mergeWidgetOptionsIntoSpec } from '../../../utils/widget';
|
||||
import { ExpressionWidget } from '../ExpressionWidget';
|
||||
|
||||
type Size = {
|
||||
width?: number | string;
|
||||
@ -14,31 +14,45 @@ export const SizeWidget: React.FC<WidgetProps<{}, Size>> = props => {
|
||||
const { value, onChange } = props;
|
||||
|
||||
return (
|
||||
<HStack width="full">
|
||||
<Text>W</Text>
|
||||
<ExpressionEditor
|
||||
compact={true}
|
||||
defaultCode={value.width === undefined ? '' : String(value.width) || ''}
|
||||
onBlur={v => {
|
||||
const newSize = {
|
||||
...value,
|
||||
width: v,
|
||||
};
|
||||
onChange(newSize);
|
||||
}}
|
||||
/>
|
||||
<Text>H</Text>
|
||||
<ExpressionEditor
|
||||
compact={true}
|
||||
defaultCode={value.height === undefined ? '' : String(value.height) || ''}
|
||||
onBlur={v => {
|
||||
const newSize = {
|
||||
...value,
|
||||
height: v,
|
||||
};
|
||||
onChange(newSize);
|
||||
}}
|
||||
/>
|
||||
<HStack>
|
||||
<HStack flex={1} minW={0}>
|
||||
<Text>W</Text>
|
||||
<Box flex={1} minW={0}>
|
||||
<ExpressionWidget
|
||||
{...props}
|
||||
spec={mergeWidgetOptionsIntoSpec(props.spec, {
|
||||
compactOptions: { height: '32px' },
|
||||
})}
|
||||
value={value.width === undefined ? '' : String(value.width) || ''}
|
||||
onChange={v => {
|
||||
const newSize = {
|
||||
...value,
|
||||
width: v,
|
||||
};
|
||||
onChange(newSize);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</HStack>
|
||||
<HStack flex={1} minW={0}>
|
||||
<Text>H</Text>
|
||||
<Box flex={1} minW={0}>
|
||||
<ExpressionWidget
|
||||
{...props}
|
||||
spec={mergeWidgetOptionsIntoSpec(props.spec, {
|
||||
compactOptions: { height: '32px' },
|
||||
})}
|
||||
value={value.height === undefined ? '' : String(value.height) || ''}
|
||||
onChange={v => {
|
||||
const newSize = {
|
||||
...value,
|
||||
height: v,
|
||||
};
|
||||
onChange(newSize);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</HStack>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ import eventWidgetSpec from './EventWidget';
|
||||
import popoverWidgetSpec from './PopoverWidget';
|
||||
import sizeWidgetSpec from './StyleWidgets/SizeWidget';
|
||||
import fontWidgetSpec from './StyleWidgets/FontWidget';
|
||||
import colorWidgetSpec from './StyleWidgets/ColorWidget';
|
||||
|
||||
export * from './SpecWidget';
|
||||
export * from './ArrayField';
|
||||
@ -34,6 +35,7 @@ export * from './EventWidget';
|
||||
export * from './PopoverWidget';
|
||||
export * from './StyleWidgets/SizeWidget';
|
||||
export * from './StyleWidgets/FontWidget';
|
||||
export * from './StyleWidgets/ColorWidget';
|
||||
|
||||
export const widgets: ImplementedWidget<any>[] = [
|
||||
specWidgetSpec,
|
||||
@ -53,4 +55,5 @@ export const widgets: ImplementedWidget<any>[] = [
|
||||
popoverWidgetSpec,
|
||||
sizeWidgetSpec,
|
||||
fontWidgetSpec,
|
||||
colorWidgetSpec,
|
||||
];
|
||||
|
3
packages/editor-sdk/src/types/react-color.d.ts
vendored
Normal file
3
packages/editor-sdk/src/types/react-color.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
declare module 'react-color' {
|
||||
export { SketchPicker } from 'react-color';
|
||||
}
|
@ -60,7 +60,7 @@ export class ComponentModel implements IComponentModel {
|
||||
}
|
||||
|
||||
get slots() {
|
||||
return (this.spec ? this.spec.spec.slots : []) as SlotName[];
|
||||
return (this.spec ? Object.keys(this.spec.spec.slots) : []) as SlotName[];
|
||||
}
|
||||
|
||||
get events() {
|
||||
|
@ -2,6 +2,7 @@ import React, { useCallback, useMemo, useState } from 'react';
|
||||
import produce from 'immer';
|
||||
import { AddIcon, ChevronDownIcon, ChevronUpIcon, CloseIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Box,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
VStack,
|
||||
@ -18,7 +19,7 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { ComponentSchema } from '@sunmao-ui/core';
|
||||
import { CORE_VERSION, CoreTraitName } from '@sunmao-ui/shared';
|
||||
import { FontWidget, SizeWidget } from '@sunmao-ui/editor-sdk';
|
||||
import { FontWidget, SizeWidget, ColorWidget } from '@sunmao-ui/editor-sdk';
|
||||
import { CssEditor } from '../../../components/CodeEditor';
|
||||
import { genOperation } from '../../../operations';
|
||||
import { formWrapperCSS } from '../style';
|
||||
@ -193,9 +194,9 @@ export const StyleTraitForm: React.FC<Props> = props => {
|
||||
</CollapsibleFormControl>
|
||||
<CollapsibleFormControl label="Size">
|
||||
<SizeWidget
|
||||
value={_cssProperties || {}}
|
||||
onChange={changeCssProperties}
|
||||
{...widgetProps}
|
||||
value={_cssProperties}
|
||||
onChange={changeCssProperties}
|
||||
/>
|
||||
</CollapsibleFormControl>
|
||||
<CollapsibleFormControl label="Font">
|
||||
@ -205,6 +206,28 @@ export const StyleTraitForm: React.FC<Props> = props => {
|
||||
{...widgetProps}
|
||||
/>
|
||||
</CollapsibleFormControl>
|
||||
<CollapsibleFormControl label="Color">
|
||||
<Box mb="8px">
|
||||
<Text mb="8px">Text Color</Text>
|
||||
<ColorWidget
|
||||
{...widgetProps}
|
||||
value={_cssProperties.color || ''}
|
||||
onChange={(color: string) =>
|
||||
changeCssProperties({ ..._cssProperties, color })
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box mb="8px">
|
||||
<Text mb="8px">Background Color</Text>
|
||||
<ColorWidget
|
||||
{...widgetProps}
|
||||
value={_cssProperties.backgroundColor || ''}
|
||||
onChange={(color: string) =>
|
||||
changeCssProperties({ ..._cssProperties, backgroundColor: color })
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</CollapsibleFormControl>
|
||||
<CollapsibleFormControl label="CSS">
|
||||
<CssEditor defaultCode={style} onBlur={v => changeStyleContent(i, v)} />
|
||||
</CollapsibleFormControl>
|
||||
|
@ -21,10 +21,11 @@ export const DropSlotMask: React.FC<Props> = observer((props: Props) => {
|
||||
const maskRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const hoverComponentType =
|
||||
editorStore.components.find(c => c.id === hoverId)?.type || `${CORE_VERSION}/${CoreComponentName.Text}`;
|
||||
editorStore.components.find(c => c.id === hoverId)?.type ||
|
||||
`${CORE_VERSION}/${CoreComponentName.Text}`;
|
||||
|
||||
const slots = useMemo(() => {
|
||||
return registry.getComponentByType(hoverComponentType).spec.slots || [];
|
||||
return Object.keys(registry.getComponentByType(hoverComponentType).spec.slots) || [];
|
||||
}, [hoverComponentType, registry]);
|
||||
|
||||
// calculate the slot which is being dragged over
|
||||
@ -59,7 +60,7 @@ export const DropSlotMask: React.FC<Props> = observer((props: Props) => {
|
||||
display="flex"
|
||||
flexDirection={vertical ? 'column' : 'row'}
|
||||
ref={maskRef}
|
||||
border='1px solid orange'
|
||||
border="1px solid orange"
|
||||
>
|
||||
{slots.map(slot => {
|
||||
return (
|
||||
|
@ -102,7 +102,12 @@ export const ComponentItemView: React.FC<Props> = props => {
|
||||
onClick={onClick}
|
||||
>
|
||||
{highlightBackground}
|
||||
<HStack width="full" justify="space-between" spacing="0" paddingLeft={noChevron ? '6' : '0'}>
|
||||
<HStack
|
||||
width="full"
|
||||
justify="space-between"
|
||||
spacing="0"
|
||||
paddingLeft={noChevron ? '6' : '0'}
|
||||
>
|
||||
{noChevron ? null : expandIcon}
|
||||
<Text
|
||||
cursor="pointer"
|
||||
|
@ -35,9 +35,7 @@ const observeSelected = (Component: React.FC<ComponentTreeProps>) => {
|
||||
}
|
||||
}, [selectedComponentId, component.id, onSelected]);
|
||||
|
||||
return (
|
||||
<Component {...props} isSelected={selectedComponentId === component.id} />
|
||||
);
|
||||
return <Component {...props} isSelected={selectedComponentId === component.id} />;
|
||||
};
|
||||
|
||||
return observer(ObserveActive);
|
||||
@ -57,14 +55,17 @@ const ComponentTree = (props: ComponentTreeProps) => {
|
||||
depth,
|
||||
} = props;
|
||||
const { registry, eventBus } = services;
|
||||
const slots = registry.getComponentByType(component.type).spec.slots;
|
||||
const slots = Object.keys(registry.getComponentByType(component.type).spec.slots);
|
||||
const [isExpanded, setIsExpanded] = useState(true);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const onChildSelected = useCallback((selectedId) => {
|
||||
setIsExpanded(true);
|
||||
onSelected?.(selectedId);
|
||||
}, [onSelected]);
|
||||
const onChildSelected = useCallback(
|
||||
selectedId => {
|
||||
setIsExpanded(true);
|
||||
onSelected?.(selectedId);
|
||||
},
|
||||
[onSelected]
|
||||
);
|
||||
|
||||
const slotsEle = useMemo(() => {
|
||||
if (slots.length === 0) {
|
||||
|
@ -101,7 +101,7 @@ export function initSunmaoUIEditor(props: SunmaoUIEditorProps = {}) {
|
||||
const onRefresh = useCallback(() => {
|
||||
// need to reregister all the traits to clear the trait states which like `HasInitializedMap`
|
||||
const traits = registry.getAllTraits();
|
||||
|
||||
|
||||
stateManager.clear();
|
||||
setStore(stateManager.store);
|
||||
registry.unregisterAllTraits();
|
||||
|
@ -1,7 +1,4 @@
|
||||
import {
|
||||
StateManager,
|
||||
ExpressionError,
|
||||
} from '../src/services/StateManager';
|
||||
import { StateManager, ExpressionError } from '../src/services/StateManager';
|
||||
|
||||
describe('evalExpression function', () => {
|
||||
const scope = {
|
||||
@ -111,7 +108,7 @@ describe('evalExpression function', () => {
|
||||
text: 'hello',
|
||||
},
|
||||
noConsoleError: true,
|
||||
ignoreEvalError: true
|
||||
ignoreEvalError: true,
|
||||
})
|
||||
).toEqual(`hello {{myModule__state0.value}}`);
|
||||
});
|
||||
|
@ -14,7 +14,14 @@ export const ImplWrapper = React.memo<ImplWrapperProps>(
|
||||
|
||||
if (prevChildren && nextChildren) {
|
||||
isEqual = shallowCompareArray(prevChildren, nextChildren);
|
||||
} else if (prevChildren === nextChildren) {
|
||||
isEqual = true;
|
||||
}
|
||||
return isEqual && prevComponent === nextComponent;
|
||||
return (
|
||||
isEqual &&
|
||||
prevComponent === nextComponent &&
|
||||
// TODO: keep ImplWrapper memorized and get slot props from store
|
||||
prevProps.slotProps === nextProps.slotProps
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -1,16 +1,16 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { merge, mergeWith, isArray } from 'lodash-es';
|
||||
import { merge, mergeWith, isArray, omit } from 'lodash-es';
|
||||
import { RuntimeTraitSchema } from '@sunmao-ui/core';
|
||||
import { watch } from '../../../utils/watchReactivity';
|
||||
import { ImplWrapperProps, TraitResult } from '../../../types';
|
||||
import { useRuntimeFunctions } from './hooks/useRuntimeFunctions';
|
||||
import { useSlotElements } from './hooks/useSlotChildren';
|
||||
import { getSlotElements } from './hooks/useSlotChildren';
|
||||
import { useGlobalHandlerMap } from './hooks/useGlobalHandlerMap';
|
||||
import { useEleRef } from './hooks/useEleMap';
|
||||
import { useGridLayout } from './hooks/useGridLayout';
|
||||
|
||||
export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps>(
|
||||
(props, ref) => {
|
||||
function ImplWrapperMain(props, ref) {
|
||||
const { component: c, children } = props;
|
||||
const { registry, stateManager } = props.services;
|
||||
|
||||
@ -24,7 +24,15 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
|
||||
|
||||
const [traitResults, setTraitResults] = useState<TraitResult<string, string>[]>(
|
||||
() => {
|
||||
return c.traits.map(t => executeTrait(t, stateManager.deepEval(t.properties, { fallbackWhenError: () => undefined })));
|
||||
return c.traits.map(t =>
|
||||
executeTrait(
|
||||
t,
|
||||
stateManager.deepEval(t.properties, {
|
||||
scopeObject: { $slot: props.slotProps },
|
||||
fallbackWhenError: () => undefined,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@ -50,7 +58,10 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
|
||||
return newResults;
|
||||
});
|
||||
},
|
||||
{ fallbackWhenError: () => undefined }
|
||||
{
|
||||
scopeObject: { $slot: props.slotProps },
|
||||
fallbackWhenError: () => undefined,
|
||||
}
|
||||
);
|
||||
stops.push(stop);
|
||||
properties.push(result);
|
||||
@ -59,7 +70,7 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
|
||||
// because mergeState will be called during the first render of component, and state will change
|
||||
setTraitResults(c.traits.map((trait, i) => executeTrait(trait, properties[i])));
|
||||
return () => stops.forEach(s => s());
|
||||
}, [c.id, c.traits, executeTrait, stateManager]);
|
||||
}, [c.id, c.traits, executeTrait, stateManager, props.slotProps]);
|
||||
|
||||
// reduce traitResults
|
||||
const propsFromTraits: TraitResult<string, string>['props'] = useMemo(() => {
|
||||
@ -84,7 +95,10 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
|
||||
// component properties
|
||||
const [evaledComponentProperties, setEvaledComponentProperties] = useState(() => {
|
||||
return merge(
|
||||
stateManager.deepEval(c.properties, { fallbackWhenError: () => undefined }),
|
||||
stateManager.deepEval(c.properties, {
|
||||
fallbackWhenError: () => undefined,
|
||||
scopeObject: { $slot: props.slotProps },
|
||||
}),
|
||||
propsFromTraits
|
||||
);
|
||||
});
|
||||
@ -95,13 +109,13 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
|
||||
({ result: newResult }: any) => {
|
||||
setEvaledComponentProperties({ ...newResult });
|
||||
},
|
||||
{ fallbackWhenError: () => undefined }
|
||||
{ fallbackWhenError: () => undefined, scopeObject: { $slot: props.slotProps } }
|
||||
);
|
||||
// must keep this line, reason is the same as above
|
||||
setEvaledComponentProperties({ ...result });
|
||||
|
||||
return stop;
|
||||
}, [c.properties, stateManager]);
|
||||
}, [c.properties, stateManager, props.slotProps]);
|
||||
|
||||
useEffect(() => {
|
||||
const clearFunctions = propsFromTraits?.componentDidMount?.map(e => e());
|
||||
@ -128,12 +142,21 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
|
||||
);
|
||||
|
||||
const unmount = traitResults.some(result => result.unmount);
|
||||
const slotElements = useSlotElements(props);
|
||||
const slotElements = getSlotElements({
|
||||
app: props.app,
|
||||
childrenMap: props.childrenMap,
|
||||
children: props.children,
|
||||
component: props.component,
|
||||
gridCallbacks: props.gridCallbacks,
|
||||
services: props.services,
|
||||
hooks: props.hooks,
|
||||
isInModule: props.isInModule,
|
||||
});
|
||||
|
||||
const C = unmount ? null : (
|
||||
<Impl
|
||||
key={c.id}
|
||||
{...props}
|
||||
{...omit(props, 'slotProps')}
|
||||
{...mergedProps}
|
||||
slotsElements={slotElements}
|
||||
mergeState={mergeState}
|
||||
|
@ -7,19 +7,24 @@ import { ImplWrapperProps, TraitResult } from '../../../types';
|
||||
import { watch } from '../../..';
|
||||
|
||||
export const UnmountImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperProps>(
|
||||
(props, ref) => {
|
||||
function UnmountImplWrapper(props, ref) {
|
||||
const { component: c, services } = props;
|
||||
const { stateManager, registry } = services;
|
||||
const { executeTrait } = useRuntimeFunctions(props);
|
||||
|
||||
const unmountTraits = useMemo(
|
||||
() => c.traits.filter(t => registry.getTraitByType(t.type).metadata.annotations?.beforeRender),
|
||||
() =>
|
||||
c.traits.filter(
|
||||
t => registry.getTraitByType(t.type).metadata.annotations?.beforeRender
|
||||
),
|
||||
[c.traits, registry]
|
||||
);
|
||||
|
||||
const [isHidden, setIsHidden] = useState(() => {
|
||||
const results: TraitResult<string, string>[] = unmountTraits.map(t => {
|
||||
const properties = stateManager.deepEval(t.properties);
|
||||
const properties = stateManager.deepEval(t.properties, {
|
||||
scopeObject: { $slot: props.slotProps },
|
||||
});
|
||||
return executeTrait(t, properties);
|
||||
});
|
||||
return results.some(result => result.unmount);
|
||||
@ -42,8 +47,12 @@ export const UnmountImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperPr
|
||||
const stops: ReturnType<typeof watch>[] = [];
|
||||
if (unmountTraits.length > 0) {
|
||||
unmountTraits.forEach(t => {
|
||||
const { result, stop } = stateManager.deepEvalAndWatch(t.properties, newValue =>
|
||||
traitChangeCallback(t, newValue.result)
|
||||
const { result, stop } = stateManager.deepEvalAndWatch(
|
||||
t.properties,
|
||||
newValue => traitChangeCallback(t, newValue.result),
|
||||
{
|
||||
scopeObject: { $slot: props.slotProps },
|
||||
}
|
||||
);
|
||||
traitChangeCallback(t, result);
|
||||
stops.push(stop);
|
||||
@ -52,7 +61,14 @@ export const UnmountImplWrapper = React.forwardRef<HTMLDivElement, ImplWrapperPr
|
||||
return () => {
|
||||
stops.forEach(stop => stop());
|
||||
};
|
||||
}, [c, executeTrait, unmountTraits, stateManager, traitChangeCallback]);
|
||||
}, [
|
||||
c,
|
||||
executeTrait,
|
||||
unmountTraits,
|
||||
stateManager,
|
||||
traitChangeCallback,
|
||||
props.slotProps,
|
||||
]);
|
||||
|
||||
// If a component is unmount, its state would be removed.
|
||||
// So if it mount again, we should init its state again.
|
||||
|
@ -1,26 +1,25 @@
|
||||
import React from 'react';
|
||||
import { RuntimeComponentSchema } from '@sunmao-ui/core';
|
||||
import { ImplWrapperProps } from '../../../../types';
|
||||
import { SlotSpec } from '@sunmao-ui/core';
|
||||
import { ImplWrapperProps, SlotsElements } from '../../../../types';
|
||||
import { ImplWrapper } from '../ImplWrapper';
|
||||
|
||||
export function useSlotElements(props: ImplWrapperProps) {
|
||||
export function getSlotElements(
|
||||
props: ImplWrapperProps & { children?: React.ReactNode }
|
||||
): SlotsElements<Record<string, SlotSpec>> {
|
||||
const { component: c, childrenMap } = props;
|
||||
const childrenCache = new Map<RuntimeComponentSchema, React.ReactElement>();
|
||||
|
||||
if (!childrenMap[c.id]) {
|
||||
return {};
|
||||
}
|
||||
const slotElements: Record<string, React.ReactElement[] | React.ReactElement> = {};
|
||||
const slotElements: SlotsElements<Record<string, SlotSpec>> = {};
|
||||
for (const slot in childrenMap[c.id]) {
|
||||
const slotChildren = childrenMap[c.id][slot].map(child => {
|
||||
if (!childrenCache.get(child)) {
|
||||
const ele = <ImplWrapper key={child.id} {...props} component={child} />;
|
||||
childrenCache.set(child, ele);
|
||||
}
|
||||
return childrenCache.get(child)!;
|
||||
return <ImplWrapper key={child.id} {...props} component={child} />;
|
||||
});
|
||||
|
||||
slotElements[slot] = slotChildren.length === 1 ? slotChildren[0] : slotChildren;
|
||||
slotElements[slot] = function getSlot(slotProps) {
|
||||
return slotChildren.map(child => React.cloneElement(child, { slotProps }));
|
||||
};
|
||||
}
|
||||
return slotElements;
|
||||
}
|
||||
|
@ -150,13 +150,7 @@ const ModuleRendererContent = React.forwardRef<
|
||||
services.apiService.off('moduleEvent', h);
|
||||
});
|
||||
};
|
||||
}, [
|
||||
evalScope,
|
||||
handlers,
|
||||
moduleId,
|
||||
services.apiService,
|
||||
services.stateManager,
|
||||
]);
|
||||
}, [evalScope, handlers, moduleId, services.apiService, services.stateManager]);
|
||||
|
||||
const result = useMemo(() => {
|
||||
// Must init components' state, otherwise store cannot listen these components' state changing
|
||||
|
@ -20,7 +20,7 @@ export default implementRuntimeComponent({
|
||||
properties: Type.Object({}),
|
||||
state: Type.Object({}),
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
|
@ -2,7 +2,7 @@ import { Type } from '@sinclair/typebox';
|
||||
import { css } from '@emotion/css';
|
||||
import { implementRuntimeComponent } from '../../utils/buildKit';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { CORE_VERSION } from '@sunmao-ui/shared';
|
||||
import { CORE_VERSION } from '@sunmao-ui/shared';
|
||||
|
||||
const PropsSpec = Type.Object({
|
||||
multiple: Type.Boolean({
|
||||
@ -57,7 +57,9 @@ export default implementRuntimeComponent({
|
||||
methods: {
|
||||
selectFile: Type.Object({}),
|
||||
},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -105,7 +107,7 @@ export default implementRuntimeComponent({
|
||||
accept={fileTypes.join(',')}
|
||||
onChange={onChange}
|
||||
/>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -54,7 +54,9 @@ export default implementRuntimeComponent({
|
||||
properties: PropsSpec,
|
||||
state: {},
|
||||
methods: {},
|
||||
slots: ['content'],
|
||||
slots: {
|
||||
content: { slotProps: Type.Object({}) },
|
||||
},
|
||||
styleSlots: ['content'],
|
||||
events: [],
|
||||
},
|
||||
@ -78,7 +80,7 @@ export default implementRuntimeComponent({
|
||||
${customStyle?.content}
|
||||
`}
|
||||
>
|
||||
{slotsElements.content}
|
||||
{slotsElements.content ? slotsElements.content({}) : null}
|
||||
</BaseGridLayout>
|
||||
</Suspense>
|
||||
);
|
||||
|
@ -23,7 +23,7 @@ export default implementRuntimeComponent({
|
||||
properties: ModuleSpec,
|
||||
state: {},
|
||||
methods: {},
|
||||
slots: [],
|
||||
slots: {},
|
||||
styleSlots: [],
|
||||
events: [],
|
||||
},
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user