@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.
Files changed (108) hide show
  1. package/dist/development/Board.cjs +116 -0
  2. package/dist/development/Board.cjs.map +1 -0
  3. package/dist/development/Board.js +116 -0
  4. package/dist/development/Board.js.map +1 -0
  5. package/dist/development/const.cjs +5 -0
  6. package/dist/development/const.cjs.map +1 -0
  7. package/dist/development/const.js +5 -0
  8. package/dist/development/const.js.map +1 -0
  9. package/dist/development/index.cjs +11 -0
  10. package/dist/development/index.cjs.map +1 -0
  11. package/dist/development/index.js +11 -0
  12. package/dist/development/index.js.map +1 -0
  13. package/dist/development/internal/useBoardColumns.cjs +44 -0
  14. package/dist/development/internal/useBoardColumns.cjs.map +1 -0
  15. package/dist/development/internal/useBoardColumns.js +44 -0
  16. package/dist/development/internal/useBoardColumns.js.map +1 -0
  17. package/dist/development/internal/useBoardItemsMethods.cjs +100 -0
  18. package/dist/development/internal/useBoardItemsMethods.cjs.map +1 -0
  19. package/dist/development/internal/useBoardItemsMethods.js +100 -0
  20. package/dist/development/internal/useBoardItemsMethods.js.map +1 -0
  21. package/dist/development/internal/useGroupItemsByColumn.cjs +19 -0
  22. package/dist/development/internal/useGroupItemsByColumn.cjs.map +1 -0
  23. package/dist/development/internal/useGroupItemsByColumn.js +19 -0
  24. package/dist/development/internal/useGroupItemsByColumn.js.map +1 -0
  25. package/dist/development/useDynamicBoard.cjs +99 -0
  26. package/dist/development/useDynamicBoard.cjs.map +1 -0
  27. package/dist/development/useDynamicBoard.js +99 -0
  28. package/dist/development/useDynamicBoard.js.map +1 -0
  29. package/dist/development/useStaticBoard.cjs +51 -0
  30. package/dist/development/useStaticBoard.cjs.map +1 -0
  31. package/dist/development/useStaticBoard.js +51 -0
  32. package/dist/development/useStaticBoard.js.map +1 -0
  33. package/dist/development/utils/arrayMove.cjs +9 -0
  34. package/dist/development/utils/arrayMove.cjs.map +1 -0
  35. package/dist/development/utils/arrayMove.js +9 -0
  36. package/dist/development/utils/arrayMove.js.map +1 -0
  37. package/dist/production/Board.cjs +116 -0
  38. package/dist/production/Board.cjs.map +1 -0
  39. package/dist/production/Board.js +116 -0
  40. package/dist/production/Board.js.map +1 -0
  41. package/dist/production/const.cjs +5 -0
  42. package/dist/production/const.cjs.map +1 -0
  43. package/dist/production/const.js +5 -0
  44. package/dist/production/const.js.map +1 -0
  45. package/dist/production/index.cjs +11 -0
  46. package/dist/production/index.cjs.map +1 -0
  47. package/dist/production/index.js +11 -0
  48. package/dist/production/index.js.map +1 -0
  49. package/dist/production/internal/useBoardColumns.cjs +44 -0
  50. package/dist/production/internal/useBoardColumns.cjs.map +1 -0
  51. package/dist/production/internal/useBoardColumns.js +44 -0
  52. package/dist/production/internal/useBoardColumns.js.map +1 -0
  53. package/dist/production/internal/useBoardItemsMethods.cjs +100 -0
  54. package/dist/production/internal/useBoardItemsMethods.cjs.map +1 -0
  55. package/dist/production/internal/useBoardItemsMethods.js +100 -0
  56. package/dist/production/internal/useBoardItemsMethods.js.map +1 -0
  57. package/dist/production/internal/useGroupItemsByColumn.cjs +19 -0
  58. package/dist/production/internal/useGroupItemsByColumn.cjs.map +1 -0
  59. package/dist/production/internal/useGroupItemsByColumn.js +19 -0
  60. package/dist/production/internal/useGroupItemsByColumn.js.map +1 -0
  61. package/dist/production/useDynamicBoard.cjs +99 -0
  62. package/dist/production/useDynamicBoard.cjs.map +1 -0
  63. package/dist/production/useDynamicBoard.js +99 -0
  64. package/dist/production/useDynamicBoard.js.map +1 -0
  65. package/dist/production/useStaticBoard.cjs +51 -0
  66. package/dist/production/useStaticBoard.cjs.map +1 -0
  67. package/dist/production/useStaticBoard.js +51 -0
  68. package/dist/production/useStaticBoard.js.map +1 -0
  69. package/dist/production/utils/arrayMove.cjs +9 -0
  70. package/dist/production/utils/arrayMove.cjs.map +1 -0
  71. package/dist/production/utils/arrayMove.js +9 -0
  72. package/dist/production/utils/arrayMove.js.map +1 -0
  73. package/dist/types/Board.d.ts +10 -0
  74. package/dist/types/Board.d.ts.map +1 -0
  75. package/dist/types/BoardBindingProps.d.ts +36 -0
  76. package/dist/types/BoardBindingProps.d.ts.map +1 -0
  77. package/dist/types/const.d.ts +2 -0
  78. package/dist/types/const.d.ts.map +1 -0
  79. package/dist/types/index.d.ts +7 -0
  80. package/dist/types/index.d.ts.map +1 -0
  81. package/dist/types/internal/useBoardColumns.d.ts +11 -0
  82. package/dist/types/internal/useBoardColumns.d.ts.map +1 -0
  83. package/dist/types/internal/useBoardItemsMethods.d.ts +15 -0
  84. package/dist/types/internal/useBoardItemsMethods.d.ts.map +1 -0
  85. package/dist/types/internal/useGroupItemsByColumn.d.ts +5 -0
  86. package/dist/types/internal/useGroupItemsByColumn.d.ts.map +1 -0
  87. package/dist/types/tsconfig.tsbuildinfo +1 -0
  88. package/dist/types/types.d.ts +31 -0
  89. package/dist/types/types.d.ts.map +1 -0
  90. package/dist/types/useDynamicBoard.d.ts +9 -0
  91. package/dist/types/useDynamicBoard.d.ts.map +1 -0
  92. package/dist/types/useStaticBoard.d.ts +8 -0
  93. package/dist/types/useStaticBoard.d.ts.map +1 -0
  94. package/dist/types/utils/arrayMove.d.ts +2 -0
  95. package/dist/types/utils/arrayMove.d.ts.map +1 -0
  96. package/package.json +48 -0
  97. package/src/Board.tsx +156 -0
  98. package/src/BoardBindingProps.ts +45 -0
  99. package/src/const.ts +1 -0
  100. package/src/index.ts +6 -0
  101. package/src/internal/useBoardColumns.ts +57 -0
  102. package/src/internal/useBoardItemsMethods.ts +141 -0
  103. package/src/internal/useGroupItemsByColumn.ts +19 -0
  104. package/src/tsconfig.json +9 -0
  105. package/src/types.ts +64 -0
  106. package/src/useDynamicBoard.ts +135 -0
  107. package/src/useStaticBoard.ts +64 -0
  108. package/src/utils/arrayMove.ts +5 -0
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './Board'
2
+ export * from './BoardBindingProps'
3
+ export * from './const'
4
+ export * from './types'
5
+ export * from './useDynamicBoard'
6
+ export * from './useStaticBoard'
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../../tsconfig.settings.json",
3
+ "compilerOptions": {
4
+ "outDir": "../dist/types"
5
+ },
6
+ "references": [
7
+ { "path": "../../react-binding/src" },
8
+ ]
9
+ }
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
+ }
@@ -0,0 +1,5 @@
1
+ export function arrayMove<T>(array: T[], from: number, to: number): T[] {
2
+ const newArray = array.slice()
3
+ newArray.splice(to, 0, newArray.splice(from, 1)[0])
4
+ return newArray
5
+ }