diff --git a/README-en.md b/README-en.md new file mode 100644 index 00000000000..43e72ea4c96 --- /dev/null +++ b/README-en.md @@ -0,0 +1,115 @@ +
+

+ +

+ +[Documentation (China)](https://aisuda.bce.baidu.com/amis/) | +[Documentation (Global)](https://baidu.github.io/amis/) | +[Visual Editor](https://aisuda.github.io/amis-editor-demo/) | +[amis-admin](https://github.com/aisuda/amis-admin) | +[AiSuDa](https://aisuda.baidu.com/) + +
+ +
+ Ruliu Group: 3395342 | + Ruliu Group 2: 5511067 | +
+ +
+ +![build](https://img.shields.io/github/actions/workflow/status/baidu/amis/gh-pages.yml) +![license](https://img.shields.io/github/license/baidu/amis.svg) +![version](https://img.shields.io/npm/v/amis) +![language](https://img.shields.io/github/languages/top/baidu/amis) +[![codecov](https://codecov.io/gh/baidu/amis/branch/master/graph/badge.svg?token=9LwimHGoE5)](https://codecov.io/gh/baidu/amis) +![last](https://img.shields.io/github/last-commit/baidu/amis.svg) + +
+ +A low-code front-end framework that allows you to generate various backend pages using JSON configuration, greatly reducing development costs, and even eliminating the need for front-end expertise. + +## Development Guide + +The following is for those who want to contribute to the development of amis. For usage, refer to the documentation above. + +> If GitHub downloads are slow, you can use the mirror on [gitee](https://gitee.com/baidu/amis). + +Node.js versions 12/14/16 are recommended. Use npm 7+ because the workspaces feature is required. + +```bash +# Install project dependencies. There may be errors with Node.js 12, but they don't affect normal use. +npm i --legacy-peer-deps + +# Start the project. Once compilation is complete, access it at http://127.0.0.1:8888/examples/pages/simple. +npm start +``` + +If you're developing the editor, access it at `http://127.0.0.1:8888/packages/amis-editor/`. + +### Testing + +> Note: After modifying code locally, you must run npm run build to complete compilation before executing test cases (`npm test --workspaces`), as Jest doesn't support TypeScript directly. + +```bash +# Install dependencies +npm i --legacy-peer-deps + +# Build the project +npm run build + +# Run all test cases +npm test --workspaces + +# Run a specific test case +# is the name of the test case, e.g., inputImage +npm test --workspace amis -- -t + +# Run a specific test file +./node_modules/.bin/jest packages/amis/__tests__/renderers/Form/buttonToolBar.test.tsx + +# Run a specific example in a test file +./node_modules/.bin/jest packages/amis/__tests__/renderers/Form/buttonToolBar.test.tsx -t 'Renderer:button-toolbar' + +# View test coverage +npm run coverage + +# Update snapshots +npm run update-snapshot + +# Update a single snapshot +# is the name of the test case, e.g., inputImage +npm run update-snapshot --workspace amis -- -t +``` + +### Release Version + +```bash +# Publish to internal registry +npm run publish + +# Publish to external environment +# First, set the version number with the following command +npm run version +npm run release +``` + +### How to Contribute + +Please use a branch for development. First, create a branch: + + git checkout -b feat-xxx + +After committing your changes, use `git push --set-upstream origin feat-xxx` to create a remote branch. + +Then submit a PR using the system-generated link: https://github.com/xxx/amis/pull/new/feat-xxx. + +Please write in TypeScript. All reasonable changes, new public renderers, test cases, or documentation submissions will be accepted. + +## Contributors + + + +## Low-Code Platform + +amis enables low-code front-end development. For a complete low-code platform, we recommend using [AiSuDa](https://aisuda.baidu.com/). diff --git a/docs/zh-CN/components/form/location-picker.md b/docs/zh-CN/components/form/location-picker.md index 4102f64d671..d7476a7fe12 100644 --- a/docs/zh-CN/components/form/location-picker.md +++ b/docs/zh-CN/components/form/location-picker.md @@ -30,6 +30,47 @@ order: 30 注意其中的 `ak` 参数只能在 amis 官网示例中使用,请前往[百度地图开放平台](http://lbsyun.baidu.com/)申请自己的 `ak`。 +## 静态展示 + +```schema: scope="body" +{ + "type": "form", + "debug": true, + "body": [ + { + "type": "location-picker", + "name": "location", + "ak": "LiZT5dVbGTsPI91tFGcOlSpe5FDehpf7", + "label": "默认展示方式", + "value": { + "address": "北京市西城区复兴门内大街97号", + "lat": 39.91404014231763, + "lng": 116.36857981150743, + "zoom": 12 + }, + "static": true + }, + { + "type": "location-picker", + "name": "location", + "ak": "LiZT5dVbGTsPI91tFGcOlSpe5FDehpf7", + "label": "内嵌地图展示", + "value": { + "address": "北京市西城区复兴门内大街97号", + "lat": 39.91404014231763, + "lng": 116.36857981150743, + "zoom": 12 + }, + "static": true, + "staticSchema": { + "embed": true, + "showAddress": true + } + } + ] +} +``` + ## 高德地图(暂不支持) ```schema: scope="body" @@ -57,16 +98,21 @@ order: 30 当做选择器表单项使用时,除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置 -| 属性名 | 类型 | 默认值 | 说明 | -| -------------------- | ------------------ | ------------------------------------ | -------------------------------------------------------------------------------- | -| value | `LocationData` | 参考 [`LocationData`](#LocationData) | | -| vendor | 'baidu' \| 'gaode' | 'baidu' | 地图厂商,目前只实现了百度地图和高德地图 | -| ak | `string` | 无 | 百度/高德地图的 ak | -| clearable | `boolean` | false | 输入框是否可清空 | -| placeholder | `string` | '请选择位置' | 默认提示 | -| autoSelectCurrentLoc | `boolean` | false | 是否自动选中当前地理位置 | -| onlySelectCurrentLoc | `boolean` | false | 是否限制只能选中当前地理位置,设置为 true 后,可用于充当定位组件 | -| coordinatesType | 'bd09' \| 'gcj02' | 'bd09' | 坐标系类型,默认百度坐标,使用高德地图时应设置为'gcj02', 高德地图不支持坐标转换 | +| 属性名 | 类型 | 默认值 | 说明 | +| ------------------------ | ------------------ | ------------------------------------ | -------------------------------------------------------------------------------- | +| value | `LocationData` | 参考 [`LocationData`](#LocationData) | | +| vendor | 'baidu' \| 'gaode' | 'baidu' | 地图厂商,目前只实现了百度地图和高德地图 | +| ak | `string` | 无 | 百度/高德地图的 ak | +| clearable | `boolean` | false | 输入框是否可清空 | +| placeholder | `string` | '请选择位置' | 默认提示 | +| autoSelectCurrentLoc | `boolean` | false | 是否自动选中当前地理位置 | +| onlySelectCurrentLoc | `boolean` | false | 是否限制只能选中当前地理位置,设置为 true 后,可用于充当定位组件 | +| coordinatesType | 'bd09' \| 'gcj02' | 'bd09' | 坐标系类型,默认百度坐标,使用高德地图时应设置为'gcj02', 高德地图不支持坐标转换 | +| staticSchema | `object` | | 静态展示,内嵌模式`{static: true: embed: true}`时的额外配置 | +| staticSchema.embed | `boolean` | false | 是否内嵌地图展示地理位置 | +| staticSchema.showAddress | `boolean` | true | 内嵌模式是否展示文字地址 | +| staticSchema.showGeoLoc | `boolean` | false | 内嵌模式是否展示定位当当前控件 | +| staticSchema.mapStyle | `object` | | 内嵌模式地图的样式,可以传宽高控制大小 | ### 坐标系说明 diff --git a/docs/zh-CN/components/table.md b/docs/zh-CN/components/table.md index dbbd98766fc..c5146570f47 100755 --- a/docs/zh-CN/components/table.md +++ b/docs/zh-CN/components/table.md @@ -1874,6 +1874,7 @@ popOver 的其它配置请参考 [popover](./popover) | align | `left` \| `right` \| `center` \| `justify` | | 单元格对齐方式 | ` 1.4.0` | | headerAlign | `left` \| `right` \| `center` \| `justify` | | 表头单元格对齐方式 | `6.7.0` | | vAlign | `top` \| `middle` \| `bottom` | | 单元格垂直对齐方式 | `6.7.0` | +| textOverflow | `string` |`default`| 文本溢出后展示形式,默认换行处理。可选值 `ellipsis` 溢出隐藏展示, `noWrap` 不换行展示(仅在列为静态文本时生效) | `6.10.0` | ## 事件表 diff --git a/docs/zh-CN/components/table2.md b/docs/zh-CN/components/table2.md index b9b5af8087e..933435e5cfd 100755 --- a/docs/zh-CN/components/table2.md +++ b/docs/zh-CN/components/table2.md @@ -3314,6 +3314,56 @@ order: 67 } ``` +可以给列配置上`textOverflow`属性,设置为`ellipsis`,可实现内容超出省略,悬浮查看更多。 +可搭配`popOver`属性,来控制弹出框的信息,需要设置图标不展示。 + +```schema: scope="body" +{ + "type": "service", + "api": "/api/sample?perPage=6", + "body": [ + { + "type": "table2", + "source": "$rows", + "columns": [ + { + "title": "Engine", + "name": "engine", + }, + { + "title": "Version", + "name": "version" + }, + { + "type": "tpl", + "title": "Browser", + "name": "browser", + "tpl": "${browser+'--'+browser}", + "textOverflow": "ellipsis", + "popOver": { + "trigger": "hover", + "position": "right-top-center-bottom", + "showIcon": false, + "body": { + "type": "tpl", + "tpl": "${browser}" + } + } + }, + { + "title": "Badge", + "name": "badgeText" + }, + { + "title": "Platform", + "name": "platform" + } + ] + } + ] +} +``` + 可以给列配置`popOverEnableOn`属性,该属性为表达式,来控制当前行是否启动`popOver`功能。 ```schema: scope="body" @@ -4163,6 +4213,7 @@ order: 67 | searchable | `boolean` \| `Schema` | `false` | 是否可快速搜索 | | width | `number` \| `string` | 列宽 | | remark | | | 提示信息 | +| textOverflow | `string` |`default`| 文本溢出后展示形式,默认换行处理。可选值 `ellipsis` 溢出隐藏展示, `noWrap` 不换行展示(仅在列为静态文本时生效) | ## 事件表 diff --git a/packages/amis-editor/src/plugin/Form/InputTable.tsx b/packages/amis-editor/src/plugin/Form/InputTable.tsx index ccb2812cda4..29d9eea08a7 100644 --- a/packages/amis-editor/src/plugin/Form/InputTable.tsx +++ b/packages/amis-editor/src/plugin/Form/InputTable.tsx @@ -1187,7 +1187,7 @@ export class TableControlPlugin extends BasePlugin { '确认模式', '开启时,新增、编辑需要点击表格右侧的“保存”按钮才能变更组件数据。未开启时,新增、编辑、删除操作直接改变组件数据。' ), - isChecked: (v: any) => v !== false, + isChecked: (v: any) => v.value !== false, falseValue: false, mode: 'normal', formType: 'extend', diff --git a/packages/amis-editor/src/renderer/style-control/ColSize.tsx b/packages/amis-editor/src/renderer/style-control/ColSize.tsx index 34076ab465c..db3b7d7695a 100644 --- a/packages/amis-editor/src/renderer/style-control/ColSize.tsx +++ b/packages/amis-editor/src/renderer/style-control/ColSize.tsx @@ -29,7 +29,8 @@ function getColSize(value: string, count: number) { const ColSize: React.FC = props => { const store = props.manager.store; - const body = [...store.getSchemaParentById(store.activeId)]; + const containerBody = store.getSchemaParentById(store.activeId); + const body = Array.isArray(containerBody) ? [...containerBody] : []; const node = store.getNodeById(store.activeId); const row = props.data.row; const rowItem = body.filter((item: any) => item.row === row); @@ -43,7 +44,10 @@ const ColSize: React.FC = props => { const tabsMode = parent?.schema?.tabsMode; const isComboRow = type === 'combo' && !multiLine && !tabsMode; - const value = isFlex || isComboRow ? props.data.colSize : props.data.size; + const value = + (isFlex || isComboRow) && body.length + ? props.data.colSize + : props.data.size; function handleColSizeChange(value: string) { if ( @@ -105,7 +109,7 @@ const ColSize: React.FC = props => { props.setValue(value, 'size'); } - return isFlex || isComboRow ? ( + return (isFlex || isComboRow) && body.length ? (
{baseColSize .filter(n => { diff --git a/packages/amis-ui/scss/components/_popoverable.scss b/packages/amis-ui/scss/components/_popoverable.scss index d7361c794f6..e229d1ec563 100644 --- a/packages/amis-ui/scss/components/_popoverable.scss +++ b/packages/amis-ui/scss/components/_popoverable.scss @@ -12,15 +12,15 @@ } } +.#{$ns}TableCell-ellipsis { + display: flex; + align-items: center; +} + .#{$ns}Field--popOverAble { outline: none; position: relative; - &--flex { - display: flex; - align-items: center; - } - .#{$ns}Field-popOverWrap { &-ellipsis { width: 200px; diff --git a/packages/amis-ui/scss/components/form/_user-select.scss b/packages/amis-ui/scss/components/form/_user-select.scss index 087e8459b19..df0b0763776 100644 --- a/packages/amis-ui/scss/components/form/_user-select.scss +++ b/packages/amis-ui/scss/components/form/_user-select.scss @@ -12,7 +12,7 @@ &-selectPopup { width: 100vw; height: 100vh; - z-index: var($zindex-top) + 1; + z-index: calc(var($zindex-top) + 1); } &-searchBox { diff --git a/packages/amis-ui/src/components/BaiduMapPicker.tsx b/packages/amis-ui/src/components/BaiduMapPicker.tsx index 3765ee48ef0..5183adbbeef 100644 --- a/packages/amis-ui/src/components/BaiduMapPicker.tsx +++ b/packages/amis-ui/src/components/BaiduMapPicker.tsx @@ -36,10 +36,14 @@ interface MapPickerProps { lat: number; lng: number; city?: string; + zoom?: number; }; onChange?: (value: any) => void; autoSelectCurrentLoc?: boolean; onlySelectCurrentLoc?: boolean; + showSug?: boolean; + showGeoLoc?: boolean; + mapStyle?: React.CSSProperties; } interface LocationItem { @@ -122,15 +126,16 @@ export class BaiduMapPicker extends React.Component< let point = value ? new BMap.Point(value.lng, value.lat) : new BMap.Point(116.404, 39.915); + const zoom = value?.zoom || 15; if (this.props.coordinatesType == 'gcj02') { point = await this.covertPoint( point, COORDINATES_GCJ02, COORDINATES_BD09 ); - map.centerAndZoom(point, 15); + map.centerAndZoom(point, zoom); } else { - map.centerAndZoom(point, 15); + map.centerAndZoom(point, zoom); } map.addControl( @@ -142,7 +147,9 @@ export class BaiduMapPicker extends React.Component< geolocationControl.addEventListener('locationSuccess', (e: any) => { this.getLocations(e.point, autoSelectCurrentLoc); }); - map.addControl(geolocationControl); + if (this.props.showGeoLoc === true) { + map.addControl(geolocationControl); + } map.addEventListener('click', (e: any) => { if (this.props.onlySelectCurrentLoc) { @@ -340,9 +347,10 @@ export class BaiduMapPicker extends React.Component< } render() { - const {classnames: cx} = this.props; + const {classnames: cx, mapStyle} = this.props; const onlySelectCurrentLoc = this.props.onlySelectCurrentLoc ?? false; const {locIndex, locs, inputValue, sugs} = this.state; + const showSug = this.props.showSug ?? true; const hasSug = Array.isArray(sugs) && sugs.length; return ( @@ -364,43 +372,50 @@ export class BaiduMapPicker extends React.Component< className={cx('MapPicker-map', { invisible: hasSug })} + style={mapStyle} /> -
- {!onlySelectCurrentLoc && - locs.map((item, index) => ( + {!showSug ? null : ( +
+ {!onlySelectCurrentLoc && + locs.map((item, index) => ( +
+
{item.title}
+
{item.address}
+ {locIndex === index ? ( + + ) : null} +
+ ))} + {onlySelectCurrentLoc && locs.length > 0 && (
-
{item.title}
-
{item.address}
- {locIndex === index ? ( +
{locs[0].title}
+
+ {locs[0].address} +
+ {locIndex === 0 ? ( ) : null}
- ))} - {onlySelectCurrentLoc && locs.length > 0 && ( -
-
{locs[0].title}
-
{locs[0].address}
- {locIndex === 0 ? : null} -
- )} -
+ )} +
+ )} - {hasSug && !onlySelectCurrentLoc ? ( + {showSug && hasSug && !onlySelectCurrentLoc ? (
{sugs.map(item => (
{ } } /** - * 非大数模式下,如果精度不满足要求,需要处理value值,遵循四舍五入的处理规则 + * 非大数模式下,如果精度不满足要求,需要处理value值,只做精度处理,不做四舍五入 */ if (!isBig && getNumberPrecision(value) !== precision) { - value = getMiniDecimal( - toFixed(num2str(value), '.', precision) - ).toNumber(); + const multiplier = Math.pow(10, precision); + const truncatedValue = Math.trunc(value * multiplier) / multiplier; + value = getMiniDecimal(truncatedValue).toNumber(); } return value; diff --git a/packages/amis/__tests__/renderers/__snapshots__/Picker.test.tsx.snap b/packages/amis/__tests__/renderers/__snapshots__/Picker.test.tsx.snap index 94ca95c5442..49cf54bec3e 100644 --- a/packages/amis/__tests__/renderers/__snapshots__/Picker.test.tsx.snap +++ b/packages/amis/__tests__/renderers/__snapshots__/Picker.test.tsx.snap @@ -28,10 +28,10 @@ exports[`1. Renderer:Picker base 1`] = ` class="cxd-PickerControl cxd-Form-control" >
{ } renderStatic(displayValue = '-') { - const {classnames: cx, value} = this.props; + const { + classnames: cx, + value, + staticSchema, + ak, + coordinatesType + } = this.props; const __ = this.props.translate; if (!value) { @@ -153,7 +159,25 @@ export class LocationControl extends React.Component { })} ref={this.domRef} > - {value.address} + {staticSchema?.embed ? ( + <> + {staticSchema.showAddress === false ? null : ( +
{value.address}
+ )} + + + ) : ( + {value.address} + )}
); } diff --git a/packages/amis/src/renderers/Form/Picker.tsx b/packages/amis/src/renderers/Form/Picker.tsx index 0bc67fbd6a2..5bae47343d3 100644 --- a/packages/amis/src/renderers/Form/Picker.tsx +++ b/packages/amis/src/renderers/Form/Picker.tsx @@ -456,7 +456,9 @@ export default class PickerControl extends React.PureComponent< } @autobind - handleFocus() { + handleFocus(e: React.MouseEvent) { + this.input.current && this.input.current.focus(); + e.stopPropagation(); this.setState({ isFocused: true }); @@ -471,7 +473,6 @@ export default class PickerControl extends React.PureComponent< @autobind handleClick() { - this.input.current && this.input.current.focus(); this.open(); } @@ -816,7 +817,7 @@ export default class PickerControl extends React.PureComponent< value={''} ref={this.input} onKeyDown={this.handleKeyDown} - onFocus={this.handleFocus} + onClick={this.handleFocus} onBlur={this.handleBlur} readOnly={mobileUI} /> diff --git a/packages/amis/src/renderers/Image.tsx b/packages/amis/src/renderers/Image.tsx index f5470485926..a327cea4a34 100644 --- a/packages/amis/src/renderers/Image.tsx +++ b/packages/amis/src/renderers/Image.tsx @@ -623,7 +623,7 @@ export class ImageField extends React.Component< themeCss: wrapperCustomStyle }) )} - style={{...style, transform: `scale(${this.state.scale})`}} + style={{transform: `scale(${this.state.scale})`, ...style}} onClick={this.handleClick} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} diff --git a/packages/amis/src/renderers/PopOver.tsx b/packages/amis/src/renderers/PopOver.tsx index 3fa4b01d479..cbb7fdfdce9 100644 --- a/packages/amis/src/renderers/PopOver.tsx +++ b/packages/amis/src/renderers/PopOver.tsx @@ -365,12 +365,8 @@ export const HocPopOver = ); } - // 便于外围扩充函数,勿动 getClassName() { - const {textOverflow, getClassName} = this.props; - if (getClassName) { - return getClassName(); - } + const {textOverflow} = this.props; return textOverflow === 'default' ? '' : textOverflow; } @@ -413,9 +409,7 @@ export const HocPopOver = diff --git a/packages/amis/src/renderers/Table/TableCell.tsx b/packages/amis/src/renderers/Table/TableCell.tsx index f34dba8e828..cc70d14117a 100644 --- a/packages/amis/src/renderers/Table/TableCell.tsx +++ b/packages/amis/src/renderers/Table/TableCell.tsx @@ -68,6 +68,7 @@ export class TableCell extends React.Component { row, showBadge, itemBadge, + textOverflow, testIdBuilder, ...rest } = this.props; @@ -188,7 +189,11 @@ export class TableCell extends React.Component { /> ) : null} {cellPrefix} - {body} + {textOverflow === 'ellipsis' && width ? ( +
{body}
+ ) : ( + body + )} {cellAffix}
);