mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 10:29:19 +08:00
deps: 更新部分第三方库依赖到最新版本 (#2543)
* chore: 更新依赖初步 * 更新部分依赖 * 修复编译报错 * 更新 snapshots
This commit is contained in:
parent
54c13b9809
commit
3641be8d78
@ -83,13 +83,9 @@ exports[`Renderer:formula 1`] = `
|
||||
class="cxd-Number-input-wrap"
|
||||
>
|
||||
<input
|
||||
aria-valuemax="9007199254740991"
|
||||
aria-valuemin="-9007199254740991"
|
||||
aria-valuenow="1"
|
||||
autocomplete="off"
|
||||
class="cxd-Number-input"
|
||||
max="9007199254740991"
|
||||
min="-9007199254740991"
|
||||
role="spinbutton"
|
||||
step="1"
|
||||
value="1"
|
||||
@ -153,13 +149,9 @@ exports[`Renderer:formula 1`] = `
|
||||
class="cxd-Number-input-wrap"
|
||||
>
|
||||
<input
|
||||
aria-valuemax="9007199254740991"
|
||||
aria-valuemin="-9007199254740991"
|
||||
aria-valuenow="2"
|
||||
autocomplete="off"
|
||||
class="cxd-Number-input"
|
||||
max="9007199254740991"
|
||||
min="-9007199254740991"
|
||||
role="spinbutton"
|
||||
step="1"
|
||||
value="2"
|
||||
@ -223,13 +215,9 @@ exports[`Renderer:formula 1`] = `
|
||||
class="cxd-Number-input-wrap"
|
||||
>
|
||||
<input
|
||||
aria-valuemax="9007199254740991"
|
||||
aria-valuemin="-9007199254740991"
|
||||
aria-valuenow="3"
|
||||
autocomplete="off"
|
||||
class="cxd-Number-input"
|
||||
max="9007199254740991"
|
||||
min="-9007199254740991"
|
||||
role="spinbutton"
|
||||
step="1"
|
||||
value="3"
|
||||
@ -293,13 +281,9 @@ exports[`Renderer:formula 1`] = `
|
||||
class="cxd-Number-input-wrap"
|
||||
>
|
||||
<input
|
||||
aria-valuemax="9007199254740991"
|
||||
aria-valuemin="-9007199254740991"
|
||||
aria-valuenow="4"
|
||||
autocomplete="off"
|
||||
class="cxd-Number-input"
|
||||
max="9007199254740991"
|
||||
min="-9007199254740991"
|
||||
role="spinbutton"
|
||||
step="1"
|
||||
value="4"
|
||||
@ -363,13 +347,9 @@ exports[`Renderer:formula 1`] = `
|
||||
class="cxd-Number-input-wrap"
|
||||
>
|
||||
<input
|
||||
aria-valuemax="9007199254740991"
|
||||
aria-valuemin="-9007199254740991"
|
||||
aria-valuenow="5"
|
||||
autocomplete="off"
|
||||
class="cxd-Number-input"
|
||||
max="9007199254740991"
|
||||
min="-9007199254740991"
|
||||
role="spinbutton"
|
||||
step="1"
|
||||
value="5"
|
||||
|
@ -83,13 +83,9 @@ exports[`Renderer:number 1`] = `
|
||||
class="cxd-Number-input-wrap"
|
||||
>
|
||||
<input
|
||||
aria-valuemax="9007199254740991"
|
||||
aria-valuemin="-9007199254740991"
|
||||
aria-valuenow="456"
|
||||
autocomplete="off"
|
||||
class="cxd-Number-input"
|
||||
max="9007199254740991"
|
||||
min="-9007199254740991"
|
||||
role="spinbutton"
|
||||
step="1"
|
||||
value="456"
|
||||
|
@ -741,25 +741,25 @@ props.onAction(event, {
|
||||
|
||||
所有`actionType`都支持的通用配置项
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ---------------- | ------------------------------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| type | `string` | `action` | 指定为 Page 渲染器。 |
|
||||
| actionType | `string` | - | 【必填】这是 action 最核心的配置,来指定该 action 的作用类型,支持:`ajax`、`link`、`url`、`drawer`、`dialog`、`confirm`、`cancel`、`prev`、`next`、`copy`、`close`。 |
|
||||
| label | `string` | - | 按钮文本。可用 `${xxx}` 取值。 |
|
||||
| level | `string` | `default` | 按钮样式,支持:`link`、`primary`、`secondary`、`info`、`success`、`warning`、`danger`、`light`、`dark`、`default`。 |
|
||||
| size | `string` | - | 按钮大小,支持:`xs`、`sm`、`md`、`lg`。 |
|
||||
| icon | `string` | - | 设置图标,例如`fa fa-plus`。 |
|
||||
| iconClassName | `string` | - | 给图标上添加类名。 |
|
||||
| rightIcon | `string` | - | 在按钮文本右侧设置图标,例如`fa fa-plus`。 |
|
||||
| rightIconClassName | `string` | - | 给右侧图标上添加类名。 |
|
||||
| active | `boolean` | - | 按钮是否高亮。 |
|
||||
| activeLevel | `string` | - | 按钮高亮时的样式,配置支持同`level`。 |
|
||||
| activeClassName | `string` | `is-active` | 给按钮高亮添加类名。 |
|
||||
| block | `boolean` | - | 用`display:"block"`来显示按钮。 |
|
||||
| confirmText | [模板](../../docs/concepts/template) | - | 当设置后,操作在开始前会询问用户。可用 `${xxx}` 取值。 |
|
||||
| reload | `string` | - | 指定此次操作完后,需要刷新的目标组件名字(组件的`name`值,自己配置的),多个请用 `,` 号隔开。 |
|
||||
| tooltip | `string` | - | 鼠标停留时弹出该段文字,也可以配置对象类型:字段为`title`和`content`。可用 `${xxx}` 取值。 |
|
||||
| disabledTip | `string` | - | 被禁用后鼠标停留时弹出该段文字,也可以配置对象类型:字段为`title`和`content`。可用 `${xxx}` 取值。 |
|
||||
| tooltipPlacement | `string` | `top` | 如果配置了`tooltip`或者`disabledTip`,指定提示信息位置,可配置`top`、`bottom`、`left`、`right`。 |
|
||||
| close | `boolean` or `string` | - | 当`action`配置在`dialog`或`drawer`的`actions`中时,配置为`true`指定此次操作完后关闭当前`dialog`或`drawer`。当值为字符串,并且是祖先层弹框的名字的时候,会把祖先弹框关闭掉。 |
|
||||
| required | `Array<string>` | - | 配置字符串数组,指定在`form`中进行操作之前,需要指定的字段名的表单项通过验证 |
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ------------------ | ------------------------------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| type | `string` | `action` | 指定为 Page 渲染器。 |
|
||||
| actionType | `string` | - | 【必填】这是 action 最核心的配置,来指定该 action 的作用类型,支持:`ajax`、`link`、`url`、`drawer`、`dialog`、`confirm`、`cancel`、`prev`、`next`、`copy`、`close`。 |
|
||||
| label | `string` | - | 按钮文本。可用 `${xxx}` 取值。 |
|
||||
| level | `string` | `default` | 按钮样式,支持:`link`、`primary`、`secondary`、`info`、`success`、`warning`、`danger`、`light`、`dark`、`default`。 |
|
||||
| size | `string` | - | 按钮大小,支持:`xs`、`sm`、`md`、`lg`。 |
|
||||
| icon | `string` | - | 设置图标,例如`fa fa-plus`。 |
|
||||
| iconClassName | `string` | - | 给图标上添加类名。 |
|
||||
| rightIcon | `string` | - | 在按钮文本右侧设置图标,例如`fa fa-plus`。 |
|
||||
| rightIconClassName | `string` | - | 给右侧图标上添加类名。 |
|
||||
| active | `boolean` | - | 按钮是否高亮。 |
|
||||
| activeLevel | `string` | - | 按钮高亮时的样式,配置支持同`level`。 |
|
||||
| activeClassName | `string` | `is-active` | 给按钮高亮添加类名。 |
|
||||
| block | `boolean` | - | 用`display:"block"`来显示按钮。 |
|
||||
| confirmText | [模板](../../docs/concepts/template) | - | 当设置后,操作在开始前会询问用户。可用 `${xxx}` 取值。 |
|
||||
| reload | `string` | - | 指定此次操作完后,需要刷新的目标组件名字(组件的`name`值,自己配置的),多个请用 `,` 号隔开。 |
|
||||
| tooltip | `string` | - | 鼠标停留时弹出该段文字,也可以配置对象类型:字段为`title`和`content`。可用 `${xxx}` 取值。 |
|
||||
| disabledTip | `string` | - | 被禁用后鼠标停留时弹出该段文字,也可以配置对象类型:字段为`title`和`content`。可用 `${xxx}` 取值。 |
|
||||
| tooltipPlacement | `string` | `top` | 如果配置了`tooltip`或者`disabledTip`,指定提示信息位置,可配置`top`、`bottom`、`left`、`right`。 |
|
||||
| close | `boolean` or `string` | - | 当`action`配置在`dialog`或`drawer`的`actions`中时,配置为`true`指定此次操作完后关闭当前`dialog`或`drawer`。当值为字符串,并且是祖先层弹框的名字的时候,会把祖先弹框关闭掉。 |
|
||||
| required | `Array<string>` | - | 配置字符串数组,指定在`form`中进行操作之前,需要指定的字段名的表单项通过验证 |
|
||||
|
@ -131,8 +131,7 @@ app.listen(8080, function () {
|
||||
{
|
||||
"type": "input-image",
|
||||
"name": "image",
|
||||
"label": "限制只能上传jpg图片",
|
||||
"accept": ".jpg",
|
||||
"label": "上传后裁剪",
|
||||
"receiver": "/api/upload/file",
|
||||
"crop": true
|
||||
}
|
||||
@ -140,6 +139,26 @@ app.listen(8080, function () {
|
||||
}
|
||||
```
|
||||
|
||||
设置裁剪比例等配置,具体细节可以参考[这里](https://github.com/fengyuanchen/cropperjs#options)。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-image",
|
||||
"name": "image",
|
||||
"label": "上传后裁剪",
|
||||
"receiver": "/api/upload/file",
|
||||
"crop": {
|
||||
"aspectRatio": 1.7777
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 自动填充
|
||||
|
||||
上传成功后,可以通过配置 `autoFill` 将上传接口返回的值填充到某个表单项中:
|
||||
|
35
package.json
35
package.json
@ -43,22 +43,20 @@
|
||||
"attr-accept": "2.2.2",
|
||||
"blueimp-canvastoblob": "2.1.0",
|
||||
"classnames": "2.3.1",
|
||||
"dom-helpers": "^3.3.1",
|
||||
"downshift": "3.1.4",
|
||||
"echarts": "5.2.0",
|
||||
"echarts-stat": "^1.2.0",
|
||||
"exceljs": "^4.3.0",
|
||||
"file-saver": "^2.0.2",
|
||||
"froala-editor": "2.9.6",
|
||||
"highlight.js": "^10.7.2",
|
||||
"hls.js": "1.0.10",
|
||||
"hoist-non-react-statics": "3.3.0",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"immutability-helper": "^3.1.1",
|
||||
"jquery": "^3.2.1",
|
||||
"keycode": "^2.1.9",
|
||||
"lodash": "^4.17.15",
|
||||
"markdown-it": "^12.0.6",
|
||||
"match-sorter": "2.2.1",
|
||||
"match-sorter": "^6.3.0",
|
||||
"mobx": "^4.5.0",
|
||||
"mobx-react": "^6.1.4",
|
||||
"mobx-state-tree": "^3.17.3",
|
||||
@ -68,15 +66,15 @@
|
||||
"papaparse": "^5.3.0",
|
||||
"prop-types": "^15.6.1",
|
||||
"punycode": "^2.1.1",
|
||||
"qrcode.react": "^0.8.0",
|
||||
"qrcode.react": "^1.0.1",
|
||||
"qs": "6.5.1",
|
||||
"rc-input-number": "6.1.1",
|
||||
"rc-input-number": "^7.3.0",
|
||||
"react": "^16.8.6",
|
||||
"react-color": "2.13.8",
|
||||
"react-cropper": "1.0.1",
|
||||
"react-color": "^2.19.3",
|
||||
"react-cropper": "^2.1.8",
|
||||
"react-datetime": "2.16.2",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-dropzone": "11.2.4",
|
||||
"react-dropzone": "^11.3.4",
|
||||
"react-input-range": "1.3.0",
|
||||
"react-json-view": "1.21.3",
|
||||
"react-overlays": "0.8.3",
|
||||
@ -85,16 +83,15 @@
|
||||
"react-visibility-sensor": "3.11.0",
|
||||
"setimmediate": "1.0.5",
|
||||
"sortablejs": "1.14.0",
|
||||
"tinymce": ">=5.9.1",
|
||||
"tinymce": "^5.9.2",
|
||||
"tslib": "^2.3.1",
|
||||
"uncontrollable": "7.0.2",
|
||||
"uncontrollable": "7.2.1",
|
||||
"video-react": "0.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@types/async": "^2.0.45",
|
||||
"@types/dom-helpers": "^3.4.1",
|
||||
"@types/echarts": "^4.9.2",
|
||||
"@types/file-saver": "^2.0.1",
|
||||
"@types/history": "^4.6.0",
|
||||
@ -109,11 +106,9 @@
|
||||
"@types/prop-types": "^15.5.2",
|
||||
"@types/qs": "^6.5.1",
|
||||
"@types/react": "^16.9.35",
|
||||
"@types/react-color": "^2.13.3",
|
||||
"@types/react-cropper": "^0.10.1",
|
||||
"@types/react-color": "^3.0.5",
|
||||
"@types/react-dom": "^16.0.7",
|
||||
"@types/react-dropzone": "^4.1.0",
|
||||
"@types/react-json-tree": "^0.6.6",
|
||||
"@types/react-onclickoutside": "^6.0.2",
|
||||
"@types/react-overlays": "^0.8.4",
|
||||
"@types/react-router": "^3.0.24",
|
||||
@ -126,9 +121,9 @@
|
||||
"bce-sdk-js": "^0.2.9",
|
||||
"concurrently": "^6.2.1",
|
||||
"copy-to-clipboard": "3.3.1",
|
||||
"core-js": "^3.7.0",
|
||||
"core-js": "^3.17.3",
|
||||
"css": "3.0.0",
|
||||
"faker": "^4.1.0",
|
||||
"faker": "^5.5.3",
|
||||
"fis-optimizer-terser": "^1.0.1",
|
||||
"fis-parser-sass": "^1.0.1",
|
||||
"fis-parser-svgr": "^1.0.0",
|
||||
@ -149,16 +144,16 @@
|
||||
"husky": "^7.0.0",
|
||||
"jest": "^27.0.6",
|
||||
"jest-canvas-mock": "^2.3.0",
|
||||
"js-yaml": "^3.10.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json5": "^2.2.0",
|
||||
"marked": "2.0.1",
|
||||
"marked": "^3.0.3",
|
||||
"mkdirp": "^1.0.4",
|
||||
"moment-timezone": "^0.5.33",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"postcss": "^8.2.1",
|
||||
"postcss-cli": "^8.3.1",
|
||||
"postcss-custom-properties": "^11.0.0",
|
||||
"prettier": "2.3.2",
|
||||
"prettier": "^2.4.0",
|
||||
"pretty-quick": "^3.1.1",
|
||||
"prismjs": "^1.20.0",
|
||||
"react-router": "3.2.0",
|
||||
|
@ -16,7 +16,7 @@ glob('./docs/**/*.md', {}, function (er, docs) {
|
||||
let m = rYml.exec(content);
|
||||
let info = {};
|
||||
if (m && m[1]) {
|
||||
info = yaml.safeLoad(m[1]);
|
||||
info = yaml.load(m[1]);
|
||||
content = content.substring(m[0].length);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ module.exports = function (content, file) {
|
||||
var m = rYml.exec(content);
|
||||
var info = {};
|
||||
if (m && m[1]) {
|
||||
info = yaml.safeLoad(m[1]);
|
||||
info = yaml.load(m[1]);
|
||||
content = content.substring(m[0].length);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
import qs from 'qs';
|
||||
import React from 'react';
|
||||
import Alert from './components/Alert2';
|
||||
import ImageGallery from './components/ImageGallery';
|
||||
|
@ -5,9 +5,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import find from 'lodash/find';
|
||||
import PropTypes from 'prop-types';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import qs from 'qs';
|
||||
import {dataMapping} from './utils/tpl-builtin';
|
||||
import {RendererEnv, RendererProps} from './factory';
|
||||
import {noop, autobind, qsstringify, qsparse} from './utils/helper';
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import css from 'dom-helpers/style/index';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import Transition, {
|
||||
EXITED,
|
||||
@ -64,10 +63,9 @@ export class Collapse extends React.Component<CollapseProps, any> {
|
||||
let offsetHeight = elem['offsetHeight'];
|
||||
const height =
|
||||
offsetHeight +
|
||||
parseInt(css(elem, 'marginTop'), 10) +
|
||||
parseInt(css(elem, 'marginBottom'), 10);
|
||||
parseInt(getComputedStyle(elem).getPropertyValue('margin-top'), 10) +
|
||||
parseInt(getComputedStyle(elem).getPropertyValue('margin-bottom'), 10);
|
||||
elem.style['height'] = `${height}px`;
|
||||
|
||||
// trigger browser reflow
|
||||
elem.offsetHeight;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {SketchPicker, GithubPicker, ColorState} from 'react-color';
|
||||
import {SketchPicker, GithubPicker, ColorResult} from 'react-color';
|
||||
import {Icon} from './icons';
|
||||
import Overlay from './Overlay';
|
||||
import {uncontrollable} from 'uncontrollable';
|
||||
@ -176,7 +176,7 @@ export class ColorControl extends React.PureComponent<
|
||||
return image.style.color !== 'rgb(255, 255, 255)';
|
||||
}
|
||||
|
||||
handleChange(color: ColorState) {
|
||||
handleChange(color: ColorResult) {
|
||||
const {
|
||||
onChange,
|
||||
format
|
||||
|
@ -12,8 +12,7 @@ import Overlay from './Overlay';
|
||||
import PopOver from './PopOver';
|
||||
import Downshift, {ControllerStateAndHelpers} from 'downshift';
|
||||
import {closeIcon, Icon} from './icons';
|
||||
// @ts-ignore
|
||||
import matchSorter from 'match-sorter';
|
||||
import {matchSorter} from 'match-sorter';
|
||||
import {noop, isObject, findTree, autobind, ucFirst} from '../utils/helper';
|
||||
import find from 'lodash/find';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
@ -703,11 +702,12 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
|
||||
let checkedAll = false;
|
||||
let checkedPartial = false;
|
||||
let filtedOptions: Array<Option> = (inputValue && isOpen && !loadOptions
|
||||
? matchSorter(options, inputValue, {
|
||||
keys: [labelField || 'label', valueField || 'value']
|
||||
})
|
||||
: options.concat()
|
||||
let filtedOptions: Array<Option> = (
|
||||
inputValue && isOpen && !loadOptions
|
||||
? matchSorter(options, inputValue, {
|
||||
keys: [labelField || 'label', valueField || 'value']
|
||||
})
|
||||
: options.concat()
|
||||
).filter((option: Option) => !option.hidden && option.visible !== false);
|
||||
|
||||
const selectionValues = selection.map(select => select[valueField]);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import qs from 'qs';
|
||||
import {RendererStore, IRendererStore, IIRendererStore} from './store/index';
|
||||
import {getEnv, destroy} from 'mobx-state-tree';
|
||||
import {wrapFetcher} from './utils/api';
|
||||
|
@ -23,7 +23,7 @@ export interface ButtonSchema extends BaseSchema {
|
||||
/**
|
||||
* icon 上的css 类名
|
||||
*/
|
||||
iconClassName?: SchemaClassName;
|
||||
iconClassName?: SchemaClassName;
|
||||
|
||||
/**
|
||||
* 右侧按钮图标, iconfont 的类名
|
||||
@ -33,7 +33,7 @@ export interface ButtonSchema extends BaseSchema {
|
||||
/**
|
||||
* 右侧 icon 上的 css 类名
|
||||
*/
|
||||
rightIconClassName?: SchemaClassName;
|
||||
rightIconClassName?: SchemaClassName;
|
||||
|
||||
/**
|
||||
* 按钮文字
|
||||
@ -365,17 +365,47 @@ import {BadgeSchema, withBadge} from '../components/Badge';
|
||||
import {str2AsyncFunction} from '../utils/api';
|
||||
|
||||
export interface ActionProps
|
||||
extends Omit<ButtonSchema, 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
extends Omit<
|
||||
ButtonSchema,
|
||||
'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
ThemeProps,
|
||||
Omit<AjaxActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<UrlActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<LinkActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<DialogActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<DrawerActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<CopyActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<ReloadActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<EmailActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'>,
|
||||
Omit<OtherActionSchema, 'type' | 'className' | 'iconClassName' | 'rightIconClassName'> {
|
||||
Omit<
|
||||
AjaxActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
UrlActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
LinkActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
DialogActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
DrawerActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
CopyActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
ReloadActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
EmailActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
>,
|
||||
Omit<
|
||||
OtherActionSchema,
|
||||
'type' | 'className' | 'iconClassName' | 'rightIconClassName'
|
||||
> {
|
||||
actionType: any;
|
||||
onAction?: (
|
||||
e: React.MouseEvent<any> | void | null,
|
||||
@ -547,7 +577,12 @@ export class Action extends React.Component<ActionProps, ActionState> {
|
||||
}
|
||||
|
||||
const iconElement = generateIcon(cx, icon, 'Button-icon', iconClassName);
|
||||
const rightIconElement = generateIcon(cx, rightIcon, 'Button-icon', rightIconClassName);
|
||||
const rightIconElement = generateIcon(
|
||||
cx,
|
||||
rightIcon,
|
||||
'Button-icon',
|
||||
rightIconClassName
|
||||
);
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
@ -29,7 +29,6 @@ import Button from '../components/Button';
|
||||
import Select from '../components/Select';
|
||||
import getExprProperties from '../utils/filter-schema';
|
||||
import pick from 'lodash/pick';
|
||||
import qs from 'qs';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {evalExpression, filter} from '../utils/tpl';
|
||||
import {
|
||||
@ -956,12 +955,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
handleDialogClose() {
|
||||
const {
|
||||
store,
|
||||
stopAutoRefreshWhenModalIsOpen,
|
||||
silentPolling,
|
||||
interval
|
||||
} = this.props;
|
||||
const {store, stopAutoRefreshWhenModalIsOpen, silentPolling, interval} =
|
||||
this.props;
|
||||
store.closeDialog();
|
||||
|
||||
if (stopAutoRefreshWhenModalIsOpen && interval) {
|
||||
@ -1194,14 +1189,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
handleSaveOrder(moved: Array<object>, rows: Array<object>) {
|
||||
const {
|
||||
store,
|
||||
saveOrderApi,
|
||||
orderField,
|
||||
primaryField,
|
||||
env,
|
||||
reload
|
||||
} = this.props;
|
||||
const {store, saveOrderApi, orderField, primaryField, env, reload} =
|
||||
this.props;
|
||||
|
||||
if (!saveOrderApi) {
|
||||
env && env.alert('CRUD saveOrderApi is required!');
|
||||
@ -1413,11 +1402,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
}
|
||||
|
||||
handleChildPopOverClose(popOver: any) {
|
||||
const {
|
||||
stopAutoRefreshWhenModalIsOpen,
|
||||
silentPolling,
|
||||
interval
|
||||
} = this.props;
|
||||
const {stopAutoRefreshWhenModalIsOpen, silentPolling, interval} =
|
||||
this.props;
|
||||
|
||||
if (popOver && ~['dialog', 'drawer'].indexOf(popOver.mode)) {
|
||||
this.props.store.setInnerModalOpened(false);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
// @ts-ignore
|
||||
import matchSorter from 'match-sorter';
|
||||
import {matchSorter} from 'match-sorter';
|
||||
import keycode from 'keycode';
|
||||
import Downshift, {StateChangeOptions} from 'downshift';
|
||||
import {autobind} from '../../utils/helper';
|
||||
|
@ -1,7 +1,5 @@
|
||||
import React from 'react';
|
||||
import {FormItem, FormControlProps, FormBaseControl} from './Item';
|
||||
import cx from 'classnames';
|
||||
import qs from 'qs';
|
||||
import find from 'lodash/find';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
// @ts-ignore
|
||||
@ -358,11 +356,12 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
if (value && value instanceof Blob) {
|
||||
files = [value as any];
|
||||
} else if (value) {
|
||||
files = (Array.isArray(value)
|
||||
? value
|
||||
: joinValues
|
||||
? `${(value as any)[valueField] || value}`.split(delimiter)
|
||||
: [value as any]
|
||||
files = (
|
||||
Array.isArray(value)
|
||||
? value
|
||||
: joinValues
|
||||
? `${(value as any)[valueField] || value}`.split(delimiter)
|
||||
: [value as any]
|
||||
)
|
||||
.map(item => FileControl.valueToFile(item, props) as FileValue)
|
||||
.filter(item => item);
|
||||
@ -404,11 +403,12 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
let files: Array<FileValue> = [];
|
||||
|
||||
if (value) {
|
||||
files = (Array.isArray(value)
|
||||
? value
|
||||
: joinValues && typeof value === 'string'
|
||||
? value.split(delimiter)
|
||||
: [value as any]
|
||||
files = (
|
||||
Array.isArray(value)
|
||||
? value
|
||||
: joinValues && typeof value === 'string'
|
||||
? value.split(delimiter)
|
||||
: [value as any]
|
||||
)
|
||||
.map(item => {
|
||||
let obj = FileControl.valueToFile(
|
||||
|
@ -6,7 +6,6 @@ import DropZone from 'react-dropzone';
|
||||
import {FileRejection} from 'react-dropzone';
|
||||
import 'blueimp-canvastoblob';
|
||||
import find from 'lodash/find';
|
||||
import qs from 'qs';
|
||||
import {Payload} from '../../types';
|
||||
import {buildApi} from '../../utils/api';
|
||||
import {
|
||||
@ -389,11 +388,12 @@ export default class ImageControl extends React.Component<
|
||||
|
||||
if (value) {
|
||||
// files = (multiple && Array.isArray(value) ? value : joinValues ? (value as string).split(delimiter) : [value])
|
||||
files = (Array.isArray(value)
|
||||
? value
|
||||
: joinValues && typeof value === 'string' && multiple
|
||||
? (value as string).split(delimiter)
|
||||
: [value]
|
||||
files = (
|
||||
Array.isArray(value)
|
||||
? value
|
||||
: joinValues && typeof value === 'string' && multiple
|
||||
? (value as string).split(delimiter)
|
||||
: [value]
|
||||
)
|
||||
.map(item => ImageControl.valueToFile(item) as FileValue)
|
||||
.filter(item => item);
|
||||
@ -444,11 +444,12 @@ export default class ImageControl extends React.Component<
|
||||
let files: Array<FileValue> = [];
|
||||
|
||||
if (value) {
|
||||
files = (Array.isArray(value)
|
||||
? value
|
||||
: joinValues && typeof value === 'string'
|
||||
? (value as string).split(delimiter)
|
||||
: [value]
|
||||
files = (
|
||||
Array.isArray(value)
|
||||
? value
|
||||
: joinValues && typeof value === 'string'
|
||||
? (value as string).split(delimiter)
|
||||
: [value]
|
||||
)
|
||||
.map(item => {
|
||||
let obj = ImageControl.valueToFile(item, props) as FileValue;
|
||||
@ -1196,14 +1197,8 @@ export default class ImageControl extends React.Component<
|
||||
fixedSizeClassName,
|
||||
translate: __
|
||||
} = this.props;
|
||||
const {
|
||||
files,
|
||||
error,
|
||||
crop,
|
||||
uploading,
|
||||
cropFile,
|
||||
frameImageWidth
|
||||
} = this.state;
|
||||
const {files, error, crop, uploading, cropFile, frameImageWidth} =
|
||||
this.state;
|
||||
let frameImageStyle: any = {};
|
||||
if (fixedSizeClassName && frameImageWidth && fixedSize) {
|
||||
frameImageStyle.width = frameImageWidth;
|
||||
|
@ -7,8 +7,7 @@ import {
|
||||
} from './Options';
|
||||
import {Action} from '../../types';
|
||||
import Downshift, {StateChangeOptions} from 'downshift';
|
||||
// @ts-ignore
|
||||
import matchSorter from 'match-sorter';
|
||||
import {matchSorter} from 'match-sorter';
|
||||
import debouce from 'lodash/debounce';
|
||||
import {filter} from '../../utils/tpl';
|
||||
import find from 'lodash/find';
|
||||
@ -140,14 +139,8 @@ export default class TextControl extends React.PureComponent<
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
formItem,
|
||||
autoComplete,
|
||||
addHook,
|
||||
formInited,
|
||||
data,
|
||||
name
|
||||
} = this.props;
|
||||
const {formItem, autoComplete, addHook, formInited, data, name} =
|
||||
this.props;
|
||||
|
||||
if (isEffectiveApi(autoComplete, data) && formItem) {
|
||||
if (formInited) {
|
||||
@ -470,13 +463,8 @@ export default class TextControl extends React.PureComponent<
|
||||
}
|
||||
|
||||
loadAutoComplete() {
|
||||
const {
|
||||
formItem,
|
||||
autoComplete,
|
||||
data,
|
||||
multiple,
|
||||
selectedOptions
|
||||
} = this.props;
|
||||
const {formItem, autoComplete, data, multiple, selectedOptions} =
|
||||
this.props;
|
||||
|
||||
if (isEffectiveApi(autoComplete, data) && formItem) {
|
||||
formItem.loadOptions(
|
||||
@ -564,9 +552,8 @@ export default class TextControl extends React.PureComponent<
|
||||
{
|
||||
'is-opened': isOpen,
|
||||
'TextControl-input--multiple': multiple,
|
||||
[`TextControl-input--border${ucFirst(
|
||||
[`TextControl-input--border${ucFirst(borderMode)}`]:
|
||||
borderMode
|
||||
)}`]: borderMode
|
||||
}
|
||||
)}
|
||||
onClick={this.handleClick}
|
||||
|
@ -10,8 +10,7 @@ import {
|
||||
} from './Options';
|
||||
import {Icon} from '../../components/icons';
|
||||
import TreeSelector from '../../components/Tree';
|
||||
// @ts-ignore
|
||||
import matchSorter from 'match-sorter';
|
||||
import {matchSorter} from 'match-sorter';
|
||||
import debouce from 'lodash/debounce';
|
||||
import find from 'lodash/find';
|
||||
import {Api} from '../../types';
|
||||
@ -297,8 +296,9 @@ export default class TreeSelectControl extends React.Component<
|
||||
|
||||
if (!option.visible && option.children) {
|
||||
option.children = this.filterOptions(option.children, keywords);
|
||||
const visibleCount = option.children.filter(item => item.visible)
|
||||
.length;
|
||||
const visibleCount = option.children.filter(
|
||||
item => item.visible
|
||||
).length;
|
||||
option.visible = !!visibleCount;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,6 @@ import Scoped, {
|
||||
ScopedComponentType
|
||||
} from '../../Scoped';
|
||||
import {IComboStore} from '../../store/combo';
|
||||
import qs from 'qs';
|
||||
import {dataMapping} from '../../utils/tpl-builtin';
|
||||
import {isApiOutdated, isEffectiveApi} from '../../utils/api';
|
||||
import Spinner from '../../components/Spinner';
|
||||
|
@ -12,9 +12,7 @@ import {
|
||||
FunctionPropertyNames
|
||||
} from '../types';
|
||||
import {filter, evalExpression} from '../utils/tpl';
|
||||
import cx from 'classnames';
|
||||
import qs from 'qs';
|
||||
import {isVisible, autobind, bulkBindFunctions, uuid} from '../utils/helper';
|
||||
import {isVisible, autobind, bulkBindFunctions} from '../utils/helper';
|
||||
import {ScopedContext, IScopedContext} from '../Scoped';
|
||||
import Alert from '../components/Alert2';
|
||||
import {isApiOutdated, isEffectiveApi} from '../utils/api';
|
||||
|
@ -5,16 +5,10 @@
|
||||
|
||||
import React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import find from 'lodash/find';
|
||||
import PropTypes from 'prop-types';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
import {RendererProps} from '../factory';
|
||||
import cx from 'classnames';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import onClickOutside from 'react-onclickoutside';
|
||||
import {Action} from '../types';
|
||||
import keycode from 'keycode';
|
||||
import matches from 'dom-helpers/query/matches';
|
||||
import Overlay from '../components/Overlay';
|
||||
import PopOver from '../components/PopOver';
|
||||
import {Icon} from '../components/icons';
|
||||
@ -90,489 +84,487 @@ export interface QuickEditState {
|
||||
let inited: boolean = false;
|
||||
let currentOpened: any;
|
||||
|
||||
export const HocQuickEdit = (config: Partial<QuickEditConfig> = {}) => (
|
||||
Component: React.ComponentType<any>
|
||||
): any => {
|
||||
class QuickEditComponent extends React.PureComponent<
|
||||
QuickEditProps,
|
||||
QuickEditState
|
||||
> {
|
||||
target: HTMLElement;
|
||||
overlay: HTMLElement;
|
||||
static ComposedComponent = Component;
|
||||
constructor(props: QuickEditProps) {
|
||||
super(props);
|
||||
export const HocQuickEdit =
|
||||
(config: Partial<QuickEditConfig> = {}) =>
|
||||
(Component: React.ComponentType<any>): any => {
|
||||
class QuickEditComponent extends React.PureComponent<
|
||||
QuickEditProps,
|
||||
QuickEditState
|
||||
> {
|
||||
target: HTMLElement;
|
||||
overlay: HTMLElement;
|
||||
static ComposedComponent = Component;
|
||||
constructor(props: QuickEditProps) {
|
||||
super(props);
|
||||
|
||||
this.openQuickEdit = this.openQuickEdit.bind(this);
|
||||
this.closeQuickEdit = this.closeQuickEdit.bind(this);
|
||||
this.handleAction = this.handleAction.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleKeyUp = this.handleKeyUp.bind(this);
|
||||
this.overlayRef = this.overlayRef.bind(this);
|
||||
this.handleWindowKeyPress = this.handleWindowKeyPress.bind(this);
|
||||
this.handleWindowKeyDown = this.handleWindowKeyDown.bind(this);
|
||||
this.formRef = this.formRef.bind(this);
|
||||
this.handleInit = this.handleInit.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.openQuickEdit = this.openQuickEdit.bind(this);
|
||||
this.closeQuickEdit = this.closeQuickEdit.bind(this);
|
||||
this.handleAction = this.handleAction.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleKeyUp = this.handleKeyUp.bind(this);
|
||||
this.overlayRef = this.overlayRef.bind(this);
|
||||
this.handleWindowKeyPress = this.handleWindowKeyPress.bind(this);
|
||||
this.handleWindowKeyDown = this.handleWindowKeyDown.bind(this);
|
||||
this.formRef = this.formRef.bind(this);
|
||||
this.handleInit = this.handleInit.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
isOpened: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.target = findDOMNode(this) as HTMLElement;
|
||||
|
||||
if (inited) {
|
||||
return;
|
||||
this.state = {
|
||||
isOpened: false
|
||||
};
|
||||
}
|
||||
|
||||
inited = true;
|
||||
document.body.addEventListener('keypress', this.handleWindowKeyPress);
|
||||
document.body.addEventListener('keydown', this.handleWindowKeyDown);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.target = findDOMNode(this) as HTMLElement;
|
||||
|
||||
formRef(ref: any) {
|
||||
const {quickEditFormRef, rowIndex, colIndex} = this.props;
|
||||
|
||||
if (quickEditFormRef) {
|
||||
while (ref && ref.getWrappedInstance) {
|
||||
ref = ref.getWrappedInstance();
|
||||
if (inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
quickEditFormRef(ref, colIndex, rowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
handleWindowKeyPress(e: Event) {
|
||||
const ns = this.props.classPrefix;
|
||||
let el: HTMLElement = (e.target as HTMLElement).closest(
|
||||
`.${ns}Field--quickEditable`
|
||||
) as HTMLElement;
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
const table = el.closest('table');
|
||||
if (!table) {
|
||||
return;
|
||||
inited = true;
|
||||
document.body.addEventListener('keypress', this.handleWindowKeyPress);
|
||||
document.body.addEventListener('keydown', this.handleWindowKeyDown);
|
||||
}
|
||||
|
||||
if (
|
||||
keycode(e) === 'space' &&
|
||||
!~['INPUT', 'TEXTAREA'].indexOf(el.tagName)
|
||||
) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
formRef(ref: any) {
|
||||
const {quickEditFormRef, rowIndex, colIndex} = this.props;
|
||||
|
||||
handleWindowKeyDown(e: Event) {
|
||||
const code = keycode(e);
|
||||
if (quickEditFormRef) {
|
||||
while (ref && ref.getWrappedInstance) {
|
||||
ref = ref.getWrappedInstance();
|
||||
}
|
||||
|
||||
if (code === 'esc' && currentOpened) {
|
||||
currentOpened.closeQuickEdit();
|
||||
} else if (
|
||||
~['INPUT', 'TEXTAREA'].indexOf((e.target as HTMLElement).tagName) ||
|
||||
(e.target as HTMLElement).contentEditable === 'true' ||
|
||||
!~['up', 'down', 'left', 'right'].indexOf(code)
|
||||
) {
|
||||
return;
|
||||
quickEditFormRef(ref, colIndex, rowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
const ns = this.props.classPrefix;
|
||||
let el: HTMLElement =
|
||||
((e.target as HTMLElement).closest(
|
||||
handleWindowKeyPress(e: Event) {
|
||||
const ns = this.props.classPrefix;
|
||||
let el: HTMLElement = (e.target as HTMLElement).closest(
|
||||
`.${ns}Field--quickEditable`
|
||||
) as HTMLElement) ||
|
||||
document.querySelector(`.${ns}Field--quickEditable`);
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
|
||||
let table = el.closest('table');
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
let current = table.querySelector(
|
||||
`.${ns}Field--quickEditable:focus`
|
||||
) as HTMLTableDataCellElement;
|
||||
|
||||
if (!current) {
|
||||
let dom = table.querySelector(
|
||||
`.${ns}Field--quickEditable[tabindex]`
|
||||
) as HTMLElement;
|
||||
dom && dom.focus();
|
||||
} else {
|
||||
let prevTr, nextTr, prevTd, nextTd;
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
const table = el.closest('table');
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 'up':
|
||||
prevTr = (current.parentNode as HTMLElement)
|
||||
.previousSibling as HTMLTableCellElement;
|
||||
if (
|
||||
keycode(e) === 'space' &&
|
||||
!~['INPUT', 'TEXTAREA'].indexOf(el.tagName)
|
||||
) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
if (prevTr) {
|
||||
let index = current.cellIndex;
|
||||
(prevTr.children[index] as HTMLElement).focus();
|
||||
}
|
||||
break;
|
||||
case 'down':
|
||||
nextTr = (current.parentNode as HTMLElement)
|
||||
.nextSibling as HTMLTableCellElement;
|
||||
handleWindowKeyDown(e: Event) {
|
||||
const code = keycode(e);
|
||||
|
||||
if (nextTr) {
|
||||
let index = current.cellIndex;
|
||||
(nextTr.children[index] as HTMLElement).focus();
|
||||
}
|
||||
break;
|
||||
case 'left':
|
||||
prevTd = current.previousElementSibling as HTMLTableCellElement;
|
||||
if (code === 'esc' && currentOpened) {
|
||||
currentOpened.closeQuickEdit();
|
||||
} else if (
|
||||
~['INPUT', 'TEXTAREA'].indexOf((e.target as HTMLElement).tagName) ||
|
||||
(e.target as HTMLElement).contentEditable === 'true' ||
|
||||
!~['up', 'down', 'left', 'right'].indexOf(code)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (prevTd) {
|
||||
if (matches(prevTd, `.${ns}Field--quickEditable[tabindex]`)) {
|
||||
break;
|
||||
e.preventDefault();
|
||||
const ns = this.props.classPrefix;
|
||||
let el: HTMLElement =
|
||||
((e.target as HTMLElement).closest(
|
||||
`.${ns}Field--quickEditable`
|
||||
) as HTMLElement) ||
|
||||
document.querySelector(`.${ns}Field--quickEditable`);
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
|
||||
let table = el.closest('table');
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
let current = table.querySelector(
|
||||
`.${ns}Field--quickEditable:focus`
|
||||
) as HTMLTableDataCellElement;
|
||||
|
||||
if (!current) {
|
||||
let dom = table.querySelector(
|
||||
`.${ns}Field--quickEditable[tabindex]`
|
||||
) as HTMLElement;
|
||||
dom && dom.focus();
|
||||
} else {
|
||||
let prevTr, nextTr, prevTd, nextTd;
|
||||
|
||||
switch (code) {
|
||||
case 'up':
|
||||
prevTr = (current.parentNode as HTMLElement)
|
||||
.previousSibling as HTMLTableCellElement;
|
||||
|
||||
if (prevTr) {
|
||||
let index = current.cellIndex;
|
||||
(prevTr.children[index] as HTMLElement).focus();
|
||||
}
|
||||
prevTd = prevTd.previousElementSibling;
|
||||
}
|
||||
break;
|
||||
case 'down':
|
||||
nextTr = (current.parentNode as HTMLElement)
|
||||
.nextSibling as HTMLTableCellElement;
|
||||
|
||||
if (prevTd) {
|
||||
(prevTd as HTMLElement).focus();
|
||||
} else if ((current.parentNode as HTMLElement).previousSibling) {
|
||||
let tds = ((current.parentNode as HTMLElement)
|
||||
.previousSibling as HTMLElement).querySelectorAll(
|
||||
`.${ns}Field--quickEditable[tabindex]`
|
||||
);
|
||||
|
||||
if (tds.length) {
|
||||
(tds[tds.length - 1] as HTMLElement).focus();
|
||||
if (nextTr) {
|
||||
let index = current.cellIndex;
|
||||
(nextTr.children[index] as HTMLElement).focus();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'right':
|
||||
nextTd = current.nextSibling;
|
||||
while (nextTd) {
|
||||
if (
|
||||
matches(
|
||||
nextTd as Element,
|
||||
`.${ns}Field--quickEditable[tabindex]`
|
||||
)
|
||||
) {
|
||||
break;
|
||||
break;
|
||||
case 'left':
|
||||
prevTd = current.previousElementSibling as HTMLTableCellElement;
|
||||
|
||||
while (prevTd) {
|
||||
if (prevTd.matches(`.${ns}Field--quickEditable[tabindex]`)) {
|
||||
break;
|
||||
}
|
||||
prevTd = prevTd.previousElementSibling;
|
||||
}
|
||||
|
||||
nextTd = nextTd.nextSibling;
|
||||
}
|
||||
if (prevTd) {
|
||||
(prevTd as HTMLElement).focus();
|
||||
} else if ((current.parentNode as HTMLElement).previousSibling) {
|
||||
let tds = (
|
||||
(current.parentNode as HTMLElement)
|
||||
.previousSibling as HTMLElement
|
||||
).querySelectorAll(`.${ns}Field--quickEditable[tabindex]`);
|
||||
|
||||
if (nextTd) {
|
||||
(nextTd as HTMLElement).focus();
|
||||
} else if ((current.parentNode as HTMLElement).nextSibling) {
|
||||
nextTd = ((current.parentNode as HTMLElement)
|
||||
.nextSibling as HTMLElement).querySelector(
|
||||
`.${ns}Field--quickEditable[tabindex]`
|
||||
);
|
||||
if (tds.length) {
|
||||
(tds[tds.length - 1] as HTMLElement).focus();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'right':
|
||||
nextTd = current.nextSibling;
|
||||
while (nextTd) {
|
||||
if (
|
||||
(nextTd as Element).matches(
|
||||
`.${ns}Field--quickEditable[tabindex]`
|
||||
)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
nextTd = nextTd.nextSibling;
|
||||
}
|
||||
|
||||
if (nextTd) {
|
||||
(nextTd as any).focus();
|
||||
(nextTd as HTMLElement).focus();
|
||||
} else if ((current.parentNode as HTMLElement).nextSibling) {
|
||||
nextTd = (
|
||||
(current.parentNode as HTMLElement).nextSibling as HTMLElement
|
||||
).querySelector(`.${ns}Field--quickEditable[tabindex]`);
|
||||
|
||||
if (nextTd) {
|
||||
(nextTd as any).focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleClickOutside() {
|
||||
// this.closeQuickEdit();
|
||||
// }
|
||||
// handleClickOutside() {
|
||||
// this.closeQuickEdit();
|
||||
// }
|
||||
|
||||
overlayRef(ref: any) {
|
||||
this.overlay = ref;
|
||||
}
|
||||
overlayRef(ref: any) {
|
||||
this.overlay = ref;
|
||||
}
|
||||
|
||||
handleAction(e: any, action: Action, ctx: object) {
|
||||
const {onAction} = this.props;
|
||||
handleAction(e: any, action: Action, ctx: object) {
|
||||
const {onAction} = this.props;
|
||||
|
||||
if (action.actionType === 'cancel' || action.actionType === 'close') {
|
||||
this.closeQuickEdit();
|
||||
return;
|
||||
}
|
||||
|
||||
onAction && onAction(e, action, ctx);
|
||||
}
|
||||
|
||||
handleSubmit(values: object) {
|
||||
const {onQuickChange, quickEdit} = this.props;
|
||||
|
||||
if (action.actionType === 'cancel' || action.actionType === 'close') {
|
||||
this.closeQuickEdit();
|
||||
return;
|
||||
onQuickChange(
|
||||
values,
|
||||
(quickEdit as QuickEditConfig).saveImmediately,
|
||||
false,
|
||||
(quickEdit as QuickEditConfig).resetOnFailed
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onAction && onAction(e, action, ctx);
|
||||
}
|
||||
|
||||
handleSubmit(values: object) {
|
||||
const {onQuickChange, quickEdit} = this.props;
|
||||
|
||||
this.closeQuickEdit();
|
||||
onQuickChange(
|
||||
values,
|
||||
(quickEdit as QuickEditConfig).saveImmediately,
|
||||
false,
|
||||
(quickEdit as QuickEditConfig).resetOnFailed
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
handleInit(values: object) {
|
||||
const {onQuickChange} = this.props;
|
||||
onQuickChange(values, false, true);
|
||||
}
|
||||
|
||||
handleChange(values: object) {
|
||||
const {onQuickChange, quickEdit} = this.props;
|
||||
|
||||
onQuickChange(
|
||||
values,
|
||||
(quickEdit as QuickEditConfig).saveImmediately,
|
||||
false,
|
||||
(quickEdit as QuickEditConfig).resetOnFailed
|
||||
);
|
||||
}
|
||||
|
||||
openQuickEdit() {
|
||||
currentOpened = this;
|
||||
this.setState({
|
||||
isOpened: true
|
||||
});
|
||||
}
|
||||
|
||||
closeQuickEdit() {
|
||||
if (!this.state.isOpened) {
|
||||
return;
|
||||
handleInit(values: object) {
|
||||
const {onQuickChange} = this.props;
|
||||
onQuickChange(values, false, true);
|
||||
}
|
||||
currentOpened = null;
|
||||
const ns = this.props.classPrefix;
|
||||
this.setState(
|
||||
{
|
||||
isOpened: false
|
||||
},
|
||||
() => {
|
||||
let el = findDOMNode(this) as HTMLElement;
|
||||
let table = el.closest('table') as HTMLElement;
|
||||
((table &&
|
||||
table.querySelectorAll(`td.${ns}Field--quickEditable:focus`)
|
||||
.length) ||
|
||||
el) &&
|
||||
el.focus();
|
||||
|
||||
handleChange(values: object) {
|
||||
const {onQuickChange, quickEdit} = this.props;
|
||||
|
||||
onQuickChange(
|
||||
values,
|
||||
(quickEdit as QuickEditConfig).saveImmediately,
|
||||
false,
|
||||
(quickEdit as QuickEditConfig).resetOnFailed
|
||||
);
|
||||
}
|
||||
|
||||
openQuickEdit() {
|
||||
currentOpened = this;
|
||||
this.setState({
|
||||
isOpened: true
|
||||
});
|
||||
}
|
||||
|
||||
closeQuickEdit() {
|
||||
if (!this.state.isOpened) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
}
|
||||
currentOpened = null;
|
||||
const ns = this.props.classPrefix;
|
||||
this.setState(
|
||||
{
|
||||
isOpened: false
|
||||
},
|
||||
() => {
|
||||
let el = findDOMNode(this) as HTMLElement;
|
||||
let table = el.closest('table') as HTMLElement;
|
||||
((table &&
|
||||
table.querySelectorAll(`td.${ns}Field--quickEditable:focus`)
|
||||
.length) ||
|
||||
el) &&
|
||||
el.focus();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
buildSchema() {
|
||||
const {quickEdit, name, label, translate: __} = this.props;
|
||||
buildSchema() {
|
||||
const {quickEdit, name, label, translate: __} = this.props;
|
||||
|
||||
let schema;
|
||||
let schema;
|
||||
|
||||
if (quickEdit === true) {
|
||||
schema = {
|
||||
type: 'form',
|
||||
title: '',
|
||||
autoFocus: true,
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name,
|
||||
placeholder: label,
|
||||
label: false
|
||||
}
|
||||
]
|
||||
};
|
||||
} else if (quickEdit) {
|
||||
if (
|
||||
quickEdit.body &&
|
||||
!~['combo', 'group', 'panel', 'fieldSet', 'fieldset'].indexOf(
|
||||
(quickEdit as any).type
|
||||
)
|
||||
) {
|
||||
if (quickEdit === true) {
|
||||
schema = {
|
||||
title: '',
|
||||
autoFocus: (quickEdit as QuickEditConfig).mode !== 'inline',
|
||||
...quickEdit,
|
||||
mode: 'normal',
|
||||
type: 'form'
|
||||
};
|
||||
} else {
|
||||
schema = {
|
||||
title: '',
|
||||
className: quickEdit.formClassName,
|
||||
type: 'form',
|
||||
autoFocus: (quickEdit as QuickEditConfig).mode !== 'inline',
|
||||
mode: 'normal',
|
||||
title: '',
|
||||
autoFocus: true,
|
||||
body: [
|
||||
{
|
||||
type: quickEdit.type || 'input-text',
|
||||
name: quickEdit.name || name,
|
||||
...quickEdit,
|
||||
mode: undefined
|
||||
type: 'input-text',
|
||||
name,
|
||||
placeholder: label,
|
||||
label: false
|
||||
}
|
||||
]
|
||||
};
|
||||
} else if (quickEdit) {
|
||||
if (
|
||||
quickEdit.body &&
|
||||
!~['combo', 'group', 'panel', 'fieldSet', 'fieldset'].indexOf(
|
||||
(quickEdit as any).type
|
||||
)
|
||||
) {
|
||||
schema = {
|
||||
title: '',
|
||||
autoFocus: (quickEdit as QuickEditConfig).mode !== 'inline',
|
||||
...quickEdit,
|
||||
mode: 'normal',
|
||||
type: 'form'
|
||||
};
|
||||
} else {
|
||||
schema = {
|
||||
title: '',
|
||||
className: quickEdit.formClassName,
|
||||
type: 'form',
|
||||
autoFocus: (quickEdit as QuickEditConfig).mode !== 'inline',
|
||||
mode: 'normal',
|
||||
body: [
|
||||
{
|
||||
type: quickEdit.type || 'input-text',
|
||||
name: quickEdit.name || name,
|
||||
...quickEdit,
|
||||
mode: undefined
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (schema) {
|
||||
schema = {
|
||||
...schema,
|
||||
wrapWithPanel: (quickEdit as QuickEditConfig).mode !== 'inline',
|
||||
actions:
|
||||
(quickEdit as QuickEditConfig).mode === 'inline'
|
||||
? []
|
||||
: [
|
||||
{
|
||||
type: 'button',
|
||||
label: __('cancel'),
|
||||
actionType: 'cancel'
|
||||
},
|
||||
|
||||
{
|
||||
label: __('confirm'),
|
||||
type: 'submit',
|
||||
primary: true
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
return schema || 'error';
|
||||
}
|
||||
|
||||
handleKeyUp(e: Event) {
|
||||
const code = keycode(e);
|
||||
if (
|
||||
code === 'space' &&
|
||||
!~['INPUT', 'TEXTAREA'].indexOf((e.target as HTMLElement).tagName)
|
||||
) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.openQuickEdit();
|
||||
}
|
||||
}
|
||||
|
||||
if (schema) {
|
||||
schema = {
|
||||
...schema,
|
||||
wrapWithPanel: (quickEdit as QuickEditConfig).mode !== 'inline',
|
||||
actions:
|
||||
(quickEdit as QuickEditConfig).mode === 'inline'
|
||||
? []
|
||||
: [
|
||||
{
|
||||
type: 'button',
|
||||
label: __('cancel'),
|
||||
actionType: 'cancel'
|
||||
},
|
||||
renderPopOver() {
|
||||
let {
|
||||
quickEdit,
|
||||
render,
|
||||
popOverContainer,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
canAccessSuperData
|
||||
} = this.props;
|
||||
|
||||
{
|
||||
label: __('confirm'),
|
||||
type: 'submit',
|
||||
primary: true
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
return schema || 'error';
|
||||
}
|
||||
|
||||
handleKeyUp(e: Event) {
|
||||
const code = keycode(e);
|
||||
if (
|
||||
code === 'space' &&
|
||||
!~['INPUT', 'TEXTAREA'].indexOf((e.target as HTMLElement).tagName)
|
||||
) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.openQuickEdit();
|
||||
}
|
||||
}
|
||||
|
||||
renderPopOver() {
|
||||
let {
|
||||
quickEdit,
|
||||
render,
|
||||
popOverContainer,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
canAccessSuperData
|
||||
} = this.props;
|
||||
|
||||
const content = (
|
||||
<div
|
||||
ref={this.overlayRef}
|
||||
className={cx((quickEdit as QuickEditConfig).className)}
|
||||
>
|
||||
{render('quick-edit-form', this.buildSchema(), {
|
||||
value: undefined,
|
||||
onSubmit: this.handleSubmit,
|
||||
onAction: this.handleAction,
|
||||
onChange: null,
|
||||
formLazyChange: false,
|
||||
ref: this.formRef,
|
||||
popOverContainer: () => this.overlay,
|
||||
canAccessSuperData
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
popOverContainer = popOverContainer || (() => findDOMNode(this));
|
||||
|
||||
return (
|
||||
<Overlay
|
||||
container={popOverContainer}
|
||||
target={() => this.target}
|
||||
onHide={this.closeQuickEdit}
|
||||
placement="left-top right-top left-bottom right-bottom left-top"
|
||||
show
|
||||
>
|
||||
<PopOver
|
||||
classPrefix={ns}
|
||||
className={cx(
|
||||
`${ns}QuickEdit-popover`,
|
||||
(quickEdit as QuickEditConfig).popOverClassName
|
||||
)}
|
||||
onHide={this.closeQuickEdit}
|
||||
overlay
|
||||
const content = (
|
||||
<div
|
||||
ref={this.overlayRef}
|
||||
className={cx((quickEdit as QuickEditConfig).className)}
|
||||
>
|
||||
{content}
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
onQuickChange,
|
||||
quickEdit,
|
||||
quickEditEnabled,
|
||||
className,
|
||||
classnames: cx,
|
||||
render,
|
||||
noHoc,
|
||||
canAccessSuperData,
|
||||
disabled
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
!quickEdit ||
|
||||
!onQuickChange ||
|
||||
quickEditEnabled === false ||
|
||||
noHoc ||
|
||||
disabled
|
||||
) {
|
||||
return <Component {...this.props} />;
|
||||
}
|
||||
|
||||
if ((quickEdit as QuickEditConfig).mode === 'inline') {
|
||||
return (
|
||||
<Component {...this.props}>
|
||||
{render('inline-form', this.buildSchema(), {
|
||||
{render('quick-edit-form', this.buildSchema(), {
|
||||
value: undefined,
|
||||
wrapperComponent: 'div',
|
||||
className: cx('Form--quickEdit'),
|
||||
ref: this.formRef,
|
||||
simpleMode: true,
|
||||
onInit: this.handleInit,
|
||||
onChange: this.handleChange,
|
||||
onSubmit: this.handleSubmit,
|
||||
onAction: this.handleAction,
|
||||
onChange: null,
|
||||
formLazyChange: false,
|
||||
ref: this.formRef,
|
||||
popOverContainer: () => this.overlay,
|
||||
canAccessSuperData
|
||||
})}
|
||||
</Component>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
|
||||
popOverContainer = popOverContainer || (() => findDOMNode(this));
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...this.props}
|
||||
className={cx(`Field--quickEditable`, className, {
|
||||
in: this.state.isOpened
|
||||
})}
|
||||
tabIndex={
|
||||
(quickEdit as QuickEditConfig).focusable === false
|
||||
? undefined
|
||||
: '0'
|
||||
}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
<Overlay
|
||||
container={popOverContainer}
|
||||
target={() => this.target}
|
||||
onHide={this.closeQuickEdit}
|
||||
placement="left-top right-top left-bottom right-bottom left-top"
|
||||
show
|
||||
>
|
||||
<Component {...this.props} wrapperComponent={''} noHoc />
|
||||
<span
|
||||
key="edit-btn"
|
||||
className={cx('Field-quickEditBtn')}
|
||||
onClick={this.openQuickEdit}
|
||||
<PopOver
|
||||
classPrefix={ns}
|
||||
className={cx(
|
||||
`${ns}QuickEdit-popover`,
|
||||
(quickEdit as QuickEditConfig).popOverClassName
|
||||
)}
|
||||
onHide={this.closeQuickEdit}
|
||||
overlay
|
||||
>
|
||||
<Icon icon="pencil" className="icon" />
|
||||
</span>
|
||||
{this.state.isOpened ? this.renderPopOver() : null}
|
||||
</Component>
|
||||
{content}
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
onQuickChange,
|
||||
quickEdit,
|
||||
quickEditEnabled,
|
||||
className,
|
||||
classnames: cx,
|
||||
render,
|
||||
noHoc,
|
||||
canAccessSuperData,
|
||||
disabled
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
!quickEdit ||
|
||||
!onQuickChange ||
|
||||
quickEditEnabled === false ||
|
||||
noHoc ||
|
||||
disabled
|
||||
) {
|
||||
return <Component {...this.props} />;
|
||||
}
|
||||
|
||||
if ((quickEdit as QuickEditConfig).mode === 'inline') {
|
||||
return (
|
||||
<Component {...this.props}>
|
||||
{render('inline-form', this.buildSchema(), {
|
||||
value: undefined,
|
||||
wrapperComponent: 'div',
|
||||
className: cx('Form--quickEdit'),
|
||||
ref: this.formRef,
|
||||
simpleMode: true,
|
||||
onInit: this.handleInit,
|
||||
onChange: this.handleChange,
|
||||
formLazyChange: false,
|
||||
canAccessSuperData
|
||||
})}
|
||||
</Component>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Component
|
||||
{...this.props}
|
||||
className={cx(`Field--quickEditable`, className, {
|
||||
in: this.state.isOpened
|
||||
})}
|
||||
tabIndex={
|
||||
(quickEdit as QuickEditConfig).focusable === false
|
||||
? undefined
|
||||
: '0'
|
||||
}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
>
|
||||
<Component {...this.props} wrapperComponent={''} noHoc />
|
||||
<span
|
||||
key="edit-btn"
|
||||
className={cx('Field-quickEditBtn')}
|
||||
onClick={this.openQuickEdit}
|
||||
>
|
||||
<Icon icon="pencil" className="icon" />
|
||||
</span>
|
||||
{this.state.isOpened ? this.renderPopOver() : null}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hoistNonReactStatic(QuickEditComponent, Component);
|
||||
hoistNonReactStatic(QuickEditComponent, Component);
|
||||
|
||||
return QuickEditComponent;
|
||||
};
|
||||
return QuickEditComponent;
|
||||
};
|
||||
|
||||
export default HocQuickEdit;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {Instance, types} from 'mobx-state-tree';
|
||||
import qs from 'qs';
|
||||
import {createObject, qsparse} from '../utils/helper';
|
||||
import {ServiceStore} from './service';
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {Api, ApiObject, fetcherResult, Payload} from '../types';
|
||||
import {fetcherConfig} from '../factory';
|
||||
import {tokenize, dataMapping} from './tpl-builtin';
|
||||
import qs from 'qs';
|
||||
import {evalExpression} from './tpl';
|
||||
import {
|
||||
isObject,
|
||||
|
@ -1,11 +1,8 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
import domOwnerDocument from 'dom-helpers/ownerDocument';
|
||||
import css from 'dom-helpers/style/index';
|
||||
import getOffset from 'dom-helpers/query/offset';
|
||||
import getPosition from 'dom-helpers/query/position';
|
||||
import getScrollTop from 'dom-helpers/query/scrollTop';
|
||||
import getOffset from './offset';
|
||||
import getPosition from './position';
|
||||
|
||||
const bsMapping: {
|
||||
[propName: string]: string;
|
||||
@ -56,7 +53,10 @@ export function getContainer(container: any, defaultContainer: any) {
|
||||
}
|
||||
|
||||
export function ownerDocument(componentOrElement: any) {
|
||||
return domOwnerDocument(ReactDOM.findDOMNode(componentOrElement) as Element);
|
||||
return (
|
||||
(ReactDOM.findDOMNode(componentOrElement) as Element)?.ownerDocument ||
|
||||
document
|
||||
);
|
||||
}
|
||||
|
||||
function getContainerDimensions(containerNode: any) {
|
||||
@ -67,11 +67,11 @@ function getContainerDimensions(containerNode: any) {
|
||||
height = window.innerHeight;
|
||||
|
||||
scroll =
|
||||
getScrollTop(ownerDocument(containerNode).documentElement) ||
|
||||
getScrollTop(containerNode);
|
||||
ownerDocument(containerNode).documentElement.scrollTop ||
|
||||
containerNode?.scrollTop;
|
||||
} else {
|
||||
({width, height} = getOffset(containerNode) as any);
|
||||
scroll = getScrollTop(containerNode);
|
||||
scroll = containerNode.scrollTop;
|
||||
}
|
||||
|
||||
return {width, height, scroll};
|
||||
@ -120,23 +120,6 @@ function getLeftDelta(
|
||||
return 0;
|
||||
}
|
||||
|
||||
// function position(node: HTMLElement, offsetParent: HTMLElement) {
|
||||
// const rect = offsetParent.getBoundingClientRect();
|
||||
// const rect2 = node.getBoundingClientRect();
|
||||
// return {
|
||||
// width:
|
||||
// rect2.width -
|
||||
// (parseInt(css(node, 'borderLeftWidth') || '', 10) || 0) -
|
||||
// parseInt(css(node, 'borderRightWidth') || '', 10) || 0,
|
||||
// height:
|
||||
// rect2.height -
|
||||
// (parseInt(css(node, 'borderTopWidth') || '', 10) || 0) -
|
||||
// parseInt(css(node, 'borderBottomWidth') || '', 10) || 0,
|
||||
// top: rect2.top - rect.top,
|
||||
// left: rect2.left - rect.left
|
||||
// };
|
||||
// }
|
||||
|
||||
export function calculatePosition(
|
||||
placement: any,
|
||||
overlayNode: any,
|
||||
|
@ -2,32 +2,10 @@
|
||||
* @file markdown 解析
|
||||
*/
|
||||
|
||||
import hljs from 'highlight.js';
|
||||
import markdownIt from 'markdown-it';
|
||||
import {escapeHtml} from 'markdown-it/lib/common/utils';
|
||||
|
||||
const markdown = markdownIt({
|
||||
linkify: true,
|
||||
highlight(str: string, lang: string) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return (
|
||||
'<pre class="hljs language-' +
|
||||
escapeHtml(lang.toLowerCase()) +
|
||||
'"><code>' +
|
||||
hljs.highlight(lang, str, true).value +
|
||||
'</code></pre>'
|
||||
);
|
||||
} catch (__) {}
|
||||
}
|
||||
return (
|
||||
'<pre class="hljs language-' +
|
||||
escapeHtml(lang.toLowerCase()) +
|
||||
'"><code>' +
|
||||
escapeHtml(str) +
|
||||
'</code></pre>'
|
||||
);
|
||||
}
|
||||
linkify: true
|
||||
});
|
||||
|
||||
export default function (content: string) {
|
||||
|
30
src/utils/offset.ts
Normal file
30
src/utils/offset.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 修改自 https://github.com/react-bootstrap/dom-helpers/blob/master/src/offset.ts
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the offset of a given element, including top and left positions, width and height.
|
||||
*
|
||||
* @param node the element
|
||||
*/
|
||||
export default function offset(node: HTMLElement) {
|
||||
const doc = node?.ownerDocument;
|
||||
|
||||
let box = {top: 0, left: 0, height: 0, width: 0};
|
||||
const docElem = doc && doc.documentElement;
|
||||
|
||||
// Make sure it's not a disconnected DOM node
|
||||
if (!docElem || !docElem.contains(node)) return box;
|
||||
|
||||
if (node.getBoundingClientRect !== undefined)
|
||||
box = node.getBoundingClientRect();
|
||||
|
||||
box = {
|
||||
top: box.top + docElem.scrollTop - (docElem.clientTop || 0),
|
||||
left: box.left + docElem.scrollLeft - (docElem.clientLeft || 0),
|
||||
width: box.width,
|
||||
height: box.height
|
||||
};
|
||||
|
||||
return box;
|
||||
}
|
21
src/utils/offsetParent.ts
Normal file
21
src/utils/offsetParent.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 删减自 https://github.com/react-bootstrap/dom-helpers/blob/master/src/offsetParent.ts
|
||||
*/
|
||||
|
||||
const isHTMLElement = (e: Element | null): e is HTMLElement =>
|
||||
!!e && 'offsetParent' in e;
|
||||
|
||||
export default function offsetParent(node: HTMLElement): HTMLElement {
|
||||
const doc = node?.ownerDocument;
|
||||
let parent = node && node.offsetParent;
|
||||
|
||||
while (
|
||||
isHTMLElement(parent) &&
|
||||
parent.nodeName !== 'HTML' &&
|
||||
getComputedStyle(parent).getPropertyValue('position') === 'static'
|
||||
) {
|
||||
parent = parent.offsetParent;
|
||||
}
|
||||
|
||||
return (parent || doc.documentElement) as HTMLElement;
|
||||
}
|
56
src/utils/position.ts
Normal file
56
src/utils/position.ts
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 删减自 https://github.com/react-bootstrap/dom-helpers/blob/master/src/position.ts
|
||||
*/
|
||||
|
||||
import getOffset from './offset';
|
||||
import getOffsetParent from './offsetParent';
|
||||
|
||||
const nodeName = (node: Element) =>
|
||||
node.nodeName && node.nodeName.toLowerCase();
|
||||
|
||||
/**
|
||||
* Returns the relative position of a given element.
|
||||
*
|
||||
* @param node the element
|
||||
* @param offsetParent the offset parent
|
||||
*/
|
||||
export default function position(
|
||||
node: HTMLElement,
|
||||
offsetParent?: HTMLElement
|
||||
) {
|
||||
let parentOffset = {top: 0, left: 0};
|
||||
let offset;
|
||||
getComputedStyle;
|
||||
// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
|
||||
// because it is its only offset parent
|
||||
if (getComputedStyle(node).getPropertyValue('position') === 'fixed') {
|
||||
offset = node.getBoundingClientRect();
|
||||
} else {
|
||||
const parent: HTMLElement = offsetParent || getOffsetParent(node);
|
||||
offset = getOffset(node);
|
||||
|
||||
if (nodeName(parent) !== 'html') parentOffset = getOffset(parent);
|
||||
const borderTop = String(
|
||||
getComputedStyle(parent).getPropertyValue('border-top-width') || 0
|
||||
);
|
||||
parentOffset.top += parseInt(borderTop, 10) - parent.scrollTop || 0;
|
||||
|
||||
const borderLeft = String(
|
||||
getComputedStyle(parent).getPropertyValue('border-left-width') || 0
|
||||
);
|
||||
parentOffset.left += parseInt(borderLeft, 10) - parent.scrollLeft || 0;
|
||||
}
|
||||
|
||||
const marginTop = String(
|
||||
getComputedStyle(node).getPropertyValue('margin-top') || 0
|
||||
);
|
||||
const marginLeft = String(
|
||||
getComputedStyle(node).getPropertyValue('margin-left') || 0
|
||||
);
|
||||
// Subtract parent offsets and node margins
|
||||
return {
|
||||
...offset,
|
||||
top: offset.top - parentOffset.top - (parseInt(marginTop, 10) || 0),
|
||||
left: offset.left - parentOffset.left - (parseInt(marginLeft, 10) || 0)
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user