antd-solid 0.0.2 → 0.0.4
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.
- package/dist/index.css +69 -0
- package/dist/index.esm.js +2369 -0
- package/dist/index.umd.js +1 -0
- package/package.json +32 -14
- package/src/index.ts +12 -5
- package/.eslintrc.cjs +0 -36
- package/.prettierrc +0 -11
- package/.vscode/settings.json +0 -13
- package/docs/.vitepress/components/Code.vue +0 -59
- package/docs/.vitepress/config.ts +0 -49
- package/docs/.vitepress/theme/index.css +0 -15
- package/docs/.vitepress/theme/index.ts +0 -13
- package/docs/components/Button.tsx +0 -20
- package/docs/components/Table.tsx +0 -34
- package/docs/components/button.md +0 -23
- package/docs/components/table.md +0 -23
- package/docs/index.md +0 -28
- package/rollup.config.js +0 -25
- package/src/Button.css +0 -14
- package/src/Button.tsx +0 -86
- package/src/ColorPicker.tsx +0 -66
- package/src/DatePicker.tsx +0 -12
- package/src/Form.tsx +0 -98
- package/src/Image.tsx +0 -29
- package/src/Input.tsx +0 -110
- package/src/InputNumber.test.tsx +0 -46
- package/src/InputNumber.tsx +0 -119
- package/src/Modal.tsx +0 -168
- package/src/Popconfirm.tsx +0 -73
- package/src/Popover.tsx +0 -30
- package/src/Progress.tsx +0 -4
- package/src/Radio.tsx +0 -132
- package/src/Result.tsx +0 -38
- package/src/Select.tsx +0 -6
- package/src/Skeleton.tsx +0 -14
- package/src/Spin.tsx +0 -23
- package/src/Switch.tsx +0 -34
- package/src/Table.tsx +0 -46
- package/src/Tabs.tsx +0 -88
- package/src/Timeline.tsx +0 -33
- package/src/Tooltip.tsx +0 -209
- package/src/Tree.tsx +0 -246
- package/src/Upload.tsx +0 -10
- package/src/hooks/createControllableValue.ts +0 -65
- package/src/hooks/createUpdateEffect.ts +0 -16
- package/src/hooks/index.ts +0 -2
- package/src/hooks/useClickAway.ts +0 -18
- package/src/hooks/useSize.ts +0 -26
- package/src/index.css +0 -21
- package/src/utils/ReactToSolid.tsx +0 -38
- package/src/utils/SolidToReact.tsx +0 -27
- package/src/utils/array.ts +0 -21
- package/src/utils/component.tsx +0 -85
- package/src/utils/solid.ts +0 -48
- package/tsconfig.json +0 -23
- package/unocss.config.ts +0 -92
package/src/Button.css
DELETED
package/src/Button.tsx
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Component,
|
|
3
|
-
mergeProps,
|
|
4
|
-
type ParentProps,
|
|
5
|
-
type JSX,
|
|
6
|
-
Show,
|
|
7
|
-
createSignal,
|
|
8
|
-
createMemo,
|
|
9
|
-
} from 'solid-js'
|
|
10
|
-
import cs from 'classnames'
|
|
11
|
-
import './Button.css'
|
|
12
|
-
|
|
13
|
-
interface ButtonProps extends ParentProps, JSX.CustomAttributes<HTMLButtonElement> {
|
|
14
|
-
type?: 'default' | 'primary' | 'text' | 'link'
|
|
15
|
-
onClick?: ((e: MouseEvent) => void) | ((e: MouseEvent) => Promise<unknown>)
|
|
16
|
-
/**
|
|
17
|
-
* 默认: middle
|
|
18
|
-
* plain: 没有多余的 padding 和高度等
|
|
19
|
-
*/
|
|
20
|
-
size?: 'large' | 'middle' | 'small' | 'plain'
|
|
21
|
-
class?: string
|
|
22
|
-
style?: JSX.CSSProperties
|
|
23
|
-
loading?: boolean
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const sizeClassMap = {
|
|
27
|
-
large: 'ant-px-15px ant-py-6px ant-h-40px ant-rounded-8px',
|
|
28
|
-
middle: 'ant-px-15px ant-py-4px ant-h-32px ant-rounded-6px',
|
|
29
|
-
small: 'ant-px-7px ant-h-24px ant-rounded-4px',
|
|
30
|
-
plain: 'ant-p-0',
|
|
31
|
-
} as const
|
|
32
|
-
|
|
33
|
-
const typeClassMap = {
|
|
34
|
-
default:
|
|
35
|
-
'ant-[border:1px_solid_rgb(217,217,217)] ant-bg-white ant-text-[var(--dark-color)] hover:ant-[border-color:var(--light-primary-color)] hover:ant-text-[var(--light-primary-color)]',
|
|
36
|
-
primary:
|
|
37
|
-
'ant-border-none ant-bg-[var(--primary-color)] hover:ant-bg-[var(--light-primary-color)] ant-text-white',
|
|
38
|
-
text: 'ant-border-none ant-bg-transparent ant-text-[var(--dark-color)] hover:ant-bg-[rgba(0,0,0,0.06)] active:ant-bg-[rgba(0,0,0,.15)]',
|
|
39
|
-
link: 'ant-border-none ant-bg-transparent ant-text-[var(--primary-color)] hover:ant-text-[var(--light-primary-color)] active:ant-text-[var(--dark-primary-color)]',
|
|
40
|
-
} as const
|
|
41
|
-
|
|
42
|
-
const Button: Component<ButtonProps> = props => {
|
|
43
|
-
const mergedProps = mergeProps({ type: 'default', size: 'middle' } as ButtonProps, props)
|
|
44
|
-
const [innerLoading, setLoading] = createSignal(false)
|
|
45
|
-
const loading = createMemo(() => props.loading ?? innerLoading())
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<button
|
|
49
|
-
ref={mergedProps.ref}
|
|
50
|
-
class={cs(
|
|
51
|
-
'ant-relative ant-cursor-pointer',
|
|
52
|
-
mergedProps.class,
|
|
53
|
-
sizeClassMap[mergedProps.size!],
|
|
54
|
-
typeClassMap[mergedProps.type!],
|
|
55
|
-
loading() && 'ant-opacity-65',
|
|
56
|
-
)}
|
|
57
|
-
style={mergedProps.style}
|
|
58
|
-
onClick={e => {
|
|
59
|
-
const res = mergedProps.onClick?.(e)
|
|
60
|
-
if (res instanceof Promise) {
|
|
61
|
-
setLoading(true)
|
|
62
|
-
res.finally(() => setLoading(false))
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (mergedProps.type === 'default' || mergedProps.type === 'primary') {
|
|
66
|
-
const div = document.createElement('div')
|
|
67
|
-
div.className =
|
|
68
|
-
'ant-absolute ant-inset-0 ant-rounded-inherit ant-[border:1px_solid_var(--light-primary-color)] ant-[animation:button-border_linear_1s]'
|
|
69
|
-
const onAnimationEnd = () => {
|
|
70
|
-
div.remove()
|
|
71
|
-
div.removeEventListener('animationend', onAnimationEnd)
|
|
72
|
-
}
|
|
73
|
-
div.addEventListener('animationend', onAnimationEnd)
|
|
74
|
-
e.currentTarget.insertBefore(div, e.currentTarget.childNodes[0])
|
|
75
|
-
}
|
|
76
|
-
}}
|
|
77
|
-
>
|
|
78
|
-
<Show when={loading()}>
|
|
79
|
-
<span class="i-ant-design:loading ant-[vertical-align:-0.125em] keyframes-spin ant-[animation:spin_1s_linear_infinite] ant-mr-8px" />
|
|
80
|
-
</Show>
|
|
81
|
-
<span>{mergedProps.children}</span>
|
|
82
|
-
</button>
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export default Button
|
package/src/ColorPicker.tsx
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { type Component, createSignal, mergeProps, untrack } from 'solid-js'
|
|
2
|
-
import { type ColorResult, SketchPicker, type Color, type RGBColor, type HSLColor } from 'react-color'
|
|
3
|
-
import { reactToSolidComponent } from './utils/component'
|
|
4
|
-
import Button from './Button'
|
|
5
|
-
import Popover from './Popover'
|
|
6
|
-
import { get, isNil } from 'lodash-es'
|
|
7
|
-
|
|
8
|
-
const _SketchPicker = reactToSolidComponent(SketchPicker)
|
|
9
|
-
|
|
10
|
-
export interface ColorPickerProps {
|
|
11
|
-
/**
|
|
12
|
-
* 默认: rgba
|
|
13
|
-
*/
|
|
14
|
-
type?: 'rgba' | 'hsla'
|
|
15
|
-
defaultColor?: string
|
|
16
|
-
onChange?: (colorString: string, color: ColorResult) => void
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function isRGBColor(color: Color): color is RGBColor {
|
|
20
|
-
return ['r', 'g', 'b'].every(k => !isNil(get(color, k)))
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function isHSLColor(color: Color): color is HSLColor {
|
|
24
|
-
return ['r', 'g', 'b'].every(k => !isNil(get(color, k)))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function colorStringify(color: Color | undefined) {
|
|
28
|
-
if (!color) return
|
|
29
|
-
|
|
30
|
-
if (isRGBColor(color)) return `rgba(${color.r},${color.g},${color.b},${color.a ?? 1})`
|
|
31
|
-
|
|
32
|
-
if (isHSLColor(color)) return `hsla(${color.h},${color.s},${color.l},${color.a ?? 1})`
|
|
33
|
-
|
|
34
|
-
return color
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const ColorPicker: Component<ColorPickerProps> = _props => {
|
|
38
|
-
const props = mergeProps({ type: 'rgba' } as ColorPickerProps, _props)
|
|
39
|
-
const [color, setColor] = createSignal(props.defaultColor ?? 'black')
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<Popover
|
|
43
|
-
content={
|
|
44
|
-
<_SketchPicker
|
|
45
|
-
color={color()}
|
|
46
|
-
onChange={colorResult =>
|
|
47
|
-
{ untrack(() => {
|
|
48
|
-
const colorString = colorStringify(
|
|
49
|
-
props.type === 'rgba' ? colorResult.rgb : colorResult.hsl,
|
|
50
|
-
)!
|
|
51
|
-
setColor(colorString)
|
|
52
|
-
|
|
53
|
-
props.onChange?.(colorString, colorResult)
|
|
54
|
-
}); }
|
|
55
|
-
}
|
|
56
|
-
/>
|
|
57
|
-
}
|
|
58
|
-
trigger="click"
|
|
59
|
-
placement="bottomLeft"
|
|
60
|
-
>
|
|
61
|
-
<Button style={{ background: color() }} />
|
|
62
|
-
</Popover>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export default ColorPicker
|
package/src/DatePicker.tsx
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { DatePicker as DatePickerAntd } from 'antd'
|
|
2
|
-
import { reactToSolidComponent, replaceClassName } from './utils/component'
|
|
3
|
-
|
|
4
|
-
const RangePicker = replaceClassName(reactToSolidComponent(DatePickerAntd.RangePicker))
|
|
5
|
-
|
|
6
|
-
const _DatePicker = replaceClassName(reactToSolidComponent(DatePickerAntd))
|
|
7
|
-
const DatePicker = _DatePicker as typeof _DatePicker & {
|
|
8
|
-
RangePicker: typeof RangePicker
|
|
9
|
-
}
|
|
10
|
-
DatePicker.RangePicker = RangePicker
|
|
11
|
-
|
|
12
|
-
export default DatePicker
|
package/src/Form.tsx
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { set } from 'lodash-es'
|
|
2
|
-
import {
|
|
3
|
-
type JSXElement,
|
|
4
|
-
type Component,
|
|
5
|
-
type JSX,
|
|
6
|
-
mergeProps,
|
|
7
|
-
Show,
|
|
8
|
-
Index,
|
|
9
|
-
createMemo,
|
|
10
|
-
} from 'solid-js'
|
|
11
|
-
import { Dynamic } from 'solid-js/web'
|
|
12
|
-
import { toArray } from './utils/array'
|
|
13
|
-
import cs from 'classnames'
|
|
14
|
-
|
|
15
|
-
export interface FormInstance<T extends {} = {}> {
|
|
16
|
-
validateFields: () => Promise<T>
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface FormProps<T extends {} = {}> {
|
|
20
|
-
ref?: (form: FormInstance<T>) => void;
|
|
21
|
-
/**
|
|
22
|
-
* 表单布局
|
|
23
|
-
* 默认: horizontal
|
|
24
|
-
*/
|
|
25
|
-
layout?: 'horizontal' | 'vertical' | 'inline'
|
|
26
|
-
/**
|
|
27
|
-
* 提交按钮
|
|
28
|
-
* @deprecated
|
|
29
|
-
*/
|
|
30
|
-
submit?: (form: FormInstance<T>) => JSXElement
|
|
31
|
-
children: JSXElement
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface FormItemComponentProps<T = any> {
|
|
35
|
-
defaultValue?: T
|
|
36
|
-
onChange?: (value: T) => void
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface FormItemProps {
|
|
40
|
-
class?: string
|
|
41
|
-
style?: JSX.CSSProperties
|
|
42
|
-
required?: boolean
|
|
43
|
-
label?: JSXElement
|
|
44
|
-
name?: string
|
|
45
|
-
initialValue?: any
|
|
46
|
-
component: Component<FormItemComponentProps>
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function Form<T extends {} = {}>(_props: FormProps<T>) {
|
|
50
|
-
const props = mergeProps({ layout: 'horizontal' } as FormProps, _props)
|
|
51
|
-
|
|
52
|
-
const resolvedChildren = createMemo(() => {
|
|
53
|
-
return toArray(props.children) as unknown as FormItemProps[]
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
const values = Object.fromEntries(
|
|
57
|
-
resolvedChildren().map(child => [child.name, child.initialValue]),
|
|
58
|
-
) as T
|
|
59
|
-
const formInstance: FormInstance<T> = {
|
|
60
|
-
async validateFields() {
|
|
61
|
-
return await Promise.resolve(values)
|
|
62
|
-
},
|
|
63
|
-
}
|
|
64
|
-
_props.ref?.(formInstance)
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<div>
|
|
68
|
-
<Index each={resolvedChildren()}>
|
|
69
|
-
{item => (
|
|
70
|
-
<div class={cs('ant-flex ant-items-center ant-mb-16px', item().class)} style={item().style}>
|
|
71
|
-
<span class="ant-flex-shrink-0 ant-mr-8px">
|
|
72
|
-
<Show when={item().required}>
|
|
73
|
-
<span class='ant-mr-4px ant-text-[var(--error-color)]'>*</span>
|
|
74
|
-
</Show>
|
|
75
|
-
<label>{item().label}</label>
|
|
76
|
-
</span>
|
|
77
|
-
|
|
78
|
-
<Dynamic
|
|
79
|
-
component={item().component}
|
|
80
|
-
defaultValue={item().initialValue}
|
|
81
|
-
onChange={(value: any) => {
|
|
82
|
-
set(values, item().name!, value)
|
|
83
|
-
}}
|
|
84
|
-
/>
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
</Index>
|
|
88
|
-
|
|
89
|
-
{props.submit?.(formInstance as FormInstance<T>)}
|
|
90
|
-
</div>
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
Form.Item = (props: FormItemProps) => props as any
|
|
95
|
-
|
|
96
|
-
Form.createForm = () => {}
|
|
97
|
-
|
|
98
|
-
export default Form
|
package/src/Image.tsx
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Image as ImageAntd } from 'antd'
|
|
2
|
-
import { configProvider, reactToSolidComponent, replaceClassName } from './utils/component'
|
|
3
|
-
import { solidToReact } from './utils/solid'
|
|
4
|
-
import { type JSXElement, createMemo } from 'solid-js'
|
|
5
|
-
import { mapValues } from 'lodash-es'
|
|
6
|
-
|
|
7
|
-
const _Image = replaceClassName(
|
|
8
|
-
reactToSolidComponent(configProvider(ImageAntd), () => (<div class="ant-inline-flex" />) as any),
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
type ImageProps = Omit<Parameters<typeof _Image>[0], 'placeholder'> & {
|
|
12
|
-
placeholder?: JSXElement
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function Image(_props: ImageProps) {
|
|
16
|
-
const props = createMemo(() =>
|
|
17
|
-
mapValues(_props, (value, key) => {
|
|
18
|
-
switch (key) {
|
|
19
|
-
case 'placeholder':
|
|
20
|
-
return solidToReact(value)
|
|
21
|
-
default:
|
|
22
|
-
return value
|
|
23
|
-
}
|
|
24
|
-
}),
|
|
25
|
-
)
|
|
26
|
-
return <_Image {...(props() as any)} />
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export default Image
|
package/src/Input.tsx
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { omit } from 'lodash-es'
|
|
2
|
-
import { Show, splitProps } from 'solid-js'
|
|
3
|
-
import type { JSX, JSXElement, Component } from 'solid-js'
|
|
4
|
-
import cs from 'classnames'
|
|
5
|
-
import createControllableValue from './hooks/createControllableValue'
|
|
6
|
-
import { Dynamic } from 'solid-js/web'
|
|
7
|
-
|
|
8
|
-
type CommonInputProps<T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement> = JSX.CustomAttributes<T> & {
|
|
9
|
-
textarea?: boolean
|
|
10
|
-
defaultValue?: string | undefined
|
|
11
|
-
value?: string | undefined
|
|
12
|
-
addonBefore?: JSXElement
|
|
13
|
-
addonAfter?: JSXElement
|
|
14
|
-
/**
|
|
15
|
-
* 仅供 InputNumber 使用
|
|
16
|
-
*/
|
|
17
|
-
inputAfter?: JSXElement
|
|
18
|
-
placeholder?: string
|
|
19
|
-
onChange?: JSX.InputEventHandler<T, InputEvent>
|
|
20
|
-
onPressEnter?: JSX.EventHandler<T, KeyboardEvent>
|
|
21
|
-
onKeyDown?: JSX.EventHandler<T, KeyboardEvent>
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function CommonInput<T extends HTMLInputElement | HTMLTextAreaElement = HTMLInputElement>(props: CommonInputProps<T> &
|
|
25
|
-
Omit<JSX.InputHTMLAttributes<T>, 'onChange' | 'onInput' | 'onKeyDown'>) {
|
|
26
|
-
const [{ onChange, onPressEnter, onKeyDown }, inputProps] = splitProps(props, [
|
|
27
|
-
'defaultValue',
|
|
28
|
-
'value',
|
|
29
|
-
'class',
|
|
30
|
-
'addonBefore',
|
|
31
|
-
'addonAfter',
|
|
32
|
-
'inputAfter',
|
|
33
|
-
'onChange',
|
|
34
|
-
'onPressEnter',
|
|
35
|
-
'onKeyDown',
|
|
36
|
-
])
|
|
37
|
-
|
|
38
|
-
const [_, controllableProps] = splitProps(props, ['onChange'])
|
|
39
|
-
const [value, setValue] = createControllableValue(controllableProps)
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div class="ant-flex ant-w-full">
|
|
43
|
-
<Show when={props.addonBefore}>
|
|
44
|
-
<div class="ant-shrink-0 ant-flex ant-justify-center ant-items-center ant-px-11px ant-bg-[rgba(0,0,0,.02)] ant-[border:1px_solid_#d9d9d9] ant-border-r-0 ant-rounded-l-6px ant-text-14px">
|
|
45
|
-
{props.addonBefore}
|
|
46
|
-
</div>
|
|
47
|
-
</Show>
|
|
48
|
-
|
|
49
|
-
<div class="ant-w-full ant-relative ant-[--input-after-display:none] hover:ant-[--input-after-display:block] p-hover-child[input]:ant-border-[var(--primary-color)]">
|
|
50
|
-
<Dynamic<Component<JSX.InputHTMLAttributes<HTMLInputElement>>>
|
|
51
|
-
component={
|
|
52
|
-
(props.textarea ? 'textarea' : 'input') as unknown as Component<
|
|
53
|
-
JSX.InputHTMLAttributes<HTMLInputElement>
|
|
54
|
-
>
|
|
55
|
-
}
|
|
56
|
-
{...inputProps as JSX.InputHTMLAttributes<HTMLInputElement>}
|
|
57
|
-
class={cs(
|
|
58
|
-
'ant-w-full ant-py-0 ant-px-11px ant-[outline:none] ant-text-14px ant-rounded-6px ant-[border:1px_solid_#d9d9d9] focus:ant-border-[var(--primary-color)] focus:ant-[box-shadow:0_0_0_2px_rgba(5,145,255,0.1)] ant-py-8px',
|
|
59
|
-
!props.textarea && 'ant-h-32px',
|
|
60
|
-
props.class,
|
|
61
|
-
props.addonBefore && 'ant-rounded-l-0',
|
|
62
|
-
props.addonAfter && 'ant-rounded-r-0',
|
|
63
|
-
)}
|
|
64
|
-
value={value() ?? ''}
|
|
65
|
-
onInput={e => {
|
|
66
|
-
setValue(e.target.value)
|
|
67
|
-
onChange?.(e as any)
|
|
68
|
-
}}
|
|
69
|
-
onKeyDown={e => {
|
|
70
|
-
if (e.key === 'Enter') {
|
|
71
|
-
onPressEnter?.(e as any)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
onKeyDown?.(e as any)
|
|
75
|
-
}}
|
|
76
|
-
/>
|
|
77
|
-
|
|
78
|
-
<Show when={props.inputAfter}>
|
|
79
|
-
<div class="ant-[display:var(--input-after-display)] ant-absolute ant-top-0 ant-bottom-0 ant-right-0 ant-h-[calc(100%-2px)] ant-translate-y-1px -ant-translate-x-1px">
|
|
80
|
-
{props.inputAfter}
|
|
81
|
-
</div>
|
|
82
|
-
</Show>
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
<Show when={props.addonAfter}>
|
|
86
|
-
<div class="ant-shrink-0 ant-flex ant-justify-center ant-items-center ant-px-11px ant-bg-[rgba(0,0,0,.02)] ant-[border:1px_solid_#d9d9d9] ant-border-l-0 ant-rounded-r-6px ant-text-14px">
|
|
87
|
-
{props.addonAfter}
|
|
88
|
-
</div>
|
|
89
|
-
</Show>
|
|
90
|
-
</div>
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export type InputProps = Omit<CommonInputProps, 'inputAfter' | 'textarea'> &
|
|
95
|
-
Omit<JSX.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onInput' | 'onKeyDown'>
|
|
96
|
-
|
|
97
|
-
export type TextAreaProps = Omit<CommonInputProps<HTMLTextAreaElement>, 'inputAfter' | 'textarea'> &
|
|
98
|
-
Omit<JSX.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange' | 'onInput' | 'onKeyDown'>
|
|
99
|
-
|
|
100
|
-
const Input: Component<InputProps> & {
|
|
101
|
-
TextArea: Component<TextAreaProps>
|
|
102
|
-
} = props => {
|
|
103
|
-
return <CommonInput {...omit(props, ['inputAfter'])} />
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
Input.TextArea = props => {
|
|
107
|
-
return <CommonInput<HTMLTextAreaElement> textarea {...omit(props, ['inputAfter'])} />
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export default Input
|
package/src/InputNumber.test.tsx
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
-
import { fireEvent, render } from '@solidjs/testing-library'
|
|
3
|
-
import InputNumber from './InputNumber'
|
|
4
|
-
import '@testing-library/jest-dom'
|
|
5
|
-
|
|
6
|
-
describe('InputNumber component', () => {
|
|
7
|
-
it('onChange', () => {
|
|
8
|
-
const onChange = vi.fn()
|
|
9
|
-
const { getByPlaceholderText } = render(() => (
|
|
10
|
-
<InputNumber placeholder="input-number" onChange={onChange} />
|
|
11
|
-
))
|
|
12
|
-
|
|
13
|
-
const input: HTMLInputElement = getByPlaceholderText('input-number')
|
|
14
|
-
input.value = '123'
|
|
15
|
-
fireEvent.input(input)
|
|
16
|
-
expect(onChange).toHaveBeenLastCalledWith(123)
|
|
17
|
-
|
|
18
|
-
input.value = '1234'
|
|
19
|
-
fireEvent.input(input)
|
|
20
|
-
expect(onChange).toBeCalledTimes(2)
|
|
21
|
-
expect(onChange).toHaveBeenLastCalledWith(1234)
|
|
22
|
-
|
|
23
|
-
input.value = '1234'
|
|
24
|
-
fireEvent.input(input)
|
|
25
|
-
expect(onChange).toBeCalledTimes(2)
|
|
26
|
-
|
|
27
|
-
input.value = '1234.'
|
|
28
|
-
fireEvent.input(input)
|
|
29
|
-
expect(onChange).toBeCalledTimes(2)
|
|
30
|
-
|
|
31
|
-
input.value = '1234.0'
|
|
32
|
-
fireEvent.input(input)
|
|
33
|
-
expect(onChange).toBeCalledTimes(2)
|
|
34
|
-
|
|
35
|
-
input.value = '1234.01'
|
|
36
|
-
fireEvent.input(input)
|
|
37
|
-
expect(onChange).toBeCalledTimes(3)
|
|
38
|
-
|
|
39
|
-
input.value = '123x'
|
|
40
|
-
fireEvent.input(input)
|
|
41
|
-
expect(onChange).toBeCalledTimes(3)
|
|
42
|
-
|
|
43
|
-
fireEvent.blur(input)
|
|
44
|
-
expect(onChange).toBeCalledTimes(3)
|
|
45
|
-
})
|
|
46
|
-
})
|
package/src/InputNumber.tsx
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { type Component, createEffect, on, splitProps } from 'solid-js'
|
|
2
|
-
import { CommonInput, type InputProps } from './Input'
|
|
3
|
-
import { isNil } from 'lodash-es'
|
|
4
|
-
import createControllableValue from './hooks/createControllableValue'
|
|
5
|
-
import { dispatchEventHandlerUnion } from './utils/solid'
|
|
6
|
-
|
|
7
|
-
export interface InputNumberProps
|
|
8
|
-
extends Omit<InputProps, 'defaultValue' | 'value' | 'onChange' | 'inputAfter' | 'onKeyDown'> {
|
|
9
|
-
defaultValue?: number | null | undefined
|
|
10
|
-
value?: number | null | undefined
|
|
11
|
-
onChange?: (value: number | null) => void
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const isEmptyValue = (value: number | string | null | undefined) => isNil(value) || value === ''
|
|
15
|
-
|
|
16
|
-
const formatNum = (
|
|
17
|
-
v: number | string | null | undefined,
|
|
18
|
-
prev?: number | null | undefined,
|
|
19
|
-
): number | null => {
|
|
20
|
-
if (isEmptyValue(v)) {
|
|
21
|
-
return null
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const num = Number(v)
|
|
25
|
-
if (prev !== undefined && Number.isNaN(num)) {
|
|
26
|
-
return prev
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return num
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const actionBtnClass =
|
|
33
|
-
'ant-text-12px ant-flex ant-justify-center ant-items-center ant-h-1/2 ant-cursor-pointer ant-opacity-70 hover:ant-h-100% hover:ant-text-[var(--primary-color)] ant-transition-color ant-transition-height ant-transition-duration-500'
|
|
34
|
-
|
|
35
|
-
const InputNumber: Component<InputNumberProps> = props => {
|
|
36
|
-
const [{ onChange, onBlur }, inputProps] = splitProps(props, [
|
|
37
|
-
'defaultValue',
|
|
38
|
-
'value',
|
|
39
|
-
'onChange',
|
|
40
|
-
'onBlur',
|
|
41
|
-
])
|
|
42
|
-
|
|
43
|
-
const [_, controllableProps] = splitProps(props, ['onChange'])
|
|
44
|
-
const [value, setValue] = createControllableValue<number | string | null | undefined>(
|
|
45
|
-
controllableProps,
|
|
46
|
-
)
|
|
47
|
-
const add = (addon: number) => {
|
|
48
|
-
setValue(v => {
|
|
49
|
-
if (isEmptyValue(v)) {
|
|
50
|
-
return addon
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const num = Number(v)
|
|
54
|
-
if (Number.isNaN(num)) {
|
|
55
|
-
return v
|
|
56
|
-
}
|
|
57
|
-
return num + addon
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
const up = () => { add(1); }
|
|
61
|
-
const down = () => { add(-1); }
|
|
62
|
-
|
|
63
|
-
createEffect(
|
|
64
|
-
on(
|
|
65
|
-
value,
|
|
66
|
-
(input, __, prev: number | null | undefined) => {
|
|
67
|
-
const num = formatNum(input, prev)
|
|
68
|
-
if (num !== prev) {
|
|
69
|
-
prev = num
|
|
70
|
-
onChange?.(num)
|
|
71
|
-
}
|
|
72
|
-
return num
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
defer: true,
|
|
76
|
-
},
|
|
77
|
-
),
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<CommonInput
|
|
82
|
-
{...inputProps}
|
|
83
|
-
inputAfter={
|
|
84
|
-
<div class="ant-flex ant-flex-col ant-h-full ant-w-24px ant-[border-left:1px_solid_#d9d9d9]">
|
|
85
|
-
<div class={actionBtnClass} onClick={up}>
|
|
86
|
-
<div class="i-ant-design:up-outlined" />
|
|
87
|
-
</div>
|
|
88
|
-
<div class={`ant-[border-top:1px_solid_#d9d9d9] ${actionBtnClass}`} onClick={down}>
|
|
89
|
-
<div class="i-ant-design:down-outlined" />
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
}
|
|
93
|
-
value={`${value() ?? ''}`}
|
|
94
|
-
onKeyDown={e => {
|
|
95
|
-
switch (e.key) {
|
|
96
|
-
case 'ArrowUp':
|
|
97
|
-
up()
|
|
98
|
-
e.preventDefault()
|
|
99
|
-
return
|
|
100
|
-
case 'ArrowDown':
|
|
101
|
-
down()
|
|
102
|
-
e.preventDefault()
|
|
103
|
-
}
|
|
104
|
-
}}
|
|
105
|
-
onChange={e => {
|
|
106
|
-
const newValue = e.target.value || null
|
|
107
|
-
setValue(newValue)
|
|
108
|
-
}}
|
|
109
|
-
onBlur={e => {
|
|
110
|
-
const newValue = e.target.value || null
|
|
111
|
-
setValue(formatNum(newValue))
|
|
112
|
-
|
|
113
|
-
dispatchEventHandlerUnion(onBlur, e)
|
|
114
|
-
}}
|
|
115
|
-
/>
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export default InputNumber
|