[+] some widgets

This commit is contained in:
王昆 2021-12-24 11:14:07 +08:00
parent bd3a342c92
commit ed163c8a1c
72 changed files with 4506 additions and 234 deletions

View File

@ -1,5 +1,7 @@
const CracoAlias = require("craco-alias");
const CracoLessPlugin = require('craco-less');
const { DefinePlugin, EnvironmentPlugin } = require("webpack");
const pxtorem = require("./craco.postcss.pxtorem");
module.exports = {
plugins: [
@ -35,4 +37,27 @@ module.exports = {
},
},
],
webpack: {
plugins: [
new DefinePlugin({
ENABLE_INNER_HTML: true,
ENABLE_ADJACENT_HTML: true,
ENABLE_TEMPLATE_CONTENT: true,
ENABLE_CLONE_NODE: true,
ENABLE_SIZE_APIS: false
}),
new EnvironmentPlugin({
TARO_ENV: 'h5',
}),
]
},
style: {
postcss: {
plugins: [
pxtorem({
h5Width: 450,
})
]
}
},
};

View File

@ -0,0 +1,342 @@
'use strict'
const postcss = require('postcss')
const objectAssign = require('object-assign')
const pxRegex = /"[^"]+"|'[^']+'|url\([^\)]+\)|(\d*\.?\d+)px/g
/*eslint-disable*/
const filterPropList = {
exact: function (list) {
return list.filter(function (m) {
return m.match(/^[^\*\!]+$/)
})
},
contain: function (list) {
return list.filter(function (m) {
return m.match(/^\*.+\*$/)
}).map(function (m) {
return m.substr(1, m.length - 2)
})
},
endWith: function (list) {
return list.filter(function (m) {
return m.match(/^\*[^\*]+$/)
}).map(function (m) {
return m.substr(1)
})
},
startWith: function (list) {
return list.filter(function (m) {
return m.match(/^[^\*\!]+\*$/)
}).map(function (m) {
return m.substr(0, m.length - 1)
})
},
notExact: function (list) {
return list.filter(function (m) {
return m.match(/^\![^\*].*$/)
}).map(function (m) {
return m.substr(1)
})
},
notContain: function (list) {
return list.filter(function (m) {
return m.match(/^\!\*.+\*$/)
}).map(function (m) {
return m.substr(2, m.length - 3)
})
},
notEndWith: function (list) {
return list.filter(function (m) {
return m.match(/^\!\*[^\*]+$/)
}).map(function (m) {
return m.substr(2)
})
},
notStartWith: function (list) {
return list.filter(function (m) {
return m.match(/^\![^\*]+\*$/)
}).map(function (m) {
return m.substr(1, m.length - 2)
})
}
}
const defaults = {
rootValue: 16,
unitPrecision: 5,
selectorBlackList: [],
propList: ['*'],
replace: true,
mediaQuery: false,
minPixelValue: 0
}
const legacyOptions = {
root_value: 'rootValue',
unit_precision: 'unitPrecision',
selector_black_list: 'selectorBlackList',
prop_white_list: 'propList',
media_query: 'mediaQuery',
propWhiteList: 'propList'
}
const deviceRatio = {
640: 2.34 / 2,
750: 1,
828: 1.81 / 2
}
// transform factor for fixed-width container
// (w / 320) * 20 * (pixels / rootValue) === (pixels / newRootValue) * 16 (default html font-size)
// so, newRootValue = (16 * 16 / w) * rootValue
const factor = 16 * 16
const baseFontSize = 40
const DEFAULT_WEAPP_OPTIONS = {
platform: 'h5',
designWidth: 750,
deviceRatio,
h5Width: 450,
}
let targetUnit
module.exports = postcss.plugin('postcss-pxtransform', function (options) {
options = Object.assign(DEFAULT_WEAPP_OPTIONS, options || {})
switch (options.platform) {
case 'weapp': {
options.rootValue = 1 / options.deviceRatio[options.designWidth]
targetUnit = 'rpx'
break
}
case 'h5': {
options.rootValue = (baseFontSize * options.designWidth / 640) * (factor / options.h5Width)
targetUnit = 'rem'
break
}
case 'rn': {
options.rootValue = options.deviceRatio[options.designWidth] * 2
targetUnit = 'px'
break
}
}
convertLegacyOptions(options)
const opts = objectAssign({}, defaults, options)
const onePxTransform = typeof options.onePxTransform === 'undefined' ? true : options.onePxTransform
const pxReplace = createPxReplace(opts.rootValue, opts.unitPrecision,
opts.minPixelValue, onePxTransform)
const satisfyPropList = createPropListMatcher(opts.propList)
return function (css) {
// only transform taroify style
const filePath = css.source.input.file;
if (filePath.match(/^((?!@taroify).)*$/) !== null) {
return
}
for (let i = 0; i < css.nodes.length; i++) {
if (css.nodes[i].type === 'comment') {
if (css.nodes[i].text === 'postcss-pxtransform disable') {
return
} else {
break
}
}
}
// delete code between comment in RN
if (options.platform === 'rn') {
css.walkComments(comment => {
if (comment.text === 'postcss-pxtransform rn eject enable') {
let next = comment.next()
while (next) {
if (next.type === 'comment' && next.text === 'postcss-pxtransform rn eject disable') {
break
}
const temp = next.next()
next.remove()
next = temp
}
}
})
}
/* #ifdef %PLATFORM% */
// 平台特有样式
/* #endif */
css.walkComments(comment => {
const wordList = comment.text.split(' ')
// 指定平台保留
if (wordList.indexOf('#ifdef') > -1) {
// 非指定平台
if (wordList.indexOf(options.platform) === -1) {
let next = comment.next()
while (next) {
if (next.type === 'comment' && next.text.trim() === '#endif') {
break
}
const temp = next.next()
next.remove()
next = temp
}
}
}
})
/* #ifndef %PLATFORM% */
// 平台特有样式
/* #endif */
css.walkComments(comment => {
const wordList = comment.text.split(' ')
// 指定平台剔除
if (wordList.indexOf('#ifndef') > -1) {
// 指定平台
if (wordList.indexOf(options.platform) > -1) {
let next = comment.next()
while (next) {
if (next.type === 'comment' && next.text.trim() === '#endif') {
break
}
const temp = next.next()
next.remove()
next = temp
}
}
}
})
css.walkDecls(function (decl, i) {
// This should be the fastest test and will remove most declarations
if (decl.value.indexOf('px') === -1) return
if (!satisfyPropList(decl.prop)) return
if (blacklistedSelector(opts.selectorBlackList,
decl.parent.selector)) return
const value = decl.value.replace(pxRegex, pxReplace)
// if rem unit already exists, do not add or replace
if (declarationExists(decl.parent, decl.prop, value)) return
if (opts.replace) {
decl.value = value
} else {
decl.parent.insertAfter(i, decl.clone({ value: value }))
}
})
if (opts.mediaQuery) {
css.walkAtRules('media', function (rule) {
if (rule.params.indexOf('px') === -1) return
rule.params = rule.params.replace(pxRegex, pxReplace)
})
}
}
})
function convertLegacyOptions (options) {
if (typeof options !== 'object') return
if (
(
(typeof options.prop_white_list !== 'undefined' &&
options.prop_white_list.length === 0) ||
(typeof options.propWhiteList !== 'undefined' &&
options.propWhiteList.length === 0)
) &&
typeof options.propList === 'undefined'
) {
options.propList = ['*']
delete options.prop_white_list
delete options.propWhiteList
}
Object.keys(legacyOptions).forEach(function (key) {
if (options.hasOwnProperty(key)) {
options[legacyOptions[key]] = options[key]
delete options[key]
}
})
}
function createPxReplace (rootValue, unitPrecision, minPixelValue, onePxTransform) {
return function (m, $1) {
if (!$1) return m
if (!onePxTransform && parseInt($1, 10) === 1) {
return m
}
const pixels = parseFloat($1)
if (pixels < minPixelValue) return m
const fixedVal = toFixed((pixels / rootValue), unitPrecision)
return (fixedVal === 0) ? '0' : fixedVal + targetUnit
}
}
function toFixed (number, precision) {
const multiplier = Math.pow(10, precision + 1)
const wholeNumber = Math.floor(number * multiplier)
return Math.round(wholeNumber / 10) * 10 / multiplier
}
function declarationExists (decls, prop, value) {
return decls.some(function (decl) {
return (decl.prop === prop && decl.value === value)
})
}
function blacklistedSelector (blacklist, selector) {
if (typeof selector !== 'string') return
return blacklist.some(function (regex) {
if (typeof regex === 'string') return selector.indexOf(regex) !== -1
return selector.match(regex)
})
}
function createPropListMatcher (propList) {
const hasWild = propList.indexOf('*') > -1
const matchAll = (hasWild && propList.length === 1)
const lists = {
exact: filterPropList.exact(propList),
contain: filterPropList.contain(propList),
startWith: filterPropList.startWith(propList),
endWith: filterPropList.endWith(propList),
notExact: filterPropList.notExact(propList),
notContain: filterPropList.notContain(propList),
notStartWith: filterPropList.notStartWith(propList),
notEndWith: filterPropList.notEndWith(propList)
}
return function (prop) {
if (matchAll) return true
return (
(
hasWild ||
lists.exact.indexOf(prop) > -1 ||
lists.contain.some(function (m) {
return prop.indexOf(m) > -1
}) ||
lists.startWith.some(function (m) {
return prop.indexOf(m) === 0
}) ||
lists.endWith.some(function (m) {
return prop.indexOf(m) === prop.length - m.length
})
) &&
!(
lists.notExact.indexOf(prop) > -1 ||
lists.notContain.some(function (m) {
return prop.indexOf(m) > -1
}) ||
lists.notStartWith.some(function (m) {
return prop.indexOf(m) === 0
}) ||
lists.notEndWith.some(function (m) {
return prop.indexOf(m) === prop.length - m.length
})
)
)
}
}

View File

@ -31,6 +31,8 @@
"@sentry/react": "^6.2.4",
"@sentry/tracing": "^6.2.4",
"@sentry/webpack-plugin": "^1.12.1",
"@taroify/core": "^0.0.21-alpha.0",
"@tarojs/components": "^3.3.14",
"@types/chance": "^1.0.7",
"@types/lodash": "^4.14.120",
"@types/moment-timezone": "^0.5.10",
@ -103,7 +105,7 @@
"moment-timezone": "^0.5.27",
"nanoid": "^2.0.4",
"node-forge": "^0.10.0",
"node-sass": "^6.0.1",
"node-sass": "4.14.1",
"normalizr": "^3.3.0",
"path-to-regexp": "^6.2.0",
"popper.js": "^1.15.0",

View File

@ -51,6 +51,8 @@ export interface CreateApplicationRequest {
orgId: string;
color?: AppColorCode;
icon?: AppIconName;
unpublishedAppLayout?: AppLayoutConfig;
publishedAppLayout?: AppLayoutConfig;
}
export interface SetDefaultPageRequest {
@ -171,7 +173,13 @@ class ApplicationApi extends Api {
return Api.post(
ApplicationApi.baseURL +
ApplicationApi.createApplicationPath(request.orgId),
{ name: request.name, color: request.color, icon: request.icon },
{
name: request.name,
color: request.color,
icon: request.icon,
unpublishedAppLayout: request.unpublishedAppLayout,
publishedAppLayout: request.publishedAppLayout,
},
);
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1639911707922" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8357" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css">@font-face { font-weight: 400; font-style: normal; font-family: Circular-Loom; src: url("https://cdn.loom.com/assets/fonts/circular/CircularXXWeb-Book-cd7d2bcec649b1243839a15d5eb8f0a3.woff2") format("woff2"); }
@font-face { font-weight: 500; font-style: normal; font-family: Circular-Loom; src: url("https://cdn.loom.com/assets/fonts/circular/CircularXXWeb-Medium-d74eac43c78bd5852478998ce63dceb3.woff2") format("woff2"); }
@font-face { font-weight: 700; font-style: normal; font-family: Circular-Loom; src: url("https://cdn.loom.com/assets/fonts/circular/CircularXXWeb-Bold-83b8ceaf77f49c7cffa44107561909e4.woff2") format("woff2"); }
@font-face { font-weight: 900; font-style: normal; font-family: Circular-Loom; src: url("https://cdn.loom.com/assets/fonts/circular/CircularXXWeb-Black-bf067ecb8aa777ceb6df7d72226febca.woff2") format("woff2"); }
</style></defs><path d="M512 170.666667a192 192 0 0 1 191.786667 182.954666l0.213333 9.045334h-42.666667a149.333333 149.333333 0 1 0-157.525333 149.12L512 512v42.666667a192 192 0 1 1 0-384z" fill="#3E3E3E" p-id="8358"></path><path d="M512 512c105.472 0 192 75.733333 192 170.666667s-86.528 170.666667-192 170.666666c-102.357333 0-186.88-71.338667-191.786667-162.346666L320 682.666667h42.666667c0 69.973333 66.261333 128 149.333333 128s149.333333-58.026667 149.333333-128c0-67.584-61.781333-123.989333-140.8-127.786667L512 554.666667v-42.666667z" fill="#3E3E3E" p-id="8359"></path><path d="M853.333333 512v42.666667H170.666667v-42.666667z" fill="#3E3E3E" p-id="8360"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -13,7 +13,7 @@ const ItemWrapper = styled.div<{ selected: boolean }>`
? props.theme.colors.propertyPane.activeButtonText
: props.theme.colors.propertyPane.multiDropdownBoxHoverBg};
cursor: pointer;
&:first-of-type {
&:not(:last-of-type) {
margin-right: 4px;
}
&&& svg {

View File

@ -186,7 +186,7 @@ function ColorPickerComponent(props: ColorPickerProps) {
)
}
onChange={handleChangeColor}
placeholder="enter color name or hex"
placeholder="输入web颜色名称或者hex"
value={color}
/>
<ColorBoard

View File

@ -264,6 +264,7 @@ export type IconProps = {
keepColors?: boolean;
loaderWithIconWrapper?: boolean;
clickable?: boolean;
isMobile?: boolean;
};
const Icon = forwardRef(

View File

@ -58,7 +58,7 @@ const StyledMenu = styled(Menu)`
margin: 0px 6px;
border-radius: ${(props) => props.theme.borderRadius};
font-size: 14px;
line-height: 14px;
line-height: 18px;
display: flex;
align-items: center;
height: 30px;

View File

@ -0,0 +1,41 @@
import React from "react";
import { Button } from "@taroify/core";
interface ButtonComponentProps {
text?: string;
color?: string;
onClick?: any;
rounded?: boolean;
isDisabled?: boolean;
isLoading?: boolean;
}
const ButtonComponent = ({
text,
color,
onClick,
rounded,
isDisabled,
isLoading,
}: ButtonComponentProps) => {
const style = {
height: "100%",
backgroundColor: color || "var(--primary-color)",
color: "#fff",
};
const shape = rounded ? "round" : "square";
return (
<Button
disabled={isDisabled}
loading={!!isLoading}
block
style={style}
onClick={onClick}
shape={shape}
>
{text || "好的"}
</Button>
);
};
export default ButtonComponent;

View File

@ -0,0 +1,163 @@
import React, { useState } from "react";
import { Text, View, ScrollView } from "@tarojs/components";
import { Grid, Image, Button } from "@taroify/core";
import { PhotoOutlined, ShoppingCartOutlined } from "@taroify/icons";
import _ from "lodash";
import styled from "styled-components";
export interface GridComponentProps {
list: any[];
gridType: "I_N" | "I_N_D" | "I_N_D_B";
urlKey: string;
titleKey: string;
descriptionKey?: string;
asPrice?: boolean;
priceUnit?: string;
buttonText?: string;
height?: string;
cols?: number;
gutter?: string;
bordered?: boolean;
titleColor?: string;
descriptionColor?: string;
buttonColor?: string;
}
const SameHeightImage = styled(Image)<{
height?: string;
}>`
height: ${(props) => props.height || "auto"};
`;
const Title = styled(Text)<{
color?: string;
}>`
color: ${(props) => props.color || "#646566"};
font-size: 16px;
`;
const Container = styled(View)<{
isBetween: boolean;
}>`
display: flex;
align-items: center;
justify-content: ${(props) =>
props.isBetween ? "space-between" : "space-around"};
margin-top: 8px;
`;
const Price = styled(Text)<{
color?: string;
}>`
color: ${(props) => props.color || "#DD4B34"};
font-size: 14px;
`;
const BuyButton = styled(Button)<{
bgColor?: string;
}>`
background-color: ${(props) => props.bgColor || "#03b365"};
color: #fff;
font-size: 14px;
padding: 0 8px;
`;
const ColorGrid = styled(Grid)<{
textColor?: string;
}>`
--grid-item-text-color: ${(props) => props.textColor};
`;
const GridComponent = (props: GridComponentProps) => {
const {
list,
gridType,
urlKey,
titleKey,
descriptionKey,
asPrice,
priceUnit,
buttonText,
height,
cols,
gutter,
bordered,
titleColor,
descriptionColor,
buttonColor,
} = props;
const items = _.isArray(list) ? list : [];
const key = urlKey + titleKey + items.length;
const isSimple = gridType === "I_N";
const onClickButton = (item: any) => (e: any) => {
e.stopPropagation();
};
const onClickGridItem = (item: any) => (e: any) => {
console.log(item);
};
return (
<ScrollView style={{ height: "100%" }} scrollY>
<ColorGrid
key={key}
columns={cols}
gutter={gutter}
bordered={bordered}
textColor={titleColor}
clickable
>
{items.map((item, index) => {
const url = item[urlKey];
const title = item[titleKey] || "";
const image = url ? (
<SameHeightImage
src={url}
height={height}
mode={isSimple ? undefined : "aspectFill"}
/>
) : (
<PhotoOutlined size={height} />
);
if (isSimple) {
return (
<Grid.Item
icon={image}
text={title}
key={index}
onClick={onClickGridItem(item)}
/>
);
}
const description = item[descriptionKey || ""] || "描述";
const price = asPrice ? priceUnit + description : description;
const priceView = <Price color={descriptionColor}>{price}</Price>;
return (
<Grid.Item key={index} onClick={onClickGridItem(item)}>
{image}
<View style={{ marginTop: "8px" }}>
<Title color={titleColor}>{title}</Title>
<Container isBetween={gridType === "I_N_D_B"}>
{priceView}
{gridType === "I_N_D_B" ? (
<BuyButton
bgColor={buttonColor}
size="mini"
shape="round"
onClick={onClickButton(item)}
>
{buttonText || <ShoppingCartOutlined />}
</BuyButton>
) : null}
</Container>
</View>
</Grid.Item>
);
})}
</ColorGrid>
</ScrollView>
);
};
export default GridComponent;

View File

@ -0,0 +1,35 @@
import React from "react";
import { Image } from "@taroify/core";
interface ImageComponentProps {
imageUrl: string;
mode: any;
onClick?: any;
isCircle?: boolean;
radius?: string;
}
const ImageComponent = ({
imageUrl,
mode,
onClick,
isCircle,
radius,
}: ImageComponentProps) => {
const style = {
height: "100%",
width: "100%",
borderRadius: radius,
};
return (
<Image
src={imageUrl}
style={style}
mode={mode}
onClick={onClick}
round={isCircle}
/>
);
};
export default ImageComponent;

View File

@ -0,0 +1,161 @@
import React, { useState } from "react";
import { Text, View, ScrollView } from "@tarojs/components";
import { Cell, Image, Button } from "@taroify/core";
import { PhotoOutlined, ShoppingCartOutlined } from "@taroify/icons";
import _ from "lodash";
import styled from "styled-components";
export interface ListComponentProps {
list: any[];
contentType: "I_N_D_P_B" | "I_N_D" | "I_N_D_P";
urlKey: string;
titleKey: string;
descriptionKey: string;
priceKey?: string;
buttonText?: string;
inset?: boolean;
width: string;
height: string;
titleColor?: string;
descriptionColor?: string;
priceColor?: string;
buttonColor?: string;
}
const FreeImage = styled(Image)<{
width: string;
height: string;
}>`
width: ${(props) => props.width};
height: ${(props) => props.height};
`;
const RowCenter = styled(View)`
display: flex;
height: 100%;
flex-direction: column;
justify-content: center;
`;
const Title = styled(Text)<{
color?: string;
}>`
color: ${(props) => props.color || "#646566"};
font-size: 16px;
`;
const Description = styled(Text)<{
color?: string;
}>`
color: ${(props) => props.color || "#646566"};
font-size: 14px;
`;
const Container = styled(View)`
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 8px;
`;
const Price = styled(Text)<{
color?: string;
}>`
color: ${(props) => props.color || "#DD4B34"};
font-size: 14px;
`;
const BuyButton = styled(Button)<{
bgColor?: string;
}>`
background-color: ${(props) => props.bgColor || "#03b365"};
color: #fff;
font-size: 14px;
padding: 0 8px;
`;
const ListComponent = (props: ListComponentProps) => {
const {
list,
contentType,
urlKey,
titleKey,
descriptionKey,
priceKey,
buttonText,
inset,
width,
height,
titleColor,
descriptionColor,
priceColor,
buttonColor,
} = props;
const items = _.isArray(list) ? list : [];
const noPrice = contentType === "I_N_D";
const hasButton = contentType === "I_N_D_P_B";
const onClickButton = (item: any) => (e: any) => {
e.stopPropagation();
};
const onClickItem = (item: any) => (e: any) => {
console.log(item);
};
return (
<ScrollView style={{ height: "100%" }} scrollY>
<Cell.Group inset={inset}>
{items.map((item, index) => {
const url = item[urlKey];
const title = item[titleKey] || "";
const description = item[descriptionKey] || "描述";
const price = `${item[priceKey || ""] || "168"}`;
const image = url ? (
<FreeImage
src={url}
height={height}
width={width}
mode="aspectFill"
/>
) : (
<PhotoOutlined
size={height > width ? height : width}
style={{ height, width }}
/>
);
const priceView = <Price color={priceColor}>{price}</Price>;
return (
<Cell key={index} onClick={onClickItem(item)} icon={image}>
<RowCenter>
<Title color={titleColor}>{title}</Title>
<View>
<Description color={descriptionColor}>
{description}
</Description>
</View>
{noPrice ? null : (
<Container>
{priceView}
{hasButton ? (
<BuyButton
bgColor={buttonColor}
size="mini"
shape="round"
onClick={onClickButton(item)}
>
{buttonText || <ShoppingCartOutlined />}
</BuyButton>
) : null}
</Container>
)}
</RowCenter>
</Cell>
);
})}
</Cell.Group>
</ScrollView>
);
};
export default ListComponent;

View File

@ -0,0 +1,202 @@
import React, { useState } from "react";
import { View, Text } from "@tarojs/components";
import VirtualList from "@tarojs/components/virtual-list";
import Taro from "@tarojs/taro";
import {
Uploader,
Cell,
Button,
Image,
Toast,
Checkbox,
Field,
NoticeBar,
Flex,
Dialog,
} from "@taroify/core";
import { Arrow } from "@taroify/icons";
interface PickerComponentProps {
title?: string;
onButtonClick?: (e: any) => void;
}
function buildData(offset = 0) {
return Array(100)
.fill(0)
.map((_, i) => i + offset);
}
const Row = React.memo(({ id, index, style, data }: any) => {
return (
<View
id={id}
className={index % 2 ? "ListItemOdd" : "ListItemEven"}
style={style}
>
Row {index} : {data[index]}
</View>
);
});
Row.displayName = "Row";
const PickerComponent = (props: PickerComponentProps) => {
const { title, onButtonClick } = props;
const [loading, setLoading] = useState(false);
const [data, setData] = useState(buildData(0));
const listReachBottom = () => {
// 如果 loading 与视图相关,那它就应该放在 `this.state` 里
// 我们这里使用的是一个同步的 API 调用 loading所以不需要
setLoading(true);
setTimeout(() => {
setData(data.concat(buildData(data.length)));
setLoading(false);
}, 1000);
};
const dataLen = data.length;
const itemSize = 100;
const [open, setOpen] = useState(false);
const [value, setValue] = useState<any>();
const [text, setText] = useState("");
const [idcard, setIdcard] = useState("");
const [number, setNumber] = useState("");
const [digit, setDigit] = useState("");
const [password, setPassword] = useState("");
const [file, setFile] = useState<Uploader.File>();
const onUpload = () => {
Taro.chooseImage({
count: 1,
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
}).then(({ tempFiles }) => {
setFile({
url: tempFiles[0].path,
type: tempFiles[0].type,
name: tempFiles[0].originalFileObj?.name,
});
});
};
const show = () => {
Taro.showToast({
title: "生活愉快!",
icon: "success",
duration: 2000,
});
};
return (
<View>
<View>
<Button color="primary" onClick={onButtonClick}>
{title}
</Button>
<Button variant="text" color="info">
</Button>
<Button variant="outlined" color="warning">
</Button>
</View>
<View>
<Cell.Group title="分组 1">
<Cell
title="打开弹窗"
rightIcon={<Arrow />}
clickable
onClick={() => setOpen(true)}
>
</Cell>
</Cell.Group>
<Cell.Group title="分组 2">
<Cell title="单元格" brief="描述信息" rightIcon={<Arrow />} clickable>
</Cell>
</Cell.Group>
</View>
<View>
<Flex justify="center" align="center">
<Image
round
mode="aspectFill"
style={{ width: "10rem", height: "10rem" }}
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
</Flex>
</View>
<View>
<Checkbox.Group
direction="horizontal"
value={value}
onChange={setValue}
>
<Checkbox name="a"> a</Checkbox>
<Checkbox name="b"> b</Checkbox>
</Checkbox.Group>
</View>
<div>
<Uploader value={file} onUpload={onUpload} onChange={setFile} />
</div>
<View>
<Cell.Group inset>
<Field
value={text}
label="文本"
placeholder="请输入文本"
onChange={(e) => setText(e.detail.value)}
/>
<Field
value={idcard}
label="身份证号"
type="idcard"
placeholder="请输入手机号"
onChange={(e) => setIdcard(e.detail.value)}
/>
<Field
value={number}
label="整数"
type="number"
placeholder="请输入整数"
onChange={(e) => setNumber(e.detail.value)}
/>
<Field
value={digit}
label="数字"
type="digit"
placeholder="请输入数字(支持小数)"
onChange={(e) => setDigit(e.detail.value)}
/>
<Field
value={password}
label="密码"
type="password"
placeholder="请输入密码"
onChange={(e) => setPassword(e.detail.value)}
/>
</Cell.Group>
</View>
<View>
<NoticeBar scrollable>{title}</NoticeBar>
</View>
<View>
<Dialog open={open} onClose={setOpen}>
<Dialog.Header>{title}</Dialog.Header>
<Dialog.Content>
</Dialog.Content>
<Dialog.Actions theme="round">
<Button onClick={() => setOpen(false)}></Button>
<Button onClick={() => setOpen(false)}></Button>
</Dialog.Actions>
</Dialog>
</View>
</View>
);
};
export default PickerComponent;

View File

@ -0,0 +1,65 @@
import React, { ReactNode, useEffect } from "react";
import styled from "styled-components";
import { getCanvasClassName } from "utils/generators";
import { Popup } from "@taroify/core";
import { Cross } from "@taroify/icons";
import { PopupProps } from "@taroify/core/popup/popup";
const PopupContainer = styled(Popup)<
{
height?: number;
} & PopupProps
>`
height: ${(props) => props.height}px;
overflow: visible;
width: 450px;
left: unset;
background: #f6f6f6;
`;
const Content = styled.div`
width: 100%;
height: 100%;
`;
export type ModalComponentProps = {
isOpen: boolean;
onClose: (e: any) => void;
onModalClose?: () => void;
children: ReactNode;
className?: string;
canOutsideClickClose: boolean;
rounded?: boolean;
height?: number;
};
/* eslint-disable react/display-name */
export function ModalComponent(props: ModalComponentProps) {
useEffect(() => {
return () => {
if (props.onModalClose) props.onModalClose();
};
}, []);
return (
<PopupContainer
open={props.isOpen}
onClose={props.onClose}
placement="bottom"
height={props.height}
rounded={props.rounded}
>
<Popup.Backdrop
closeable={props.canOutsideClickClose}
style={{ left: "unset", right: "unset", width: "450px" }}
/>
<Popup.Close>
<Cross size="24px" style={{ zIndex: 2 }} />
</Popup.Close>
<Content className={`${getCanvasClassName()} ${props.className}`}>
{props.children}
</Content>
</PopupContainer>
);
}
export default ModalComponent;

View File

@ -0,0 +1,46 @@
import React, { useState } from "react";
import { Navigator } from "@tarojs/components";
import { Swiper, Image } from "@taroify/core";
import _ from "lodash";
import styled from "styled-components";
interface SwiperComponentProps {
list: any[];
urlKey: string;
}
const Empty = styled.div`
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
color: #fff;
background: var(--primary-color);
height: 100%;
`;
const SwiperComponent = (props: SwiperComponentProps) => {
const { list, urlKey } = props;
const items = _.isArray(list) ? list : [];
const key = urlKey + items.length;
return (
<Swiper style={{ height: "100%" }} autoplay={4000} key={key}>
<Swiper.Indicator />
{items.map((item, index) => {
const url = _.isString(item) ? item : item[urlKey];
const content = url ? (
<Image src={url} mode="aspectFill" />
) : (
<Empty>{index + 1}</Empty>
);
return (
<Swiper.Item key={index}>
<Navigator>{content}</Navigator>
</Swiper.Item>
);
})}
</Swiper>
);
};
export default SwiperComponent;

View File

@ -0,0 +1,89 @@
import * as React from "react";
import { Text, View } from "@tarojs/components";
import styled from "styled-components";
import { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
import { TextAlign } from "widgets/TextWidget";
import {
FontStyleTypes,
TextSize,
TEXT_SIZES,
} from "constants/WidgetConstants";
export const TextContainer = styled(View)`
height: 100%;
width: 100%;
`;
export const StyledText = styled(Text)<{
scroll: boolean;
textAlign: string;
backgroundColor?: string;
textColor?: string;
fontStyle?: string;
fontSize?: TextSize;
}>`
height: 100%;
overflow-y: ${(props) => (props.scroll ? "auto" : "hidden")};
text-overflow: ellipsis;
text-align: ${(props) => props.textAlign.toLowerCase()};
display: flex;
width: 100%;
justify-content: ${(props) =>
props.textAlign === "LEFT"
? "flex-start"
: props.textAlign === "RIGHT"
? "flex-end"
: "center"};
align-items: ${(props) => (props.scroll ? "flex-start" : "center")};
background: ${(props) => props?.backgroundColor};
color: ${(props) => props?.textColor};
font-style: ${(props) =>
props?.fontStyle?.includes(FontStyleTypes.ITALIC) ? "italic" : ""};
text-decoration: ${(props) =>
props?.fontStyle?.includes(FontStyleTypes.LINETHROUGH)
? "line-through"
: ""};
font-weight: ${(props) =>
props?.fontStyle?.includes(FontStyleTypes.BOLD) ? "bold" : "normal"};
font-size: ${(props) => props?.fontSize && TEXT_SIZES[props?.fontSize]};
`;
export interface TextComponentProps extends ComponentProps {
text?: string;
textAlign: TextAlign;
fontSize?: TextSize;
isLoading: boolean;
shouldScroll?: boolean;
backgroundColor?: string;
textColor?: string;
fontStyle?: string;
}
class TextComponent extends React.Component<TextComponentProps> {
render() {
const {
backgroundColor,
fontSize,
fontStyle,
text,
textAlign,
textColor,
} = this.props;
return (
<TextContainer>
<StyledText
backgroundColor={backgroundColor}
fontSize={fontSize}
fontStyle={fontStyle}
scroll={!!this.props.shouldScroll}
textAlign={textAlign}
textColor={textColor}
>
{text}
</StyledText>
</TextContainer>
);
}
}
export default TextComponent;

View File

@ -63,7 +63,7 @@ const EmptyContainer = styled.div`
width: 400px;
height: 400px;
margin-top: -180px;
margin-left: -100px;
margin-left: -70px;
text-align: center;
opacity: 0.5;
@ -74,6 +74,7 @@ const EmptyContainer = styled.div`
& img {
height: 100%;
width: 70%;
}
`;
@ -219,12 +220,17 @@ export function DropTargetComponent(props: DropTargetComponentProps) {
// Only show propertypane if this is a new widget.
// If it is not a new widget, then let the DraggableComponent handle it.
// Give evaluations a second to complete.
const waitingTime =
widget.type === WidgetTypes.MODAL_WIDGET ||
widget.type === WidgetTypes.TARO_POPUP_WIDGET
? 1000
: 100;
setTimeout(() => {
if (showPropertyPane && updateWidgetParams.payload.newWidgetId) {
showPropertyPane(updateWidgetParams.payload.newWidgetId);
// toggleEditWidgetName(updateWidgetParams.payload.newWidgetId, true);
}
}, 100);
}, waitingTime);
// Select the widget if it is a new widget
selectWidget && selectWidget(widget.widgetId);

View File

@ -96,6 +96,11 @@ const getStyles = (
background: Colors.OUTER_SPACE,
color: Colors.WHITE,
};
default:
return {
background: Colors.OUTER_SPACE,
color: Colors.WHITE,
};
}
};

View File

@ -132,7 +132,8 @@ export function WidgetNameComponent(props: WidgetNameComponentProps) {
!!props.errorCount;
let currentActivity =
props.type === WidgetTypes.MODAL_WIDGET
props.type === WidgetTypes.MODAL_WIDGET ||
props.type === WidgetTypes.TARO_POPUP_WIDGET
? Activities.HOVERING
: Activities.NONE;
if (focusedWidget === props.widgetId) currentActivity = Activities.HOVERING;

View File

@ -2596,6 +2596,10 @@ export const theme: Theme = {
},
};
export { css, createGlobalStyle, keyframes, ThemeProvider };
const taroifyTheme = {
primaryColor: Colors.MINT_GREEN,
};
export { css, createGlobalStyle, keyframes, ThemeProvider, taroifyTheme };
export default styled;

View File

@ -139,6 +139,58 @@ export const HelpMap = {
path: "/widget-reference/",
searchKey: "Formily",
},
TARO_PICKER_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Picker",
},
TARO_SWIPER_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Swiper",
},
TARO_GRID_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Grid",
},
TARO_LIST_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro List",
},
TARO_TEXT_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Text",
},
TARO_POPUP_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Popup",
},
TARO_BUTTON_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Button",
},
TARO_IMAGE_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Image",
},
TARO_CELL_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Cell",
},
TARO_HTML_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Html",
},
TARO_SIMPLE_FORM_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Simple Form",
},
TARO_KV_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro KV",
},
TARO_TABS_WIDGET: {
path: "/widget-reference/",
searchKey: "Taro Tabs",
},
};
export const HelpBaseURL = "https://docs.appsmith.com";

View File

@ -33,6 +33,19 @@ export enum WidgetTypes {
DIVIDER_WIDGET = "DIVIDER_WIDGET",
MENU_BUTTON_WIDGET = "MENU_BUTTON_WIDGET",
FORMILY_WIDGET = "FORMILY_WIDGET",
TARO_PICKER_WIDGET = "TARO_PICKER_WIDGET",
TARO_SWIPER_WIDGET = "TARO_SWIPER_WIDGET",
TARO_GRID_WIDGET = "TARO_GRID_WIDGET",
TARO_TEXT_WIDGET = "TARO_TEXT_WIDGET",
TARO_LIST_WIDGET = "TARO_LIST_WIDGET",
TARO_POPUP_WIDGET = "TARO_POPUP_WIDGET",
TARO_IMAGE_WIDGET = "TARO_IMAGE_WIDGET",
TARO_BUTTON_WIDGET = "TARO_BUTTON_WIDGET",
TARO_CELL_WIDGET = "TARO_CELL_WIDGET",
TARO_HTML_WIDGET = "TARO_HTML_WIDGET",
TARO_SIMPLE_FORM_WIDGET = "TARO_SIMPLE_FORM_WIDGET",
TARO_KV_WIDGET = "TARO_KV_WIDGET",
TARO_TABS_WIDGET = "TARO_TABS_WIDGET",
}
export type WidgetType = keyof typeof WidgetTypes;
@ -100,6 +113,7 @@ export const layoutConfigurations: LayoutConfigurations = {
DESKTOP: { minWidth: 1160, maxWidth: 1280 },
TABLET: { minWidth: 650, maxWidth: 800 },
FLUID: { minWidth: -1, maxWidth: -1 },
MOBILE_FLUID: { minWidth: 450, maxWidth: 450 },
};
export const LATEST_PAGE_VERSION = 30;
@ -136,6 +150,7 @@ export enum FontStyleTypes {
ITALIC = "ITALIC",
REGULAR = "REGULAR",
UNDERLINE = "UNDERLINE",
LINETHROUGH = "LINETHROUGH",
}
export enum TextSizes {

View File

@ -82,7 +82,7 @@ export const JAVASCRIPT_KEYWORDS = {
export const DATA_TREE_KEYWORDS = {
actionPaths: "actionPaths",
appsmith: "appsmith",
global: "global",
pageList: "pageList",
[EXECUTION_PARAM_KEY]: EXECUTION_PARAM_KEY,
};

View File

@ -207,7 +207,11 @@ export const GEN_TEMPLATE_FORM_ROUTE = "/form";
export const getGenerateTemplateURL = (
applicationId = ":applicationId",
pageId = ":pageId",
): string => `${BUILDER_PAGE_URL(applicationId, pageId)}${GEN_TEMPLATE_URL}`;
isMobile = false,
): string =>
`${BUILDER_PAGE_URL(applicationId, pageId)}${
isMobile ? "" : GEN_TEMPLATE_URL
}`;
export const getGenerateTemplateFormURL = (
applicationId = ":applicationId",

View File

@ -124,13 +124,13 @@ export class DataTreeFactory {
});
dataTree.pageList = pageList;
dataTree.appsmith = {
dataTree.global = {
...appData,
// combine both persistent and transient state with the transient state
// taking precedence in case the key is the same
store: { ...appData.store.persistent, ...appData.store.transient },
} as DataTreeAppsmith;
(dataTree.appsmith as DataTreeAppsmith).ENTITY_TYPE = ENTITY_TYPE.APPSMITH;
(dataTree.global as DataTreeAppsmith).ENTITY_TYPE = ENTITY_TYPE.APPSMITH;
return dataTree;
}
}

View File

@ -28,6 +28,7 @@ import { ReactComponent as HideColumnIcon } from "assets/icons/control/columns-v
import { ReactComponent as DeleteColumnIcon } from "assets/icons/control/delete-column.svg";
import { ReactComponent as BoldFontIcon } from "assets/icons/control/bold.svg";
import { ReactComponent as ItalicsFontIcon } from "assets/icons/control/italics.svg";
import { ReactComponent as LineThroughFontIcon } from "assets/icons/control/line-through.svg";
import { ReactComponent as LeftAlignIcon } from "assets/icons/control/left-align.svg";
import { ReactComponent as CenterAlignIcon } from "assets/icons/control/center-align.svg";
import { ReactComponent as RightAlignIcon } from "assets/icons/control/right-align.svg";
@ -206,6 +207,11 @@ export const ControlIcons: {
<ItalicsFontIcon />
</IconWrapper>
),
LINETHROUGH_FONT: (props: IconProps) => (
<IconWrapper {...props}>
<LineThroughFontIcon />
</IconWrapper>
),
LEFT_ALIGN: (props: IconProps) => (
<IconWrapper {...props}>
<LeftAlignIcon />

View File

@ -178,6 +178,71 @@ export const WidgetIcons: {
<FormIcon />
</IconWrapper>
),
TARO_PICKER_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<MultiSelectIcon />
</IconWrapper>
),
TARO_SWIPER_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<VideoIcon />
</IconWrapper>
),
TARO_GRID_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<TableIcon />
</IconWrapper>
),
TARO_TEXT_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<TextIcon />
</IconWrapper>
),
TARO_LIST_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<ListIcon />
</IconWrapper>
),
TARO_POPUP_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<ModalIcon />
</IconWrapper>
),
TARO_IMAGE_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<ImageIcon />
</IconWrapper>
),
TARO_BUTTON_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<ButtonIcon />
</IconWrapper>
),
TARO_CELL_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<ListIcon />
</IconWrapper>
),
TARO_HTML_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<RichTextEditorIcon />
</IconWrapper>
),
TARO_SIMPLE_FORM_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<FormIcon />
</IconWrapper>
),
TARO_KV_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<TextIcon />
</IconWrapper>
),
TARO_TABS_WIDGET: (props: IconProps) => (
<IconWrapper {...props}>
<TabsIcon />
</IconWrapper>
),
};
export type WidgetIcon = typeof WidgetIcons[keyof typeof WidgetIcons];

View File

@ -3,7 +3,7 @@ import "./wdyr";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import "./index.less";
import { ThemeProvider } from "constants/DefaultTheme";
import { ThemeProvider, taroifyTheme } from "constants/DefaultTheme";
import { appInitializer } from "utils/AppsmithUtils";
import { Slide } from "react-toastify";
import store from "./store";
@ -17,6 +17,8 @@ import { setThemeMode } from "actions/themeActions";
import { StyledToastContainer } from "components/ads/Toast";
import localStorage from "utils/localStorage";
import "./polyfills/corejs-add-on";
import AppErrorBoundary from "./AppErrorBoundry";
import GlobalStyles from "globalStyles";
// locale
import { ConfigProvider } from "antd";
import zhCNAntd from "antd/lib/locale/zh_CN";
@ -27,9 +29,20 @@ import "moment/locale/zh-cn";
import { setAutoFreeze } from "immer";
const shouldAutoFreeze = process.env.NODE_ENV === "development";
setAutoFreeze(shouldAutoFreeze);
// taro-components polyfills
import { ConfigProvider as TaroifyTheme } from "@taroify/core";
import {
applyPolyfills,
defineCustomElements,
} from "@tarojs/components/loader";
import "@tarojs/components/dist/taro-components/taro-components.css";
import "@taroify/icons/index.scss";
import "@taroify/core/index.scss";
applyPolyfills().then(() => {
defineCustomElements(window);
});
import AppErrorBoundary from "./AppErrorBoundry";
import GlobalStyles from "globalStyles";
// app init
appInitializer();
function App() {
@ -68,7 +81,9 @@ class ThemedApp extends React.Component<{
<AppErrorBoundary>
<IntlProvider locale="zh-CN" messages={zhCN}>
<ConfigProvider locale={zhCNAntd}>
<AppRouter />
<TaroifyTheme theme={taroifyTheme}>
<AppRouter />
</TaroifyTheme>
</ConfigProvider>
</IntlProvider>
</AppErrorBoundary>

View File

@ -1231,6 +1231,172 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
showReset: true,
resetLabel: "重置",
},
[WidgetTypes.TARO_PICKER_WIDGET]: {
widgetName: "m_picker",
rows: 2 * GRID_DENSITY_MIGRATION_V1,
columns: 4 * GRID_DENSITY_MIGRATION_V1,
title: "喵喵",
},
[WidgetTypes.TARO_SWIPER_WIDGET]: {
widgetName: "m_swiper",
rows: 6 * GRID_DENSITY_MIGRATION_V1,
columns: 16 * GRID_DENSITY_MIGRATION_V1,
list: [
{ url: "https://img01.yzcdn.cn/vant/apple-1.jpg" },
{ url: "https://img01.yzcdn.cn/vant/apple-2.jpg" },
{ url: "https://img01.yzcdn.cn/vant/apple-3.jpg" },
{ url: "https://img01.yzcdn.cn/vant/apple-4.jpg" },
],
urlKey: "url",
},
[WidgetTypes.TARO_GRID_WIDGET]: {
widgetName: "m_grid",
rows: 6 * GRID_DENSITY_MIGRATION_V1,
columns: 16 * GRID_DENSITY_MIGRATION_V1,
list: [
{ url: "", name: "文本" },
{ url: "", name: "文本" },
{ url: "", name: "文本" },
{ url: "", name: "文本" },
{ url: "", name: "文本" },
{ url: "", name: "文本" },
],
urlKey: "url",
titleKey: "name",
cols: 4,
gutter: "0",
bordered: true,
gridType: "I_N",
titleColor: "#646566",
descriptionColor: "#DD4B34",
buttonColor: "#03b365",
priceUnit: "¥",
},
[WidgetTypes.TARO_TEXT_WIDGET]: {
widgetName: "m_text",
text: "文本",
fontSize: "PARAGRAPH",
textAlign: "LEFT",
textColor: Colors.THUNDER,
rows: 1 * GRID_DENSITY_MIGRATION_V1,
columns: 4 * GRID_DENSITY_MIGRATION_V1,
version: 1,
},
[WidgetTypes.TARO_LIST_WIDGET]: {
widgetName: "m_list",
rows: 6 * GRID_DENSITY_MIGRATION_V1,
columns: 16 * GRID_DENSITY_MIGRATION_V1,
list: [
{ url: "", name: "标题", description: "描述" },
{ url: "", name: "标题", description: "描述" },
{ url: "", name: "标题", description: "描述" },
{ url: "", name: "标题", description: "描述" },
],
urlKey: "url",
titleKey: "name",
descriptionKey: "description",
contentType: "I_N_D",
width: "100px",
height: "80px",
inset: false,
titleColor: "#646566",
descriptionColor: "#999",
priceColor: "#DD4B34",
buttonColor: "#03b365",
},
[WidgetTypes.TARO_POPUP_WIDGET]: {
widgetName: "m_popup",
rows: 10 * GRID_DENSITY_MIGRATION_V1,
columns: 12 * GRID_DENSITY_MIGRATION_V1,
// detachFromLayout is set true for widgets that are not bound to the widgets within the layout.
// setting it to true will only render the widgets(from sidebar) on the main container without any collision check.
detachFromLayout: true,
canOutsideClickClose: true,
rounded: true,
height: 400,
children: [],
version: 1,
blueprint: {
view: [
{
type: "CANVAS_WIDGET",
position: { left: 0, top: 0 },
props: {
detachFromLayout: true,
canExtend: false,
isVisible: true,
isDisabled: false,
shouldScrollContents: false,
children: [],
version: 1,
blueprint: {
view: [
{
type: "TEXT_WIDGET",
position: { left: 1, top: 1 },
size: {
rows: 1 * GRID_DENSITY_MIGRATION_V1,
cols: 10 * GRID_DENSITY_MIGRATION_V1,
},
props: {
text: "Modal Title",
fontSize: "HEADING1",
version: 1,
},
},
],
},
},
},
],
},
},
[WidgetTypes.TARO_IMAGE_WIDGET]: {
widgetName: "m_image",
rows: 6 * GRID_DENSITY_MIGRATION_V1,
columns: 8 * GRID_DENSITY_MIGRATION_V1,
src: "https://img.yzcdn.cn/vant/cat.jpeg",
version: 1,
},
[WidgetTypes.TARO_BUTTON_WIDGET]: {
widgetName: "m_button",
rows: 1 * GRID_DENSITY_MIGRATION_V1,
columns: 6 * GRID_DENSITY_MIGRATION_V1,
version: 1,
rounded: true,
text: "好的",
},
[WidgetTypes.TARO_CELL_WIDGET]: {
widgetName: "m_cell",
rows: 1 * GRID_DENSITY_MIGRATION_V1,
columns: 4 * GRID_DENSITY_MIGRATION_V1,
version: 1,
},
[WidgetTypes.TARO_HTML_WIDGET]: {
widgetName: "m_html",
rows: 6 * GRID_DENSITY_MIGRATION_V1,
columns: 8 * GRID_DENSITY_MIGRATION_V1,
content: "<span style='color: red'>五彩斑斓的黑</span>",
version: 1,
},
[WidgetTypes.TARO_SIMPLE_FORM_WIDGET]: {
widgetName: "m_form",
rows: 1 * GRID_DENSITY_MIGRATION_V1,
columns: 4 * GRID_DENSITY_MIGRATION_V1,
version: 1,
},
[WidgetTypes.TARO_KV_WIDGET]: {
widgetName: "m_kv",
rows: 1 * GRID_DENSITY_MIGRATION_V1,
columns: 4 * GRID_DENSITY_MIGRATION_V1,
version: 1,
},
[WidgetTypes.TARO_TABS_WIDGET]: {
widgetName: "m_tabs",
rows: 1 * GRID_DENSITY_MIGRATION_V1,
columns: 4 * GRID_DENSITY_MIGRATION_V1,
version: 1,
},
},
configVersion: 1,
};

View File

@ -135,6 +135,84 @@ const WidgetSidebarResponse: WidgetCardProps[] = [
widgetCardName: "复杂表单",
key: generateReactKey(),
},
// {
// type: "TARO_PICKER_WIDGET",
// widgetCardName: "Picker",
// key: generateReactKey(),
// isMobile: true,
// },
{
type: "TARO_SWIPER_WIDGET",
widgetCardName: "轮播",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_GRID_WIDGET",
widgetCardName: "网格内容",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_TEXT_WIDGET",
widgetCardName: "文本",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_LIST_WIDGET",
widgetCardName: "列表",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_POPUP_WIDGET",
widgetCardName: "底部弹窗",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_IMAGE_WIDGET",
widgetCardName: "图片",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_BUTTON_WIDGET",
widgetCardName: "按钮",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_CELL_WIDGET",
widgetCardName: "单元格",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_HTML_WIDGET",
widgetCardName: "富文本",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_SIMPLE_FORM_WIDGET",
widgetCardName: "快速表单",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_KV_WIDGET",
widgetCardName: "键值对",
key: generateReactKey(),
isMobile: true,
},
{
type: "TARO_TABS_WIDGET",
widgetCardName: "标签页",
key: generateReactKey(),
isMobile: true,
},
];
export default WidgetSidebarResponse;

View File

@ -255,6 +255,27 @@ const OrgShareUsers = styled.div`
display: flex;
align-items: center;
`;
const AddIcon = styled(Icon)`
position: absolute;
top: ${(props) => (props.isMobile ? "12" : "10")}px;
left: 50%;
margin-left: -4.5px;
& svg {
width: 9px;
height: 9px;
}
`;
const AddTypeIcon = styled(Icon)`
& svg {
width: 39px;
height: 39px;
}
`;
const IconGroup = styled.div`
position: relative;
`;
function Item(props: {
label: string;
@ -613,7 +634,11 @@ function ApplicationsSection(props: any) {
);
}
const createNewApplication = (applicationName: string, orgId: string) => {
const createNewApplication = (
applicationName: string,
orgId: string,
isMobile: boolean,
) => {
const color = getRandomPaletteColor(theme.colors.appCardColors);
const icon =
AppIconCollection[Math.floor(Math.random() * AppIconCollection.length)];
@ -625,10 +650,58 @@ function ApplicationsSection(props: any) {
orgId,
icon,
color,
isMobile,
},
});
};
const CreateApp = ({ isMobile, orgId, applications }: any) => {
return (
<PaddingWrapper>
<ApplicationAddCardWrapper
onClick={() => {
if (
Object.entries(creatingApplicationMap).length === 0 ||
(creatingApplicationMap && !creatingApplicationMap[orgId])
) {
createNewApplication(
getNextEntityName(
"未命名应用 ",
applications.map((el: any) => el.name),
),
orgId,
isMobile,
);
}
}}
>
{creatingApplicationMap && creatingApplicationMap[orgId] ? (
<Spinner size={IconSize.XXXL} />
) : (
<>
<IconGroup>
<AddTypeIcon
className="t--create-app-popup"
name={isMobile ? "mobile" : "desktop"}
size={IconSize.LARGE}
/>
<AddIcon
className="t--create-app-popup"
name={"plus"}
size={IconSize.LARGE}
isMobile={isMobile}
/>
</IconGroup>
<CreateNewLabel className="createnew" type={TextType.H4}>
{isMobile ? "移动" : "桌面"}
</CreateNewLabel>
</>
)}
</ApplicationAddCardWrapper>
</PaddingWrapper>
);
};
let updatedOrgs;
if (!isFetchingApplications) {
updatedOrgs = userOrgs;
@ -820,44 +893,17 @@ function ApplicationsSection(props: any) {
PERMISSION_TYPE.CREATE_APPLICATION,
) &&
!isFetchingApplications && (
<PaddingWrapper>
<ApplicationAddCardWrapper
onClick={() => {
if (
Object.entries(creatingApplicationMap).length === 0 ||
(creatingApplicationMap &&
!creatingApplicationMap[organization.id])
) {
createNewApplication(
getNextEntityName(
"未命名应用 ",
applications.map((el: any) => el.name),
),
organization.id,
);
}
}}
>
{creatingApplicationMap &&
creatingApplicationMap[organization.id] ? (
<Spinner size={IconSize.XXXL} />
) : (
<>
<Icon
className="t--create-app-popup"
name={"plus"}
size={IconSize.LARGE}
/>
<CreateNewLabel
className="createnew"
type={TextType.H4}
>
</CreateNewLabel>
</>
)}
</ApplicationAddCardWrapper>
</PaddingWrapper>
<>
<CreateApp
orgId={organization.id}
applications={applications}
/>
<CreateApp
orgId={organization.id}
applications={applications}
isMobile
/>
</>
)}
{applications.map((application: any) => {
return (

View File

@ -113,7 +113,9 @@ export const WidgetEntity = memo((props: WidgetEntityProps) => {
* so we track the immediate modal parent for the widget
*/
const parentModalIdForChildren = useMemo(() => {
return widgetType === "MODAL_WIDGET" ? widgetId : parentModalId;
return widgetType === "MODAL_WIDGET" || widgetType === "TARO_POPUP_WIDGET"
? widgetId
: parentModalId;
}, [widgetType, widgetId, parentModalId]);
if (UNREGISTERED_WIDGETS.indexOf(props.widgetType) > -1) return null;

View File

@ -33,7 +33,10 @@ export const useNavigateToWidget = () => {
pageId: string,
parentModalId?: string,
) => {
if (widgetType === WidgetTypes.MODAL_WIDGET) {
if (
widgetType === WidgetTypes.MODAL_WIDGET ||
widgetType === WidgetTypes.TARO_POPUP_WIDGET
) {
dispatch(showModal(widgetId));
return;
}

View File

@ -42,11 +42,11 @@ const AppsmithLayouts: AppsmithLayoutConfigOption[] = [
type: "TABLET",
icon: "tablet",
},
{
name: "手机宽度",
type: "MOBILE",
icon: "mobile",
},
// {
// name: "手机宽度",
// type: "MOBILE",
// icon: "mobile",
// },
{
name: "自适应宽度",
type: "FLUID",
@ -71,9 +71,14 @@ const LayoutControlWrapper = styled.div`
}
`;
const EmptyBlock = styled.div`
height: 30px;
`;
export function MainContainerLayoutControl() {
const appId = useSelector(getCurrentApplicationId);
const appLayout = useSelector(getCurrentApplicationLayout);
const isMobile = appLayout?.type === "MOBILE_FLUID";
const layoutOptions = AppsmithLayouts.map((each) => {
return {
...each,
@ -89,8 +94,8 @@ export function MainContainerLayoutControl() {
const selectedLayout = appLayout
? layoutOptions.find((each) => each.type === appLayout.type)
: layoutOptions[0];
const dispatch = useDispatch();
const dispatch = useDispatch();
const updateAppLayout = (layoutConfig: AppLayoutConfig) => {
const { type } = layoutConfig;
dispatch(
@ -101,6 +106,10 @@ export function MainContainerLayoutControl() {
}),
);
};
if (isMobile) {
return <EmptyBlock />;
}
return (
<LayoutControlWrapper>
<div className="layout-control t--layout-control-wrapper">

View File

@ -55,6 +55,7 @@ export const excludeList = [
WidgetTypes.TABS_WIDGET,
WidgetTypes.FORM_WIDGET,
WidgetTypes.MODAL_WIDGET,
WidgetTypes.TARO_POPUP_WIDGET,
WidgetTypes.DIVIDER_WIDGET,
WidgetTypes.FILE_PICKER_WIDGET,
WidgetTypes.BUTTON_WIDGET,

View File

@ -146,7 +146,8 @@ export type SupportedLayouts =
| "TABLET_LARGE"
| "TABLET"
| "MOBILE"
| "FLUID";
| "FLUID"
| "MOBILE_FLUID";
export interface AppLayoutConfig {
type: SupportedLayouts;
}

View File

@ -35,6 +35,19 @@ import { RateWidgetProps } from "widgets/RateWidget";
import { IframeWidgetProps } from "widgets/IframeWidget";
import { MenuButtonWidgetProps } from "widgets/MenuButtonWidget";
import { FormilyWidgetProps } from "widgets/FormilyWidget";
import { PickerWidgetProps } from "widgets/taro/PickerWidget";
import { SwiperWidgetProps } from "widgets/taro/SwiperWidget";
import { GridWidgetProps } from "widgets/taro/GridWidget";
import { MTextWidgetProps } from "widgets/taro/TextWidget";
import { MListWidgetProps } from "widgets/taro/ListWidget";
import { MPopupWidgetProps } from "widgets/taro/PopupWidget";
import { MImageWidgetProps } from "widgets/taro/ImageWidget";
import { MButtonWidgetProps } from "widgets/taro/ButtonWidget";
import { MCellWidgetProps } from "widgets/taro/CellWidget";
import { MHtmlWidgetProps } from "widgets/taro/HtmlWidget";
import { MSimpleFormWidgetProps } from "widgets/taro/SimpleFormWidget";
import { MKVWidgetProps } from "widgets/taro/KVWidget";
import { MTabsWidgetProps } from "widgets/taro/TabsWidget";
const initialState: WidgetConfigReducerState = WidgetConfigResponse;
@ -94,6 +107,20 @@ export interface WidgetConfigReducerState {
IFRAME_WIDGET: Partial<IframeWidgetProps> & WidgetConfigProps;
MENU_BUTTON_WIDGET: Partial<MenuButtonWidgetProps> & WidgetConfigProps;
FORMILY_WIDGET: Partial<FormilyWidgetProps> & WidgetConfigProps;
TARO_PICKER_WIDGET: Partial<PickerWidgetProps> & WidgetConfigProps;
TARO_SWIPER_WIDGET: Partial<SwiperWidgetProps> & WidgetConfigProps;
TARO_GRID_WIDGET: Partial<GridWidgetProps> & WidgetConfigProps;
TARO_TEXT_WIDGET: Partial<MTextWidgetProps> & WidgetConfigProps;
TARO_LIST_WIDGET: Partial<MListWidgetProps> & WidgetConfigProps;
TARO_POPUP_WIDGET: Partial<MPopupWidgetProps> & WidgetConfigProps;
TARO_IMAGE_WIDGET: Partial<MImageWidgetProps> & WidgetConfigProps;
TARO_BUTTON_WIDGET: Partial<MButtonWidgetProps> & WidgetConfigProps;
TARO_CELL_WIDGET: Partial<MCellWidgetProps> & WidgetConfigProps;
TARO_HTML_WIDGET: Partial<MHtmlWidgetProps> & WidgetConfigProps;
TARO_SIMPLE_FORM_WIDGET: Partial<MSimpleFormWidgetProps> &
WidgetConfigProps;
TARO_KV_WIDGET: Partial<MKVWidgetProps> & WidgetConfigProps;
TARO_TABS_WIDGET: Partial<MTabsWidgetProps> & WidgetConfigProps;
};
configVersion: number;
}

View File

@ -63,6 +63,7 @@ import { deleteRecentAppEntities } from "utils/storage";
import { reconnectWebsocket as reconnectWebsocketAction } from "actions/websocketActions";
import { getCurrentOrg } from "selectors/organizationSelectors";
import { Org } from "constants/orgConstants";
import { AppLayoutConfig } from "reducers/entityReducers/pageListReducer";
const getDefaultPageId = (
pages?: ApplicationPagePayload[],
@ -392,12 +393,20 @@ export function* createApplicationSaga(
applicationName: string;
icon: AppIconName;
color: AppColorCode;
isMobile: boolean;
orgId: string;
resolve: any;
reject: any;
}>,
) {
const { applicationName, color, icon, orgId, reject } = action.payload;
const {
applicationName,
color,
icon,
orgId,
reject,
isMobile,
} = action.payload;
try {
const userOrgs = yield select(getUserApplicationsOrgsList);
const existingOrgs = userOrgs.filter(
@ -423,11 +432,16 @@ export function* createApplicationSaga(
} else {
yield put(resetCurrentApplication());
const layout: AppLayoutConfig = {
type: isMobile ? "MOBILE_FLUID" : "DESKTOP",
};
const request: CreateApplicationRequest = {
name: applicationName,
icon: icon,
color: color,
orgId,
unpublishedAppLayout: layout,
publishedAppLayout: layout,
};
const response: CreateApplicationResponse = yield call(
ApplicationApi.createApplication,
@ -441,6 +455,7 @@ export function* createApplicationSaga(
};
AnalyticsUtil.logEvent("CREATE_APP", {
appName: application.name,
isMobile,
});
// This sets ui.pageWidgets = {} to ensure that
// widgets are cleaned up from state before
@ -458,6 +473,7 @@ export function* createApplicationSaga(
const pageURL = getGenerateTemplateURL(
application.id,
application.defaultPageId,
isMobile,
);
history.push(pageURL);

View File

@ -27,6 +27,7 @@ import {
getWidgetsMeta,
getWidgetIdsByType,
getWidgetMetaProps,
getWidgetIdsByTypes,
} from "sagas/selectors";
import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
import { updateWidgetMetaProperty } from "actions/metaActions";
@ -34,21 +35,23 @@ import { focusWidget } from "actions/widgetActions";
import log from "loglevel";
import { flatten } from "lodash";
import AppsmithConsole from "utils/AppsmithConsole";
import { isMobileLayout } from "selectors/editorSelectors";
export function* createModalSaga(action: ReduxAction<{ modalName: string }>) {
try {
const isMobile: boolean = yield select(isMobileLayout);
const modalWidgetId = generateReactKey();
const props: WidgetAddChild = {
widgetId: MAIN_CONTAINER_WIDGET_ID,
widgetName: action.payload.modalName,
type: WidgetTypes.MODAL_WIDGET,
type: isMobile ? WidgetTypes.TARO_POPUP_WIDGET : WidgetTypes.MODAL_WIDGET,
newWidgetId: modalWidgetId,
parentRowSpace: 1,
parentRowSpace: isMobile ? 10 : 1,
parentColumnSpace: 1,
leftColumn: 0,
topRow: 0,
columns: 0,
rows: 0,
rows: isMobile ? 40 : 0,
tabId: "",
};
yield put({
@ -98,7 +101,10 @@ export function* showModalByNameSaga(
export function* showIfModalSaga(
action: ReduxAction<{ widgetId: string; type: string }>,
) {
if (action.payload.type === "MODAL_WIDGET") {
if (
action.payload.type === "MODAL_WIDGET" ||
action.payload.type === WidgetTypes.TARO_POPUP_WIDGET
) {
yield put({
type: ReduxActionTypes.SHOW_MODAL,
payload: { modalId: action.payload.widgetId },
@ -160,10 +166,10 @@ export function* closeModalSaga(
const metaProps: Record<string, any> = yield select(getWidgetsMeta);
// Get widgetIds of all widgets of type MODAL_WIDGET
const modalWidgetIds: string[] = yield select(
getWidgetIdsByType,
const modalWidgetIds: string[] = yield select(getWidgetIdsByTypes, [
WidgetTypes.MODAL_WIDGET,
);
WidgetTypes.TARO_POPUP_WIDGET,
]);
// Loop through all modal widgetIds
modalWidgetIds.forEach((widgetId: string) => {

View File

@ -71,6 +71,7 @@ import {
getCurrentLayoutId,
getCurrentPageId,
getCurrentPageName,
isMobileLayout,
} from "selectors/editorSelectors";
import {
fetchActionsForPage,
@ -486,6 +487,7 @@ export function* createPageSaga(
const request: CreatePageRequest = createPageAction.payload;
const response: FetchPageResponse = yield call(PageApi.createPage, request);
const isValidResponse: boolean = yield validateResponse(response);
const isMobile: boolean = yield select(isMobileLayout);
if (isValidResponse) {
yield put({
type: ReduxActionTypes.CREATE_PAGE_SUCCESS,
@ -508,6 +510,7 @@ export function* createPageSaga(
getGenerateTemplateURL(
createPageAction.payload.applicationId,
response.data.id,
isMobile,
),
);
}

View File

@ -29,6 +29,12 @@ export const getWidgetIdsByType = (state: AppState, type: WidgetType) => {
.map((widget: FlattenedWidgetProps) => widget.widgetId);
};
export const getWidgetIdsByTypes = (state: AppState, types: WidgetType[]) => {
return Object.values(state.entities.canvasWidgets)
.filter((widget: FlattenedWidgetProps) => _.includes(types, widget.type))
.map((widget: FlattenedWidgetProps) => widget.widgetId);
};
export const getWidgetOptionsTree = createSelector(getWidgets, (widgets) =>
Object.values(widgets)
.filter((w) => w.type !== "CANVAS_WIDGET" && w.type !== "BUTTON_WIDGET")

View File

@ -21,6 +21,7 @@ import _ from "lodash";
import { ContainerWidgetProps } from "widgets/ContainerWidget";
import { DataTreeWidget, ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
import { getActions } from "selectors/entitiesSelector";
import { AppLayoutConfig } from "reducers/entityReducers/pageListReducer";
import { getCanvasWidgets } from "./entitiesSelector";
import { WidgetTypes } from "../constants/WidgetConstants";
@ -109,6 +110,9 @@ export const getViewModePageList = createSelector(
export const getCurrentApplicationLayout = (state: AppState) =>
state.ui.applications.currentApplication?.appLayout;
export const isMobileLayout = (state: AppState) =>
state.ui.applications.currentApplication?.appLayout?.type === "MOBILE_FLUID";
export const getCurrentPageName = createSelector(
getPageListState,
(pageList: PageListReduxState) =>
@ -119,11 +123,15 @@ export const getCurrentPageName = createSelector(
export const getWidgetCards = createSelector(
getWidgetSideBar,
getWidgetConfigs,
isMobileLayout,
(
widgetCards: WidgetSidebarReduxState,
widgetConfigs: WidgetConfigReducerState,
isMobile: boolean,
) => {
const cards = widgetCards.cards;
const cards = widgetCards.cards.filter((c) =>
isMobile ? c.isMobile : !c.isMobile,
);
return cards
.map((widget: WidgetCardProps) => {
const {

View File

@ -367,7 +367,10 @@ const getParentModalId = (widget: any, pageWidgets: Record<string, any>) => {
let { parentId } = widget;
let parentWidget = pageWidgets[parentId];
while (parentId && parentId !== MAIN_CONTAINER_WIDGET_ID) {
if (parentWidget?.type === "MODAL_WIDGET") {
if (
parentWidget?.type === "MODAL_WIDGET" ||
parentWidget?.type === "TARO_POPUP_WIDGET"
) {
parentModalId = parentId;
break;
}

View File

@ -4,6 +4,7 @@ import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReduc
import { WidgetTypes } from "constants/WidgetConstants";
import { getExistingWidgetNames, getWidgetNamePrefix } from "sagas/selectors";
import { getNextEntityName } from "utils/AppsmithUtils";
import { isMobileLayout } from "selectors/editorSelectors";
const getCanvasWidgets = (state: AppState) => state.entities.canvasWidgets;
export const getModalDropdownList = createSelector(
@ -11,7 +12,8 @@ export const getModalDropdownList = createSelector(
(widgets) => {
const modalWidgets = Object.values(widgets).filter(
(widget: FlattenedWidgetProps) =>
widget.type === WidgetTypes.MODAL_WIDGET,
widget.type === WidgetTypes.MODAL_WIDGET ||
widget.type === WidgetTypes.TARO_POPUP_WIDGET,
);
if (modalWidgets.length === 0) return undefined;
@ -23,8 +25,12 @@ export const getModalDropdownList = createSelector(
},
);
const getModalNamePrefix = (state: AppState) =>
getWidgetNamePrefix(state, WidgetTypes.MODAL_WIDGET);
const getModalNamePrefix = (state: AppState) => {
const type = isMobileLayout(state)
? WidgetTypes.TARO_POPUP_WIDGET
: WidgetTypes.MODAL_WIDGET;
return getWidgetNamePrefix(state, type);
};
export const getNextModalName = createSelector(
getExistingWidgetNames,

View File

@ -1267,7 +1267,11 @@ export const generateWidgetProps = (
const others = {};
const props: ContainerWidgetProps<WidgetProps> = {
isVisible: WidgetTypes.MODAL_WIDGET === type ? undefined : true,
isVisible:
WidgetTypes.MODAL_WIDGET === type ||
WidgetTypes.TARO_POPUP_WIDGET === type
? undefined
: true,
...widgetConfig,
type,
widgetName,

View File

@ -127,6 +127,58 @@ import FormilyWidget, {
FormilyWidgetProps,
ProfiledFormilyWidget,
} from "widgets/FormilyWidget";
import PickerWidget, {
PickerWidgetProps,
ProfiledPickerWidget,
} from "widgets/taro/PickerWidget";
import SwiperWidget, {
SwiperWidgetProps,
ProfiledSwiperWidget,
} from "widgets/taro/SwiperWidget";
import GridWidget, {
GridWidgetProps,
ProfiledGridWidget,
} from "widgets/taro/GridWidget";
import MTextWidget, {
MTextWidgetProps,
MProfiledTextWidget,
} from "widgets/taro/TextWidget";
import MListWidget, {
MListWidgetProps,
MProfiledListWidget,
} from "widgets/taro/ListWidget";
import MPopupWidget, {
MPopupWidgetProps,
MProfiledPopupWidget,
} from "widgets/taro/PopupWidget";
import MImageWidget, {
MImageWidgetProps,
MProfiledImageWidget,
} from "widgets/taro/ImageWidget";
import MButtonWidget, {
MButtonWidgetProps,
MProfiledButtonWidget,
} from "widgets/taro/ButtonWidget";
import MCellWidget, {
MCellWidgetProps,
MProfiledCellWidget,
} from "widgets/taro/CellWidget";
import MHtmlWidget, {
MHtmlWidgetProps,
MProfiledHtmlWidget,
} from "widgets/taro/HtmlWidget";
import MSimpleFormWidget, {
MSimpleFormWidgetProps,
MProfiledSimpleFormWidget,
} from "widgets/taro/SimpleFormWidget";
import MKVWidget, {
MKVWidgetProps,
MProfiledKVWidget,
} from "widgets/taro/KVWidget";
import MTabsWidget, {
MTabsWidgetProps,
MProfiledTabsWidget,
} from "widgets/taro/TabsWidget";
export default class WidgetBuilderRegistry {
static registerWidgetBuilders() {
@ -555,5 +607,174 @@ export default class WidgetBuilderRegistry {
FormilyWidget.getMetaPropertiesMap(),
FormilyWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_PICKER_WIDGET,
{
buildWidget(widgetData: PickerWidgetProps): JSX.Element {
return <ProfiledPickerWidget {...widgetData} />;
},
},
PickerWidget.getDerivedPropertiesMap(),
PickerWidget.getDefaultPropertiesMap(),
PickerWidget.getMetaPropertiesMap(),
PickerWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_SWIPER_WIDGET,
{
buildWidget(widgetData: SwiperWidgetProps): JSX.Element {
return <ProfiledSwiperWidget {...widgetData} />;
},
},
SwiperWidget.getDerivedPropertiesMap(),
SwiperWidget.getDefaultPropertiesMap(),
SwiperWidget.getMetaPropertiesMap(),
SwiperWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_GRID_WIDGET,
{
buildWidget(widgetData: GridWidgetProps): JSX.Element {
return <ProfiledGridWidget {...widgetData} />;
},
},
GridWidget.getDerivedPropertiesMap(),
GridWidget.getDefaultPropertiesMap(),
GridWidget.getMetaPropertiesMap(),
GridWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_TEXT_WIDGET,
{
buildWidget(widgetData: MTextWidgetProps): JSX.Element {
return <MProfiledTextWidget {...widgetData} />;
},
},
MTextWidget.getDerivedPropertiesMap(),
MTextWidget.getDefaultPropertiesMap(),
MTextWidget.getMetaPropertiesMap(),
MTextWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_LIST_WIDGET,
{
buildWidget(widgetData: MListWidgetProps): JSX.Element {
return <MProfiledListWidget {...widgetData} />;
},
},
MListWidget.getDerivedPropertiesMap(),
MListWidget.getDefaultPropertiesMap(),
MListWidget.getMetaPropertiesMap(),
MListWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_POPUP_WIDGET,
{
buildWidget(widgetData: MPopupWidgetProps): JSX.Element {
return <MProfiledPopupWidget {...widgetData} />;
},
},
MPopupWidget.getDerivedPropertiesMap(),
MPopupWidget.getDefaultPropertiesMap(),
MPopupWidget.getMetaPropertiesMap(),
MPopupWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_IMAGE_WIDGET,
{
buildWidget(widgetData: MImageWidgetProps): JSX.Element {
return <MProfiledImageWidget {...widgetData} />;
},
},
MImageWidget.getDerivedPropertiesMap(),
MImageWidget.getDefaultPropertiesMap(),
MImageWidget.getMetaPropertiesMap(),
MImageWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_BUTTON_WIDGET,
{
buildWidget(widgetData: MButtonWidgetProps): JSX.Element {
return <MProfiledButtonWidget {...widgetData} />;
},
},
MButtonWidget.getDerivedPropertiesMap(),
MButtonWidget.getDefaultPropertiesMap(),
MButtonWidget.getMetaPropertiesMap(),
MButtonWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_CELL_WIDGET,
{
buildWidget(widgetData: MCellWidgetProps): JSX.Element {
return <MProfiledCellWidget {...widgetData} />;
},
},
MCellWidget.getDerivedPropertiesMap(),
MCellWidget.getDefaultPropertiesMap(),
MCellWidget.getMetaPropertiesMap(),
MCellWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_HTML_WIDGET,
{
buildWidget(widgetData: MHtmlWidgetProps): JSX.Element {
return <MProfiledHtmlWidget {...widgetData} />;
},
},
MHtmlWidget.getDerivedPropertiesMap(),
MHtmlWidget.getDefaultPropertiesMap(),
MHtmlWidget.getMetaPropertiesMap(),
MHtmlWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_SIMPLE_FORM_WIDGET,
{
buildWidget(widgetData: MSimpleFormWidgetProps): JSX.Element {
return <MProfiledSimpleFormWidget {...widgetData} />;
},
},
MSimpleFormWidget.getDerivedPropertiesMap(),
MSimpleFormWidget.getDefaultPropertiesMap(),
MSimpleFormWidget.getMetaPropertiesMap(),
MSimpleFormWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_KV_WIDGET,
{
buildWidget(widgetData: MKVWidgetProps): JSX.Element {
return <MProfiledKVWidget {...widgetData} />;
},
},
MKVWidget.getDerivedPropertiesMap(),
MKVWidget.getDefaultPropertiesMap(),
MKVWidget.getMetaPropertiesMap(),
MKVWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder(
WidgetTypes.TARO_TABS_WIDGET,
{
buildWidget(widgetData: MTabsWidgetProps): JSX.Element {
return <MProfiledTabsWidget {...widgetData} />;
},
},
MTabsWidget.getDerivedPropertiesMap(),
MTabsWidget.getDefaultPropertiesMap(),
MTabsWidget.getMetaPropertiesMap(),
MTabsWidget.getPropertyPaneConfig(),
);
}
}

View File

@ -293,6 +293,59 @@ export const entityDefinitions = {
isVisible: isVisible,
formData: "any",
},
TARO_PICKER_WIDGET: {
"!doc": "Taro 选择器",
"!url": "https://docs.appsmith.com/widget-reference/input",
isVisible: isVisible,
},
TARO_SWIPER_WIDGET: {
"!doc": "轮播",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_GRID_WIDGET: {
"!doc": "网格内容",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_TEXT_WIDGET: {
"!doc": "文本",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_LIST_WIDGET: {
"!doc": "列表",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_POPUP_WIDGET: {
"!doc": "底部弹窗",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_IMAGE_WIDGET: {
"!doc": "图片",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_BUTTON_WIDGET: {
"!doc": "按钮",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_CELL_WIDGET: {
"!doc": "单元格",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_HTML_WIDGET: {
"!doc": "富文本",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_SIMPLE_FORM_WIDGET: {
"!doc": "快速表单",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_KV_WIDGET: {
"!doc": "键值对",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
TARO_TABS_WIDGET: {
"!doc": "标签页",
"!url": "https://docs.appsmith.com/widget-reference/input",
},
};
export const GLOBAL_DEFS = {

View File

@ -52,8 +52,8 @@ export const dataTreeTypeDefCreator = (
subType: "ACTION",
});
} else if (isAppsmithEntity(entity)) {
def.appsmith = generateTypeDef(_.omit(entity, "ENTITY_TYPE"));
entityMap.set("appsmith", {
def.global = generateTypeDef(_.omit(entity, "ENTITY_TYPE"));
entityMap.set("global", {
type: ENTITY_TYPE.APPSMITH,
subType: ENTITY_TYPE.APPSMITH,
});

View File

@ -492,6 +492,7 @@ export interface WidgetCardProps {
key?: string;
widgetCardName: string;
isBeta?: boolean;
isMobile?: boolean;
}
export const WidgetOperations = {

View File

@ -125,7 +125,6 @@ class FormilyWidget extends BaseWidget<FormilyWidgetProps, WidgetState> {
};
getPageView() {
console.log("----widget--props--", this.props);
const {
title,
formType,

View File

@ -0,0 +1,136 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import ButtonComponent from "components/designSystems/taro/ButtonComponent";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import withMeta, { WithMeta } from "../MetaHOC";
class MButtonWidget extends BaseWidget<MButtonWidgetProps, ButtonWidgetState> {
state = {
isLoading: false,
};
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "text",
label: "按钮文字",
controlType: "INPUT_TEXT",
placeholderText: "输入按钮文字",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "color",
label: "按钮颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "rounded",
label: "是否圆角",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isVisible",
label: "是否可见",
helpText: "控制按钮显示/隐藏",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isDisabled",
label: "禁用",
controlType: "SWITCH",
helpText: "禁止按钮交互",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "动作",
children: [
{
helpText: "点击按钮时触发动作",
propertyName: "onClick",
label: "onClick",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
onButtonClick = () => {
if (this.props.onClick) {
this.setState({
isLoading: true,
});
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: this.props.onClick,
event: {
type: EventType.ON_CLICK,
callback: this.handleActionComplete,
},
});
}
};
handleActionComplete = () => {
this.setState({
isLoading: false,
});
};
getPageView() {
return (
<ButtonComponent
isDisabled={this.props.isDisabled}
isLoading={this.props.isLoading || this.state.isLoading}
onClick={!this.props.isDisabled ? this.onButtonClick : undefined}
text={this.props.text}
color={this.props.color}
rounded={this.props.rounded}
/>
);
}
getWidgetType(): WidgetType {
return "TARO_BUTTON_WIDGET";
}
}
export interface MButtonWidgetProps extends WidgetProps, WithMeta {
text?: string;
color?: string;
onClick?: string;
rounded?: boolean;
isDisabled?: boolean;
isVisible?: boolean;
}
interface ButtonWidgetState extends WidgetState {
isLoading: boolean;
}
export default MButtonWidget;
export const MProfiledButtonWidget = withMeta(MButtonWidget);

View File

@ -0,0 +1,136 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import ButtonComponent from "components/designSystems/taro/ButtonComponent";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import withMeta, { WithMeta } from "../MetaHOC";
class MCellWidget extends BaseWidget<MCellWidgetProps, CellWidgetState> {
state = {
isLoading: false,
};
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "text",
label: "按钮文字",
controlType: "INPUT_TEXT",
placeholderText: "输入按钮文字",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "color",
label: "按钮颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "rounded",
label: "是否圆角",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isVisible",
label: "是否可见",
helpText: "控制按钮显示/隐藏",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isDisabled",
label: "禁用",
controlType: "SWITCH",
helpText: "禁止按钮交互",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "动作",
children: [
{
helpText: "点击按钮时触发动作",
propertyName: "onClick",
label: "onClick",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
onButtonClick = () => {
if (this.props.onClick) {
this.setState({
isLoading: true,
});
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: this.props.onClick,
event: {
type: EventType.ON_CLICK,
callback: this.handleActionComplete,
},
});
}
};
handleActionComplete = () => {
this.setState({
isLoading: false,
});
};
getPageView() {
return (
<ButtonComponent
isDisabled={this.props.isDisabled}
isLoading={this.props.isLoading || this.state.isLoading}
onClick={!this.props.isDisabled ? this.onButtonClick : undefined}
text={this.props.text}
color={this.props.color}
rounded={this.props.rounded}
/>
);
}
getWidgetType(): WidgetType {
return "TARO_BUTTON_WIDGET";
}
}
export interface MCellWidgetProps extends WidgetProps, WithMeta {
text?: string;
color?: string;
onClick?: string;
rounded?: boolean;
isDisabled?: boolean;
isVisible?: boolean;
}
interface CellWidgetState extends WidgetState {
isLoading: boolean;
}
export default MCellWidget;
export const MProfiledCellWidget = withMeta(MCellWidget);

View File

@ -0,0 +1,243 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
import GridComponent, {
GridComponentProps,
} from "components/designSystems/taro/GridComponent";
import { ValidationTypes } from "constants/WidgetValidation";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
class GridWidget extends BaseWidget<GridWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
helpText: "数组,通过 {{}} 进行数据绑定",
propertyName: "list",
label: "数据",
controlType: "INPUT_TEXT",
placeholderText: '[{ "url": "", title: "" }]',
inputType: "ARRAY",
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.OBJECT_ARRAY,
params: {
default: [],
},
},
evaluationSubstitutionType:
EvaluationSubstitutionType.SMART_SUBSTITUTE,
},
{
propertyName: "gridType",
label: "内容类型",
controlType: "DROP_DOWN",
options: [
{
label: "图片+标题",
value: "I_N",
},
{
label: "图片+标题+描述",
value: "I_N_D",
},
{
label: "图片+标题+描述+按钮",
value: "I_N_D_B",
},
],
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "urlKey",
label: "图片字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "titleKey",
label: "标题字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "descriptionKey",
label: "描述字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
dependencies: ["gridType"],
hidden: (props: GridWidgetProps) => {
return props.gridType === "I_N";
},
},
{
propertyName: "asPrice",
label: "描述是价格",
controlType: "SWITCH",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
dependencies: ["gridType"],
hidden: (props: GridWidgetProps) => {
return props.gridType === "I_N";
},
},
{
propertyName: "priceUnit",
label: "价格单位符号",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
dependencies: ["gridType", "asPrice"],
hidden: (props: GridWidgetProps) => {
return props.gridType === "I_N" || !props.asPrice;
},
},
{
propertyName: "buttonText",
label: "按钮文本",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
dependencies: ["gridType"],
hidden: (props: GridWidgetProps) => {
return props.gridType !== "I_N_D_B";
},
},
],
},
{
sectionName: "样式",
children: [
{
propertyName: "height",
label: "图片高度",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "cols",
label: "列数",
controlType: "INPUT_TEXT",
placeholderText: "网格显示多少列",
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.NUMBER,
params: { min: 2, default: 4 },
},
},
{
propertyName: "gutter",
label: "网格间距",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "bordered",
label: "是否显示边框",
controlType: "SWITCH",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "titleColor",
label: "标题颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "descriptionColor",
label: "描述颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
dependencies: ["gridType"],
hidden: (props: GridWidgetProps) => {
return props.gridType === "I_N";
},
},
{
propertyName: "buttonColor",
label: "按钮颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
dependencies: ["gridType"],
hidden: (props: GridWidgetProps) => {
return props.gridType !== "I_N_D_B";
},
},
],
},
];
}
getPageView() {
const {
list,
gridType,
urlKey,
titleKey,
descriptionKey,
asPrice,
priceUnit,
buttonText,
height,
cols,
gutter,
bordered,
titleColor,
descriptionColor,
buttonColor,
} = this.props;
return (
<GridComponent
{...{
list,
gridType,
urlKey,
titleKey,
descriptionKey,
asPrice,
priceUnit,
buttonText,
height,
cols,
gutter,
bordered,
titleColor,
descriptionColor,
buttonColor,
}}
/>
);
}
getWidgetType(): WidgetType {
return WidgetTypes.TARO_GRID_WIDGET;
}
}
export interface GridWidgetProps extends WidgetProps, GridComponentProps {}
export default GridWidget;
export const ProfiledGridWidget = GridWidget;

View File

@ -0,0 +1,55 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { ScrollView, RichText } from "@tarojs/components";
import { WidgetType } from "constants/WidgetConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import styled from "styled-components";
const Container = styled(ScrollView)`
width: 100%;
height: 100%;
& img {
width: 100%;
}
`;
class MHtmlWidget extends BaseWidget<MHtmlWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "content",
label: "HTML内容",
controlType: "INPUT_TEXT",
placeholderText: "输入HTML格式内容",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
],
},
];
}
getPageView() {
const { content } = this.props;
return (
<Container scrollY>
<RichText style={{ fontSize: 0 }} nodes={content} />
</Container>
);
}
getWidgetType(): WidgetType {
return "TARO_HTML_WIDGET";
}
}
export interface MHtmlWidgetProps extends WidgetProps {
content: string;
}
export default MHtmlWidget;
export const MProfiledHtmlWidget = MHtmlWidget;

View File

@ -0,0 +1,136 @@
import * as React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType, RenderModes } from "constants/WidgetConstants";
import ImageComponent from "components/designSystems/taro/ImageComponent";
import { ValidationTypes } from "constants/WidgetValidation";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
class MImageWidget extends BaseWidget<MImageWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "src",
label: "图片地址",
controlType: "INPUT_TEXT",
placeholderText: "输入图片 URL",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.IMAGE_URL },
},
{
helpText: "设置图片填充父容器的方式",
propertyName: "mode",
label: "图片填充方式",
controlType: "DROP_DOWN",
defaultValue: "aspectFill",
options: [
{
label: "封面模式,保持原始比例",
value: "aspectFill",
},
{
label: "填充模式,不保持原始比例",
value: "scaleToFill",
},
{
label: "包含模式,保持原始比例",
value: "aspectFit",
},
],
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "isCircle",
label: "显示为圆形",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "radius",
label: "圆角大小(默认单位 px",
controlType: "INPUT_TEXT",
isBindProperty: false,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
dependencies: ["isCircle"],
hidden: (props: MImageWidgetProps) => {
return !!props.isCircle;
},
},
{
helpText: "控制组件显示/隐藏",
propertyName: "isVisible",
label: "是否可见",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "动作",
children: [
{
helpText: "当用户点击图片时触发",
propertyName: "onClick",
label: "onClick",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
getPageView() {
const { src, onClick, mode, isCircle, radius } = this.props;
return (
<ImageComponent
imageUrl={src}
onClick={onClick ? this.onImageClick : undefined}
mode={mode}
isCircle={isCircle}
radius={radius}
/>
);
}
onImageClick = () => {
if (this.props.onClick) {
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: this.props.onClick,
event: {
type: EventType.ON_CLICK,
},
});
}
};
getWidgetType(): WidgetType {
return "TARO_IMAGE_WIDGET";
}
}
export type ImageFillMode = "aspectFill" | "scaleToFill" | "aspectFit";
export interface MImageWidgetProps extends WidgetProps {
src: string;
mode: ImageFillMode;
isCircle?: boolean;
radius?: string;
onClick?: string;
}
export default MImageWidget;
export const MProfiledImageWidget = MImageWidget;

View File

@ -0,0 +1,136 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import ButtonComponent from "components/designSystems/taro/ButtonComponent";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import withMeta, { WithMeta } from "../MetaHOC";
class MKVWidget extends BaseWidget<MKVWidgetProps, KVWidgetState> {
state = {
isLoading: false,
};
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "text",
label: "按钮文字",
controlType: "INPUT_TEXT",
placeholderText: "输入按钮文字",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "color",
label: "按钮颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "rounded",
label: "是否圆角",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isVisible",
label: "是否可见",
helpText: "控制按钮显示/隐藏",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isDisabled",
label: "禁用",
controlType: "SWITCH",
helpText: "禁止按钮交互",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "动作",
children: [
{
helpText: "点击按钮时触发动作",
propertyName: "onClick",
label: "onClick",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
onButtonClick = () => {
if (this.props.onClick) {
this.setState({
isLoading: true,
});
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: this.props.onClick,
event: {
type: EventType.ON_CLICK,
callback: this.handleActionComplete,
},
});
}
};
handleActionComplete = () => {
this.setState({
isLoading: false,
});
};
getPageView() {
return (
<ButtonComponent
isDisabled={this.props.isDisabled}
isLoading={this.props.isLoading || this.state.isLoading}
onClick={!this.props.isDisabled ? this.onButtonClick : undefined}
text={this.props.text}
color={this.props.color}
rounded={this.props.rounded}
/>
);
}
getWidgetType(): WidgetType {
return "TARO_BUTTON_WIDGET";
}
}
export interface MKVWidgetProps extends WidgetProps, WithMeta {
text?: string;
color?: string;
onClick?: string;
rounded?: boolean;
isDisabled?: boolean;
isVisible?: boolean;
}
interface KVWidgetState extends WidgetState {
isLoading: boolean;
}
export default MKVWidget;
export const MProfiledKVWidget = withMeta(MKVWidget);

View File

@ -0,0 +1,220 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
import ListComponent, {
ListComponentProps,
} from "components/designSystems/taro/ListComponent";
import { ValidationTypes } from "constants/WidgetValidation";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
class ListWidget extends BaseWidget<MListWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
helpText: "数组,通过 {{}} 进行数据绑定",
propertyName: "list",
label: "数据",
controlType: "INPUT_TEXT",
placeholderText: '[{ "url": "", name: "" }]',
inputType: "ARRAY",
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.OBJECT_ARRAY,
params: {
default: [],
},
},
evaluationSubstitutionType:
EvaluationSubstitutionType.SMART_SUBSTITUTE,
},
{
propertyName: "contentType",
label: "内容类型",
controlType: "DROP_DOWN",
options: [
{
label: "图片+标题+描述",
value: "I_N_D",
},
{
label: "图片+标题+描述+价格",
value: "I_N_D_P",
},
{
label: "图片+标题+描述+价格+按钮",
value: "I_N_D_P_B",
},
],
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "urlKey",
label: "图片字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "titleKey",
label: "标题字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "descriptionKey",
label: "描述字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "priceKey",
label: "价格字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
dependencies: ["contentType"],
hidden: (props: MListWidgetProps) => {
return props.contentType === "I_N_D";
},
},
{
propertyName: "buttonText",
label: "按钮文本",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
dependencies: ["contentType"],
hidden: (props: MListWidgetProps) => {
return props.contentType !== "I_N_D_P_B";
},
},
],
},
{
sectionName: "样式",
children: [
{
propertyName: "inset",
label: "圆角风格",
controlType: "SWITCH",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "width",
label: "图片宽度",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "height",
label: "图片高度",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "titleColor",
label: "标题颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "descriptionColor",
label: "描述颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "priceColor",
label: "价格颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
dependencies: ["contentType"],
hidden: (props: MListWidgetProps) => {
return props.contentType === "I_N_D";
},
},
{
propertyName: "buttonColor",
label: "按钮颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
dependencies: ["contentType"],
hidden: (props: MListWidgetProps) => {
return props.contentType !== "I_N_D_P_B";
},
},
],
},
];
}
getPageView() {
const {
list,
contentType,
urlKey,
titleKey,
descriptionKey,
priceKey,
buttonText,
inset,
width,
height,
titleColor,
descriptionColor,
priceColor,
buttonColor,
} = this.props;
return (
<ListComponent
{...{
list,
contentType,
urlKey,
titleKey,
descriptionKey,
priceKey,
buttonText,
inset,
width,
height,
titleColor,
descriptionColor,
priceColor,
buttonColor,
}}
/>
);
}
getWidgetType(): WidgetType {
return WidgetTypes.TARO_LIST_WIDGET;
}
}
export interface MListWidgetProps extends WidgetProps, ListComponentProps {}
export default ListWidget;
export const MProfiledListWidget = ListWidget;

View File

@ -0,0 +1,82 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
import PickerComponent from "components/designSystems/taro/PickerComponent";
import { ValidationTypes } from "constants/WidgetValidation";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "../MetaHOC";
class PickerWidget extends BaseWidget<PickerWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "title",
label: "这是什么",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
],
},
{
sectionName: "动作",
children: [
{
propertyName: "onTap",
label: "被点击后执行",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
onButtonClick = (e: any) => {
e.stopPropagation();
if (this.props.onTap) {
super.executeAction({
triggerPropertyName: "onTap",
dynamicString: this.props.onTap,
event: {
type: EventType.ON_CLICK,
},
});
}
};
static getMetaPropertiesMap(): Record<string, undefined> {
return {};
}
getPageView() {
const { title } = this.props;
return (
<PickerComponent
onButtonClick={this.onButtonClick}
{...{
title,
}}
/>
);
}
getWidgetType(): WidgetType {
return WidgetTypes.TARO_PICKER_WIDGET;
}
}
export interface PickerWidgetProps extends WidgetProps, WithMeta {
title?: string;
onTap?: string;
}
export default PickerWidget;
export const ProfiledPickerWidget = Sentry.withProfiler(withMeta(PickerWidget));

View File

@ -0,0 +1,178 @@
import React, { ReactNode } from "react";
import { connect } from "react-redux";
import { ReduxActionTypes } from "constants/ReduxActionConstants";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import WidgetFactory from "utils/WidgetFactory";
import { ValidationTypes } from "constants/WidgetValidation";
import ModalComponent from "components/designSystems/taro/PopoverComponent";
import {
WidgetTypes,
RenderMode,
MAIN_CONTAINER_WIDGET_ID,
} from "constants/WidgetConstants";
import { generateClassName } from "utils/generators";
import withMeta, { WithMeta } from "../MetaHOC";
import { AppState } from "reducers";
import { getWidget } from "sagas/selectors";
export class MPopupWidget extends BaseWidget<MPopupWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "height",
label: "弹窗高度(不带单位的数字)",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.NUMBER,
params: { min: 200, max: 800 },
},
},
{
propertyName: "canOutsideClickClose",
label: "点击背景关闭",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "rounded",
label: "圆角风格",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
},
],
},
{
sectionName: "动作",
children: [
{
helpText: "弹窗关闭后触发",
propertyName: "onClose",
label: "onClose",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
getModalWidth() {
return this.props.mainContainer.rightColumn;
}
renderChildWidget = (childWidgetData: WidgetProps): ReactNode => {
childWidgetData.parentId = this.props.widgetId;
childWidgetData.shouldScrollContents = false;
childWidgetData.canExtend = false;
childWidgetData.bottomRow = childWidgetData.bottomRow;
childWidgetData.isVisible = this.props.isVisible;
childWidgetData.containerStyle = "none";
childWidgetData.minHeight = this.props.height;
childWidgetData.rightColumn = this.getModalWidth();
return WidgetFactory.createWidget(childWidgetData, this.props.renderMode);
};
onModalClose = () => {
if (this.props.onClose) {
super.executeAction({
triggerPropertyName: "onClose",
dynamicString: this.props.onClose,
event: {
type: EventType.ON_MODAL_CLOSE,
},
});
}
};
closeModal = () => {
this.props.showPropertyPane(undefined);
this.props.updateWidgetMetaProperty("isVisible", false);
};
getChildren(): ReactNode {
if (this.props.children && this.props.children.length > 0) {
const children = this.props.children.filter(Boolean);
return children.length > 0 && children.map(this.renderChildWidget);
}
}
makeModalComponent(content: ReactNode) {
return (
<ModalComponent
canOutsideClickClose={!!this.props.canOutsideClickClose}
className={`t--modal-widget ${generateClassName(this.props.widgetId)}`}
height={this.props.height}
rounded={this.props.rounded}
isOpen={!!this.props.isVisible}
onClose={this.closeModal}
onModalClose={this.onModalClose}
>
{content}
</ModalComponent>
);
}
getCanvasView() {
let children = this.getChildren();
children = this.showWidgetName(children, true);
return this.makeModalComponent(children);
}
getPageView() {
const children = this.getChildren();
return this.makeModalComponent(children);
}
getWidgetType() {
return WidgetTypes.TARO_POPUP_WIDGET;
}
}
export interface MPopupWidgetProps extends WidgetProps, WithMeta {
renderMode: RenderMode;
children?: WidgetProps[];
canOutsideClickClose?: boolean;
rounded?: boolean;
height?: number;
showPropertyPane: (widgetId?: string) => void;
onClose: string;
mainContainer: WidgetProps;
}
const mapDispatchToProps = (dispatch: any) => ({
showPropertyPane: (
widgetId?: string,
callForDragOrResize?: boolean,
force = false,
) => {
dispatch({
type:
widgetId || callForDragOrResize
? ReduxActionTypes.SHOW_PROPERTY_PANE
: ReduxActionTypes.HIDE_PROPERTY_PANE,
payload: { widgetId, callForDragOrResize, force },
});
},
});
const mapStateToProps = (state: AppState) => {
const props = {
mainContainer: getWidget(state, MAIN_CONTAINER_WIDGET_ID),
};
return props;
};
export default MPopupWidget;
export const MProfiledPopupWidget = connect(
mapStateToProps,
mapDispatchToProps,
)(withMeta(MPopupWidget));

View File

@ -0,0 +1,139 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import ButtonComponent from "components/designSystems/taro/ButtonComponent";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import withMeta, { WithMeta } from "../MetaHOC";
class MSimpleFormWidget extends BaseWidget<
MSimpleFormWidgetProps,
SimpleFormWidgetState
> {
state = {
isLoading: false,
};
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "text",
label: "按钮文字",
controlType: "INPUT_TEXT",
placeholderText: "输入按钮文字",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "color",
label: "按钮颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "rounded",
label: "是否圆角",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isVisible",
label: "是否可见",
helpText: "控制按钮显示/隐藏",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isDisabled",
label: "禁用",
controlType: "SWITCH",
helpText: "禁止按钮交互",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "动作",
children: [
{
helpText: "点击按钮时触发动作",
propertyName: "onClick",
label: "onClick",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
onButtonClick = () => {
if (this.props.onClick) {
this.setState({
isLoading: true,
});
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: this.props.onClick,
event: {
type: EventType.ON_CLICK,
callback: this.handleActionComplete,
},
});
}
};
handleActionComplete = () => {
this.setState({
isLoading: false,
});
};
getPageView() {
return (
<ButtonComponent
isDisabled={this.props.isDisabled}
isLoading={this.props.isLoading || this.state.isLoading}
onClick={!this.props.isDisabled ? this.onButtonClick : undefined}
text={this.props.text}
color={this.props.color}
rounded={this.props.rounded}
/>
);
}
getWidgetType(): WidgetType {
return "TARO_BUTTON_WIDGET";
}
}
export interface MSimpleFormWidgetProps extends WidgetProps, WithMeta {
text?: string;
color?: string;
onClick?: string;
rounded?: boolean;
isDisabled?: boolean;
isVisible?: boolean;
}
interface SimpleFormWidgetState extends WidgetState {
isLoading: boolean;
}
export default MSimpleFormWidget;
export const MProfiledSimpleFormWidget = withMeta(MSimpleFormWidget);

View File

@ -0,0 +1,63 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
import SwiperComponent from "components/designSystems/taro/SwiperComponent";
import { ValidationTypes } from "constants/WidgetValidation";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import _ from "lodash";
class SwiperWidget extends BaseWidget<SwiperWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
helpText: "轮播数据列表,通过 {{}} 进行数据绑定",
propertyName: "list",
label: "数据",
controlType: "INPUT_TEXT",
placeholderText: '例如 [{ "url": "val1", link: "val2" }]',
inputType: "ARRAY",
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.OBJECT_ARRAY,
params: {
default: [],
},
},
evaluationSubstitutionType: EvaluationSubstitutionType.SMART_SUBSTITUTE,
},
{
propertyName: "urlKey",
label: "图片字段",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
];
}
getPageView() {
const { list, urlKey } = this.props;
return (
<SwiperComponent
{...{
list,
urlKey,
}}
/>
);
}
getWidgetType(): WidgetType {
return WidgetTypes.TARO_SWIPER_WIDGET;
}
}
export interface SwiperWidgetProps extends WidgetProps {
list: any[];
urlKey: string;
}
export default SwiperWidget;
export const ProfiledSwiperWidget = SwiperWidget;

View File

@ -0,0 +1,136 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import ButtonComponent from "components/designSystems/taro/ButtonComponent";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import withMeta, { WithMeta } from "../MetaHOC";
class MTabsWidget extends BaseWidget<MTabsWidgetProps, TabsWidgetState> {
state = {
isLoading: false,
};
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "text",
label: "按钮文字",
controlType: "INPUT_TEXT",
placeholderText: "输入按钮文字",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "color",
label: "按钮颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "rounded",
label: "是否圆角",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isVisible",
label: "是否可见",
helpText: "控制按钮显示/隐藏",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
{
propertyName: "isDisabled",
label: "禁用",
controlType: "SWITCH",
helpText: "禁止按钮交互",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "动作",
children: [
{
helpText: "点击按钮时触发动作",
propertyName: "onClick",
label: "onClick",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
onButtonClick = () => {
if (this.props.onClick) {
this.setState({
isLoading: true,
});
super.executeAction({
triggerPropertyName: "onClick",
dynamicString: this.props.onClick,
event: {
type: EventType.ON_CLICK,
callback: this.handleActionComplete,
},
});
}
};
handleActionComplete = () => {
this.setState({
isLoading: false,
});
};
getPageView() {
return (
<ButtonComponent
isDisabled={this.props.isDisabled}
isLoading={this.props.isLoading || this.state.isLoading}
onClick={!this.props.isDisabled ? this.onButtonClick : undefined}
text={this.props.text}
color={this.props.color}
rounded={this.props.rounded}
/>
);
}
getWidgetType(): WidgetType {
return "TARO_BUTTON_WIDGET";
}
}
export interface MTabsWidgetProps extends WidgetProps, WithMeta {
text?: string;
color?: string;
onClick?: string;
rounded?: boolean;
isDisabled?: boolean;
isVisible?: boolean;
}
interface TabsWidgetState extends WidgetState {
isLoading: boolean;
}
export default MTabsWidget;
export const MProfiledTabsWidget = withMeta(MTabsWidget);

View File

@ -0,0 +1,202 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
import { WidgetType, TextSize } from "constants/WidgetConstants";
import TextComponent from "components/designSystems/taro/TextComponent";
import { ValidationTypes } from "constants/WidgetValidation";
import { DerivedPropertiesMap } from "utils/WidgetFactory";
class TextWidget extends BaseWidget<MTextWidgetProps, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "属性",
children: [
{
propertyName: "text",
label: "文本",
controlType: "INPUT_TEXT",
placeholderText: "请输入文本内容",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "shouldScroll",
label: "允许滚动",
helpText: "内容超长时允许滚动,不然文本会被截断",
controlType: "SWITCH",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "isVisible",
label: "是否可见",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "样式",
children: [
{
propertyName: "backgroundColor",
label: "背景颜色",
controlType: "COLOR_PICKER",
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "textColor",
label: "文本颜色",
controlType: "COLOR_PICKER",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
params: {
regex: /^(?![<|{{]).+/,
},
},
},
{
propertyName: "fontSize",
label: "字体大小",
controlType: "DROP_DOWN",
options: [
{
label: "一级标题",
value: "HEADING1",
subText: "24px",
icon: "HEADING_ONE",
},
{
label: "二级标题",
value: "HEADING2",
subText: "18px",
icon: "HEADING_TWO",
},
{
label: "三级标题",
value: "HEADING3",
subText: "16px",
icon: "HEADING_THREE",
},
{
label: "一级段落",
value: "PARAGRAPH",
subText: "14px",
icon: "PARAGRAPH",
},
{
label: "二级段落",
value: "PARAGRAPH2",
subText: "12px",
icon: "PARAGRAPH_TWO",
},
],
isBindProperty: false,
isTriggerProperty: false,
},
{
propertyName: "fontStyle",
label: "字体风格",
controlType: "BUTTON_TABS",
options: [
{
icon: "BOLD_FONT",
value: "BOLD",
},
{
icon: "ITALICS_FONT",
value: "ITALIC",
},
{
icon: "LINETHROUGH_FONT",
value: "LINETHROUGH",
},
],
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "textAlign",
label: "文字对齐",
controlType: "ICON_TABS",
options: [
{
icon: "LEFT_ALIGN",
value: "LEFT",
},
{
icon: "CENTER_ALIGN",
value: "CENTER",
},
{
icon: "RIGHT_ALIGN",
value: "RIGHT",
},
],
defaultValue: "LEFT",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
],
},
];
}
getPageView() {
return (
<TextComponent
backgroundColor={this.props.backgroundColor}
fontSize={this.props.fontSize}
fontStyle={this.props.fontStyle}
isLoading={this.props.isLoading}
key={this.props.widgetId}
shouldScroll={this.props.shouldScroll}
text={this.props.text}
textAlign={this.props.textAlign ? this.props.textAlign : "LEFT"}
textColor={this.props.textColor}
widgetId={this.props.widgetId}
/>
);
}
static getDerivedPropertiesMap(): DerivedPropertiesMap {
return {
value: `{{ this.text }}`,
};
}
getWidgetType(): WidgetType {
return "TARO_TEXT_WIDGET";
}
}
export type TextAlign = "LEFT" | "CENTER" | "RIGHT" | "JUSTIFY";
export interface TextStyles {
backgroundColor?: string;
textColor?: string;
fontStyle?: string;
fontSize?: TextSize;
textAlign?: TextAlign;
}
export interface MTextWidgetProps extends WidgetProps, TextStyles {
text?: string;
isLoading: boolean;
shouldScroll: boolean;
}
export default TextWidget;
export const MProfiledTextWidget = TextWidget;

View File

@ -3,7 +3,9 @@
"baseUrl": "src",
"paths": {
"@appsmith/*": ["enterprise/*"],
"test/*": ["../test/*"]
"test/*": ["../test/*"],
"@tarojs/components$": ["../node_modules/@tarojs/components/dist-h5/react"],
"@tarojs/taro$": ["../node_modules/@tarojs/taro-h5/dist/index.cjs.js"]
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,9 @@ public class CloudOSConfig {
@Value("${pageplug.cloudos.mock_baseurl}")
String mockUrl;
@Value("${pageplug.cloudos.db_baseurl}")
String dbUrl;
@Value("${pageplug.cloudos.in_cloudos}")
Boolean inCloudOS;

View File

@ -56,10 +56,8 @@ public class Application extends BaseDomain {
String icon;
@JsonIgnore
AppLayout unpublishedAppLayout;
@JsonIgnore
AppLayout publishedAppLayout;
Boolean forkingEnabled;
@ -118,6 +116,7 @@ public class Application extends BaseDomain {
TABLET,
MOBILE,
FLUID,
MOBILE_FLUID,
}
}

View File

@ -15,10 +15,7 @@ import com.appsmith.server.domains.NewPage;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.Page;
import com.appsmith.server.domains.User;
import com.appsmith.server.dtos.ActionDTO;
import com.appsmith.server.dtos.ApplicationPagesDTO;
import com.appsmith.server.dtos.PageDTO;
import com.appsmith.server.dtos.PageNameIdDTO;
import com.appsmith.server.dtos.*;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.ApplicationRepository;
@ -255,6 +252,15 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
return applicationWithPoliciesMono
.flatMap(applicationService::createDefault)
.flatMap(savedApplication -> {
final Application.AppLayout appLayout = savedApplication.getPublishedAppLayout();
if (appLayout != null && appLayout.getType() == Application.AppLayout.Type.MOBILE_FLUID) {
final ApplicationAccessDTO applicationAccessDTO = new ApplicationAccessDTO();
applicationAccessDTO.setPublicAccess(true);
return this.applicationService.changeViewAccess(savedApplication.getId(), applicationAccessDTO);
}
return Mono.just(savedApplication);
})
.flatMap(savedApplication -> {
PageDTO page = new PageDTO();

View File

@ -113,8 +113,13 @@ public class CloudOSActionSolution {
String componentId = instance.get("component_id");
String serviceAddress = instance.get("service_address");
String datasourceName = componentName == null ? componentId : componentName;
String dbPrefix = cloudOSConfig.getDbUrl();
return datasourceService.findByNameAndOrganizationId(datasourceName, application.getOrganizationId(), AclPermission.MANAGE_DATASOURCES)
.flatMap(datasource -> {
final String oldUrl = datasource.getDatasourceConfiguration().getUrl();
if (oldUrl.contains(dbPrefix)) {
return Mono.just(datasource);
}
final Datasource deployedDatasource = new Datasource();
final DatasourceConfiguration datasourceConfiguration = new DatasourceConfiguration();
datasourceConfiguration.setUrl(serviceAddress);
@ -221,6 +226,14 @@ public class CloudOSActionSolution {
final String componentId = (String) bp.get("componentId");
final String componentDisplay = componentName == null ? componentId : componentName;
List<Map<String, ?>> cloudOSApiList = (List<Map<String, ?>>) bp.get("apis");
log.debug("绑定组件 " + componentName + " 的API");
log.debug(cloudOSApiList.toString());
Boolean isDbApi = cloudOSApiList.stream().anyMatch(ca -> {
final String apiKey = (String) ca.get("apiKey");
return apiKey != null;
});
final String apiHost = isDbApi ? cloudOSConfig.getDbUrl() : cloudOSConfig.getMockUrl() + "/" + projectId + "/" + componentId;
log.debug("数据源地址:" + apiHost);
// create new datasource
Datasource newSource = new Datasource();
@ -229,7 +242,7 @@ public class CloudOSActionSolution {
newSource.setName(componentDisplay);
DatasourceConfiguration datasourceConfiguration = new DatasourceConfiguration();
datasourceConfiguration.setUrl(cloudOSConfig.getMockUrl() + "/" + projectId + "/" + componentId);
datasourceConfiguration.setUrl(apiHost);
ArrayList<Property> properties = new ArrayList<>();
properties.add(new Property("isSendSessionEnabled", "N"));
properties.add(new Property("sessionSignatureKey", ""));

View File

@ -101,5 +101,6 @@ google.recaptcha.key.secret= ${APPSMITH_RECAPTCHA_SECRET_KEY:}
# CloudOS config
pageplug.cloudos.api_baseurl = ${CLOUDOS_API_BASE_URL:}
pageplug.cloudos.mock_baseurl = ${CLOUDOS_MOCK_BASE_URL:}
pageplug.cloudos.db_baseurl = ${CLOUDOS_DB_BASE_URL:}
pageplug.cloudos.in_cloudos = ${CLOUDOS_IN_CLOUDOS:false}
pageplug.cloudos.jwt_secret_key = ${CLOUDOS_JWT_SECRET_KET:}

View File

@ -13,6 +13,7 @@ APPSMITH_CODEC_SIZE=10
CLOUDOS_API_BASE_URL="http://10.10.11.20:8035"
CLOUDOS_MOCK_BASE_URL="http://10.10.11.20:8899"
CLOUDOS_DB_BASE_URL="http://db-manager.dev.staros.local/api/db-manager"
CLOUDOS_IN_CLOUDOS=false
CLOUDOS_JWT_SECRET_KET="jKriFBzevooCpDi"