@v-c/collapse 0.0.1

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.
@@ -0,0 +1,195 @@
1
+ import type { VueNode } from '@v-c/util/dist/type'
2
+ import type {
3
+ RendererElement,
4
+ RendererNode,
5
+ VNode,
6
+ VNodeNormalizedChildren,
7
+ } from 'vue'
8
+ import type {
9
+ CollapsePanelProps,
10
+ CollapseProps,
11
+ ItemType,
12
+ Key,
13
+ } from '../interface'
14
+ import { toArray } from '@v-c/util/dist/Children/toArray'
15
+ import { isEmptyElement } from '@v-c/util/dist/props-util'
16
+ import { cloneElement } from '@v-c/util/dist/vnode'
17
+ import CollapsePanel from '../Panel'
18
+
19
+ type Props = Pick<
20
+ CollapsePanelProps,
21
+ | 'prefixCls'
22
+ | 'onItemClick'
23
+ | 'openMotion'
24
+ | 'expandIcon'
25
+ | 'classNames'
26
+ | 'styles'
27
+ > &
28
+ Pick<CollapseProps, 'accordion' | 'collapsible'> & {
29
+ activeKey: Key[]
30
+ }
31
+
32
+ interface ChildrenSlots {
33
+ default?: () => VueNode
34
+ }
35
+
36
+ function convertItemsToNodes(items: ItemType[], props: Props) {
37
+ const {
38
+ prefixCls,
39
+ accordion,
40
+ collapsible,
41
+ onItemClick,
42
+ activeKey,
43
+ openMotion,
44
+ expandIcon,
45
+ classNames: collapseClassNames,
46
+ styles,
47
+ } = props
48
+
49
+ return items.map((item, index) => {
50
+ const {
51
+ label,
52
+ key: rawKey,
53
+ collapsible: rawCollapsible,
54
+ onItemClick: rawOnItemClick,
55
+ ...restProps
56
+ } = item
57
+
58
+ const key = String(rawKey ?? index)
59
+ const mergeCollapsible = rawCollapsible ?? collapsible
60
+
61
+ const handleItemClick = (value: Key) => {
62
+ if (mergeCollapsible === 'disabled')
63
+ return
64
+
65
+ onItemClick?.(value)
66
+ rawOnItemClick?.(value)
67
+ }
68
+
69
+ let isActive = false
70
+
71
+ if (accordion) {
72
+ isActive = activeKey?.[0] === key
73
+ }
74
+ else {
75
+ isActive = activeKey.includes(key)
76
+ }
77
+
78
+ return (
79
+ <CollapsePanel
80
+ {...restProps}
81
+ classNames={collapseClassNames}
82
+ styles={styles}
83
+ prefixCls={prefixCls}
84
+ key={key}
85
+ panelKey={key}
86
+ isActive={isActive}
87
+ accordion={accordion}
88
+ openMotion={openMotion}
89
+ expandIcon={expandIcon}
90
+ header={label}
91
+ collapsible={mergeCollapsible}
92
+ onItemClick={handleItemClick}
93
+ />
94
+ )
95
+ })
96
+ }
97
+
98
+ /**
99
+ * @deprecated The next major version will be removed
100
+ */
101
+ function getNewChild(
102
+ child: VNode<RendererNode, RendererElement, CollapsePanelProps>,
103
+ index: number,
104
+ props: Props,
105
+ ) {
106
+ if (isEmptyElement(child) || !child)
107
+ return null
108
+
109
+ if (
110
+ typeof child === 'boolean'
111
+ || typeof child === 'number'
112
+ || typeof child === 'string'
113
+ ) {
114
+ return child
115
+ }
116
+
117
+ const {
118
+ prefixCls,
119
+ accordion,
120
+ collapsible,
121
+ onItemClick,
122
+ activeKey,
123
+ openMotion,
124
+ expandIcon,
125
+ classNames: collapseClassNames,
126
+ styles,
127
+ } = props
128
+
129
+ const key = child.key || String(index)
130
+
131
+ const {
132
+ header,
133
+ headerClass,
134
+ collapsible: childCollapsible,
135
+ onItemClick: childOnItemClick,
136
+ } = child.props || {}
137
+
138
+ let isActive = false
139
+ if (accordion) {
140
+ isActive = activeKey[0] === key
141
+ }
142
+ else {
143
+ isActive = activeKey.includes(key as Key)
144
+ }
145
+
146
+ const mergeCollapsible = childCollapsible ?? collapsible
147
+
148
+ const handleItemClick = (value: Key) => {
149
+ if (mergeCollapsible === 'disabled')
150
+ return
151
+ onItemClick?.(value)
152
+ childOnItemClick?.(value)
153
+ }
154
+
155
+ const childProps = {
156
+ key,
157
+ panelKey: key,
158
+ header,
159
+ headerClass,
160
+ classNames: collapseClassNames,
161
+ styles,
162
+ isActive,
163
+ prefixCls,
164
+ openMotion,
165
+ accordion,
166
+ children: (child.children as ChildrenSlots)?.default?.(),
167
+ onItemClick: handleItemClick,
168
+ expandIcon,
169
+ collapsible: mergeCollapsible,
170
+ }
171
+
172
+ Object.keys(childProps).forEach((propName) => {
173
+ if (
174
+ typeof childProps[propName as keyof typeof childProps] === 'undefined'
175
+ ) {
176
+ delete childProps[propName as keyof typeof childProps]
177
+ }
178
+ })
179
+
180
+ return cloneElement(child, childProps)
181
+ }
182
+
183
+ export function useItems(
184
+ items?: ItemType[],
185
+ children?: () => VNode | VNodeNormalizedChildren,
186
+ props?: Props,
187
+ ) {
188
+ if (Array.isArray(items)) {
189
+ return convertItemsToNodes(items, props!)
190
+ }
191
+
192
+ return toArray(children?.()).map((target, index) =>
193
+ getNewChild(target, index, props!),
194
+ )
195
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ import Collapse from './Collapse'
2
+ import Panel from './Panel'
3
+
4
+ export type { CollapsePanelProps, CollapseProps } from './interface'
5
+
6
+ export default Collapse
7
+
8
+ export { Panel }
@@ -0,0 +1,147 @@
1
+ import type { Key, VueNode } from '@v-c/util/dist/type'
2
+ import type {
3
+ CSSProperties,
4
+ PropType,
5
+ Ref,
6
+ TransitionProps,
7
+ VNode,
8
+ } from 'vue'
9
+
10
+ export type CollapsibleType = 'header' | 'icon' | 'disabled'
11
+
12
+ export type SemanticName = 'header' | 'title' | 'body' | 'icon'
13
+
14
+ export function generatorCollapsePanelProps() {
15
+ return {
16
+ id: String,
17
+ header: [String, Object] as PropType<string | VNode>,
18
+ prefixCls: String,
19
+ headerClass: String,
20
+ showArrow: {
21
+ type: Boolean as PropType<boolean | undefined>,
22
+ default: true,
23
+ },
24
+ className: String,
25
+ classNames: {
26
+ type: Object as PropType<Partial<Record<SemanticName, string>>>,
27
+ default: () => ({}),
28
+ },
29
+ style: Object as PropType<Record<string, string>>,
30
+ styles: {
31
+ type: Object as PropType<Partial<Record<SemanticName, CSSProperties>>>,
32
+ default: () => ({}),
33
+ },
34
+ isActive: Boolean,
35
+ openMotion: Object as PropType<Partial<TransitionProps>>,
36
+ destroyInactivePanel: Boolean as PropType<boolean | undefined>,
37
+ accordion: Boolean,
38
+ forceRender: Boolean as PropType<boolean | undefined>,
39
+ onItemClick: Function as PropType<(props: Key) => void>,
40
+ extra: [String, Object] as PropType<string | VueNode>,
41
+ panelKey: [String, Number],
42
+ collapsible: String as PropType<CollapsibleType>,
43
+ expandIcon: Function as PropType<(props: any) => VueNode>,
44
+ role: String,
45
+ children: [Object, String] as PropType<VueNode | string>,
46
+ }
47
+ }
48
+
49
+ export interface CollapsePanelProps {
50
+ id?: string
51
+ header?: VueNode
52
+ prefixCls?: string
53
+ headerClass?: string
54
+ showArrow?: boolean
55
+ className?: string
56
+ classNames?: Partial<Record<SemanticName, string>>
57
+ style?: object
58
+ styles?: Partial<Record<SemanticName, CSSProperties>>
59
+ isActive?: boolean
60
+ openMotion?: TransitionProps
61
+ destroyOnHidden?: boolean
62
+ accordion?: boolean
63
+ forceRender?: boolean
64
+ extra?: VueNode
65
+ onItemClick?: (panelKey: Key) => void
66
+ expandIcon?: (props: object) => any
67
+ panelKey?: Key
68
+ role?: string
69
+ collapsible?: CollapsibleType
70
+ children?: VueNode | string
71
+ }
72
+
73
+ export interface ItemType
74
+ extends Omit<
75
+ CollapsePanelProps,
76
+ | 'header' // alias of label
77
+ | 'prefixCls'
78
+ | 'panelKey' // alias of key
79
+ | 'isActive'
80
+ | 'accordion'
81
+ | 'openMotion'
82
+ | 'expandIcon'
83
+ > {
84
+ key?: CollapsePanelProps['panelKey']
85
+ label?: CollapsePanelProps['header']
86
+ children?: VueNode
87
+ ref?: Ref<HTMLDivElement>
88
+ }
89
+
90
+ export function generatorCollapseProps() {
91
+ return {
92
+ prefixCls: String,
93
+ activeKey: [String, Number, Array] as PropType<Key | Key[]>,
94
+ defaultActiveKey: [String, Number, Array] as PropType<Key | Key[]>,
95
+ openMotion: Object,
96
+ onChange: Function as PropType<(key: Key[]) => void>,
97
+ accordion: Boolean,
98
+ className: String,
99
+ classNames: Object as PropType<Partial<Record<SemanticName, string>>>,
100
+ style: Object,
101
+ styles: Object as PropType<Partial<Record<SemanticName, CSSProperties>>>,
102
+ destroyInactivePanel: Boolean,
103
+ expandIcon: Function as PropType<(props: any) => VueNode>,
104
+ collapsible: String as PropType<CollapsibleType>,
105
+ items: Array as PropType<ItemType[]>,
106
+ }
107
+ }
108
+
109
+ export interface CollapseProps {
110
+ prefixCls?: string
111
+ activeKey?: Key | Key[]
112
+ defaultActiveKey?: Key | Key[]
113
+ openMotion?: TransitionProps
114
+ onChange?: (key: Key[]) => void
115
+ accordion?: boolean
116
+ className?: string
117
+ style?: object
118
+ destroyOnHidden?: boolean
119
+ expandIcon?: (props: object) => any
120
+ collapsible?: CollapsibleType
121
+ /**
122
+ * Collapse items content
123
+ * @since 3.6.0
124
+ */
125
+ items?: ItemType[]
126
+ classNames?: Partial<Record<SemanticName, string>>
127
+ styles?: Partial<Record<SemanticName, CSSProperties>>
128
+ }
129
+ export function generatorCollapsePanelContentProps() {
130
+ return {
131
+ isActive: Boolean,
132
+ prefixCls: String,
133
+ className: String,
134
+ classNames: Object as PropType<{ header?: string, body?: string }>,
135
+ style: Object as PropType<Record<string, string>>,
136
+ styles: Object as PropType<{
137
+ header?: CSSProperties
138
+ body?: CSSProperties
139
+ }>,
140
+ role: String,
141
+ forceRender: Boolean,
142
+ }
143
+ }
144
+
145
+ export type {
146
+ Key,
147
+ }
@@ -0,0 +1,3 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`collapse > props items > should work with nested 1`] = ``;