From 55f5894a3cb4b648eab21c69874ba200472bf790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E8=8C=82=E5=B3=B0?= Date: Tue, 12 Jul 2022 17:24:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E6=BC=94=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scena/viewport/ScreenViewport.tsx | 2 +- src/properties/AlignPanel.tsx | 15 +- src/properties/CurrentElementInformation.tsx | 15 +- src/properties/DsignAutoLayout.tsx | 20 +- src/properties/DsignColor.tsx | 14 +- src/properties/DynaActionForm.tsx | 8 +- src/properties/FormField.tsx | 4 +- src/properties/IconButton.tsx | 6 +- src/properties/ListTree.tsx | 6 +- src/properties/RadiusAllSetting.tsx | 7 +- src/properties/combine/MultipleWrapper.tsx | 8 +- src/properties/combine/ObjectCombiner.tsx | 14 +- src/properties/combine/WrapperItem.tsx | 3 + .../combine/style/WrapperPopover.less | 18 +- src/properties/data-entry/Input.tsx | 2 +- src/properties/data-entry/InputNumber.tsx | 2 +- src/properties/data-entry/Select.tsx | 12 + src/properties/data-entry/TextArea.tsx | 2 +- src/properties/index.ts | 1 + src/properties/typings.ts | 9 +- src/style/design.less | 78 ++++-- src/style/form.component.less | 91 ++++++- src/style/sketch.less | 125 +++++++-- src/sunmao.ts | 4 + stories/Properties.stories.tsx | 257 +++++++++++++++++- 25 files changed, 626 insertions(+), 97 deletions(-) diff --git a/src/components/scena/viewport/ScreenViewport.tsx b/src/components/scena/viewport/ScreenViewport.tsx index 802fe85..c098413 100644 --- a/src/components/scena/viewport/ScreenViewport.tsx +++ b/src/components/scena/viewport/ScreenViewport.tsx @@ -76,7 +76,7 @@ function ScreenSize(props: ScreenSizeProps) { return ( ); } diff --git a/src/properties/AlignPanel.tsx b/src/properties/AlignPanel.tsx index 24accaa..c3890cf 100644 --- a/src/properties/AlignPanel.tsx +++ b/src/properties/AlignPanel.tsx @@ -6,12 +6,12 @@ import styled from 'styled-components'; import IconButton from './IconButton'; const aligns = [ - { icon: 'AlignLeft', title: '左对齐' }, - { icon: 'AlignHorizontalCenters', title: '水平居中对齐' }, - { icon: 'AlignRight', title: '右对齐' }, - { icon: 'AlignTop', title: '顶部对齐' }, - { icon: 'AlignVerticalCenters', title: '垂直居中对齐' }, - { icon: 'AlignBottom', title: '底部对齐' }, + { icon: 'AsanyEditor/AlignLeft', title: '左对齐' }, + { icon: 'AsanyEditor/AlignHorizontalCenters', title: '水平居中对齐' }, + { icon: 'AsanyEditor/AlignRight', title: '右对齐' }, + { icon: 'AsanyEditor/AlignTop', title: '顶部对齐' }, + { icon: 'AsanyEditor/AlignVerticalCenters', title: '垂直居中对齐' }, + { icon: 'AsanyEditor/AlignBottom', title: '底部对齐' }, ]; const MoreOptions = styled.div``; @@ -24,12 +24,11 @@ const AlignPanel = () => { ))} - + {/* TidyUp // DistributeVerticalSpacing // DistributeHorizontalSpacing
-
*/} diff --git a/src/properties/CurrentElementInformation.tsx b/src/properties/CurrentElementInformation.tsx index 9c41be1..aad8057 100644 --- a/src/properties/CurrentElementInformation.tsx +++ b/src/properties/CurrentElementInformation.tsx @@ -110,17 +110,18 @@ const CurrentElementInformation = () => { className="header-font design-rows-items frame-preset-dropdown" popoverClassName="asanyeditor-frame-preset-popover" renderTitle={() => '画框'} + dropdownMatchSelectWidth={224} value={{ label: screen.name, value: screen.size.join('x') } as any} options={[...deviceTypes]} onChange={handleFrameSizeChange} /> - +
@@ -152,7 +153,7 @@ const CurrentElementInformation = () => { />
@@ -160,16 +161,16 @@ const CurrentElementInformation = () => { format={rotateFormat} onChange={handleChange(IconsConst.Rotate)} value={state.current[IconsConst.Rotate]} - icon="VectorRotate" + icon="AsanyEditor/VectorRotate" /> - +
{radiusDisabled && ( diff --git a/src/properties/DsignAutoLayout.tsx b/src/properties/DsignAutoLayout.tsx index f098cb9..f5b3782 100644 --- a/src/properties/DsignAutoLayout.tsx +++ b/src/properties/DsignAutoLayout.tsx @@ -23,22 +23,32 @@ const DsignAutoLayout = () => { options={[ { value: 'VerticalDirection', - icon: 'VectorArrowButtom', + icon: 'AsanyEditor/VectorArrowButtom', label: '垂直方向', }, { value: 'HorizontalDirection', - icon: 'VectorArrowRight', + icon: 'AsanyEditor/VectorArrowRight', label: '水平方向', }, ]} /> - - + +
diff --git a/src/properties/DsignColor.tsx b/src/properties/DsignColor.tsx index 72c6574..601e13a 100644 --- a/src/properties/DsignColor.tsx +++ b/src/properties/DsignColor.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import ScrubbableControl from './data-entry/ScrubbableControl'; +import IconButton from './IconButton'; import DsignIcons from './OptionButton'; import { inputFormat } from './utils'; interface DsignColorProp {} @@ -33,18 +34,19 @@ const DsignColor = (_: DsignColorProp) => { - ); }; + export default DsignColor; diff --git a/src/properties/DynaActionForm.tsx b/src/properties/DynaActionForm.tsx index da20ce9..0b07f7f 100644 --- a/src/properties/DynaActionForm.tsx +++ b/src/properties/DynaActionForm.tsx @@ -23,7 +23,7 @@ interface FormItemWrapperProps { component: React.ComponentType; field: IField; defaultValue?: any; - size: string; + size?: string; } export function FormItemWrapper({ component: Item, field, defaultValue, ...props }: FormItemWrapperProps) { @@ -86,7 +86,7 @@ const PanelBody = (props: PanelBodyProps) => { layout={item.layout || layout} className={classnames(`form-item-${group}-${item.name}`, getComponentClassName(item))} > - + ); @@ -99,6 +99,10 @@ function getComponentClassName(item: IField) { if (typeof item.renderer.name === 'string') { return `form-component-${item.renderer.name.toLowerCase()}`; } + const name = item.renderer.component.name || item.renderer.component?.type?.name; + if (name) { + return `form-component-${name.toLowerCase()}`; + } return null; } diff --git a/src/properties/FormField.tsx b/src/properties/FormField.tsx index 4b46855..60fae65 100644 --- a/src/properties/FormField.tsx +++ b/src/properties/FormField.tsx @@ -24,8 +24,8 @@ function FormField({ field, className, children, layout = 'Inline', ...props }: )}
{React.cloneElement(React.Children.only(children), props)} diff --git a/src/properties/IconButton.tsx b/src/properties/IconButton.tsx index 84deca4..b29d651 100644 --- a/src/properties/IconButton.tsx +++ b/src/properties/IconButton.tsx @@ -1,4 +1,4 @@ -import React, { MutableRefObject, forwardRef, useRef } from 'react'; +import React, { CSSProperties, MutableRefObject, forwardRef, useRef } from 'react'; import Icon from '@asany/icons'; import { Tooltip } from 'antd'; @@ -9,11 +9,12 @@ interface IconButtonProps { className?: string; icon: string; checked?: boolean; + style?: CSSProperties; onClick?: () => void; } const IconButton = (props: IconButtonProps, externalRef: React.ForwardedRef) => { - const { tooltip, onClick, icon, className, checked } = props; + const { tooltip, onClick, style, icon, className, checked } = props; const ref = useRef(null); const handleClick = () => { onClick && onClick(); @@ -29,6 +30,7 @@ const IconButton = (props: IconButtonProps, externalRef: React.ForwardedRef {parentNode && ( -
+
{parentNode[labelName]}
@@ -109,7 +109,7 @@ function ListTree(props: ListTreeProps) { {dirs.map((item) => (
  • )}
    -
      +
        {list .filter((item) => !(item.children || []).length) .map((item) => ( diff --git a/src/properties/RadiusAllSetting.tsx b/src/properties/RadiusAllSetting.tsx index 5f1aa10..8ad04ec 100644 --- a/src/properties/RadiusAllSetting.tsx +++ b/src/properties/RadiusAllSetting.tsx @@ -7,7 +7,12 @@ import isEqual from 'lodash/isEqual'; import { onlyNumber } from './utils'; import { RadiusAllSettingProps } from './typings'; -const icons = ['TopLeftCornerRadius', 'TopRightCornerRadius', 'BottomRightCornerRadius', 'BottomLeftCornerRadius']; +const icons = [ + 'AsanyEditor/TopLeftCornerRadius', + 'AsanyEditor/TopRightCornerRadius', + 'AsanyEditor/BottomRightCornerRadius', + 'AsanyEditor/BottomLeftCornerRadius', +]; const RadiusAllSetting = (props: RadiusAllSettingProps) => { const { onChange, value: [tl = 0, tr = 0, br = 0, bl = 0] = [0, 0, 0, 0] } = props; diff --git a/src/properties/combine/MultipleWrapper.tsx b/src/properties/combine/MultipleWrapper.tsx index b88fba8..08671c1 100644 --- a/src/properties/combine/MultipleWrapper.tsx +++ b/src/properties/combine/MultipleWrapper.tsx @@ -34,6 +34,7 @@ export interface IMultipleWrapperData { export interface MultipleWrapperProps { /** 配置标题 */ name?: string; + placeholder?: string; /** 孩子组件 */ children: React.ReactElement; /** 可以添加项目,显示按钮且可以使用 */ @@ -60,18 +61,20 @@ type ItemRender = (props: any) => React.ReactElement; type BuildItemRenderOptions = { buildChange: (data: IMultipleWrapperData) => (newData: any) => void; className?: string; + placeholder?: string; isObject: boolean; showPopoverImmediatelyAtCreated: boolean; children: any; }; const buildItemRender = (XItemRender: ItemRender | undefined, options: BuildItemRenderOptions) => { - const { children, className, isObject, buildChange, showPopoverImmediatelyAtCreated } = options; + const { children, placeholder, className, isObject, buildChange, showPopoverImmediatelyAtCreated } = options; const InnerItemRender = React.forwardRef((props: any, ref: any) => { if (!children && !XItemRender) { return ( (props: MultipleWrapperProps) { canSortItem = true, immediatelyShowPopoverWhenCreated: immediatelyShow = true, itemName, + placeholder, pipeline, itemClassName, itemRender: defaultItemRender, @@ -208,6 +212,7 @@ export function MultipleWrapper(props: MultipleWrapperProps) { buildChange: handleItemChange, className: itemClassName, isObject, + placeholder, showPopoverImmediatelyAtCreated: immediatelyShow, children, }), @@ -231,7 +236,6 @@ export function MultipleWrapper(props: MultipleWrapperProps) { 没有数据
    } tag="ul" items={value} itemRender={itemRender} diff --git a/src/properties/combine/ObjectCombiner.tsx b/src/properties/combine/ObjectCombiner.tsx index a864fa5..2858e8d 100644 --- a/src/properties/combine/ObjectCombiner.tsx +++ b/src/properties/combine/ObjectCombiner.tsx @@ -3,12 +3,14 @@ import React, { useEffect } from 'react'; import { Form } from 'antd'; import isEqual from 'lodash/isEqual'; import { ComponentPropertyRendererSetting, IField, useSunmao } from 'sunmao'; +import { FormLayout } from 'antd/lib/form/Form'; import { getRenderer } from '../renderers'; import { FormItemWrapper, visibleFilter } from '../DynaActionForm'; interface ObjectCombinerProps { value?: any; + layout?: FormLayout; onChange?: (value: any) => void; className?: string; fields: IField[]; @@ -34,7 +36,13 @@ function ObjectCombiner(props: ObjectCombinerProps) { } }, [form, value]); return ( -
    + {fields.filter(visibleFilter(props.value)).map((item) => { const { component, props = {} } = item.renderer as ComponentPropertyRendererSetting; const ComponentForm = component as React.ComponentType; @@ -43,12 +51,12 @@ function ObjectCombiner(props: ObjectCombinerProps) { return ( - + ); })} diff --git a/src/properties/combine/WrapperItem.tsx b/src/properties/combine/WrapperItem.tsx index 5d7b21c..434ac0c 100644 --- a/src/properties/combine/WrapperItem.tsx +++ b/src/properties/combine/WrapperItem.tsx @@ -32,6 +32,7 @@ export const SortableHandler = () => { export interface WrapperItemProps { /** 名称只读 */ nameReadonly: boolean; + placeholder?: string; /** 名称链接 对应 数据的某个key */ nameLink?: string; displayField?: string; @@ -63,6 +64,7 @@ function WrapperItem(props: WrapperItemProps) { canDelete, editable = true, nameLink = 'title', + placeholder = '请输入内容', } = props; const handleChange = (key: string) => (event: React.ChangeEvent) => { @@ -89,6 +91,7 @@ function WrapperItem(props: WrapperItemProps) { {data.icon && } { placeholder = '请选择', popover: SelectPopover = SelectModal, popoverClassName, + dropdownMatchSelectWidth, className, } = props; const ref = useRef(null); const [visible, setVisible] = useState(false); const [value, setValue] = useState(initialValue); + const [width, setWidth] = useState(); useEffect(() => { if (initialValue === value) { @@ -149,6 +151,15 @@ const Select = (props: SelectProps) => { setVisible(false); }, []); + useEffect(() => { + if (dropdownMatchSelectWidth === true) { + const _width = ref.current?.getBoundingClientRect().width; + _width && setWidth(_width); + } else if (typeof dropdownMatchSelectWidth == 'number') { + setWidth(dropdownMatchSelectWidth); + } + }, [dropdownMatchSelectWidth]); + const popoverContent = ( { targetOffset: [0, 0], offset: [0, -32], }} + overlayInnerStyle={{ width }} arrowPointAtCenter={false} overlayClassName={classnames('asanyeditor-dsign-popover', popoverClassName)} content={popoverContent} diff --git a/src/properties/data-entry/TextArea.tsx b/src/properties/data-entry/TextArea.tsx index 8399e5e..419bfaa 100644 --- a/src/properties/data-entry/TextArea.tsx +++ b/src/properties/data-entry/TextArea.tsx @@ -13,7 +13,7 @@ interface TextAreaProps { } function TextArea(props: TextAreaProps) { - const { value, placeholder, onChange, className, autoSize } = props; + const { value, placeholder = '请输入字符串', onChange, className, autoSize } = props; return ( SelectOption; placeholder?: string; resultType?: 'object' | 'string'; + dropdownMatchSelectWidth?: boolean | number; options?: (SelectOption | SelectOptionGroup)[]; compare?: Compare; onChange?: (value: string) => void; diff --git a/src/style/design.less b/src/style/design.less index db7bc50..74c1906 100644 --- a/src/style/design.less +++ b/src/style/design.less @@ -16,7 +16,7 @@ padding: 0 0 0 7px; color: var(--primary-color); font-size: 12px; - line-height: 16px; + // line-height: 16px; background-color: transparent; background-clip: padding-box; border: 1px solid transparent; @@ -36,17 +36,35 @@ width: 100%; min-height: 160px; + .dsign-popover-select { + height: 28px; + line-height: 28px; + min-height: 28px; + } + + .design-rows { + .design-rows-items { + height: 28px; + line-height: 28px; + min-height: 28px; + } + + .scrubbable-control { + grid-column-end: span 11; + } + } + .current-box-header { - grid-column-start: 29; + grid-column-start: 25; grid-column-end: span 4; .segmented-control-container { - grid-column-start: 21; + grid-column-start: 18; grid-column-end: span 7; } .resize-to-fit { - grid-column: 29 / span 4; + grid-column: 25 / span 4; } } @@ -54,7 +72,7 @@ display: flex; align-items: center; height: 32px; - padding-left: 4px; + padding-left: 10px; .ant-checkbox-wrapper { font-weight: 400; @@ -116,13 +134,13 @@ .raidus-change-box { height: 32px; - padding-left: 0 !important; + padding-left: 8px; .change-input { display: grid; grid-auto-columns: 7px; grid-auto-flow: column; - grid-column-end: span 18; + grid-column-end: span 17; grid-template-rows: 30px; align-content: center; align-items: center; @@ -181,15 +199,18 @@ padding-right: 1px; &:nth-child(2) { - grid-column-start: 15; + grid-column-start: 13; } &.design-input .ant-input, &.design-input .ant-input-number { - height: auto; + padding-left: 0; border: none; .ant-input-number-handler-wrap { + height: 26px; + margin-top: 1px; + .ant-input-number-handler .svg-icon { display: flex; align-items: center; @@ -198,7 +219,7 @@ } .ant-input-number-input { - height: auto; + padding: 0; } &.ant-input-number-focused { @@ -257,7 +278,7 @@ .design-color { .color-input { display: flex; - grid-column-end: span 20; + grid-column-end: span 18; align-items: center; box-sizing: border-box; height: 28px; @@ -270,8 +291,8 @@ .color-percentage::before { position: absolute; - top: 0; - bottom: 0; + top: 2px; + bottom: 2px; left: -1px; width: 1px; background-color: rgba(0, 0, 0, 0.1); @@ -332,10 +353,12 @@ .color-value { flex: 1 0 56px; + padding-left: 8px; } .color-percentage { position: relative; + padding-left: 8px; flex: 0 0 48px; } } @@ -347,7 +370,7 @@ grid-template-rows: 32px; .option-button { - grid-column-start: 29; + grid-column-start: 24; grid-column-end: span 4; } } @@ -355,6 +378,7 @@ .design-rows-items { box-sizing: border-box; min-height: 30px; + height: 32px; .ant-input { @@ -369,7 +393,7 @@ .design-colums { position: relative; display: grid; - grid-template-columns: repeat(33, 8px); + grid-template-columns: repeat(240 / 8 - 2, 8px); align-items: center; } @@ -513,6 +537,8 @@ align-items: center; padding: 0 4px 0 7px; border: 1px solid transparent; + height: 32px; + line-height: 32px; &.exist-icon { padding: 0 7px 0 0; @@ -616,11 +642,13 @@ border-bottom: 1px solid hsla(0, 0%, 100%, 0.2); &:not(:first-child) { - padding-top: 8px; + padding-top: 4px; } .group-name { font-size: 12px; + height: 24px; + line-height: 24px; padding-left: 8px; color: var(--primary-third-color); } @@ -679,7 +707,7 @@ .frame-preset-dropdown { position: relative; flex-grow: 1; - grid-column-end: span 18; + grid-column-end: span 17; font-size: 12px; border: 1px solid transparent; } @@ -687,10 +715,6 @@ .align-panel { display: flex; - &>.icon-button { - margin-right: 6px; - } - .more-options { position: relative; @@ -700,13 +724,15 @@ } } - &>.svg-icon { + .more-arrow { + font-size: 8px; position: absolute; top: 50%; right: 4px; transform: translateY(-50%) !important; pointer-events: none; } + } } @@ -790,20 +816,22 @@ } .asanyeditor-auto-layout { + padding-left: 8px; + .segmented-control-container { grid-column: 1 / span 6; } .spacing-between-items { - grid-column: 9 / span 9; + grid-column: 8 / span 8; } .padding-around-items { - grid-column: 19 / span 9; + grid-column: 16 / span 8; } .alignment-and-padding { - grid-column-start: 29; + grid-column-start: 24; grid-column-end: span 4; &.active, diff --git a/src/style/form.component.less b/src/style/form.component.less index 65286d5..17e0e82 100644 --- a/src/style/form.component.less +++ b/src/style/form.component.less @@ -10,6 +10,7 @@ border-bottom: 1px solid var(--shallow-color); .ant-checkbox-wrapper, + .ant-radio-wrapper, .ant-btn { font-size: 12px; } @@ -56,24 +57,88 @@ &-layout-stacked, &-layout-inline { .basic-input { - padding-left: 4px; + padding-left: 7px; + height: 32px; + line-height: 32px; } + &.form-component-input:not(.inline-show-label) { .smart-form-field-value { - padding-left: 10px; + padding-left: 8px; } } + &.form-component-select:not(.inline-show-label) { .smart-form-field-value { padding-left: 8px; } } + + &.form-component-checkboxgroup:not(.inline-show-label), + &.form-component-checkbox:not(.inline-show-label) { + .smart-form-field-value { + .ant-checkbox-wrapper { + height: 32px; + line-height: 32px; + + &:first-child { + padding-left: 8px; + } + } + + } + } + + &.form-component-switch:not(.inline-show-label) { + .smart-form-field-value { + padding-left: 16px; + } + } + + &.form-component-radiogroup:not(.inline-show-label) { + .smart-form-field-value { + .ant-radio-group { + padding-left: 8px; + + .ant-radio-wrapper { + height: 32px; + line-height: 32px; + } + } + } + } + + &.form-component-textarea:not(.inline-show-label) { + .smart-form-field-value { + height: auto; + + .is_textarea { + height: auto; + textarea { + min-height: 30px; + line-height: 22px; + } + line-height: 30px; + } + } + } + + &.form-component-multiplewrapper:not(.inline-show-label) { + .smart-form-field-value { + padding-left: 0; + min-height: 0; + } + } + + &.inline-show-label { .smart-form-field-label { padding-left: 16px; } + .smart-form-field-value { padding-left: 0; + // TODO: 后续需要删除的样式 .ant-btn { height: 24px; @@ -98,6 +163,11 @@ flex-direction: column; align-items: start; padding-top: 8px; + padding-bottom: 8px; + + &:not(:last-child) { + border-bottom: 1px solid var(--shallow-color); + } &:first-child { padding-top: 0; @@ -119,8 +189,8 @@ } .smart-form-field-value { - padding: 0 8px 8px 16px; - border-bottom: 1px solid var(--shallow-color); + padding: 0 8px 0 8px; + .design-input { margin: 0; } @@ -135,25 +205,30 @@ } } } + .ant-input.ant-input-rimless { border: none; border-bottom: 1px solid transparent; outline: none; + &:hover { border: none; border-bottom: 1px solid transparent; } + &:focus { border: none; border-bottom: 1px solid #d9d9d9; outline: none; box-shadow: none; } + background-color: transparent; } .list-tree-container { font-size: 12px; + &:hover { .tree-current-node { background-color: transparent; @@ -173,6 +248,7 @@ font-weight: 500; } } + .ae-tree { li { min-height: 32px; @@ -186,22 +262,27 @@ width: 16px; font-size: 10px; } + &:hover:not(.active) { background-color: var(--gray-darkest); } } } + .tree-node-content { padding: 8px; } + .list-tree-scrollbar { max-height: 360px; } + .svg-icon { + &.drillup, &.folder { width: 24px; font-size: 16px; } } -} +} \ No newline at end of file diff --git a/src/style/sketch.less b/src/style/sketch.less index c697a0f..37f3627 100644 --- a/src/style/sketch.less +++ b/src/style/sketch.less @@ -21,15 +21,19 @@ --selected-background-color: rgba(0, 0, 0, 0.1); --editor-navigation-height: 50px; } + .text-grey-darker { color: #606f7b; } + .text-grey-dark { color: #8795a1; } + .border-grey-dark { border-color: #8795a1; } + .asany-editor-loading { position: absolute; top: var(--editor-navigation-height); @@ -51,23 +55,28 @@ display: flex; opacity: 0; } + &-enter-active, &-appear-active { opacity: 1; transition: opacity 0.5s ease-in; } + &-enter-done { display: flex; opacity: 1; } + &-exit { display: flex; opacity: 1; } + &-exit-active { opacity: 0; transition: opacity 0.7s ease-in; } + &-exit-done { opacity: 0; } @@ -98,7 +107,7 @@ background: rgb(242, 242, 242); } - & > div { + &>div { padding-bottom: 0; } @@ -109,7 +118,8 @@ align-items: center; height: 100%; padding-right: 10px; - & > .back-icon { + + &>.back-icon { display: flex; align-items: center; justify-content: center; @@ -122,7 +132,7 @@ transition: all 0.1s linear 0s; } - & > .title { + &>.title { display: inline; max-width: initial !important; overflow: hidden; @@ -143,6 +153,7 @@ min-width: 44px; height: 100%; color: rgb(91, 107, 115); + &.disabled { position: relative; color: rgb(200, 205, 208) !important; @@ -150,6 +161,7 @@ .toolbar-icon-tip { color: rgb(200, 205, 208) !important; + &::after { position: absolute; top: 0; @@ -162,6 +174,7 @@ } } } + // &.save-icon { // margin-right: 6px; // } @@ -172,6 +185,7 @@ width: 18px; height: 16px; } + .toolbar-icon-tip { // margin-top: 8px; color: rgb(65, 80, 88); @@ -186,7 +200,8 @@ flex: 1 1 0%; height: 100%; padding: 0 27px; - & > .toolbar-icon { + + &>.toolbar-icon { margin-right: 8px; } } @@ -198,6 +213,7 @@ padding-left: 39px; } } + //body侧边栏 .sketch-sidebar { display: flex; @@ -207,6 +223,7 @@ &.sidebar-out { width: 0; transform: translate3d(-52px, 0, 0); + .sidebar-resizer { display: none; } @@ -228,6 +245,7 @@ width: 52px; background-color: var(--general-background); border-right: 1px solid var(--gray-darkest); + ul { margin: 0; } @@ -240,6 +258,7 @@ &.tool-panel-list { flex: 1; + li.selected:last-child { border-bottom: 1px solid var(--gray-darkest); } @@ -262,7 +281,7 @@ border-bottom: 0 !important; } - > .svg-icon { + >.svg-icon { font-size: 16px; } @@ -284,6 +303,7 @@ fill: var(--main-color-brand); } } + &:last-child { border-bottom: 0; } @@ -323,6 +343,7 @@ .panel-header-title { flex: 1; } + .panel-header-info { display: flex; font-size: 14px; @@ -344,14 +365,18 @@ .panel-view { overflow-y: auto; + .ant-tree.ant-tree-directory { color: #878787; font-size: 13px; + .ant-tree-treenode { padding-bottom: 1px; + &::before { bottom: 1px; } + .ant-tree-switcher { display: inline-flex; align-items: center; @@ -359,26 +384,31 @@ height: 36px; line-height: 36px; } + &.ant-tree-treenode-selected { .ant-tree-switcher { color: #2e2e2e; } + &::before { background-color: #f0f0f0; } + .ant-tree-node-content-wrapper { color: #2e2e2e; } } + .ant-tree-node-content-wrapper { - > span { + >span { display: inline-block; height: 32px; line-height: 32px; } } + &.drag-over-gap-top { - & > [draggable] { + &>[draggable] { border-top-width: 3px; border-right-color: #b1d7fa !important; border-bottom-color: #b1d7fa !important; @@ -386,8 +416,9 @@ border-left-color: #b1d7fa !important; } } + &.drag-over-gap-bottom { - & > [draggable] { + &>[draggable] { border-top-color: #b1d7fa !important; border-top-width: 1px; border-right-color: #b1d7fa !important; @@ -395,6 +426,7 @@ border-left-color: #b1d7fa !important; } } + .ant-tree-node-content-wrapper[draggable='true'] { display: inline-flex; align-items: center; @@ -402,6 +434,7 @@ padding-left: 0; border-right: 1px transparent solid; border-left: 1px transparent solid; + .ant-tree-icon__customize { display: inline-flex; align-items: center; @@ -424,6 +457,7 @@ .sketch-body { display: flex; height: calc(100vh - var(--editor-navigation-height)); + .sketch-scena { position: relative; display: flex; @@ -435,6 +469,7 @@ .box { display: none; } + .ruler { display: none; } @@ -457,6 +492,7 @@ border-bottom: 1px solid #dedee4; cursor: pointer; } + .ruler { position: absolute; top: 0; @@ -467,11 +503,13 @@ width: 100%; height: 30px; } + &.vertical { width: 30px; height: 100%; } } + .scena-viewer { position: absolute !important; top: var(--editor-navigation-height); @@ -491,6 +529,7 @@ &.properties-panel-container .settings-menu-header { height: 40px; margin-bottom: 5px; + &::before { position: absolute; right: 0; @@ -499,6 +538,7 @@ border-bottom: 1px solid #f0f0f0; content: ''; } + .settings-menu-header-action { display: flex; align-items: center; @@ -508,6 +548,7 @@ margin-left: -10px; font-size: 12px; } + h4 { margin-left: -55px; font-weight: 500 !important; @@ -533,6 +574,7 @@ color: var(--text-color-contrast); font-weight: 700; } + .ant-collapse-content .ant-collapse-content-box { padding: 2px 10px 10px 10px; } @@ -554,6 +596,7 @@ margin: 0; color: var(--gray-light); font-size: 11px; + &::after { content: ''; } @@ -562,9 +605,11 @@ .ant-form-item-control { display: flex; + .ant-form-item-control-input-content { display: flex; } + .ant-picker { flex: 1; } @@ -573,11 +618,12 @@ .multiple-wrapper { flex: 1; + &-header { position: relative; display: flex; width: 100%; - border-bottom: 1px solid rgba(0, 0, 0, 0.3); + a { position: absolute; width: 32px; @@ -587,16 +633,19 @@ display: flex; justify-content: center; align-items: center; + span.svg-icon { font-size: 12px; color: var(--gray-light); } } } + &-list { + margin-bottom: 0; padding-top: 3px; - margin-left: -5px; border: 0; + .sortable-handler { display: flex; align-items: center; @@ -604,13 +653,31 @@ color: rgba(0, 0, 0, 0.3); cursor: move; opacity: 0.6; + + .sortable-handler-icon { + opacity: 0; + } + + &:hover { + .sortable-handler-icon { + opacity: 1; + } + } + } + &-item-body { display: flex; flex: 1; - & > :first-child { + + .ant-input-rimless { + padding-left: 0 !important; + } + + &> :first-child { flex: 1; } + a { text-align: center; width: 28px; @@ -621,6 +688,7 @@ &.delete { width: 32px; + span.svg-icon { font-size: 14px; } @@ -631,19 +699,23 @@ color: var(--gray-light); } } + .ant-input-rimless { padding-left: 5px; font-size: 12px; border-bottom: none; } } - > .sortable-flipper > li { + + >.sortable-flipper li { background-color: #fff; display: flex; } - > li { + + >li { display: flex; height: 28px; + a { text-align: center; height: 32px; @@ -651,6 +723,7 @@ display: flex; justify-content: center; align-items: center; + span.svg-icon { font-size: 12px; color: var(--gray-light); @@ -678,7 +751,7 @@ padding: 10px; border-top: 1px solid var(--gray-darkest); - > div { + >div { user-select: none; } } @@ -691,6 +764,7 @@ .zoom-out { z-index: 2; } + .zoom-in { z-index: 2; left: -2px; @@ -703,6 +777,7 @@ background: var(--general-background); border-top: 1px solid var(--gray-darkest); border-bottom: 1px solid var(--gray-darkest); + input { flex-basis: 20px; max-width: 39px; @@ -716,9 +791,11 @@ border-left: 0; border-radius: 0; outline: none; + &:focus { box-shadow: none; } + &::placeholder { color: #2f2f2f !important; } @@ -749,6 +826,7 @@ border: 1px solid var(--gray-darkest); border-radius: 2px; cursor: pointer; + &::before { position: absolute; top: 0; @@ -768,6 +846,7 @@ fill: var(--toolbar-icon); } } + .guides { .icon-container { display: flex; @@ -783,6 +862,7 @@ &::after { border: 1px solid #d9d9d9; } + .ant-checkbox-inner { background-color: #fff; border-color: #d9d9d9; @@ -801,16 +881,19 @@ .site-collapse-compactness-collapse.ant-collapse { .ant-collapse-item { border-bottom: 0; + &.ant-collapse-compactness-header-right { .ant-collapse-header { padding: 3px 10px 0 10px; } + &.hidden-header { .ant-collapse-header { display: none; } } } + .ant-collapse-header { position: relative; height: 32px; @@ -823,13 +906,16 @@ background-color: rgba(170, 170, 170, 0.1); border-top: 1 solid var(--gray-darkest); border-bottom: 0 solid var(--gray-darkest); + span { color: rgba(0, 0, 0, 0.5) !important; } + &:hover { background-color: #fafafa; } } + .ant-collapse-content { background-color: var(--general-background); @@ -846,15 +932,18 @@ height: 12px; border-left: 1px solid var(--gray-darkest); } + &::-webkit-scrollbar-corner { background-color: transparent; } + &::-webkit-scrollbar-thumb { background-color: var(--gray-dark); background-clip: padding-box; border: 4px solid transparent; border-radius: 10px; } + &::-webkit-scrollbar-track { background-color: transparent; background-clip: padding-box; @@ -862,18 +951,22 @@ border-radius: 10px; } } + .guides-popover { .ant-popover-inner { border-radius: 3px; } + .ant-popover-inner-content { padding: 6px 8px; - > div { + + >div { width: 150px; height: 200px; } } } + // ::-webkit-scrollbar { // width: 6px; // height: 6px; @@ -887,4 +980,4 @@ // } // ::-webkit-scrollbar-track { // background-color: transparent; -// } +// } \ No newline at end of file diff --git a/src/sunmao.ts b/src/sunmao.ts index 790f43e..45c4d7e 100644 --- a/src/sunmao.ts +++ b/src/sunmao.ts @@ -5,6 +5,7 @@ import MultipleWrapper from './properties/combine/MultipleWrapper'; import WrapperItem from './properties/combine/WrapperItem'; import WrapperPopover from './properties/combine/WrapperPopover'; import { Input, InputNumber, Select, TextArea } from './properties/data-entry'; +import DsignColor from './properties/DsignColor'; @library({ name: 'AsanyEditor', namespace: 'cn.asany.ui.editor.properties' }) class EditorLibrary { @@ -32,6 +33,9 @@ class EditorLibrary { @component({}) TextArea = TextArea; + @component({}) + DsignColor = DsignColor; + @component({}) MultipleWrapper = MultipleWrapper; diff --git a/stories/Properties.stories.tsx b/stories/Properties.stories.tsx index d845820..5a3f390 100644 --- a/stories/Properties.stories.tsx +++ b/stories/Properties.stories.tsx @@ -2,7 +2,18 @@ import React, { useCallback, useEffect } from 'react'; import { Meta, Story } from '@storybook/react'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; -import AsanyEditor, { useEditor, buildAside, libraries } from '../src'; +import AsanyEditor, { + useEditor, + buildAside, + libraries, + AlignPanel, + CurrentElementInformation, + SegmentedControl, + ScrubbableControl, + OptionButton, + DsignAutoLayout, + ObjectCombiner, +} from '../src'; import Sunmao, { ICustomizer, SunmaoProvider, useSunmao } from 'sunmao'; import DemoPlugin from './editors/demo'; @@ -10,6 +21,8 @@ import DemoPlugin from './editors/demo'; import 'antd/dist/antd.css'; import { useMemo } from '@storybook/addons'; import cloneDeepWith from 'lodash/cloneDeepWith'; +import WrapperPopover from '../src/properties/combine/WrapperPopover'; +import MultipleWrapper from '../src/properties/combine/MultipleWrapper'; const meta: Meta = { title: '编辑器/属性面板', @@ -24,6 +37,33 @@ const plugin = cloneDeepWith(DemoPlugin); const customizer: ICustomizer = { fields: [ + { + name: 'align_panel', + label: 'AlignPanel', + type: 'String', + renderer: { + component: AlignPanel, + props: {}, + }, + }, + // { + // name: 'current_element_information', + // label: 'CurrentElementInformation', + // type: 'String', + // renderer: { + // component: CurrentElementInformation, + // props: {}, + // }, + // }, + { + name: 'dsign_auto_layout', + label: 'DsignAutoLayout', + type: 'String', + renderer: { + component: DsignAutoLayout, + props: {}, + }, + }, { name: 'input', label: 'Input', @@ -104,8 +144,223 @@ const customizer: ICustomizer = { }, }, }, + { + name: 'input_number', + label: 'InputNumber', + type: 'String', + renderer: { + component: 'InputNumber', + props: {}, + }, + }, + { + name: 'checkbox', + label: 'Checkbox', + type: 'String', + renderer: { + component: 'Checkbox', + props: { + children: 'Checkbox', + }, + }, + }, + { + name: 'checkbox_group', + label: 'CheckboxGroup', + type: 'String', + renderer: { + component: 'CheckboxGroup', + props: { + options: [ + { label: 'Apple', value: 'Apple' }, + { label: 'Pear', value: 'Pear' }, + { label: 'Orange', value: 'Orange', disabled: false }, + ], + }, + }, + }, + { + name: 'radio_group', + label: 'RadioGroup', + type: 'String', + renderer: { + component: 'RadioGroup', + props: { + options: [ + { label: 'Apple', value: 'Apple' }, + { label: 'Pear', value: 'Pear' }, + { label: 'Orange', value: 'Orange', disabled: false }, + ], + }, + }, + }, + { + name: 'switch', + label: 'Switch', + type: 'String', + renderer: { + component: 'Switch', + props: { + checkedChildren: '开启', + unCheckedChildren: '关闭', + }, + }, + }, + { + name: 'textarea', + label: 'TextArea', + type: 'String', + renderer: { + component: 'TextArea', + props: { + autoSize: { + maxRows: 3, + }, + }, + }, + }, + { + name: 'dsign_color', + label: 'DsignColor', + type: 'String', + renderer: { + component: 'DsignColor', + props: {}, + }, + }, + { + name: 'segmented_control', + label: 'SegmentedControl', + type: 'String', + renderer: { + component: SegmentedControl, + props: { + options: [ + { + label: '111', + value: '111', + icon: 'AsanyEditor/SketchFrame', + }, + { + label: '222', + value: '222', + icon: 'AsanyEditor/SketchImage', + }, + ], + }, + }, + }, + { + name: 'scrubbable_control', + label: 'ScrubbableControl', + type: 'String', + renderer: { + component: ScrubbableControl, + props: { + icon: 'AsanyEditor/VectorRadiusRB', + }, + }, + }, + { + name: 'option_button', + label: 'OptionButton', + type: 'String', + renderer: { + component: OptionButton, + props: { + icon: 'AsanyEditor/VectorSpacing', + }, + }, + }, + { + name: 'wrapper_popover', + label: 'WrapperPopover', + type: 'String', + multiple: true, + }, + { + name: 'object_combiner', + label: 'ObjectCombiner', + type: 'String', + renderer: { + component: ObjectCombiner, + props: { + fields: [ + { + name: 'input', + label: 'Input', + type: 'String', + }, + { + name: 'select', + type: 'String', + label: 'Select', + renderer: { + component: 'Select', + props: { + options: [ + { + label: '1', + value: '1', + }, + { + label: '2', + value: '2', + }, + { + label: '3', + value: '3', + }, + ], + }, + }, + }, + ], + }, + }, + }, + { + name: 'object_combiner2', + label: 'ObjectCombiner2', + type: 'String', + renderer: { + component: ObjectCombiner, + props: { + fields: [ + { + name: 'input', + type: 'String', + }, + { + name: 'select', + type: 'String', + renderer: { + component: 'Select', + props: { + options: [ + { + label: '1', + value: '1', + }, + { + label: '2', + value: '2', + }, + { + label: '3', + value: '3', + }, + ], + }, + }, + }, + ], + }, + }, + }, ], }; + const custom1 = { ...customizer }; const custom2 = { ...customizer };