antd-solid 0.0.8 → 0.0.9
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/package.json +5 -4
- package/src/Button.tsx +125 -0
- package/src/Collapse/index.tsx +86 -0
- package/src/ColorPicker.tsx +11 -0
- package/src/Compact.tsx +15 -0
- package/src/DatePicker.tsx +30 -0
- package/src/Empty/PRESENTED_IMAGE_SIMPLE.tsx +15 -0
- package/src/Empty/assets/EmptySvg.tsx +43 -0
- package/src/Empty/assets/SimpleEmptySvg.tsx +16 -0
- package/src/Empty/index.tsx +20 -0
- package/src/Image.tsx +29 -0
- package/src/Input.tsx +202 -0
- package/src/InputNumber.test.tsx +46 -0
- package/src/InputNumber.tsx +125 -0
- package/src/Modal.tsx +196 -0
- package/src/Popconfirm.tsx +75 -0
- package/src/Popover.tsx +30 -0
- package/src/Progress.tsx +4 -0
- package/src/Radio.tsx +132 -0
- package/src/Result.tsx +38 -0
- package/src/Segmented/index.tsx +95 -0
- package/src/Select.tsx +128 -0
- package/src/Skeleton.tsx +14 -0
- package/src/Spin.tsx +23 -0
- package/src/Switch.tsx +34 -0
- package/src/Table.tsx +53 -0
- package/src/Tabs.tsx +131 -0
- package/src/Timeline.tsx +33 -0
- package/src/Tooltip.tsx +340 -0
- package/src/Tree.tsx +246 -0
- package/src/Upload.tsx +10 -0
- package/src/form/Form.tsx +94 -0
- package/src/form/FormItem.tsx +139 -0
- package/src/form/context.ts +16 -0
- package/src/form/index.ts +13 -0
- package/src/hooks/createControllableValue.ts +68 -0
- package/src/hooks/createUpdateEffect.ts +16 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useClickAway.ts +18 -0
- package/src/hooks/useSize.ts +26 -0
- package/src/index.ts +44 -0
- package/src/types/index.ts +5 -0
- package/src/utils/EventEmitter.ts +15 -0
- package/src/utils/ReactToSolid.tsx +38 -0
- package/src/utils/SolidToReact.tsx +27 -0
- package/src/utils/array.ts +21 -0
- package/src/utils/component.tsx +85 -0
- package/src/utils/solid.ts +53 -0
- package/src/utils/zh_CN.ts +236 -0
package/src/Select.tsx
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type JSXElement,
|
|
3
|
+
type Component,
|
|
4
|
+
For,
|
|
5
|
+
createSelector,
|
|
6
|
+
createSignal,
|
|
7
|
+
Show,
|
|
8
|
+
createMemo,
|
|
9
|
+
} from 'solid-js'
|
|
10
|
+
import Tooltip from './Tooltip'
|
|
11
|
+
import { type Key } from './types'
|
|
12
|
+
import createControllableValue from './hooks/createControllableValue'
|
|
13
|
+
import cs from 'classnames'
|
|
14
|
+
import { useClickAway } from './hooks'
|
|
15
|
+
import { isNil } from 'lodash-es'
|
|
16
|
+
|
|
17
|
+
interface SelectOption {
|
|
18
|
+
label: JSXElement
|
|
19
|
+
value: Key
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface SelectProps {
|
|
23
|
+
value?: Key
|
|
24
|
+
onChange?: (value: Key) => void
|
|
25
|
+
options: SelectOption[]
|
|
26
|
+
placeholder?: string
|
|
27
|
+
allowClear?: boolean
|
|
28
|
+
class?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const Select: Component<SelectProps> = props => {
|
|
32
|
+
let select: HTMLDivElement
|
|
33
|
+
|
|
34
|
+
const [value, setValue] = createControllableValue<Key | undefined>(props)
|
|
35
|
+
const selectedValue = createSelector(value)
|
|
36
|
+
const selectedOption = createMemo(() => !isNil(value()) ? props.options.find(option => option.value === value()) : undefined)
|
|
37
|
+
|
|
38
|
+
const [open, setOpen] = createSignal(false)
|
|
39
|
+
useClickAway(
|
|
40
|
+
() => setOpen(false),
|
|
41
|
+
() => select!,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const [width, setWidth] = createSignal(0)
|
|
45
|
+
const [hover, setHover] = createSignal(false)
|
|
46
|
+
const showClearBtn = createMemo(() => props.allowClear && hover() && !isNil(value()))
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Tooltip
|
|
50
|
+
mode="light"
|
|
51
|
+
open={open()}
|
|
52
|
+
onOpenChange={setOpen}
|
|
53
|
+
trigger={[]}
|
|
54
|
+
placement="bottomLeft"
|
|
55
|
+
arrow={false}
|
|
56
|
+
contentStyle={{
|
|
57
|
+
padding: 0,
|
|
58
|
+
}}
|
|
59
|
+
content={close => (
|
|
60
|
+
<div class="ant-bg-white ant-w-200px" style={{ width: `${width()}px` }}>
|
|
61
|
+
<For each={props.options}>
|
|
62
|
+
{item => (
|
|
63
|
+
<div
|
|
64
|
+
class={cs(
|
|
65
|
+
'ant-box-content ant-px-12px ant-py-5px ant-h-22px ant-leading-22px hover:ant-bg-[var(--hover-bg-color)]',
|
|
66
|
+
selectedValue(item.value) ? '!ant-bg-[var(--active-bg-color)]' : '',
|
|
67
|
+
)}
|
|
68
|
+
onClick={() => {
|
|
69
|
+
setValue(item.value)
|
|
70
|
+
close()
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
{item.label}
|
|
74
|
+
</div>
|
|
75
|
+
)}
|
|
76
|
+
</For>
|
|
77
|
+
</div>
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
<div
|
|
81
|
+
ref={select!}
|
|
82
|
+
class={cs('ant-h-32px ant-leading-32px ant-rounded-6px ant-[border:1px_solid_var(--ant-color-border)] ant-px-11px focus:ant-[border-color:var(--primary-color)]', props.class)}
|
|
83
|
+
tabIndex="0"
|
|
84
|
+
onClick={e => {
|
|
85
|
+
setOpen(true)
|
|
86
|
+
setWidth(e.currentTarget.offsetWidth)
|
|
87
|
+
e.currentTarget.focus()
|
|
88
|
+
}}
|
|
89
|
+
onMouseEnter={() => setHover(true)}
|
|
90
|
+
onMouseLeave={() => setHover(false)}
|
|
91
|
+
style={{
|
|
92
|
+
'--ant-arrow-color': 'rgba(146, 146, 146, 1)',
|
|
93
|
+
'--ant-clear-color': 'rgba(146, 146, 146, 1)',
|
|
94
|
+
'--ant-clear-color-hover': 'rgba(194, 194, 194, 1)',
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
<div class="ant-relative ant-h-full">
|
|
98
|
+
<Show
|
|
99
|
+
when={!isNil(value())}
|
|
100
|
+
fallback={
|
|
101
|
+
<input
|
|
102
|
+
class="ant-h-full ant-w-full ant-float-left ant-[outline:none]"
|
|
103
|
+
readOnly
|
|
104
|
+
placeholder={props.placeholder}
|
|
105
|
+
/>
|
|
106
|
+
}
|
|
107
|
+
>
|
|
108
|
+
<div>{selectedOption()!.label ?? value()}</div>
|
|
109
|
+
</Show>
|
|
110
|
+
|
|
111
|
+
<div class="ant-absolute ant-top-0 ant-bottom-0 ant-right-0">
|
|
112
|
+
<Show when={showClearBtn()} fallback={<span class="i-ant-design:down-outlined ant-text-[var(--ant-allow-color)]" />}>
|
|
113
|
+
<span
|
|
114
|
+
class="i-ant-design:close-circle-filled ant-cursor-pointer ant-text-[var(--ant-clear-color)] hover:ant-text-[var(--ant-clear-color-hover)]"
|
|
115
|
+
onClick={e => {
|
|
116
|
+
e.stopPropagation()
|
|
117
|
+
setValue(undefined)
|
|
118
|
+
}}
|
|
119
|
+
/>
|
|
120
|
+
</Show>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</Tooltip>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default Select
|
package/src/Skeleton.tsx
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Skeleton as SkeletonAntd } from 'antd'
|
|
2
|
+
import { reactToSolidComponent, replaceClassName } from './utils/component'
|
|
3
|
+
|
|
4
|
+
const _Skeleton = replaceClassName(reactToSolidComponent(SkeletonAntd))
|
|
5
|
+
|
|
6
|
+
const Image = replaceClassName(reactToSolidComponent(SkeletonAntd.Image))
|
|
7
|
+
|
|
8
|
+
const Skeleton = _Skeleton as typeof _Skeleton & {
|
|
9
|
+
Image: typeof Image
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
Skeleton.Image = Image
|
|
13
|
+
|
|
14
|
+
export default Skeleton
|
package/src/Spin.tsx
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Show, type Component, type ParentProps } from 'solid-js'
|
|
2
|
+
|
|
3
|
+
interface SpinProps extends ParentProps {
|
|
4
|
+
/**
|
|
5
|
+
* 是否为加载中状态
|
|
6
|
+
*/
|
|
7
|
+
spinning?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Spin: Component<SpinProps> = props => {
|
|
11
|
+
return (
|
|
12
|
+
<div class="ant-relative ant-min-h-32px">
|
|
13
|
+
{props.children}
|
|
14
|
+
<Show when={props.spinning}>
|
|
15
|
+
<div class="ant-absolute ant-inset-0 ant-flex ant-items-center ant-justify-center ant-bg-[rgba(255,255,255,.5)]">
|
|
16
|
+
<span class="i-ant-design:loading keyframes-spin ant-[animation:spin_1s_linear_infinite] ant-text-32px ant-text-[var(--primary-color)]" />
|
|
17
|
+
</div>
|
|
18
|
+
</Show>
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default Spin
|
package/src/Switch.tsx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Component } from 'solid-js'
|
|
2
|
+
import createControllableValue from './hooks/createControllableValue'
|
|
3
|
+
import cs from 'classnames'
|
|
4
|
+
|
|
5
|
+
export interface SwitchProps {
|
|
6
|
+
defaultChecked?: boolean
|
|
7
|
+
checked?: boolean
|
|
8
|
+
onChange?: (checked: boolean) => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const Switch: Component<SwitchProps> = props => {
|
|
12
|
+
const [checked, setChecked] = createControllableValue<boolean>(props, {
|
|
13
|
+
defaultValuePropName: 'defaultChecked',
|
|
14
|
+
valuePropName: 'checked',
|
|
15
|
+
})
|
|
16
|
+
return (
|
|
17
|
+
<button
|
|
18
|
+
class={cs(
|
|
19
|
+
'ant-w-44px ant-h-22px ant-rounded-100px ant-relative',
|
|
20
|
+
checked() ? 'ant-bg-[var(--primary-color)]' : 'ant-bg-[rgba(0,0,0,0.45)]',
|
|
21
|
+
)}
|
|
22
|
+
onClick={() => setChecked(c => !c)}
|
|
23
|
+
>
|
|
24
|
+
<div
|
|
25
|
+
class={cs(
|
|
26
|
+
'ant-w-18px ant-h-18px ant-rounded-50% ant-bg-white ant-absolute ant-top-1/2 -ant-translate-y-1/2 ant-transition-left',
|
|
27
|
+
checked() ? 'ant-left-[calc(100%-20px)]' : 'ant-left-2px',
|
|
28
|
+
)}
|
|
29
|
+
/>
|
|
30
|
+
</button>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default Switch
|
package/src/Table.tsx
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import Empty from './Empty'
|
|
2
|
+
import { type JSXElement, For, Show } from 'solid-js'
|
|
3
|
+
|
|
4
|
+
export interface TableColumn<R extends {}> {
|
|
5
|
+
title: JSXElement
|
|
6
|
+
render: (row: R) => JSXElement
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface TableProps<R extends {}> {
|
|
10
|
+
columns: Array<TableColumn<R>>
|
|
11
|
+
dataSource: R[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const Table = <R extends {}>(props: TableProps<R>) => {
|
|
15
|
+
return (
|
|
16
|
+
<div>
|
|
17
|
+
<table class="ant-w-full">
|
|
18
|
+
<thead>
|
|
19
|
+
<tr>
|
|
20
|
+
<For each={props.columns}>
|
|
21
|
+
{item => (
|
|
22
|
+
<th class="ant-p-16px ant-bg-[var(--light-bg-color)] ant-font-bold ant-[border-bottom:1px_solid_var(--secondary-border-color)] ant-text-left">
|
|
23
|
+
{item.title}
|
|
24
|
+
</th>
|
|
25
|
+
)}
|
|
26
|
+
</For>
|
|
27
|
+
</tr>
|
|
28
|
+
</thead>
|
|
29
|
+
<tbody>
|
|
30
|
+
<For each={props.dataSource}>
|
|
31
|
+
{row => (
|
|
32
|
+
<tr class="hover:ant-bg-[var(--light-bg-color)]">
|
|
33
|
+
<For each={props.columns}>
|
|
34
|
+
{item => (
|
|
35
|
+
<td class="ant-p-16px ant-[border-bottom:1px_solid_var(--secondary-border-color)]">
|
|
36
|
+
{item.render(row)}
|
|
37
|
+
</td>
|
|
38
|
+
)}
|
|
39
|
+
</For>
|
|
40
|
+
</tr>
|
|
41
|
+
)}
|
|
42
|
+
</For>
|
|
43
|
+
</tbody>
|
|
44
|
+
</table>
|
|
45
|
+
|
|
46
|
+
<Show when={!props.dataSource.length}>
|
|
47
|
+
<Empty.PRESENTED_IMAGE_SIMPLE />
|
|
48
|
+
</Show>
|
|
49
|
+
</div>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default Table
|
package/src/Tabs.tsx
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Component,
|
|
3
|
+
For,
|
|
4
|
+
createSelector,
|
|
5
|
+
createSignal,
|
|
6
|
+
onMount,
|
|
7
|
+
untrack,
|
|
8
|
+
type JSX,
|
|
9
|
+
onCleanup,
|
|
10
|
+
mergeProps,
|
|
11
|
+
Switch,
|
|
12
|
+
Match,
|
|
13
|
+
} from 'solid-js'
|
|
14
|
+
import cs from 'classnames'
|
|
15
|
+
import Segmented from './Segmented'
|
|
16
|
+
import { type StringOrJSXElement } from './types'
|
|
17
|
+
import { unwrapStringOrJSXElement } from './utils/solid'
|
|
18
|
+
|
|
19
|
+
export interface Tab {
|
|
20
|
+
key: string
|
|
21
|
+
label: StringOrJSXElement
|
|
22
|
+
children?: StringOrJSXElement
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface TabsProps {
|
|
26
|
+
type?: 'line' | 'segment'
|
|
27
|
+
class?: string
|
|
28
|
+
navClass?: string
|
|
29
|
+
navItemClass?: string
|
|
30
|
+
contentClass?: string
|
|
31
|
+
items: Tab[]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const Tabs: Component<TabsProps> = _props => {
|
|
35
|
+
const props = mergeProps(
|
|
36
|
+
{
|
|
37
|
+
type: 'line',
|
|
38
|
+
} as TabsProps,
|
|
39
|
+
_props,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const [selectedItem, setSelectedItem] = createSignal<Tab | undefined>(
|
|
43
|
+
untrack(() => props.items[0]),
|
|
44
|
+
)
|
|
45
|
+
const isSelectedItem = createSelector(() => selectedItem()?.key)
|
|
46
|
+
const [selectedBarStyle, setSelectedBarStyle] = createSignal<JSX.CSSProperties>({
|
|
47
|
+
left: '0px',
|
|
48
|
+
width: '0px',
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
let nav: HTMLDivElement | undefined
|
|
52
|
+
const updateSelectedBarStyle = () => {
|
|
53
|
+
if (!nav) return
|
|
54
|
+
|
|
55
|
+
const el = nav.querySelector<HTMLElement>(':scope > .selected')
|
|
56
|
+
if (!el) return
|
|
57
|
+
|
|
58
|
+
setSelectedBarStyle({
|
|
59
|
+
left: `${el.offsetLeft}px`,
|
|
60
|
+
width: `${el.clientWidth}px`,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
onMount(() => {
|
|
64
|
+
if (!nav) return
|
|
65
|
+
|
|
66
|
+
updateSelectedBarStyle()
|
|
67
|
+
|
|
68
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
69
|
+
updateSelectedBarStyle()
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
resizeObserver.observe(nav)
|
|
73
|
+
onCleanup(() => {
|
|
74
|
+
resizeObserver.disconnect()
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div class={props.class}>
|
|
80
|
+
<Switch>
|
|
81
|
+
<Match when={props.type === 'line'}>
|
|
82
|
+
<div
|
|
83
|
+
ref={nav!}
|
|
84
|
+
class={cs(
|
|
85
|
+
'ant-mb-16px ant-flex ant-gap-32px ant-[border-bottom:solid_1px_rgba(5,5,5,0.1)] ant-relative',
|
|
86
|
+
props.navClass,
|
|
87
|
+
)}
|
|
88
|
+
>
|
|
89
|
+
<For each={props.items}>
|
|
90
|
+
{item => (
|
|
91
|
+
<div
|
|
92
|
+
class={cs(
|
|
93
|
+
'ant-py-12px ant-cursor-pointer',
|
|
94
|
+
props.navItemClass,
|
|
95
|
+
isSelectedItem(item.key) && 'ant-text-[var(--primary-color)] selected',
|
|
96
|
+
)}
|
|
97
|
+
onClick={() => {
|
|
98
|
+
setSelectedItem(item)
|
|
99
|
+
updateSelectedBarStyle()
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
{unwrapStringOrJSXElement(item.label)}
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
105
|
+
</For>
|
|
106
|
+
|
|
107
|
+
<div
|
|
108
|
+
role={'selected-bar' as any}
|
|
109
|
+
class="ant-absolute ant-bottom-0 ant-bg-[var(--primary-color)] ant-h-2px ant-transition-left"
|
|
110
|
+
style={selectedBarStyle()}
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
</Match>
|
|
114
|
+
<Match when={props.type === 'segment'}>
|
|
115
|
+
<Segmented
|
|
116
|
+
block
|
|
117
|
+
options={props.items.map(item => ({
|
|
118
|
+
label: item.label,
|
|
119
|
+
value: item.key,
|
|
120
|
+
onClick: () => setSelectedItem(item),
|
|
121
|
+
}))}
|
|
122
|
+
/>
|
|
123
|
+
</Match>
|
|
124
|
+
</Switch>
|
|
125
|
+
|
|
126
|
+
<div class={props.contentClass}>{unwrapStringOrJSXElement(selectedItem()?.children)}</div>
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export default Tabs
|
package/src/Timeline.tsx
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Accessor, type Component, For, type JSXElement } from 'solid-js'
|
|
2
|
+
import { type TimelineItemProps as TimelineItemAntdProps } from 'antd'
|
|
3
|
+
|
|
4
|
+
interface TimelineItemProps extends Omit<TimelineItemAntdProps, 'children' | 'dot' | 'label'> {
|
|
5
|
+
dot?: JSXElement
|
|
6
|
+
label?: JSXElement
|
|
7
|
+
children?: Accessor<JSXElement>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface TimelineProps {
|
|
11
|
+
class?: string
|
|
12
|
+
items: TimelineItemProps[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Timeline: Component<TimelineProps> = props => {
|
|
16
|
+
return (
|
|
17
|
+
<div class="ant-flex ant-flex-col ant-gap-[16px]">
|
|
18
|
+
<For each={props.items}>
|
|
19
|
+
{(item, i) => (
|
|
20
|
+
<div class="ant-flex ant-relative">
|
|
21
|
+
{i() !== props.items.length - 1 && (
|
|
22
|
+
<div class="ant-absolute ant-top-[8px] ant-bottom-[-24px] ant-left-[4px] ant-w-[2px] ant-bg-[rgba(5,5,5,.06)]" />
|
|
23
|
+
)}
|
|
24
|
+
<div class="ant-w-[10px] ant-h-[10px] ant-border-solid ant-border-width-[3px] ant-border-[var(--primary-color)] ant-bg-white ant-rounded-[50%] ant-mt-[8px]" />
|
|
25
|
+
<div class="ant-ml-[8px]">{item.children?.()}</div>
|
|
26
|
+
</div>
|
|
27
|
+
)}
|
|
28
|
+
</For>
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default Timeline
|