@gm-mobile/c-react 3.9.3-beta.0 → 3.9.3-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/package.json +5 -5
  2. package/src/component/button/button.tsx +6 -3
  3. package/src/component/button/stories.tsx +2 -3
  4. package/src/component/button/style.less +5 -7
  5. package/src/component/button/types.ts +1 -1
  6. package/src/component/calendar/index.ts +1 -0
  7. package/src/component/cell/cell.tsx +29 -27
  8. package/src/component/cell/style.less +8 -5
  9. package/src/component/dialog/dialog.tsx +6 -1
  10. package/src/component/dialog/types.ts +9 -8
  11. package/src/component/digital_keyboard/Base.tsx +13 -13
  12. package/src/component/digital_keyboard/Btn.ts +3 -3
  13. package/src/component/digital_keyboard/index.tsx +14 -10
  14. package/src/component/digital_keyboard/stories.tsx +35 -41
  15. package/src/component/draggable/draggable.tsx +1 -0
  16. package/src/component/error/error.tsx +23 -0
  17. package/src/component/error/index.ts +1 -0
  18. package/src/component/error/style.less +42 -0
  19. package/src/component/error/types.ts +5 -0
  20. package/src/component/layout_root/layout_root.tsx +0 -1
  21. package/src/component/popup/popup.tsx +4 -1
  22. package/src/component/popup/popup_v1.tsx +2 -1
  23. package/src/component/popup/style.less +1 -1
  24. package/src/component/popup/types.ts +4 -0
  25. package/src/component/text_field/TextField.tsx +7 -3
  26. package/src/component/text_field/stories.tsx +0 -1
  27. package/src/component/text_field/types.ts +1 -1
  28. package/src/index.less +19 -18
  29. package/src/index.ts +1 -0
  30. package/src/less/animation.less +9 -4
  31. package/src/less/bg.less +7 -0
  32. package/src/less/border.less +14 -3
  33. package/src/less/{btn.less → button.less} +3 -1
  34. package/src/less/distance.less +2 -0
  35. package/src/less/text.less +16 -24
  36. package/src/less/variable.less +12 -11
  37. package/src/less/variable_page.less +0 -129
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gm-mobile/c-react",
3
- "version": "3.9.3-beta.0",
3
+ "version": "3.9.3-beta.12",
4
4
  "description": "> TODO: description",
5
5
  "author": "liyatang <liyatang@qq.com>",
6
6
  "homepage": "https://github.com/gmfe/gm-mobile#readme",
@@ -21,9 +21,9 @@
21
21
  "url": "https://github.com/gmfe/gm-mobile/issues"
22
22
  },
23
23
  "dependencies": {
24
- "@gm-mobile/c-font": "^3.9.3-beta.0",
25
- "@gm-mobile/c-tool": "^3.9.3-beta.0",
26
- "@gm-mobile/locales": "^3.9.3-beta.0"
24
+ "@gm-mobile/c-font": "^3.9.3-beta.12",
25
+ "@gm-mobile/c-tool": "^3.9.3-beta.12",
26
+ "@gm-mobile/locales": "^3.9.3-beta.12"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@tarojs/components": "3.0.18",
@@ -33,5 +33,5 @@
33
33
  "prop-types": "^15.7.2",
34
34
  "react": "^16.13.1"
35
35
  },
36
- "gitHead": "007be6106ba75dbc286cd3d0a24105d49a707bb4"
36
+ "gitHead": "56e1593b2b488c637ea9dbcf4e1ac1a5f06b832e"
37
37
  }
@@ -5,13 +5,14 @@ import { Loading } from '../loading'
5
5
  import BaseButton from './base'
6
6
  import { is } from '@gm-mobile/c-tool'
7
7
  import type { ButtonProps } from './types'
8
+ import { Flex } from '../flex'
8
9
 
9
10
  export const Button: FC<ButtonProps> = ({
10
11
  type = 'default',
11
12
  plain,
12
13
  mini,
13
14
  block,
14
- noRound,
15
+ round,
15
16
  disabled,
16
17
  onClick = _.noop,
17
18
  loading,
@@ -59,7 +60,7 @@ export const Button: FC<ButtonProps> = ({
59
60
  {
60
61
  'm-btn-block': block,
61
62
  'm-btn-mini': mini,
62
- 'm-btn-no-round': noRound,
63
+ 'm-btn-round': round,
63
64
  'm-btn-plain': type !== 'link' && plain,
64
65
  },
65
66
  className
@@ -72,7 +73,9 @@ export const Button: FC<ButtonProps> = ({
72
73
  onClick={handleClick}
73
74
  >
74
75
  {loadFlag && <Loading className='m-btn-loading' />}
75
- {children}
76
+ <Flex alignCenter justifyCenter style={{ display: 'inline-flex' }}>
77
+ {children}
78
+ </Flex>
76
79
  </BaseButton>
77
80
  )
78
81
  }
@@ -64,16 +64,15 @@ export const normal: FC<ButtonProps> = (args) => (
64
64
  </View>
65
65
  block
66
66
  <View>
67
- <Button {...args} block type='primary'>
67
+ <Button {...args} block type='primary' round>
68
68
  主色
69
69
  </Button>
70
70
  <Button {...args} block mini plain>
71
71
  主色
72
72
  </Button>
73
73
  </View>
74
- noRound
75
74
  <View>
76
- <Button {...args} noRound type='primary'>
75
+ <Button {...args} type='primary'>
77
76
  主色
78
77
  </Button>
79
78
  </View>
@@ -2,7 +2,6 @@
2
2
  height: var(--m-size-form-height);
3
3
  line-height: var(--m-size-form-height);
4
4
  border-width: 0;
5
- border-radius: var(--m-size-form-height);
6
5
  display: inline-block;
7
6
  text-align: center;
8
7
  vertical-align: middle;
@@ -12,7 +11,7 @@
12
11
  font-size: var(--m-size-text-16);
13
12
  user-select: none;
14
13
  outline: none;
15
-
14
+ border-radius: var(--m-btn-border-radius);
16
15
  &.m-btn-default {
17
16
  .mBtnVariants(var(--m-btn-color-bg-default), var(--m-btn-color-bg-default-active));
18
17
 
@@ -50,7 +49,6 @@
50
49
 
51
50
  &.m-btn-link {
52
51
  background: transparent;
53
- border-radius: 0;
54
52
  color: var(--m-color-link);
55
53
  padding: 0 15px;
56
54
  min-width: 0;
@@ -77,11 +75,11 @@
77
75
  width: 100%;
78
76
  }
79
77
 
80
- &.m-btn-no-round {
81
- border-radius: 0;
78
+ &.m-btn-round {
79
+ border-radius: var(--m-size-form-height);
82
80
 
83
81
  &::after {
84
- border-radius: 0;
82
+ border-radius: var(--m-size-form-height);
85
83
  }
86
84
  }
87
85
 
@@ -130,7 +128,7 @@
130
128
  top: 0;
131
129
  left: 0;
132
130
  border: 1px solid @borderColor;
133
- border-radius: @height;
131
+ border-radius: calc(var(--m-btn-border-radius) * 2);
134
132
  transform: scale(0.5);
135
133
  transform-origin: 0 0;
136
134
  box-sizing: border-box;
@@ -14,7 +14,7 @@ interface ButtonProps extends HTMLAttributes<HTMLButtonElement> {
14
14
  plain?: boolean
15
15
  mini?: boolean
16
16
  block?: boolean
17
- noRound?: boolean
17
+ round?: boolean
18
18
  loading?: boolean
19
19
  /** 仅web 用。原生的 type */
20
20
  htmlType?: ButtonHTMLType
@@ -5,5 +5,6 @@ export { default as MultipleCalendar } from './multiple_calendar'
5
5
  export type {
6
6
  BaseCalendarProps,
7
7
  RangeCalendarProps,
8
+ CalendarProps,
8
9
  MultipleCalendarProps,
9
10
  } from './types'
@@ -19,35 +19,37 @@ export const Cell: FC<CellProps> = ({
19
19
  ...rest
20
20
  }) => {
21
21
  return (
22
- <Flex
23
- {...rest}
24
- alignCenter
25
- className={classNames(
26
- 'm-cell',
27
- {
28
- 'm-cell-access': access,
29
- 'm-cell-with-icon': icon,
30
- 'm-cell-no-active': noActive,
31
- },
32
- className
33
- )}
34
- onClick={onClick}
35
- >
36
- {icon && <View className='m-cell-icon'>{icon}</View>}
37
- {left && <View className='m-cell-left'>{left}</View>}
38
- <View className='m-cell-body'>{children}</View>
39
- <Flex alignCenter>
40
- {right &&
41
- (_.isString(right) ? (
42
- <View className='m-cell-right'>{right}</View>
43
- ) : (
44
- right
45
- ))}
46
- {access && (
47
- <Text className='m-font m-font-angle-right m-cell-access-icon' />
22
+ <>
23
+ <Flex
24
+ {...rest}
25
+ alignCenter
26
+ className={classNames(
27
+ 'm-cell',
28
+ {
29
+ 'm-cell-access': access,
30
+ 'm-cell-with-icon': icon,
31
+ 'm-cell-no-active': noActive,
32
+ },
33
+ className
48
34
  )}
35
+ onClick={onClick}
36
+ >
37
+ {icon && <View className='m-cell-icon'>{icon}</View>}
38
+ {left && <View className='m-cell-left'>{left}</View>}
39
+ <View className='m-cell-body'>{children}</View>
40
+ <Flex alignCenter>
41
+ {right &&
42
+ (_.isString(right) ? (
43
+ <View className='m-cell-right'>{right}</View>
44
+ ) : (
45
+ right
46
+ ))}
47
+ {access && (
48
+ <Text className='m-font m-font-angle-right m-cell-access-icon' />
49
+ )}
50
+ </Flex>
49
51
  </Flex>
50
- </Flex>
52
+ </>
51
53
  )
52
54
  }
53
55
 
@@ -30,7 +30,6 @@
30
30
  background: var(--m-color-bg-white);
31
31
  }
32
32
  }
33
- .mCellBorderBottomAfter(15px, 0);
34
33
 
35
34
  &.m-cell-access {
36
35
  cursor: pointer;
@@ -41,10 +40,6 @@
41
40
  }
42
41
  }
43
42
 
44
- &.m-cell-with-icon {
45
- .mCellBorderBottomAfter(50px, 0);
46
- }
47
-
48
43
  .m-cell-icon {
49
44
  width: 35px;
50
45
  }
@@ -105,4 +100,12 @@
105
100
  .m-cell:not(.m-cell-form):last-child::after {
106
101
  display: none;
107
102
  }
103
+
104
+ .m-cell {
105
+ .mCellBorderBottomAfter(15px, 0);
106
+
107
+ &.m-cell-with-icon {
108
+ .mCellBorderBottomAfter(50px, 0);
109
+ }
110
+ }
108
111
  }
@@ -44,6 +44,11 @@ const ErrorInput: FC<ErrorInputProps> = ({
44
44
 
45
45
  const DialogStatics: DialogStaticsTypes<string | RenderOptions> = {
46
46
  render(options, type) {
47
+ const autoHide = !(
48
+ typeof options === 'object' &&
49
+ options.onConfirm &&
50
+ typeof options.children === 'object'
51
+ )
47
52
  if (typeof options === 'string') {
48
53
  options = {
49
54
  children: options as string,
@@ -92,7 +97,7 @@ const DialogStatics: DialogStaticsTypes<string | RenderOptions> = {
92
97
  }
93
98
 
94
99
  Promise.resolve(result).then(() => {
95
- DialogStatics.hide()
100
+ if (autoHide) DialogStatics.hide()
96
101
 
97
102
  return setTimeout(() => {
98
103
  resolve(type === 'prompt' ? inputValue : undefined)
@@ -23,22 +23,23 @@ interface DialogBaseProps {
23
23
  promptGetError?: (value: string) => string | void
24
24
  hideBottom?: boolean
25
25
  }
26
- interface RenderOptions extends PromptOptions {
27
- children?: string | React.ReactNode
28
- confirmText?: React.ReactNode
29
- onCancel?: () => void
30
- otherText?: string
31
- onOther?: () => void
32
- hideBottom?: boolean
33
- }
34
26
 
35
27
  interface PromptOptions {
28
+ title?: string
36
29
  promptGetError?: (value: string) => string | void
37
30
  promptText?: string
38
31
  promptInputProps?: ErrorInputProps
39
32
  onConfirm?: (value: string) => void | boolean
40
33
  }
41
34
 
35
+ interface RenderOptions extends PromptOptions {
36
+ children?: string | React.ReactNode
37
+ confirmText?: React.ReactNode
38
+ onCancel?: () => void
39
+ otherText?: string
40
+ onOther?: () => void
41
+ hideBottom?: boolean
42
+ }
42
43
  interface DialogStaticsTypes<T> {
43
44
  render: (options: T, type?: string) => Promise<void | string>
44
45
  alert: (options: string | RenderOptions) => Promise<void | string>
@@ -2,7 +2,7 @@ import React, { FC, HTMLAttributes } from 'react'
2
2
  // import { Flex, Popup, View } from '@gm-mobile/mp'
3
3
  import _ from 'lodash'
4
4
  import classNames from 'classnames'
5
- import Btn from './Btn'
5
+ import DKBtn from './Btn'
6
6
  import './base.less'
7
7
  import './font/iconfont.css'
8
8
  import { View } from '../view'
@@ -11,11 +11,11 @@ import { Flex } from '../flex'
11
11
 
12
12
  /** 数字按钮 */
13
13
  export const defaultDigitalKeys = [
14
- ...['7', '8', '9'].map((v, _) => new Btn({ label: v })),
15
- ...['4', '5', '6'].map((v, _) => new Btn({ label: v })),
16
- ...['1', '2', '3'].map((v, _) => new Btn({ label: v })),
17
- new Btn({ label: '0' }),
18
- new Btn({
14
+ ...['7', '8', '9'].map((v, _) => new DKBtn({ label: v })),
15
+ ...['4', '5', '6'].map((v, _) => new DKBtn({ label: v })),
16
+ ...['1', '2', '3'].map((v, _) => new DKBtn({ label: v })),
17
+ new DKBtn({ label: '0' }),
18
+ new DKBtn({
19
19
  label: '.',
20
20
  fn: (value = '') => {
21
21
  if (value === '') {
@@ -28,7 +28,7 @@ export const defaultDigitalKeys = [
28
28
  }
29
29
  },
30
30
  }),
31
- new Btn({
31
+ new DKBtn({
32
32
  className: 'iconfont icon-backspace',
33
33
  fn: (value) => {
34
34
  if (value.length === 0) return value
@@ -39,9 +39,9 @@ export const defaultDigitalKeys = [
39
39
 
40
40
  /** 右侧功能按钮 */
41
41
  export const defaultActionKeys = [
42
- new Btn({ label: '取消', fn: (_) => '' }),
43
- new Btn({ label: '完成', className: 'm-bg-primary' }),
44
- new Btn({
42
+ new DKBtn({ label: '取消', fn: (_) => '' }),
43
+ new DKBtn({ label: '完成', className: 'm-bg-primary' }),
44
+ new DKBtn({
45
45
  label: '大按钮',
46
46
  flex: 2,
47
47
  className: 'm-bg-primary',
@@ -57,9 +57,9 @@ export interface KeyboardProps
57
57
  /** 输入框当前值 */
58
58
  value: string
59
59
  /** 虚拟键盘的点击事件 */
60
- onInput?: (value: string | undefined, key: Btn) => void
60
+ onInput?: (value: string | undefined, key: DKBtn) => void
61
61
  /** 虚拟键盘的功能键(actionKeys)点击事件 */
62
- onAction?: (key: Btn) => void
62
+ onAction?: (key: DKBtn) => void
63
63
  /** 自定义功能键盘 */
64
64
  actionKeys?: typeof defaultActionKeys
65
65
  /** 自定义数字键盘 */
@@ -81,7 +81,7 @@ export const Keyboard: FC<KeyboardProps> = ({
81
81
  int,
82
82
  ...rest
83
83
  }) => {
84
- const handleInput = (btn: Btn) => {
84
+ const handleInput = (btn: DKBtn) => {
85
85
  if (!btn.fn) {
86
86
  onInput && onInput(undefined, btn)
87
87
  return
@@ -1,4 +1,4 @@
1
- export class Btn {
1
+ export class DKBtn {
2
2
  /** 按钮文本 */
3
3
  label?: string
4
4
  /** 按钮占位,默认1个位置 */
@@ -8,7 +8,7 @@ export class Btn {
8
8
  /** 按钮功能,传入value为输入框当前值,返回一个按钮功能处理后的值 */
9
9
  fn?: (value: string) => string
10
10
  type?: 'digit' | 'action'
11
- constructor({ label = '', flex = 0, className = '', fn }: Btn) {
11
+ constructor({ label = '', flex = 0, className = '', fn }: DKBtn) {
12
12
  this.type = /([0-9.])/.test(label) ? 'digit' : 'action'
13
13
  if (!fn && this.type === 'digit') {
14
14
  fn = (value = '') => value + label
@@ -17,4 +17,4 @@ export class Btn {
17
17
  }
18
18
  }
19
19
 
20
- export default Btn
20
+ export default DKBtn
@@ -1,10 +1,10 @@
1
- import React, { ReactNode, useEffect, useState } from 'react'
1
+ import React, { ReactNode, useEffect, useRef, useState } from 'react'
2
2
  import { makeObservable } from 'mobx'
3
3
  import { Keyboard, KeyboardProps } from './Base'
4
4
  import { observer } from 'mobx-react'
5
5
  import { clamp } from 'lodash'
6
6
  import { View } from '../view'
7
- import Btn from './Btn'
7
+ import { DKBtn } from './Btn'
8
8
  import { Popup } from '../popup'
9
9
 
10
10
  /** 是否小程序端 */
@@ -30,6 +30,7 @@ export type DigitalKeyboardProps = Omit<KeyboardProps, 'value' | 'int'> & {
30
30
  min?: number
31
31
  /** 最大值 */
32
32
  max?: number
33
+ withUseRef?: boolean
33
34
  }
34
35
 
35
36
  export class DigitalKeyboard {
@@ -45,11 +46,12 @@ export class DigitalKeyboard {
45
46
  min,
46
47
  max,
47
48
  style,
49
+ withUseRef = true,
48
50
  ...rest
49
51
  }: DigitalKeyboardProps) {
50
52
  this.form = form
51
53
  this.active = active || Object.keys(form)[0]
52
- const Children = observer(() => {
54
+ const Node = observer(() => {
53
55
  const sys = mp && wx.getSystemInfoSync()
54
56
  const safeMargin =
55
57
  withSafeArea && mp ? sys.screenHeight - sys.safeArea.bottom : 5
@@ -125,7 +127,7 @@ export class DigitalKeyboard {
125
127
  </View>
126
128
  )
127
129
  })
128
- this.children = <Children />
130
+ this.node = <Node />
129
131
  makeObservable(this, {
130
132
  form: true,
131
133
  active: true,
@@ -135,6 +137,8 @@ export class DigitalKeyboard {
135
137
  int: true,
136
138
  setInt: true,
137
139
  })
140
+ // eslint-disable-next-line react-hooks/rules-of-hooks
141
+ return withUseRef ? useRef(this).current : this
138
142
  }
139
143
 
140
144
  active: string
@@ -144,7 +148,7 @@ export class DigitalKeyboard {
144
148
  }
145
149
 
146
150
  /** 键盘组件 */
147
- readonly children: ReactNode
151
+ readonly node: ReactNode
148
152
  /** 整数型键盘 */
149
153
  int = false
150
154
  /** 设置为整数型键盘 */
@@ -156,8 +160,8 @@ export class DigitalKeyboard {
156
160
  /** 自定义功能按钮 */
157
161
  get actionKeys() {
158
162
  return [
159
- new Btn({ label: '清零', fn: (_) => '' }),
160
- new Btn({
163
+ new DKBtn({ label: '清零', fn: (_) => '' }),
164
+ new DKBtn({
161
165
  label: '下一个',
162
166
  className: 'm-bg-primary m-text-white',
163
167
  fn: (value) => {
@@ -165,7 +169,7 @@ export class DigitalKeyboard {
165
169
  return this.form[this.active]
166
170
  },
167
171
  }),
168
- new Btn({
172
+ new DKBtn({
169
173
  label: '确认',
170
174
  flex: 2,
171
175
  className: 'm-bg-primary m-text-white',
@@ -211,7 +215,7 @@ export class DigitalKeyboard {
211
215
  disabledHeader: true,
212
216
  disabledAnimate: false,
213
217
  bottom: true,
214
- children: this.children,
218
+ children: this.node,
215
219
  })
216
220
  mp && wx.hideKeyboard()
217
221
  }
@@ -222,4 +226,4 @@ export class DigitalKeyboard {
222
226
  }
223
227
  export default DigitalKeyboard
224
228
 
225
- export { Btn } from './Btn'
229
+ export { DKBtn } from './Btn'
@@ -3,7 +3,7 @@ import { Story } from '@storybook/react'
3
3
  import { TextField } from '../text_field'
4
4
  import { DigitalKeyboard, DigitalKeyboardProps } from '.'
5
5
  import { Text } from '../text'
6
- import { Btn } from './Btn'
6
+ import { DKBtn } from './Btn'
7
7
  import { View } from '../view'
8
8
  import { Toast } from '../toast'
9
9
  import { Page } from '../page'
@@ -19,19 +19,17 @@ const Template: Story<DigitalKeyboardProps> = (args) => {
19
19
  apple: '1.00',
20
20
  peach: '0.50',
21
21
  }
22
- const { current: keyboard } = useRef(
23
- new DigitalKeyboard({
24
- ...args,
25
- form: form,
26
- active: '',
27
- async onAction(btn) {
28
- if (btn.label === '确认') {
29
- console.log('result:', 'apple', keyboard.get('apple'))
30
- keyboard.hide()
31
- }
32
- },
33
- })
34
- )
22
+ const keyboard = new DigitalKeyboard({
23
+ ...args,
24
+ form: form,
25
+ active: '',
26
+ async onAction(btn) {
27
+ if (btn.label === '确认') {
28
+ console.log('result:', 'apple', keyboard.get('apple'))
29
+ keyboard.hide()
30
+ }
31
+ },
32
+ })
35
33
 
36
34
  return (
37
35
  <View style={{ height: '300px' }}>
@@ -60,7 +58,7 @@ const Template: Story<DigitalKeyboardProps> = (args) => {
60
58
  export const Usage = Template.bind({})
61
59
  Usage.argTypes = {
62
60
  form: {
63
- description: '`Object` 表单的字段键值对',
61
+ description: '`Object` 表单的字段键值对,可以通过.set增改,通过.get读取',
64
62
  type: {
65
63
  required: true,
66
64
  },
@@ -122,13 +120,13 @@ Usage.argTypes = {
122
120
  },
123
121
  onInput: {
124
122
  description:
125
- '`(value: string | undefined, key: Btn) => void` 虚拟键盘的点击事件',
123
+ '`(value: string | undefined, key: DKBtn) => void` 虚拟键盘的点击事件',
126
124
  control: false,
127
125
  type: {},
128
126
  },
129
127
  onAction: {
130
128
  description:
131
- '`(value: string | undefined, key: Btn) => void` 虚拟键盘的功能键(actionKeys)点击事件',
129
+ '`(value: string | undefined, key: DKBtn) => void` 虚拟键盘的功能键(actionKeys)点击事件',
132
130
  control: false,
133
131
  type: {},
134
132
  },
@@ -154,7 +152,7 @@ Usage.argTypes = {
154
152
  name: 'function',
155
153
  },
156
154
  },
157
- '.children': {
155
+ '.node': {
158
156
  description: '`ReactComponent` 键盘组件节点',
159
157
  type: {
160
158
  name: 'function',
@@ -210,12 +208,10 @@ export const CustomLayout = () => {
210
208
  apple: '1.00',
211
209
  peach: '0.50',
212
210
  }
213
- const { current: keyboard } = useRef(
214
- new DigitalKeyboard({
215
- form: form,
216
- active: '',
217
- })
218
- )
211
+ const keyboard = new DigitalKeyboard({
212
+ form: form,
213
+ active: '',
214
+ })
219
215
 
220
216
  return (
221
217
  <Page style={{ width: '100%' }}>
@@ -228,7 +224,7 @@ export const CustomLayout = () => {
228
224
  头部
229
225
  </Flex>
230
226
  <View>显示在指定位置</View>
231
- <View>{keyboard.children}</View>
227
+ <View>{keyboard.node}</View>
232
228
  <Flex
233
229
  height='100px'
234
230
  className='m-bg-accent m-margin-tb-10'
@@ -246,7 +242,7 @@ export const CustomActions = () => {
246
242
  class Keyboard extends DigitalKeyboard {
247
243
  get actionKeys() {
248
244
  return [
249
- new Btn({
245
+ new DKBtn({
250
246
  className: 'm-bg-accent m-text-white',
251
247
  label: '自定义',
252
248
  fn: (value) => {
@@ -254,7 +250,7 @@ export const CustomActions = () => {
254
250
  return '一键输入自定义内容'
255
251
  },
256
252
  }),
257
- new Btn({
253
+ new DKBtn({
258
254
  label: '确认',
259
255
  flex: 3,
260
256
  className: 'm-bg-primary m-text-white',
@@ -267,20 +263,18 @@ export const CustomActions = () => {
267
263
  }
268
264
  }
269
265
 
270
- const { current: keyboard } = useRef(
271
- new Keyboard({
272
- rewriteMode: true,
273
- fractionDigits: 2,
274
- min: 0,
275
- max: 9999.99,
276
- // 也可以通过这里自定义keys
277
- // digitalKeys: [],
278
- // actionKeys: [],
279
- form: {
280
- input: '',
281
- },
282
- })
283
- )
266
+ const keyboard = new Keyboard({
267
+ rewriteMode: true,
268
+ fractionDigits: 2,
269
+ min: 0,
270
+ max: 9999.99,
271
+ // 也可以通过这里自定义keys
272
+ // digitalKeys: [],
273
+ // actionKeys: [],
274
+ form: {
275
+ input: '',
276
+ },
277
+ })
284
278
  return (
285
279
  <View style={{ height: '300px' }}>
286
280
  <TextField
@@ -197,6 +197,7 @@ export const Draggable: FC<DraggableProps> = ({
197
197
  justifyContent: 'center',
198
198
  cursor: 'pointer',
199
199
  userSelect: 'none',
200
+ zIndex: 2,
200
201
  }
201
202
  const options: any = mp
202
203
  ? {
@@ -0,0 +1,23 @@
1
+ import React, { FC } from 'react'
2
+ import classNames from 'classnames'
3
+ import _ from 'lodash'
4
+ import { View } from '../view'
5
+ import { ErrorProps } from './types'
6
+ import { Text } from '../text'
7
+
8
+ export const Error: FC<ErrorProps> = ({ className, topLine, children }) => {
9
+ return children ? (
10
+ <View
11
+ className={classNames('error', className, {
12
+ 'm-border-1px-top-before': topLine,
13
+ 'has-error': !!children,
14
+ })}
15
+ >
16
+ <View className='error-message'>{children}</View>
17
+ </View>
18
+ ) : (
19
+ <></>
20
+ )
21
+ }
22
+
23
+ export default Error
@@ -0,0 +1 @@
1
+ export { default as Error } from './error'
@@ -0,0 +1,42 @@
1
+ .error {
2
+ @red: fade(red, 50);
3
+ color: @red;
4
+ font-size: 10px;
5
+ width: 100%;
6
+ padding: 5px 0;
7
+ &.m-border-1px-top-before::before {
8
+ border-color: @red;
9
+ }
10
+ .error-message {
11
+ display: inline-block;
12
+ animation-name: headShake;
13
+ animation-timing-function: ease;
14
+ animation-duration: 0.75s;
15
+ }
16
+ }
17
+
18
+ @keyframes headShake {
19
+ 0% {
20
+ transform: translateX(0);
21
+ }
22
+
23
+ 6.5% {
24
+ transform: translateX(-6px) rotateY(-9deg);
25
+ }
26
+
27
+ 18.5% {
28
+ transform: translateX(5px) rotateY(7deg);
29
+ }
30
+
31
+ 31.5% {
32
+ transform: translateX(-3px) rotateY(-5deg);
33
+ }
34
+
35
+ 43.5% {
36
+ transform: translateX(2px) rotateY(3deg);
37
+ }
38
+
39
+ 50% {
40
+ transform: translateX(0);
41
+ }
42
+ }
@@ -0,0 +1,5 @@
1
+ import { HTMLAttributes } from 'react'
2
+
3
+ export interface ErrorProps extends HTMLAttributes<HTMLDivElement> {
4
+ topLine?: boolean
5
+ }
@@ -24,7 +24,6 @@ const LayoutRoot: FC & LayoutRootStatic = () => {
24
24
  [type]: component,
25
25
  }))
26
26
  }
27
-
28
27
  return () => {
29
28
  delete cbMap[path]
30
29
  }
@@ -38,6 +38,8 @@ const PopupBase: FC<PopupProps> = ({
38
38
  /** 动画有卡顿现象,先禁用 */
39
39
  disabledAnimate = true,
40
40
  children,
41
+ hasCustomTab = true,
42
+ disableBottomSafeArea,
41
43
  ...rest
42
44
  }) => {
43
45
  devWarnForHook(() => {
@@ -57,6 +59,7 @@ const PopupBase: FC<PopupProps> = ({
57
59
  'm-animated-slide-in-left': left,
58
60
  'm-animated-slide-in-right': right,
59
61
  'm-animated-slide-in-bottom': bottom,
62
+ 'm-bottom-safe-area': !disableBottomSafeArea,
60
63
  },
61
64
  className
62
65
  )
@@ -90,7 +93,7 @@ const PopupBase: FC<PopupProps> = ({
90
93
  </Flex>
91
94
  )}
92
95
  <View className='m-popup-content'>{children}</View>
93
- <CustomTabbar />
96
+ {hasCustomTab && <CustomTabbar />}
94
97
  </View>
95
98
  </View>
96
99
  )
@@ -51,6 +51,7 @@ const PopupBase: FC<PopupV1Props> = ({
51
51
  titleClassName,
52
52
  titleCenter,
53
53
  clickMaskClose = true,
54
+ disableBottomSafeArea,
54
55
  ...rest
55
56
  }) => {
56
57
  devWarnForHook(() => {
@@ -128,7 +129,7 @@ const PopupBase: FC<PopupV1Props> = ({
128
129
  </Flex>
129
130
  )}
130
131
  <View className='m-popup-content'>{children}</View>
131
- <CustomTabbar />
132
+ {!disableBottomSafeArea && <CustomTabbar />}
132
133
  </View>
133
134
  </View>
134
135
  )
@@ -65,7 +65,7 @@
65
65
 
66
66
  @supports (bottom: constant(safe-area-inset-bottom)) or
67
67
  (bottom: env(safe-area-inset-bottom)) {
68
- .m-popup {
68
+ .m-popup.m-bottom-safe-area {
69
69
  padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */
70
70
  padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */
71
71
  }
@@ -19,6 +19,10 @@ interface PopupProps extends HTMLAttributes<HTMLDivElement> {
19
19
  disabledAnimate?: boolean
20
20
  /** 内部用 */
21
21
  isPickPopup?: boolean
22
+ /** 禁用下方安全边距,默认为false */
23
+ disableBottomSafeArea?: boolean
24
+ /** 预留底部自定义导航高度,默认为true */
25
+ hasCustomTab?: boolean
22
26
  }
23
27
 
24
28
  interface PopupStaticsTypes {
@@ -159,7 +159,7 @@ export class TextField extends Component<TextFieldProps, TextFieldState> {
159
159
  disabled,
160
160
  highlight,
161
161
  cursorSpacing = 30,
162
- maxLength,
162
+ maxLength = -1,
163
163
  confirmType,
164
164
  adjustPosition,
165
165
  block,
@@ -170,6 +170,7 @@ export class TextField extends Component<TextFieldProps, TextFieldState> {
170
170
  onClick,
171
171
  onConfirm,
172
172
  fractionDigits,
173
+ alwaysEmbed = true,
173
174
  ...rest
174
175
  // 注意,不用传给input或area的props要在此列出来,不然rest会带过去
175
176
  } = this.props
@@ -180,7 +181,7 @@ export class TextField extends Component<TextFieldProps, TextFieldState> {
180
181
  const common = {
181
182
  disabled: disabled,
182
183
  onInput: this.onInput.bind(this),
183
- onChange: this.onInput.bind(this),
184
+ // onChange: this.onInput.bind(this),
184
185
  onClick: this.onClick.bind(this),
185
186
  onBlur: () => {
186
187
  onBlur && onBlur()
@@ -207,6 +208,7 @@ export class TextField extends Component<TextFieldProps, TextFieldState> {
207
208
  focus,
208
209
  password,
209
210
  placeholderClass: 'text-field-placeholder',
211
+ alwaysEmbed: alwaysEmbed,
210
212
  onConfirm,
211
213
  })
212
214
  } else {
@@ -300,7 +302,9 @@ export class TextField extends Component<TextFieldProps, TextFieldState> {
300
302
  </Flex>
301
303
  )}
302
304
  <View
303
- className={classNames('text-field-error-message', errClassName)}
305
+ className={classNames('text-field-error-message', errClassName, {
306
+ 'has-error': err,
307
+ })}
304
308
  >
305
309
  {err}
306
310
  </View>
@@ -68,7 +68,6 @@ WithButton.args = {
68
68
  right: (
69
69
  <Button
70
70
  mini
71
- noRound
72
71
  onClick={() => new Promise((resolve) => setTimeout(resolve, 3000))}
73
72
  >
74
73
  获取验证码
@@ -7,7 +7,7 @@ interface TextFieldProps
7
7
  'style' | 'onBlur' | 'onFocus' | 'onClick' | 'onChange' | 'type'
8
8
  > {
9
9
  value: string
10
- /** 输入事件, e在web中为ChangeEvent,在小程序中为onInputEventDetail */
10
+ /** 输入事件, e在web中为ChangeEvent(value为e.target.value),在小程序中为onInputEventDetail(value为e.detail.value) */
11
11
  onChange?: (e: any) => void
12
12
  /** 输入框类型, web端和小程序端取值有差异 */
13
13
  type?: InputProps['type']
package/src/index.less CHANGED
@@ -4,27 +4,10 @@
4
4
 
5
5
  // variable
6
6
  @import './less/variable';
7
- @import './less/variable_page';
8
7
  // theme
9
8
  @import './theme/dark';
10
9
  @import './theme/taobao';
11
10
  @import './theme/jd';
12
- // 公共
13
- @import './less/mixin';
14
- @import './less/base';
15
- @import './less/distance';
16
- @import './less/bg';
17
- @import './less/display';
18
- @import './less/position';
19
- @import './less/overflow';
20
- @import './less/text';
21
- @import './less/border';
22
- @import './less/animation';
23
- @import './less/shadow';
24
- @import './less/btn';
25
- @import './less/ellipsis';
26
- @import './less/lineheight';
27
- @import './less/opacity';
28
11
 
29
12
  // 具体业务
30
13
  @import './component/button/style';
@@ -54,4 +37,22 @@
54
37
  @import './component/picker/style.less';
55
38
  @import './component/nav/style.less';
56
39
  @import './component/date_selector/style.less';
57
- @import './component//text_field/style.less';
40
+ @import './component/text_field/style.less';
41
+ @import './component/error/style.less';
42
+
43
+ // 公共
44
+ @import './less/mixin';
45
+ @import './less/base';
46
+ @import './less/button';
47
+ @import './less/distance';
48
+ @import './less/bg';
49
+ @import './less/display';
50
+ @import './less/position';
51
+ @import './less/overflow';
52
+ @import './less/text';
53
+ @import './less/border';
54
+ @import './less/animation';
55
+ @import './less/shadow';
56
+ @import './less/ellipsis';
57
+ @import './less/lineheight';
58
+ @import './less/opacity';
package/src/index.ts CHANGED
@@ -42,3 +42,4 @@ export * from './component/text_field'
42
42
  export * from './component/digital_keyboard'
43
43
  export * from './component/draggable'
44
44
  export * from './component/form'
45
+ export * from './component/error'
@@ -1,6 +1,7 @@
1
1
  .m-animated {
2
- animation-duration: 0.2s;
3
- animation-fill-mode: none;
2
+ // animation-duration: 0.2s;
3
+ // animation-fill-mode: none;
4
+ transition: all 0.2s;
4
5
  }
5
6
 
6
7
  .m-animated-fade-in {
@@ -153,10 +154,14 @@
153
154
 
154
155
  @keyframes slide-in-bottom {
155
156
  from {
156
- transform: translate3d(0, 100%, 0);
157
+ // transform: translate3d(0, 100%, 0);
158
+ max-height: 0%;
159
+ overflow: hidden;
157
160
  }
158
161
 
159
162
  to {
160
- transform: translate3d(0, 0, 0);
163
+ // transform: translate3d(0, 0, 0);
164
+ max-height: 100%;
165
+ overflow: hidden;
161
166
  }
162
167
  }
package/src/less/bg.less CHANGED
@@ -26,6 +26,10 @@
26
26
  background: var(--m-color-bg-accent-light) !important;
27
27
  }
28
28
 
29
+ .m-bg-transparent {
30
+ background: transparent !important;
31
+ }
32
+
29
33
  .m-bg-white-active-with {
30
34
  .mBgWhiteActiveWith();
31
35
  }
@@ -61,4 +65,7 @@ each(@colors,.(@color,@colorKey,@index){
61
65
  .generate-colors(@opacity+1);
62
66
  }
63
67
  .generate-colors(0);
68
+ .m-bg-@{colorKey}{
69
+ background-color: @color!important;
70
+ }
64
71
  });
@@ -2,6 +2,17 @@
2
2
  border: 1px solid var(--m-color-border) !important;
3
3
  }
4
4
 
5
+ // @directions: top, right, bottom, left;
6
+ // .for-each(@direction in @directions) {
7
+ // .generate-border(@size) when (@size<=10) {
8
+ // .m-border-@{direction}-@{size} {
9
+ // border-@{direction}: @size solid var(--m-color-border) !important;
10
+ // }
11
+ // .generate-border(@size+1);
12
+ // }
13
+ // .generate-border(0);
14
+ // }
15
+
5
16
  .m-border-top {
6
17
  border-top: 1px solid var(--m-color-border) !important;
7
18
  }
@@ -87,13 +98,13 @@
87
98
  }
88
99
 
89
100
  .m-border-radius-circle {
90
- border-radius: 50%;
101
+ border-radius: 50%!important;
91
102
  }
92
103
 
93
104
  .m-border-radius-chip {
94
- border-radius: 100px;
105
+ border-radius: 100px!important;
95
106
  }
96
107
 
97
108
  .m-border-radius-5 {
98
- border-radius: 5px;
109
+ border-radius: 5px!important;
99
110
  }
@@ -46,7 +46,7 @@
46
46
  padding: 0 10px;
47
47
  border-radius: 3px;
48
48
  box-sizing: border-box;
49
- line-height: 1;
49
+ line-height: 2;
50
50
  min-height: @button-normal;
51
51
  cursor: pointer;
52
52
  user-select: none;
@@ -68,6 +68,7 @@
68
68
  }
69
69
  .m-button {
70
70
  .m-button-text();
71
+ line-height: 1;
71
72
  background-color: @button-with-white-text[default];
72
73
  }
73
74
 
@@ -112,6 +113,7 @@ each(@button-with-black-text,.(@value,@key,@index){
112
113
 
113
114
  .m-button-icon {
114
115
  .m-button-text();
116
+ line-height: 1;
115
117
  min-width: @button-normal;
116
118
  padding: 10px;
117
119
  border-radius: 50%;
@@ -23,6 +23,8 @@
23
23
  10: 10px;
24
24
  15: 15px;
25
25
  20: 20px;
26
+ 25: 25px;
27
+ 30: 30px;
26
28
  };
27
29
 
28
30
  each(@size, {
@@ -1,27 +1,3 @@
1
- .m-text-20 {
2
- font-size: var(--m-size-text-20) !important;
3
- }
4
-
5
- .m-text-18 {
6
- font-size: var(--m-size-text-18) !important;
7
- }
8
-
9
- .m-text-16 {
10
- font-size: var(--m-size-text-16) !important;
11
- }
12
-
13
- .m-text-14 {
14
- font-size: var(--m-size-text-14) !important;
15
- }
16
-
17
- .m-text-12 {
18
- font-size: var(--m-size-text-12) !important;
19
- }
20
-
21
- .m-text-10 {
22
- font-size: var(--m-size-text-10) !important;
23
- }
24
-
25
1
  .m-text-center {
26
2
  text-align: center !important;
27
3
  }
@@ -123,4 +99,20 @@ each(@colors,.(@color,@colorKey,@index){
123
99
  .generate-colors(@opacity+1);
124
100
  }
125
101
  .generate-colors(0);
102
+ .m-text-@{colorKey}{
103
+ color: @color!important;
104
+ }
126
105
  });
106
+
107
+ // 生成size, .m-text-{8-32}, --m-size-text-{8-32}
108
+ .generate-size(@size) when (@size<=32) {
109
+ :root,
110
+ page {
111
+ --m-size-text-@{size}: ~'@{size}px';
112
+ }
113
+ .m-text-@{size} {
114
+ font-size: e(%('var(--m-size-text-%s)!important', @size));
115
+ }
116
+ .generate-size(@size + 2);
117
+ }
118
+ .generate-size(8);
@@ -7,7 +7,8 @@
7
7
  // stylelint-disable
8
8
 
9
9
  // 颜色,会通过主题更改
10
- :root {
10
+ :root,
11
+ page {
11
12
  // color
12
13
  --m-color-default: #353535; // 主内容
13
14
  --m-color-desc: #888; // 次要内容
@@ -32,13 +33,20 @@
32
33
  --m-btn-color-default-active: darken(#888, 10%);
33
34
  --m-btn-color-bg-default: #f6f6f6;
34
35
  --m-btn-color-bg-default-active: #ececec;
36
+ --m-btn-border-radius: 8px;
35
37
 
36
38
  // calendar
37
39
  --m-calendar-bg-active: fadeout(rgba(30, 172, 82, 1), 80%);
40
+
41
+ // 输入框大小
42
+ --m-textfield-height-mini: 32px;
43
+ --m-textfield-height-normal: 48px;
44
+ --m-textfield-height-large: 64px;
38
45
  }
39
46
 
40
47
  // 不变的颜色
41
- :root {
48
+ :root,
49
+ page {
42
50
  // color
43
51
  --m-color-placeholder: #b2b2b2;
44
52
  --m-color-accent: #ff6500;
@@ -81,15 +89,8 @@
81
89
  }
82
90
 
83
91
  // 非颜色
84
- :root {
85
- // 字体尺寸
86
- --m-size-text-10: 10px;
87
- --m-size-text-12: 12px;
88
- --m-size-text-14: 14px;
89
- --m-size-text-16: 16px;
90
- --m-size-text-18: 18px;
91
- --m-size-text-20: 20px;
92
-
92
+ :root,
93
+ page {
93
94
  // line-height
94
95
  --m-size-line-height: 1.6;
95
96
 
@@ -1,129 +0,0 @@
1
- /*
2
- 规则
3
- --color 颜色相关
4
- --size 尺寸相关
5
- --btn 具体业务
6
- */
7
- // stylelint-disable
8
-
9
- // 颜色,会通过主题更改
10
- page {
11
- // color
12
- --m-color-default: #353535; // 主内容
13
- --m-color-desc: #888; // 次要内容
14
- --m-color-primary: rgba(30, 172, 82, 1);
15
- --m-color-white: white;
16
- --m-color-black: black;
17
-
18
- // bg
19
- --m-color-bg-white: white;
20
- --m-color-bg-back: #f6f6f6; // 背景色
21
- --m-color-bg-light: #fbfbfb; // 亮点的背景色
22
- --m-color-bg-primary: rgba(30, 172, 82, 1);
23
- --m-color-bg-secondary: fadeout(rgba(30, 172, 82, 1), 80%);
24
-
25
- // active
26
- --m-color-bg-white-active: #ececec;
27
- --m-color-bg-back-active: #ececec;
28
- --m-color-bg-primary-active: darken(rgba(30, 172, 82, 1), 10%);
29
-
30
- // btn
31
- --m-btn-color-default: #888;
32
- --m-btn-color-default-active: darken(#888, 10%);
33
- --m-btn-color-bg-default: #f6f6f6;
34
- --m-btn-color-bg-default-active: #ececec;
35
-
36
- // calendar
37
- --m-calendar-bg-active: fadeout(rgba(30, 172, 82, 1), 80%);
38
-
39
- // shadow
40
- --m-shadow: #ecf0f5;
41
- }
42
-
43
- // 不变的颜色
44
- page {
45
- // color
46
- --m-color-placeholder: #b2b2b2;
47
- --m-color-accent: #ff6500;
48
- --m-color-success: #1eac52;
49
- --m-color-danger: #fa5151;
50
- --m-color-link: #576b95;
51
- --m-color-red: red;
52
- --m-color-true-white: white; // 一定是白色
53
- --m-color-true-black: black; // 一定是黑色
54
-
55
- // bg
56
- --m-color-bg-accent: #ff6500;
57
- --m-color-bg-accent-light: tint(#ff6500, 80%);
58
- --m-color-bg-danger: #fa5151;
59
- --m-color-bg-red: red;
60
- --m-color-bg-black: black;
61
-
62
- // active
63
- --m-color-bg-danger-active: darken(#fa5151, 10%);
64
-
65
- // border
66
- --m-color-border: rgba(0, 0, 0, 0.1);
67
- // 深色 border
68
- --m-color-border-dark: rgba(0, 0, 0, 0.3);
69
-
70
- // mask 背景色
71
- --m-color-bg-mask: rgba(0, 0, 0, 0.6);
72
-
73
- // toast
74
- --m-color-bg-toast: #606060;
75
-
76
- // coupon
77
- --m-color-coupon-disabled: #b2b2b2;
78
- --m-color-bg-coupon-disabled: #b2b2b2;
79
- --m-color-coupon-bg-vip: #24282c;
80
- --m-color-coupon-vip: #d7b08a;
81
-
82
- // 阴影色
83
- --m-color-box-shadow: rgba(0, 0, 0, 0.4);
84
-
85
- // 按钮大小
86
- --m-button-height-small: 34px;
87
- --m-button-height-normal: 44px;
88
- --m-button-height-large: 54px;
89
-
90
- // 输入框大小
91
- --m-textfield-height-mini: 32px;
92
- --m-textfield-height-normal: 48px;
93
- --m-textfield-height-large: 64px;
94
- }
95
-
96
- // 非颜色
97
- page {
98
- // 字体尺寸
99
- --m-size-text-10: 10px;
100
- --m-size-text-12: 12px;
101
- --m-size-text-14: 14px;
102
- --m-size-text-16: 16px;
103
- --m-size-text-18: 18px;
104
- --m-size-text-20: 20px;
105
-
106
- // line-height
107
- --m-size-line-height: 1.6;
108
-
109
- // height
110
- --m-size-tabbar-height: 49px;
111
- --m-size-header-height: 48px;
112
- --m-size-form-height: 40px;
113
- --m-size-form-height-sm: 30px;
114
- --m-size-cell-height: 52px;
115
- --m-size-cell-height-mini: 32px;
116
-
117
- // zIndex
118
- --m-z-index-header: 20;
119
- --m-z-index-tabbar: 20;
120
- --m-z-index-innerLayer: 900;
121
- --m-z-index-mask: 1000;
122
- --m-z-index-popup: 2000;
123
- --m-z-index-trigger: 2000;
124
- --m-z-index-previewImage: 4000;
125
- --m-z-index-dialog: 5000;
126
- --m-z-index-picker: 6000;
127
- --m-z-index-toast: 7000;
128
- --m-z-index-nprogress: 9999;
129
- }