@v-c/collapse 0.0.4 → 1.0.0

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