@contember/react-board 1.3.0-alpha.10
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/development/Board.cjs +116 -0
- package/dist/development/Board.cjs.map +1 -0
- package/dist/development/Board.js +116 -0
- package/dist/development/Board.js.map +1 -0
- package/dist/development/const.cjs +5 -0
- package/dist/development/const.cjs.map +1 -0
- package/dist/development/const.js +5 -0
- package/dist/development/const.js.map +1 -0
- package/dist/development/index.cjs +11 -0
- package/dist/development/index.cjs.map +1 -0
- package/dist/development/index.js +11 -0
- package/dist/development/index.js.map +1 -0
- package/dist/development/internal/useBoardColumns.cjs +44 -0
- package/dist/development/internal/useBoardColumns.cjs.map +1 -0
- package/dist/development/internal/useBoardColumns.js +44 -0
- package/dist/development/internal/useBoardColumns.js.map +1 -0
- package/dist/development/internal/useBoardItemsMethods.cjs +100 -0
- package/dist/development/internal/useBoardItemsMethods.cjs.map +1 -0
- package/dist/development/internal/useBoardItemsMethods.js +100 -0
- package/dist/development/internal/useBoardItemsMethods.js.map +1 -0
- package/dist/development/internal/useGroupItemsByColumn.cjs +19 -0
- package/dist/development/internal/useGroupItemsByColumn.cjs.map +1 -0
- package/dist/development/internal/useGroupItemsByColumn.js +19 -0
- package/dist/development/internal/useGroupItemsByColumn.js.map +1 -0
- package/dist/development/useDynamicBoard.cjs +99 -0
- package/dist/development/useDynamicBoard.cjs.map +1 -0
- package/dist/development/useDynamicBoard.js +99 -0
- package/dist/development/useDynamicBoard.js.map +1 -0
- package/dist/development/useStaticBoard.cjs +51 -0
- package/dist/development/useStaticBoard.cjs.map +1 -0
- package/dist/development/useStaticBoard.js +51 -0
- package/dist/development/useStaticBoard.js.map +1 -0
- package/dist/development/utils/arrayMove.cjs +9 -0
- package/dist/development/utils/arrayMove.cjs.map +1 -0
- package/dist/development/utils/arrayMove.js +9 -0
- package/dist/development/utils/arrayMove.js.map +1 -0
- package/dist/production/Board.cjs +116 -0
- package/dist/production/Board.cjs.map +1 -0
- package/dist/production/Board.js +116 -0
- package/dist/production/Board.js.map +1 -0
- package/dist/production/const.cjs +5 -0
- package/dist/production/const.cjs.map +1 -0
- package/dist/production/const.js +5 -0
- package/dist/production/const.js.map +1 -0
- package/dist/production/index.cjs +11 -0
- package/dist/production/index.cjs.map +1 -0
- package/dist/production/index.js +11 -0
- package/dist/production/index.js.map +1 -0
- package/dist/production/internal/useBoardColumns.cjs +44 -0
- package/dist/production/internal/useBoardColumns.cjs.map +1 -0
- package/dist/production/internal/useBoardColumns.js +44 -0
- package/dist/production/internal/useBoardColumns.js.map +1 -0
- package/dist/production/internal/useBoardItemsMethods.cjs +100 -0
- package/dist/production/internal/useBoardItemsMethods.cjs.map +1 -0
- package/dist/production/internal/useBoardItemsMethods.js +100 -0
- package/dist/production/internal/useBoardItemsMethods.js.map +1 -0
- package/dist/production/internal/useGroupItemsByColumn.cjs +19 -0
- package/dist/production/internal/useGroupItemsByColumn.cjs.map +1 -0
- package/dist/production/internal/useGroupItemsByColumn.js +19 -0
- package/dist/production/internal/useGroupItemsByColumn.js.map +1 -0
- package/dist/production/useDynamicBoard.cjs +99 -0
- package/dist/production/useDynamicBoard.cjs.map +1 -0
- package/dist/production/useDynamicBoard.js +99 -0
- package/dist/production/useDynamicBoard.js.map +1 -0
- package/dist/production/useStaticBoard.cjs +51 -0
- package/dist/production/useStaticBoard.cjs.map +1 -0
- package/dist/production/useStaticBoard.js +51 -0
- package/dist/production/useStaticBoard.js.map +1 -0
- package/dist/production/utils/arrayMove.cjs +9 -0
- package/dist/production/utils/arrayMove.cjs.map +1 -0
- package/dist/production/utils/arrayMove.js +9 -0
- package/dist/production/utils/arrayMove.js.map +1 -0
- package/dist/types/Board.d.ts +10 -0
- package/dist/types/Board.d.ts.map +1 -0
- package/dist/types/BoardBindingProps.d.ts +36 -0
- package/dist/types/BoardBindingProps.d.ts.map +1 -0
- package/dist/types/const.d.ts +2 -0
- package/dist/types/const.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/internal/useBoardColumns.d.ts +11 -0
- package/dist/types/internal/useBoardColumns.d.ts.map +1 -0
- package/dist/types/internal/useBoardItemsMethods.d.ts +15 -0
- package/dist/types/internal/useBoardItemsMethods.d.ts.map +1 -0
- package/dist/types/internal/useGroupItemsByColumn.d.ts +5 -0
- package/dist/types/internal/useGroupItemsByColumn.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dist/types/types.d.ts +31 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/useDynamicBoard.d.ts +9 -0
- package/dist/types/useDynamicBoard.d.ts.map +1 -0
- package/dist/types/useStaticBoard.d.ts +8 -0
- package/dist/types/useStaticBoard.d.ts.map +1 -0
- package/dist/types/utils/arrayMove.d.ts +2 -0
- package/dist/types/utils/arrayMove.d.ts.map +1 -0
- package/package.json +48 -0
- package/src/Board.tsx +156 -0
- package/src/BoardBindingProps.ts +45 -0
- package/src/const.ts +1 -0
- package/src/index.ts +6 -0
- package/src/internal/useBoardColumns.ts +57 -0
- package/src/internal/useBoardItemsMethods.ts +141 -0
- package/src/internal/useGroupItemsByColumn.ts +19 -0
- package/src/tsconfig.json +9 -0
- package/src/types.ts +64 -0
- package/src/useDynamicBoard.ts +135 -0
- package/src/useStaticBoard.ts +64 -0
- package/src/utils/arrayMove.ts +5 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BoardColumn, BoardColumnValue } from '../BoardBindingProps'
|
|
2
|
+
import { useMemo } from 'react'
|
|
3
|
+
import { UseGroupItemsByColumn } from './useGroupItemsByColumn'
|
|
4
|
+
import { EntityListAccessor } from '@contember/react-binding'
|
|
5
|
+
import { BoardNullColumnPlaceholder } from '../const'
|
|
6
|
+
import { BoardNullBehaviourProps } from '../types'
|
|
7
|
+
|
|
8
|
+
export const useBoardColumns = <ColumnValue extends BoardColumnValue>({ groupItemsByColumn, items, columns, nullColumn, nullColumnPlacement, columnIdGetter }: {
|
|
9
|
+
items: EntityListAccessor
|
|
10
|
+
columns: Iterable<ColumnValue>
|
|
11
|
+
columnIdGetter: (column: ColumnValue) => string | number
|
|
12
|
+
groupItemsByColumn: UseGroupItemsByColumn,
|
|
13
|
+
} & BoardNullBehaviourProps): BoardColumn<ColumnValue>[] => {
|
|
14
|
+
|
|
15
|
+
return useMemo(() => {
|
|
16
|
+
const itemsByColumn = groupItemsByColumn(items)
|
|
17
|
+
|
|
18
|
+
const result: BoardColumn<ColumnValue>[] = []
|
|
19
|
+
let index = 0
|
|
20
|
+
const nullItems = itemsByColumn.get(null) ?? []
|
|
21
|
+
|
|
22
|
+
const pushNullColumn = () => {
|
|
23
|
+
if (nullColumn === 'never') {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
if (nullColumn === 'auto' && nullItems.length === 0) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
result.push({
|
|
31
|
+
id: BoardNullColumnPlaceholder,
|
|
32
|
+
index: index++,
|
|
33
|
+
value: null,
|
|
34
|
+
items: nullItems.map((it, index) => ({ value: it, id: it.id, index })),
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (nullColumnPlacement === 'start') {
|
|
39
|
+
index--
|
|
40
|
+
pushNullColumn()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const column of columns) {
|
|
44
|
+
result.push({
|
|
45
|
+
id: columnIdGetter(column),
|
|
46
|
+
index: index++,
|
|
47
|
+
value: column,
|
|
48
|
+
items: itemsByColumn.get(columnIdGetter(column))?.map((it, index) => ({ value: it, id: it.id, index })) ?? [],
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (nullColumnPlacement !== 'start') {
|
|
53
|
+
pushNullColumn()
|
|
54
|
+
}
|
|
55
|
+
return result
|
|
56
|
+
}, [columnIdGetter, columns, groupItemsByColumn, items, nullColumn, nullColumnPlacement])
|
|
57
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { BoardAddItemMethod, BoardColumnValue, BoardMethods, BoardMoveItemMethod, BoardRemoveItemMethod } from '../BoardBindingProps'
|
|
2
|
+
import { useCallback, useMemo } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
BatchUpdatesOptions,
|
|
5
|
+
BindingError,
|
|
6
|
+
EntityAccessor,
|
|
7
|
+
EntityListAccessor,
|
|
8
|
+
RelativeSingleField,
|
|
9
|
+
repairEntitiesOrder, sortEntities,
|
|
10
|
+
} from '@contember/react-binding'
|
|
11
|
+
import { BoardColumnKey, UseGroupItemsByColumn } from './useGroupItemsByColumn'
|
|
12
|
+
import { arrayMove } from '../utils/arrayMove'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export type UseBoardItemsMethodsProps<ColumnValue extends BoardColumnValue> = {
|
|
16
|
+
itemEntities: EntityListAccessor
|
|
17
|
+
connectItemToColumn: (item: EntityAccessor, column: ColumnValue | null) => void
|
|
18
|
+
desugaredSortableByField: RelativeSingleField | undefined
|
|
19
|
+
sortScope?: 'column' | 'board'
|
|
20
|
+
groupItemsByColumn: UseGroupItemsByColumn,
|
|
21
|
+
getDiscriminatorValue: (entity: EntityAccessor) => BoardColumnKey
|
|
22
|
+
columnIdGetter: (column: ColumnValue) => string | number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type BoardItemsMethods<ColumnValue extends BoardColumnValue> = Pick<BoardMethods<ColumnValue>, 'moveItem' | 'addItem' | 'removeItem'>
|
|
26
|
+
|
|
27
|
+
export const useBoardItemsMethods = <ColumnValue extends BoardColumnValue>({
|
|
28
|
+
itemEntities,
|
|
29
|
+
desugaredSortableByField,
|
|
30
|
+
connectItemToColumn,
|
|
31
|
+
groupItemsByColumn,
|
|
32
|
+
getDiscriminatorValue,
|
|
33
|
+
columnIdGetter,
|
|
34
|
+
sortScope = 'column',
|
|
35
|
+
}: UseBoardItemsMethodsProps<ColumnValue>): BoardItemsMethods<ColumnValue> => {
|
|
36
|
+
|
|
37
|
+
const itemEntitiesEntitiesGetter = itemEntities.getAccessor
|
|
38
|
+
|
|
39
|
+
const getSortScopeItems = useCallback((column: string | number | null) => {
|
|
40
|
+
const itemEntities = itemEntitiesEntitiesGetter()
|
|
41
|
+
return sortScope === 'column'
|
|
42
|
+
? groupItemsByColumn(itemEntities).get(column)?.slice() ?? []
|
|
43
|
+
: sortEntities(Array.from(itemEntities), desugaredSortableByField)
|
|
44
|
+
}, [desugaredSortableByField, groupItemsByColumn, itemEntitiesEntitiesGetter, sortScope])
|
|
45
|
+
|
|
46
|
+
const resolveScopedIndex = useCallback((column: string | number | null, index: number | undefined) => {
|
|
47
|
+
if (index === undefined) {
|
|
48
|
+
return undefined
|
|
49
|
+
}
|
|
50
|
+
if (sortScope === 'column') {
|
|
51
|
+
return index
|
|
52
|
+
}
|
|
53
|
+
const columnItems = groupItemsByColumn(itemEntities).get(column)?.slice() ?? []
|
|
54
|
+
const columnOnIndex = columnItems[index]
|
|
55
|
+
if (!columnOnIndex) {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const sortScopeItems = getSortScopeItems(column)
|
|
60
|
+
return sortScopeItems.findIndex(it => it.id === columnOnIndex.id) ?? sortScopeItems.length
|
|
61
|
+
}, [getSortScopeItems, groupItemsByColumn, itemEntities, sortScope])
|
|
62
|
+
|
|
63
|
+
const addItem = useCallback<BoardAddItemMethod<ColumnValue>>((column, index, preprocess) => {
|
|
64
|
+
const itemEntities = itemEntitiesEntitiesGetter()
|
|
65
|
+
const resolvedPreprocess = (getAccessor: () => EntityAccessor, options: BatchUpdatesOptions) => {
|
|
66
|
+
connectItemToColumn(getAccessor(), column)
|
|
67
|
+
preprocess?.(getAccessor, options)
|
|
68
|
+
}
|
|
69
|
+
if (!desugaredSortableByField) {
|
|
70
|
+
if (index === undefined) {
|
|
71
|
+
return itemEntities.createNewEntity(resolvedPreprocess)
|
|
72
|
+
}
|
|
73
|
+
throw new BindingError('Cannot add item at specific index without sortableBy field')
|
|
74
|
+
}
|
|
75
|
+
const columnId = column ? columnIdGetter(column) : null
|
|
76
|
+
const sortScopeItems = getSortScopeItems(columnId)
|
|
77
|
+
|
|
78
|
+
const resolvedIndex = resolveScopedIndex(columnId, index) ?? sortScopeItems.length
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
itemEntities.createNewEntity((getEntity, options) => {
|
|
82
|
+
sortScopeItems.splice(resolvedIndex, 0, getEntity())
|
|
83
|
+
repairEntitiesOrder(desugaredSortableByField, sortScopeItems)
|
|
84
|
+
resolvedPreprocess?.(getEntity, options)
|
|
85
|
+
})
|
|
86
|
+
}, [columnIdGetter, connectItemToColumn, desugaredSortableByField, getSortScopeItems, itemEntitiesEntitiesGetter, resolveScopedIndex])
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
const moveItem = useMemo<BoardMoveItemMethod<ColumnValue> | undefined>(() => {
|
|
90
|
+
if (!desugaredSortableByField) {
|
|
91
|
+
return undefined
|
|
92
|
+
}
|
|
93
|
+
return (entity, column, index) => {
|
|
94
|
+
const currentColumn = getDiscriminatorValue(entity)
|
|
95
|
+
const columnId = column ? columnIdGetter(column) : null
|
|
96
|
+
|
|
97
|
+
connectItemToColumn(entity, column)
|
|
98
|
+
|
|
99
|
+
if (currentColumn === columnId || sortScope === 'board') {
|
|
100
|
+
const sortScopeItems = getSortScopeItems(columnId)
|
|
101
|
+
const currentIndex = sortScopeItems.findIndex(it => it.id === entity.id)
|
|
102
|
+
const resolvedIndex = resolveScopedIndex(columnId, index) ?? sortScopeItems.length
|
|
103
|
+
const resortedItems = arrayMove(sortScopeItems, currentIndex, resolvedIndex)
|
|
104
|
+
repairEntitiesOrder(desugaredSortableByField, resortedItems)
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
// sort scope is column
|
|
110
|
+
const itemEntities = itemEntitiesEntitiesGetter()
|
|
111
|
+
const groupedItems = groupItemsByColumn(itemEntities)
|
|
112
|
+
|
|
113
|
+
const currentColumnItems = groupedItems.get(currentColumn ?? null)?.slice() ?? []
|
|
114
|
+
const currentIndex = currentColumnItems.findIndex(it => it.id === entity.id)
|
|
115
|
+
currentColumnItems.splice(currentIndex, 1)
|
|
116
|
+
repairEntitiesOrder(desugaredSortableByField, currentColumnItems)
|
|
117
|
+
|
|
118
|
+
const newColumnItems = groupedItems.get(columnId)?.slice() ?? []
|
|
119
|
+
newColumnItems.splice(index, 0, entity)
|
|
120
|
+
repairEntitiesOrder(desugaredSortableByField, newColumnItems)
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
}, [columnIdGetter, connectItemToColumn, desugaredSortableByField, getDiscriminatorValue, getSortScopeItems, groupItemsByColumn, itemEntitiesEntitiesGetter, resolveScopedIndex, sortScope])
|
|
124
|
+
|
|
125
|
+
const removeItem = useCallback<BoardRemoveItemMethod>(entity => {
|
|
126
|
+
if (desugaredSortableByField) {
|
|
127
|
+
const currentColumn = getDiscriminatorValue(entity)
|
|
128
|
+
const sortScopeItems = getSortScopeItems(currentColumn)
|
|
129
|
+
const currentIndex = sortScopeItems.findIndex(it => it.id === entity.id)
|
|
130
|
+
sortScopeItems.splice(currentIndex, 1)
|
|
131
|
+
repairEntitiesOrder(desugaredSortableByField, sortScopeItems)
|
|
132
|
+
}
|
|
133
|
+
entity.deleteEntity()
|
|
134
|
+
}, [desugaredSortableByField, getDiscriminatorValue, getSortScopeItems])
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
addItem,
|
|
138
|
+
moveItem,
|
|
139
|
+
removeItem,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EntityAccessor, EntityId, EntityListAccessor, RelativeSingleField, sortEntities } from '@contember/react-binding'
|
|
2
|
+
import { useCallback } from 'react'
|
|
3
|
+
|
|
4
|
+
export type BoardColumnKey = string | EntityId | null
|
|
5
|
+
export type UseGroupItemsByColumn = (itemEntities: EntityListAccessor) => Map<BoardColumnKey, EntityAccessor[]>
|
|
6
|
+
export const useGroupItemsByColumn = (getDiscriminatorValue: (entity: EntityAccessor) => BoardColumnKey, sortBy: RelativeSingleField | undefined): UseGroupItemsByColumn => {
|
|
7
|
+
return useCallback((itemEntities: EntityListAccessor) => {
|
|
8
|
+
const itemsByColumn = new Map<BoardColumnKey, EntityAccessor[]>()
|
|
9
|
+
|
|
10
|
+
for (const item of sortEntities(Array.from(itemEntities), sortBy)) {
|
|
11
|
+
const discriminatedBy = getDiscriminatorValue(item)
|
|
12
|
+
if (!itemsByColumn.has(discriminatedBy)) {
|
|
13
|
+
itemsByColumn.set(discriminatedBy, [])
|
|
14
|
+
}
|
|
15
|
+
itemsByColumn.get(discriminatedBy)?.push(item)
|
|
16
|
+
}
|
|
17
|
+
return itemsByColumn
|
|
18
|
+
}, [getDiscriminatorValue, sortBy])
|
|
19
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { SugaredQualifiedEntityList, SugaredRelativeEntityList, SugaredRelativeSingleEntity, SugaredRelativeSingleField } from '@contember/react-binding'
|
|
3
|
+
|
|
4
|
+
export type BoardDynamicColumnsBindingProps = {
|
|
5
|
+
columns: SugaredQualifiedEntityList['entities']
|
|
6
|
+
columnsSortableBy?: string | SugaredRelativeSingleField
|
|
7
|
+
discriminationField: string | SugaredRelativeSingleEntity
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type BoardStaticColumnsBindingProps = {
|
|
11
|
+
columns: {
|
|
12
|
+
value: string,
|
|
13
|
+
label: ReactNode
|
|
14
|
+
}[]
|
|
15
|
+
discriminationField: string | SugaredRelativeSingleField
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type BoardNullBehaviourProps = {
|
|
19
|
+
nullColumn?: 'never' | 'always' | 'auto'
|
|
20
|
+
nullColumnPlacement?: 'start' | 'end'
|
|
21
|
+
}
|
|
22
|
+
export type BoardCommonProps =
|
|
23
|
+
& BoardNullBehaviourProps
|
|
24
|
+
& {
|
|
25
|
+
children: ReactNode
|
|
26
|
+
sortableBy?: string | SugaredRelativeSingleField
|
|
27
|
+
sortScope?: 'column' | 'board'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type BoardQualifiedItemsProps =
|
|
31
|
+
& Pick<SugaredQualifiedEntityList, 'entities' | 'orderBy' | 'limit' | 'offset'>
|
|
32
|
+
|
|
33
|
+
export type BoardRelativeItemsProps =
|
|
34
|
+
& Pick<SugaredRelativeEntityList, 'field' | 'orderBy' | 'limit' | 'offset'>
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
export type BoardQualifiedDynamicProps =
|
|
38
|
+
& BoardCommonProps
|
|
39
|
+
& BoardDynamicColumnsBindingProps
|
|
40
|
+
& BoardQualifiedItemsProps
|
|
41
|
+
|
|
42
|
+
export type BoardRelativeDynamicProps =
|
|
43
|
+
& BoardCommonProps
|
|
44
|
+
& BoardDynamicColumnsBindingProps
|
|
45
|
+
& BoardRelativeItemsProps
|
|
46
|
+
|
|
47
|
+
export type BoardQualifiedStaticProps =
|
|
48
|
+
& BoardCommonProps
|
|
49
|
+
& BoardStaticColumnsBindingProps
|
|
50
|
+
& BoardQualifiedItemsProps
|
|
51
|
+
|
|
52
|
+
export type BoardRelativeStaticProps =
|
|
53
|
+
& BoardCommonProps
|
|
54
|
+
& BoardStaticColumnsBindingProps
|
|
55
|
+
& BoardRelativeItemsProps
|
|
56
|
+
|
|
57
|
+
export type BoardBaseProps<RendererExtraProps> =
|
|
58
|
+
& (
|
|
59
|
+
| BoardQualifiedDynamicProps
|
|
60
|
+
| BoardRelativeDynamicProps
|
|
61
|
+
| BoardQualifiedStaticProps
|
|
62
|
+
| BoardRelativeStaticProps
|
|
63
|
+
)
|
|
64
|
+
& RendererExtraProps
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
addEntityAtIndex,
|
|
4
|
+
BindingError,
|
|
5
|
+
EntityAccessor,
|
|
6
|
+
EntityListAccessor,
|
|
7
|
+
RelativeSingleField,
|
|
8
|
+
repairEntitiesOrder,
|
|
9
|
+
sortEntities,
|
|
10
|
+
useDesugaredRelativeSingleEntity,
|
|
11
|
+
useDesugaredRelativeSingleField,
|
|
12
|
+
} from '@contember/react-binding'
|
|
13
|
+
import { BoardAddColumnMethod, BoardBindingProps, BoardMoveColumnMethod, BoardRemoveColumnMethod } from './BoardBindingProps'
|
|
14
|
+
import { useGroupItemsByColumn } from './internal/useGroupItemsByColumn'
|
|
15
|
+
import { useBoardColumns } from './internal/useBoardColumns'
|
|
16
|
+
import { BoardCommonProps, BoardDynamicColumnsBindingProps } from './types'
|
|
17
|
+
import { useBoardItemsMethods } from './internal/useBoardItemsMethods'
|
|
18
|
+
import { arrayMove } from './utils/arrayMove'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export type UseDynamicBoardBindingProps =
|
|
22
|
+
& Omit<BoardCommonProps, 'children'>
|
|
23
|
+
& BoardDynamicColumnsBindingProps
|
|
24
|
+
& {
|
|
25
|
+
columnEntities: EntityListAccessor
|
|
26
|
+
itemEntities: EntityListAccessor
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const useGetSortedColumns = (desugaredColumnSortableByField: RelativeSingleField | undefined) => {
|
|
30
|
+
return useCallback((columnEntities: EntityListAccessor) => {
|
|
31
|
+
return sortEntities(Array.from(columnEntities), desugaredColumnSortableByField)
|
|
32
|
+
}, [desugaredColumnSortableByField])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const useDynamicBoard = ({
|
|
36
|
+
sortableBy,
|
|
37
|
+
sortScope,
|
|
38
|
+
columnsSortableBy,
|
|
39
|
+
discriminationField,
|
|
40
|
+
columnEntities,
|
|
41
|
+
itemEntities,
|
|
42
|
+
nullColumnPlacement = 'end',
|
|
43
|
+
nullColumn = 'auto',
|
|
44
|
+
}: UseDynamicBoardBindingProps): BoardBindingProps<EntityAccessor> => {
|
|
45
|
+
|
|
46
|
+
const desugaredSortableByField = useDesugaredRelativeSingleField(sortableBy)
|
|
47
|
+
const desugaredColumnSortableByField = useDesugaredRelativeSingleField(columnsSortableBy)
|
|
48
|
+
const desugaredDiscriminationField = useDesugaredRelativeSingleEntity(discriminationField)
|
|
49
|
+
|
|
50
|
+
const columnEntitiesGetter = columnEntities.getAccessor
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const exitingColumnIds = useMemo(() => new Set(Array.from(columnEntities).map(it => it.id)), [columnEntities])
|
|
54
|
+
|
|
55
|
+
const getDiscriminatorValue = useCallback((entity: EntityAccessor) => {
|
|
56
|
+
const entityId = entity.getRelativeSingleEntity(desugaredDiscriminationField).id
|
|
57
|
+
return exitingColumnIds.has(entityId) ? entityId : null
|
|
58
|
+
}, [desugaredDiscriminationField, exitingColumnIds])
|
|
59
|
+
|
|
60
|
+
const groupItemsByColumn = useGroupItemsByColumn(getDiscriminatorValue, desugaredSortableByField)
|
|
61
|
+
|
|
62
|
+
const getSortedColumns = useGetSortedColumns(desugaredColumnSortableByField)
|
|
63
|
+
|
|
64
|
+
const columnsResult = useBoardColumns<EntityAccessor>({
|
|
65
|
+
columns: getSortedColumns(columnEntities),
|
|
66
|
+
columnIdGetter: it => it.id,
|
|
67
|
+
groupItemsByColumn,
|
|
68
|
+
items: itemEntities,
|
|
69
|
+
nullColumn,
|
|
70
|
+
nullColumnPlacement,
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const addColumn = useCallback<BoardAddColumnMethod>((index, preprocess) => {
|
|
74
|
+
const columnEntities = columnEntitiesGetter()
|
|
75
|
+
if (!desugaredColumnSortableByField) {
|
|
76
|
+
if (index === undefined) {
|
|
77
|
+
return columnEntities.createNewEntity(preprocess)
|
|
78
|
+
}
|
|
79
|
+
throw new BindingError('Cannot add column at specific index without sortableBy field')
|
|
80
|
+
}
|
|
81
|
+
addEntityAtIndex(columnEntities, desugaredColumnSortableByField, columnEntities.length, preprocess)
|
|
82
|
+
}, [columnEntitiesGetter, desugaredColumnSortableByField])
|
|
83
|
+
|
|
84
|
+
const connectItemToColumn = useCallback((item: EntityAccessor, column: EntityAccessor | null) => {
|
|
85
|
+
const hasOne = desugaredDiscriminationField.hasOneRelationPath
|
|
86
|
+
const parentEntity = item.getRelativeSingleEntity({ hasOneRelationPath: hasOne.slice(0, -1) })
|
|
87
|
+
if (column) {
|
|
88
|
+
parentEntity.connectEntityAtField(hasOne[hasOne.length - 1].field, column)
|
|
89
|
+
} else {
|
|
90
|
+
parentEntity.disconnectEntityAtField(hasOne[hasOne.length - 1].field)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
}, [desugaredDiscriminationField.hasOneRelationPath])
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
const moveColumn = useMemo<BoardMoveColumnMethod | undefined>(() => {
|
|
97
|
+
if (!desugaredColumnSortableByField) {
|
|
98
|
+
return undefined
|
|
99
|
+
}
|
|
100
|
+
return (entity, index) => {
|
|
101
|
+
const sortedColumns = getSortedColumns(columnEntitiesGetter())
|
|
102
|
+
const currentIndex = sortedColumns.findIndex(it => it.id === entity.id)
|
|
103
|
+
const resortedItems = arrayMove(sortedColumns, currentIndex, index)
|
|
104
|
+
repairEntitiesOrder(desugaredColumnSortableByField, resortedItems)
|
|
105
|
+
}
|
|
106
|
+
}, [columnEntitiesGetter, desugaredColumnSortableByField, getSortedColumns])
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
const removeColumn = useCallback<BoardRemoveColumnMethod>(entity => {
|
|
110
|
+
entity.deleteEntity()
|
|
111
|
+
if (desugaredSortableByField) {
|
|
112
|
+
repairEntitiesOrder(desugaredSortableByField, Array.from(columnEntitiesGetter()))
|
|
113
|
+
}
|
|
114
|
+
}, [columnEntitiesGetter, desugaredSortableByField])
|
|
115
|
+
|
|
116
|
+
const { addItem, moveItem, removeItem } = useBoardItemsMethods({
|
|
117
|
+
columnIdGetter: it => it.id,
|
|
118
|
+
connectItemToColumn,
|
|
119
|
+
desugaredSortableByField,
|
|
120
|
+
sortScope,
|
|
121
|
+
getDiscriminatorValue,
|
|
122
|
+
groupItemsByColumn,
|
|
123
|
+
itemEntities,
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
columns: columnsResult,
|
|
128
|
+
addColumn,
|
|
129
|
+
addItem,
|
|
130
|
+
moveColumn,
|
|
131
|
+
moveItem,
|
|
132
|
+
removeColumn,
|
|
133
|
+
removeItem,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import { EntityAccessor, EntityListAccessor, useDesugaredRelativeSingleField } from '@contember/react-binding'
|
|
3
|
+
import { BoardBindingProps, BoardStaticColumnValue } from './BoardBindingProps'
|
|
4
|
+
import { useGroupItemsByColumn } from './internal/useGroupItemsByColumn'
|
|
5
|
+
import { useBoardColumns } from './internal/useBoardColumns'
|
|
6
|
+
import { BoardCommonProps, BoardStaticColumnsBindingProps } from './types'
|
|
7
|
+
import { useBoardItemsMethods } from './internal/useBoardItemsMethods'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export type UseStaticBoardBindingProps =
|
|
11
|
+
& Omit<BoardCommonProps, 'children'>
|
|
12
|
+
& BoardStaticColumnsBindingProps
|
|
13
|
+
& {
|
|
14
|
+
itemEntities: EntityListAccessor
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const useStaticBoard = ({
|
|
18
|
+
sortableBy,
|
|
19
|
+
sortScope,
|
|
20
|
+
columns,
|
|
21
|
+
discriminationField,
|
|
22
|
+
itemEntities,
|
|
23
|
+
nullColumnPlacement = 'end',
|
|
24
|
+
nullColumn = 'auto',
|
|
25
|
+
}: UseStaticBoardBindingProps): BoardBindingProps<BoardStaticColumnValue> => {
|
|
26
|
+
|
|
27
|
+
const desugaredSortableByField = useDesugaredRelativeSingleField(sortableBy)
|
|
28
|
+
const desugaredDiscriminationField = useDesugaredRelativeSingleField(discriminationField)
|
|
29
|
+
|
|
30
|
+
const getDiscriminatorValue = useCallback((entity: EntityAccessor) => {
|
|
31
|
+
return entity.getRelativeSingleField<string>(desugaredDiscriminationField).value
|
|
32
|
+
}, [desugaredDiscriminationField])
|
|
33
|
+
|
|
34
|
+
const groupItemsByColumn = useGroupItemsByColumn(getDiscriminatorValue, desugaredSortableByField)
|
|
35
|
+
|
|
36
|
+
const columnsResult = useBoardColumns({
|
|
37
|
+
columns,
|
|
38
|
+
columnIdGetter: it => it.value,
|
|
39
|
+
groupItemsByColumn,
|
|
40
|
+
items: itemEntities,
|
|
41
|
+
nullColumn,
|
|
42
|
+
nullColumnPlacement,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const connectItemToColumn = useCallback((item: EntityAccessor, column: BoardStaticColumnValue | null) => {
|
|
46
|
+
item.getRelativeSingleField(desugaredDiscriminationField).updateValue(column?.value ?? null)
|
|
47
|
+
}, [desugaredDiscriminationField])
|
|
48
|
+
|
|
49
|
+
const { addItem, moveItem, removeItem } = useBoardItemsMethods({
|
|
50
|
+
columnIdGetter: it => it.value,
|
|
51
|
+
connectItemToColumn,
|
|
52
|
+
groupItemsByColumn,
|
|
53
|
+
itemEntities,
|
|
54
|
+
desugaredSortableByField,
|
|
55
|
+
sortScope,
|
|
56
|
+
getDiscriminatorValue,
|
|
57
|
+
})
|
|
58
|
+
return {
|
|
59
|
+
columns: columnsResult,
|
|
60
|
+
addItem,
|
|
61
|
+
moveItem,
|
|
62
|
+
removeItem,
|
|
63
|
+
}
|
|
64
|
+
}
|