@kaspernj/api-maker 1.0.445 → 1.0.446
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 +2 -1
- package/src/draggable-sort/controller.mjs +137 -0
- package/src/draggable-sort/index.jsx +108 -0
- package/src/draggable-sort/item.jsx +174 -0
- package/src/table/components/column.jsx +8 -2
- package/src/table/components/header.jsx +2 -2
- package/src/table/header-column.jsx +59 -79
- package/src/table/model-column.jsx +11 -5
- package/src/table/model-row.jsx +9 -5
- package/src/table/settings/column-row.jsx +2 -1
- package/src/table/table.jsx +143 -65
- package/src/table/{widths.mjs → widths.jsx} +11 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaspernj/api-maker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.446",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "index.js",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"object-to-formdata": ">= 4.1.0",
|
|
36
36
|
"on-location-changed": ">= 1.0.13",
|
|
37
37
|
"qs": ">= 6.9.3",
|
|
38
|
+
"react-native-draglist": "^3.8.0",
|
|
38
39
|
"react-native-vector-icons": "^10.2.0",
|
|
39
40
|
"replaceall": ">= 0.1.6",
|
|
40
41
|
"set-state-compare": ">= 1.0.53",
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
import EventEmitter from "events"
|
|
3
|
+
|
|
4
|
+
export default class DraggableSortController {
|
|
5
|
+
constructor({data, events, keyExtractor}) {
|
|
6
|
+
this.data = data
|
|
7
|
+
this.currentOrder = [...data]
|
|
8
|
+
this.events = events || new EventEmitter()
|
|
9
|
+
this.keyExtractor = keyExtractor
|
|
10
|
+
|
|
11
|
+
this.draggedItem = null
|
|
12
|
+
this.draggedItemData = null
|
|
13
|
+
this.draggedItemNewPosition = null
|
|
14
|
+
|
|
15
|
+
this.draggedOverItem = null
|
|
16
|
+
this.draggedOverItemData = null
|
|
17
|
+
|
|
18
|
+
this.itemData = {}
|
|
19
|
+
|
|
20
|
+
for (const itemIndex in data) {
|
|
21
|
+
this.itemData[itemIndex] = {
|
|
22
|
+
index: itemIndex,
|
|
23
|
+
item: data[itemIndex],
|
|
24
|
+
position: itemIndex
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getEvents = () => this.events
|
|
30
|
+
getItemDataForItem = (item) => this.getItemDataForIndex(this.data.indexOf(item))
|
|
31
|
+
getItemDataForKey = (key) => this.itemData.find((itemDataI) => digg(itemDataI, "key") == key)
|
|
32
|
+
getItemDataForIndex = (index) => digg(this, "itemData", index)
|
|
33
|
+
|
|
34
|
+
onDragStart = ({item, itemIndex}) => {
|
|
35
|
+
if (item) {
|
|
36
|
+
this.draggedItem = item
|
|
37
|
+
this.draggedItemData = this.getItemDataForIndex(itemIndex)
|
|
38
|
+
this.draggedItemIndex = itemIndex
|
|
39
|
+
this.draggedItemPosition = this.draggedItemData.position
|
|
40
|
+
this.events.emit("onDragStart", {item, itemData: this.draggedItemData})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
onDragEnd = () => {
|
|
45
|
+
const itemData = this.draggedItemData
|
|
46
|
+
const fromIndex = itemData.index
|
|
47
|
+
const fromPosition = digg(this, "draggedItemPosition")
|
|
48
|
+
const toPosition = this.draggedItemNewPosition
|
|
49
|
+
const fromItem = this.draggedItem
|
|
50
|
+
const toItem = this.draggedOverItem
|
|
51
|
+
const callbackArgs = {item: itemData.item, itemData, fromIndex, fromItem, fromPosition, toItem, toPosition}
|
|
52
|
+
|
|
53
|
+
this.draggedItemData.events.emit("resetPosition", {
|
|
54
|
+
callback: () => {
|
|
55
|
+
this.events.emit("onDragEndAnimation", callbackArgs)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
this.draggedItem = null
|
|
60
|
+
this.draggedItemData = null
|
|
61
|
+
this.draggedItemNewPosition = null
|
|
62
|
+
|
|
63
|
+
this.draggedOverItem = null
|
|
64
|
+
this.draggedOverItemData = null
|
|
65
|
+
|
|
66
|
+
this.events.emit("onDragEnd", callbackArgs)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onItemLayout = ({events, index, item, layout}) => {
|
|
70
|
+
if (!(index in this.itemData)) throw new Error(`Item not found for index ${index}`)
|
|
71
|
+
|
|
72
|
+
const itemData = this.itemData[index]
|
|
73
|
+
|
|
74
|
+
itemData.layout = layout
|
|
75
|
+
|
|
76
|
+
if (!itemData.initialLayout) {
|
|
77
|
+
itemData.baseX = layout.x
|
|
78
|
+
itemData.events = events
|
|
79
|
+
itemData.initialLayout = layout
|
|
80
|
+
itemData.key = this.keyExtractor(item)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onMove = ({gestate}) => {
|
|
85
|
+
// Send move-event to the item being dragged so it will actually move around
|
|
86
|
+
this.draggedItemData?.events?.emit("move", {gestate})
|
|
87
|
+
|
|
88
|
+
const moveX = gestate.dx + this.initialDragPosition.x
|
|
89
|
+
|
|
90
|
+
for (const itemIndex in this.itemData) {
|
|
91
|
+
const itemData = this.getItemDataForIndex(itemIndex)
|
|
92
|
+
const baseX = digg(itemData, "baseX")
|
|
93
|
+
let smallestWidth = this.draggedItemData.layout.width
|
|
94
|
+
|
|
95
|
+
if (itemData.layout.width < smallestWidth) smallestWidth = itemData.layout.width
|
|
96
|
+
|
|
97
|
+
if (moveX > baseX && moveX < (baseX + smallestWidth) && itemIndex != this.draggedItemData.index) {
|
|
98
|
+
this.draggedOverItem = itemData.item
|
|
99
|
+
this.draggedOverItemData = itemData
|
|
100
|
+
|
|
101
|
+
const positionOfDraggedItem = this.currentOrder.indexOf(this.draggedItemData.item)
|
|
102
|
+
const positionOfOverItem = this.currentOrder.indexOf(this.draggedOverItemData.item)
|
|
103
|
+
|
|
104
|
+
this.currentOrder[positionOfDraggedItem] = this.draggedOverItemData.item
|
|
105
|
+
this.currentOrder[positionOfOverItem] = this.draggedItemData.item
|
|
106
|
+
|
|
107
|
+
this.draggedItemData.position = positionOfOverItem
|
|
108
|
+
this.draggedOverItemData.position = positionOfDraggedItem
|
|
109
|
+
|
|
110
|
+
this.updatePositionOfItems()
|
|
111
|
+
this.draggedItemNewPosition = positionOfOverItem
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setInitialDragPosition = (initialDragPosition) => {
|
|
117
|
+
this.initialDragPosition = initialDragPosition
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
updatePositionOfItems() {
|
|
121
|
+
let currentPosition = 0
|
|
122
|
+
|
|
123
|
+
for (const item of this.currentOrder) {
|
|
124
|
+
const itemData = this.getItemDataForItem(item)
|
|
125
|
+
|
|
126
|
+
if (digg(itemData, "index") != digg(this, "draggedItemData", "index")) { // Dont animate dragged element to a new position because it is currently being dragged
|
|
127
|
+
itemData.events.emit("moveToPosition", {
|
|
128
|
+
x: currentPosition,
|
|
129
|
+
y: 0
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
itemData.baseX = currentPosition
|
|
134
|
+
currentPosition += digg(itemData, "layout", "width")
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {useMemo} from "react"
|
|
2
|
+
import {Animated, PanResponder} from "react-native"
|
|
3
|
+
import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component.js"
|
|
4
|
+
import Controller from "./controller.mjs"
|
|
5
|
+
import DraggableSortItem from "./item"
|
|
6
|
+
import EventEmitter from "events"
|
|
7
|
+
import memo from "set-state-compare/src/memo"
|
|
8
|
+
import PropTypes from "prop-types"
|
|
9
|
+
import propTypesExact from "prop-types-exact"
|
|
10
|
+
import useEventEmitter from "../use-event-emitter.mjs"
|
|
11
|
+
|
|
12
|
+
export default memo(shapeComponent(class DraggableSort extends ShapeComponent {
|
|
13
|
+
static defaultProps = {
|
|
14
|
+
horizontal: false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static propTypes = propTypesExact({
|
|
18
|
+
cacheKeyExtractor: PropTypes.func,
|
|
19
|
+
data: PropTypes.array.isRequired,
|
|
20
|
+
dataSet: PropTypes.object,
|
|
21
|
+
events: PropTypes.instanceOf(EventEmitter),
|
|
22
|
+
horizontal: PropTypes.bool.isRequired,
|
|
23
|
+
keyExtractor: PropTypes.func.isRequired,
|
|
24
|
+
onDragItemEnd: PropTypes.func,
|
|
25
|
+
onDragItemStart: PropTypes.func,
|
|
26
|
+
onItemMoved: PropTypes.func,
|
|
27
|
+
onReordered: PropTypes.func.isRequired,
|
|
28
|
+
renderItem: PropTypes.func.isRequired
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
setup() {
|
|
32
|
+
const {data, keyExtractor} = this.p
|
|
33
|
+
const {events} = this.props
|
|
34
|
+
|
|
35
|
+
this.controller = useMemo(() => new Controller({data, events, keyExtractor}), [])
|
|
36
|
+
this.panResponder = useMemo(
|
|
37
|
+
() => PanResponder.create({
|
|
38
|
+
onStartShouldSetPanResponder: (e) => {
|
|
39
|
+
const initialDragPosition = {x: e.nativeEvent.locationX, y: e.nativeEvent.locationY}
|
|
40
|
+
|
|
41
|
+
this.controller.setInitialDragPosition(initialDragPosition)
|
|
42
|
+
|
|
43
|
+
if (this.controller.draggedItemData) {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
onPanResponderMove: (e, gestate) => {
|
|
48
|
+
this.tt.controller.onMove({gestate})
|
|
49
|
+
},
|
|
50
|
+
onPanResponderRelease: (e, gestate) => {
|
|
51
|
+
if (this.controller.draggedItem) {
|
|
52
|
+
this.tt.controller.onDragEnd()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
[]
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
useEventEmitter(this.controller.getEvents(), "onDragStart", this.tt.onDragItemStart)
|
|
60
|
+
useEventEmitter(this.controller.getEvents(), "onDragEnd", this.tt.onDragItemEnd)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
render() {
|
|
64
|
+
const {data, horizontal, keyExtractor, renderItem} = this.p
|
|
65
|
+
const {cacheKeyExtractor, dataSet} = this.props
|
|
66
|
+
const actualDataSet = useMemo(
|
|
67
|
+
() => Object.assign(
|
|
68
|
+
{
|
|
69
|
+
component: "draggable-sort"
|
|
70
|
+
},
|
|
71
|
+
dataSet
|
|
72
|
+
),
|
|
73
|
+
[dataSet]
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<Animated.View dataSet={actualDataSet} style={{flexDirection: horizontal ? "row" : "column"}} {...this.tt.panResponder.panHandlers}>
|
|
78
|
+
{data.map((item, itemIndex) =>
|
|
79
|
+
<DraggableSortItem
|
|
80
|
+
cacheKey={cacheKeyExtractor ? cacheKeyExtractor(item) : undefined}
|
|
81
|
+
controller={this.tt.controller}
|
|
82
|
+
item={item}
|
|
83
|
+
itemIndex={itemIndex}
|
|
84
|
+
key={keyExtractor(item)}
|
|
85
|
+
onItemMoved={this.props.onItemMoved}
|
|
86
|
+
renderItem={renderItem}
|
|
87
|
+
/>
|
|
88
|
+
)}
|
|
89
|
+
</Animated.View>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
onDragItemStart = ({itemData}) => {
|
|
94
|
+
if (this.props.onDragItemStart) {
|
|
95
|
+
this.p.onDragItemStart({itemData})
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
onDragItemEnd = (args) => {
|
|
100
|
+
if (args.toPosition !== null) {
|
|
101
|
+
this.p.onReordered(args)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (this.props.onDragItemEnd) {
|
|
105
|
+
this.p.onDragItemEnd(args)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}))
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import {useMemo} from "react"
|
|
2
|
+
import {Animated, Easing, PanResponder} from "react-native"
|
|
3
|
+
import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component.js"
|
|
4
|
+
import EventEmitter from "events"
|
|
5
|
+
import memo from "set-state-compare/src/memo"
|
|
6
|
+
import PropTypes from "prop-types"
|
|
7
|
+
import propTypesExact from "prop-types-exact"
|
|
8
|
+
import useEventEmitter from "../use-event-emitter.mjs"
|
|
9
|
+
|
|
10
|
+
export default memo(shapeComponent(class DraggableSortItem extends ShapeComponent {
|
|
11
|
+
static propTypes = propTypesExact({
|
|
12
|
+
cacheKey: PropTypes.string,
|
|
13
|
+
controller: PropTypes.object.isRequired,
|
|
14
|
+
item: PropTypes.any.isRequired,
|
|
15
|
+
itemIndex: PropTypes.number.isRequired,
|
|
16
|
+
onItemMoved: PropTypes.func,
|
|
17
|
+
renderItem: PropTypes.func.isRequired
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
initialLayout = null
|
|
21
|
+
|
|
22
|
+
setup() {
|
|
23
|
+
this.useStates({
|
|
24
|
+
active: false,
|
|
25
|
+
dragging: false
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
this.events = useMemo(() => new EventEmitter(), [])
|
|
29
|
+
this.position = useMemo(() => new Animated.ValueXY(), [])
|
|
30
|
+
this.panResponder = useMemo(
|
|
31
|
+
() => PanResponder.create({
|
|
32
|
+
onStartShouldSetPanResponder: (e, ) => {
|
|
33
|
+
this.setState({dragging: true})
|
|
34
|
+
this.p.controller.onDragStart({item: this.p.item, itemIndex: this.p.itemIndex})
|
|
35
|
+
|
|
36
|
+
return false
|
|
37
|
+
}
|
|
38
|
+
}),
|
|
39
|
+
[]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
useEventEmitter(this.p.controller.getEvents(), "onDragStart", this.tt.onDragStart)
|
|
43
|
+
useEventEmitter(this.p.controller.getEvents(), "onDragEndAnimation", this.tt.onDragEndAnimation)
|
|
44
|
+
useEventEmitter(this.tt.events, "move", this.tt.onMove)
|
|
45
|
+
useEventEmitter(this.tt.events, "moveToPosition", this.tt.onMoveToPosition)
|
|
46
|
+
useEventEmitter(this.tt.events, "resetPosition", this.tt.onResetPosition)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
render() {
|
|
50
|
+
const {item, renderItem} = this.p
|
|
51
|
+
const {active} = this.s
|
|
52
|
+
const style = useMemo(
|
|
53
|
+
() => {
|
|
54
|
+
const style = {
|
|
55
|
+
transform: this.tt.position.getTranslateTransform()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (active) {
|
|
59
|
+
style.backgroundColor = "#fff"
|
|
60
|
+
style.elevation = 2
|
|
61
|
+
style.zIndex = 99999
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return style
|
|
65
|
+
},
|
|
66
|
+
[active]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<Animated.View dataSet={{component: "draggable-sort/item"}} onLayout={this.tt.onLayout} style={style}>
|
|
71
|
+
{renderItem({isActive: active, item, touchProps: this.tt.panResponder.panHandlers})}
|
|
72
|
+
</Animated.View>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
onDragStart = ({itemData}) => {
|
|
77
|
+
const newState = {dragging: true}
|
|
78
|
+
|
|
79
|
+
if (itemData.index == this.p.itemIndex) {
|
|
80
|
+
newState.active = true
|
|
81
|
+
this.baseXAtStartedDragging = this.getBaseX()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.setState(newState)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
onDragEndAnimation = () => this.setState({active: false, dragging: false})
|
|
88
|
+
|
|
89
|
+
onLayout = (e) => {
|
|
90
|
+
const {controller, item, itemIndex} = this.p
|
|
91
|
+
|
|
92
|
+
controller.onItemLayout({events: this.tt.events, index: itemIndex, item, layout: e.nativeEvent.layout})
|
|
93
|
+
|
|
94
|
+
if (!this.tt.initialLayout) {
|
|
95
|
+
this.initialLayout = e.nativeEvent.layout
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
onMove = ({gestate}) => {
|
|
100
|
+
const x = gestate.dx + this.tt.baseXAtStartedDragging - this.tt.initialLayout.x
|
|
101
|
+
const y = this.tt.initialLayout.y
|
|
102
|
+
|
|
103
|
+
this.tt.position.setValue({x, y})
|
|
104
|
+
|
|
105
|
+
if (this.props.onItemMoved) {
|
|
106
|
+
this.p.onItemMoved({itemIndex: this.p.itemIndex, x, y})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onMoveToPosition = ({x, y}) => {
|
|
111
|
+
const calculatedXFromStartingPosition = x - this.tt.initialLayout.x
|
|
112
|
+
const animationArgs = {
|
|
113
|
+
duration: 200,
|
|
114
|
+
easing: Easing.inOut(Easing.linear),
|
|
115
|
+
toValue: {
|
|
116
|
+
x: calculatedXFromStartingPosition,
|
|
117
|
+
y
|
|
118
|
+
},
|
|
119
|
+
useNativeDriver: true,
|
|
120
|
+
}
|
|
121
|
+
const animationEventArgs = {animationArgs, animationType: "moveToPosition", item: this.p.item}
|
|
122
|
+
|
|
123
|
+
this.p.controller.events.emit("onAnimationStart", animationEventArgs)
|
|
124
|
+
|
|
125
|
+
Animated
|
|
126
|
+
.timing(this.tt.position, animationArgs)
|
|
127
|
+
.start(() => {
|
|
128
|
+
this.p.controller.events.emit("onAnimationEnd", animationEventArgs)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
if (this.props.onItemMoved) {
|
|
132
|
+
this.p.onItemMoved({
|
|
133
|
+
animationArgs,
|
|
134
|
+
itemIndex: this.p.itemIndex,
|
|
135
|
+
x: calculatedXFromStartingPosition,
|
|
136
|
+
y
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
getBaseX = () => this.p.controller.getItemDataForIndex(this.p.itemIndex).baseX
|
|
142
|
+
|
|
143
|
+
onResetPosition = (args) => {
|
|
144
|
+
const baseX = this.getBaseX() - this.tt.initialLayout.x
|
|
145
|
+
const animationArgs = {
|
|
146
|
+
duration: 200,
|
|
147
|
+
easing: Easing.inOut(Easing.linear),
|
|
148
|
+
toValue: {
|
|
149
|
+
x: baseX,
|
|
150
|
+
y: 0
|
|
151
|
+
},
|
|
152
|
+
useNativeDriver: true,
|
|
153
|
+
}
|
|
154
|
+
const animationEventArgs = {animationArgs, animationType: "resetPosition", item: this.p.item}
|
|
155
|
+
|
|
156
|
+
this.p.controller.events.emit("onAnimationStart", animationEventArgs)
|
|
157
|
+
|
|
158
|
+
Animated
|
|
159
|
+
.timing(this.tt.position, animationArgs)
|
|
160
|
+
.start(() => {
|
|
161
|
+
this.p.controller.events.emit("onAnimationEnd", animationEventArgs)
|
|
162
|
+
if (args?.callback) args.callback()
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
if (this.props.onItemMoved) {
|
|
166
|
+
this.p.onItemMoved({
|
|
167
|
+
animationArgs,
|
|
168
|
+
itemIndex: this.p.itemIndex,
|
|
169
|
+
x: baseX,
|
|
170
|
+
y: 0
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}))
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import BaseComponent from "../../base-component"
|
|
2
2
|
import memo from "set-state-compare/src/memo"
|
|
3
3
|
import {shapeComponent} from "set-state-compare/src/shape-component"
|
|
4
|
-
import {View} from "react-native"
|
|
4
|
+
import {Animated, View} from "react-native"
|
|
5
5
|
|
|
6
6
|
export default memo(shapeComponent(class SharedTableColumn extends BaseComponent {
|
|
7
7
|
render() {
|
|
8
|
+
const {dataSet, ...restProps} = this.props
|
|
9
|
+
const actualDataSet = Object.assign(
|
|
10
|
+
{component: "api-maker/table/components/column"},
|
|
11
|
+
dataSet
|
|
12
|
+
)
|
|
13
|
+
|
|
8
14
|
return (
|
|
9
|
-
<View {...
|
|
15
|
+
<Animated.View dataSet={actualDataSet} {...restProps} />
|
|
10
16
|
)
|
|
11
17
|
}
|
|
12
18
|
}))
|
|
@@ -2,7 +2,7 @@ import BaseComponent from "../../base-component"
|
|
|
2
2
|
import classNames from "classnames"
|
|
3
3
|
import memo from "set-state-compare/src/memo"
|
|
4
4
|
import {shapeComponent} from "set-state-compare/src/shape-component"
|
|
5
|
-
import {
|
|
5
|
+
import {Animated} from "react-native"
|
|
6
6
|
|
|
7
7
|
export default memo(shapeComponent(class SharedTableHeader extends BaseComponent {
|
|
8
8
|
render() {
|
|
@@ -14,7 +14,7 @@ export default memo(shapeComponent(class SharedTableHeader extends BaseComponent
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
return (
|
|
17
|
-
<View dataSet={actualDataSet} {...restProps} />
|
|
17
|
+
<Animated.View dataSet={actualDataSet} {...restProps} />
|
|
18
18
|
)
|
|
19
19
|
}
|
|
20
20
|
}))
|
|
@@ -1,23 +1,27 @@
|
|
|
1
|
+
import {useMemo} from "react"
|
|
1
2
|
import BaseComponent from "../base-component"
|
|
2
3
|
import classNames from "classnames"
|
|
4
|
+
import FontAwesomeIcon from "react-native-vector-icons/FontAwesome"
|
|
3
5
|
import Header from "./components/header"
|
|
4
6
|
import HeaderColumnContent from "./header-column-content"
|
|
5
7
|
import memo from "set-state-compare/src/memo"
|
|
6
|
-
import {
|
|
8
|
+
import {Animated, PanResponder} from "react-native"
|
|
7
9
|
import PropTypes from "prop-types"
|
|
8
10
|
import propTypesExact from "prop-types-exact"
|
|
9
11
|
import {shapeComponent} from "set-state-compare/src/shape-component"
|
|
10
12
|
import useBreakpoint from "../use-breakpoint"
|
|
11
|
-
import useEventListener from "../use-event-listener.mjs"
|
|
12
13
|
import Widths from "./widths"
|
|
13
14
|
|
|
14
15
|
export default memo(shapeComponent(class ApiMakerTableHeaderColumn extends BaseComponent {
|
|
15
16
|
static propTypes = propTypesExact({
|
|
17
|
+
active: PropTypes.bool.isRequired,
|
|
18
|
+
animatedWidth: PropTypes.instanceOf(Animated.Value).isRequired,
|
|
19
|
+
animatedZIndex: PropTypes.instanceOf(Animated.Value).isRequired,
|
|
16
20
|
column: PropTypes.object.isRequired,
|
|
17
21
|
resizing: PropTypes.bool.isRequired,
|
|
18
22
|
table: PropTypes.object.isRequired,
|
|
19
23
|
tableSettingColumn: PropTypes.object.isRequired,
|
|
20
|
-
|
|
24
|
+
touchProps: PropTypes.object.isRequired,
|
|
21
25
|
widths: PropTypes.instanceOf(Widths).isRequired
|
|
22
26
|
})
|
|
23
27
|
|
|
@@ -25,29 +29,64 @@ export default memo(shapeComponent(class ApiMakerTableHeaderColumn extends BaseC
|
|
|
25
29
|
const {name: breakpoint, mdUp, smDown} = useBreakpoint()
|
|
26
30
|
|
|
27
31
|
this.setInstance({breakpoint, mdUp, smDown})
|
|
28
|
-
|
|
29
|
-
useEventListener(window, "mousemove", this.tt.onWindowMouseMove)
|
|
30
|
-
useEventListener(window, "mouseup", this.tt.onWindowMouseUp)
|
|
31
|
-
|
|
32
32
|
this.useStates({
|
|
33
|
-
cursorX: undefined,
|
|
34
|
-
originalWidth: undefined,
|
|
35
33
|
resizing: false
|
|
36
34
|
})
|
|
35
|
+
|
|
36
|
+
this.resizePanResponder = useMemo(
|
|
37
|
+
() => PanResponder.create({
|
|
38
|
+
onStartShouldSetPanResponder: (_e) => {
|
|
39
|
+
this.originalWidth = this.currentWidth
|
|
40
|
+
this.setState({resizing: true})
|
|
41
|
+
this.p.table.setState({resizing: true})
|
|
42
|
+
|
|
43
|
+
return true
|
|
44
|
+
},
|
|
45
|
+
onPanResponderMove: (_e, gestate) => {
|
|
46
|
+
const newWidth = this.tt.originalWidth + gestate.dx
|
|
47
|
+
|
|
48
|
+
this.p.widths.setWidthOfColumn({
|
|
49
|
+
identifier: this.p.tableSettingColumn.identifier(),
|
|
50
|
+
width: newWidth
|
|
51
|
+
})
|
|
52
|
+
},
|
|
53
|
+
onPanResponderRelease: this.tt.onResizeEnd,
|
|
54
|
+
onPanResponderTerminate: this.tt.onResizeEnd,
|
|
55
|
+
onPanResponderTerminationRequest: () => false // Don't let another PanResponder steal focus and stop resizing until release
|
|
56
|
+
}),
|
|
57
|
+
[]
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onResizeEnd = async () => {
|
|
62
|
+
this.p.table.setState({lastUpdate: new Date(), resizing: false})
|
|
63
|
+
this.setState({resizing: false})
|
|
64
|
+
|
|
65
|
+
const width = this.p.widths.getWidthOfColumn(this.p.tableSettingColumn.identifier())
|
|
66
|
+
|
|
67
|
+
await this.p.tableSettingColumn.update({width})
|
|
37
68
|
}
|
|
38
69
|
|
|
39
70
|
render() {
|
|
40
71
|
const {mdUp} = this.tt
|
|
41
|
-
const {column, resizing, table, tableSettingColumn,
|
|
72
|
+
const {active, animatedWidth, column, resizing, table, tableSettingColumn, touchProps} = this.p
|
|
42
73
|
const {styleForHeader} = table.tt
|
|
43
74
|
const headerProps = table.headerProps(column)
|
|
44
75
|
const {style, ...restColumnProps} = headerProps
|
|
45
|
-
const actualStyle =
|
|
46
|
-
{
|
|
47
|
-
|
|
48
|
-
|
|
76
|
+
const actualStyle = useMemo(
|
|
77
|
+
() => {
|
|
78
|
+
const actualStyle = Object.assign(
|
|
79
|
+
{
|
|
80
|
+
cursor: resizing ? "col-resize" : undefined,
|
|
81
|
+
width: mdUp ? animatedWidth : "100%",
|
|
82
|
+
height: mdUp ? "100%" : undefined
|
|
83
|
+
},
|
|
84
|
+
style
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return actualStyle
|
|
49
88
|
},
|
|
50
|
-
style
|
|
89
|
+
[active, animatedWidth, mdUp, resizing, style]
|
|
51
90
|
)
|
|
52
91
|
|
|
53
92
|
return (
|
|
@@ -60,11 +99,12 @@ export default memo(shapeComponent(class ApiMakerTableHeaderColumn extends BaseC
|
|
|
60
99
|
style={styleForHeader({style: actualStyle})}
|
|
61
100
|
{...restColumnProps}
|
|
62
101
|
>
|
|
102
|
+
{mdUp &&
|
|
103
|
+
<FontAwesomeIcon name="bars" style={{marginRight: 3, fontSize: 12}} {...touchProps} />
|
|
104
|
+
}
|
|
63
105
|
<HeaderColumnContent column={column} table={table} tableSettingColumn={tableSettingColumn} />
|
|
64
106
|
{mdUp &&
|
|
65
|
-
<
|
|
66
|
-
onMouseDown={Platform.OS == "web" ? this.tt.onResizeMouseDown : undefined}
|
|
67
|
-
onPressIn={this.tt.onResizePressIn}
|
|
107
|
+
<Animated.View
|
|
68
108
|
style={{
|
|
69
109
|
position: "absolute",
|
|
70
110
|
top: 0,
|
|
@@ -74,6 +114,7 @@ export default memo(shapeComponent(class ApiMakerTableHeaderColumn extends BaseC
|
|
|
74
114
|
cursor: "col-resize",
|
|
75
115
|
zIndex: 9999
|
|
76
116
|
}}
|
|
117
|
+
{...this.tt.resizePanResponder.panHandlers}
|
|
77
118
|
/>
|
|
78
119
|
}
|
|
79
120
|
</Header>
|
|
@@ -85,65 +126,4 @@ export default memo(shapeComponent(class ApiMakerTableHeaderColumn extends BaseC
|
|
|
85
126
|
|
|
86
127
|
this.currentWidth = width
|
|
87
128
|
}
|
|
88
|
-
|
|
89
|
-
onResizeEnd = async () => {
|
|
90
|
-
this.setState({cursorX: undefined, resizing: false})
|
|
91
|
-
this.p.table.setState({resizing: false})
|
|
92
|
-
|
|
93
|
-
const width = this.p.widths.getWidthOfColumn(this.p.tableSettingColumn.identifier())
|
|
94
|
-
|
|
95
|
-
await this.p.tableSettingColumn.update({width})
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Otherwise text is selectable on web
|
|
99
|
-
onResizeMouseDown = (e) => {
|
|
100
|
-
e.preventDefault()
|
|
101
|
-
e.stopPropagation()
|
|
102
|
-
|
|
103
|
-
const originalWidth = this.currentWidth
|
|
104
|
-
const cursorX = e.nativeEvent.pageX
|
|
105
|
-
|
|
106
|
-
this.setState({
|
|
107
|
-
cursorX,
|
|
108
|
-
originalWidth,
|
|
109
|
-
resizing: true
|
|
110
|
-
})
|
|
111
|
-
this.p.table.setState({resizing: true})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
onResizePressIn = (e) => {
|
|
115
|
-
e.preventDefault()
|
|
116
|
-
e.stopPropagation()
|
|
117
|
-
|
|
118
|
-
const originalWidth = this.currentWidth
|
|
119
|
-
const cursorX = e.nativeEvent.pageX
|
|
120
|
-
|
|
121
|
-
this.setState({
|
|
122
|
-
cursorX,
|
|
123
|
-
originalWidth,
|
|
124
|
-
resizing: true
|
|
125
|
-
})
|
|
126
|
-
this.p.table.setState({resizing: true})
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
onWindowMouseMove = (e) => {
|
|
130
|
-
const {cursorX, resizing, originalWidth} = this.s
|
|
131
|
-
|
|
132
|
-
if (resizing) {
|
|
133
|
-
const newCursorX = e.pageX
|
|
134
|
-
const diffX = newCursorX - cursorX
|
|
135
|
-
const newWidth = originalWidth + diffX
|
|
136
|
-
|
|
137
|
-
this.p.widths.setWidthOfColumn({
|
|
138
|
-
identifier: this.p.tableSettingColumn.identifier(),
|
|
139
|
-
width: newWidth
|
|
140
|
-
})
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
onWindowMouseUp = () => {
|
|
145
|
-
if (this.s.resizing) {
|
|
146
|
-
this.onResizeEnd()
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
129
|
}))
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {View} from "react-native"
|
|
1
|
+
import {Animated, View} from "react-native"
|
|
2
2
|
import BaseComponent from "../base-component"
|
|
3
3
|
import classNames from "classnames"
|
|
4
4
|
import Column from "./components/column"
|
|
5
5
|
import ColumnContent from "./column-content"
|
|
6
6
|
import columnIdentifier from "./column-identifier.mjs"
|
|
7
|
+
import EventEmitter from "events"
|
|
7
8
|
import PropTypes from "prop-types"
|
|
8
9
|
import propTypesExact from "prop-types-exact"
|
|
9
10
|
import memo from "set-state-compare/src/memo"
|
|
@@ -13,18 +14,21 @@ import useBreakpoint from "../use-breakpoint"
|
|
|
13
14
|
|
|
14
15
|
export default memo(shapeComponent(class ApiMakerTableModelColumn extends BaseComponent {
|
|
15
16
|
static propTypes = propTypesExact({
|
|
17
|
+
animatedPosition: PropTypes.instanceOf(Animated.ValueXY).isRequired,
|
|
18
|
+
animatedWidth: PropTypes.instanceOf(Animated.Value).isRequired,
|
|
19
|
+
animatedZIndex: PropTypes.instanceOf(Animated.Value).isRequired,
|
|
16
20
|
column: PropTypes.object.isRequired,
|
|
17
21
|
columnIndex: PropTypes.number.isRequired,
|
|
18
22
|
even: PropTypes.bool.isRequired,
|
|
23
|
+
events: PropTypes.instanceOf(EventEmitter).isRequired,
|
|
19
24
|
model: PropTypes.object.isRequired,
|
|
20
25
|
table: PropTypes.object.isRequired,
|
|
21
|
-
tableSettingColumn: PropTypes.object.isRequired
|
|
22
|
-
width: PropTypes.number.isRequired
|
|
26
|
+
tableSettingColumn: PropTypes.object.isRequired
|
|
23
27
|
})
|
|
24
28
|
|
|
25
29
|
render() {
|
|
26
30
|
const {mdUp} = useBreakpoint()
|
|
27
|
-
const {column, columnIndex, even, model, table
|
|
31
|
+
const {animatedWidth, animatedZIndex, column, columnIndex, even, model, table} = this.props
|
|
28
32
|
const columnProps = table.columnProps(column)
|
|
29
33
|
const {style, ...restColumnProps} = columnProps
|
|
30
34
|
const actualStyle = Object.assign(
|
|
@@ -33,7 +37,9 @@ export default memo(shapeComponent(class ApiMakerTableModelColumn extends BaseCo
|
|
|
33
37
|
columnIndex,
|
|
34
38
|
even,
|
|
35
39
|
style: {
|
|
36
|
-
|
|
40
|
+
zIndex: animatedZIndex,
|
|
41
|
+
transform: this.p.animatedPosition.getTranslateTransform(),
|
|
42
|
+
width: mdUp ? animatedWidth : "100%"
|
|
37
43
|
}
|
|
38
44
|
}),
|
|
39
45
|
style
|
package/src/table/model-row.jsx
CHANGED
|
@@ -2,7 +2,7 @@ import {Pressable} from "react-native"
|
|
|
2
2
|
import BaseComponent from "../base-component"
|
|
3
3
|
import Column from "./components/column"
|
|
4
4
|
import columnIdentifier from "./column-identifier.mjs"
|
|
5
|
-
import
|
|
5
|
+
import EventEmitter from "events"
|
|
6
6
|
import FontAwesomeIcon from "react-native-vector-icons/FontAwesome"
|
|
7
7
|
import * as inflection from "inflection"
|
|
8
8
|
import modelCallbackArgs from "./model-callback-args.mjs"
|
|
@@ -19,11 +19,12 @@ const WorkerPluginsCheckbox = React.lazy(() => import("./worker-plugins-checkbox
|
|
|
19
19
|
export default memo(shapeComponent(class ApiMakerBootStrapLiveTableModelRow extends BaseComponent {
|
|
20
20
|
static propTypes = propTypesExact({
|
|
21
21
|
cacheKey: PropTypes.string.isRequired,
|
|
22
|
+
columns: PropTypes.array,
|
|
22
23
|
columnWidths: PropTypes.object.isRequired,
|
|
24
|
+
events: PropTypes.instanceOf(EventEmitter).isRequired,
|
|
23
25
|
index: PropTypes.number.isRequired,
|
|
24
26
|
model: PropTypes.object.isRequired,
|
|
25
27
|
table: PropTypes.object.isRequired,
|
|
26
|
-
preparedColumns: PropTypes.array,
|
|
27
28
|
tableSettingFullCacheKey: PropTypes.string.isRequired
|
|
28
29
|
})
|
|
29
30
|
|
|
@@ -85,18 +86,21 @@ export default memo(shapeComponent(class ApiMakerBootStrapLiveTableModelRow exte
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
columnsContentFromColumns(model, even) {
|
|
88
|
-
const {
|
|
89
|
+
const {columns, events, table} = this.p
|
|
89
90
|
|
|
90
|
-
return
|
|
91
|
+
return columns?.map(({animatedPosition, animatedWidth, animatedZIndex, column, tableSettingColumn}, columnIndex) =>
|
|
91
92
|
<ModelColumn
|
|
93
|
+
animatedPosition={animatedPosition}
|
|
94
|
+
animatedWidth={animatedWidth}
|
|
95
|
+
animatedZIndex={animatedZIndex}
|
|
92
96
|
column={column}
|
|
93
97
|
columnIndex={columnIndex}
|
|
94
98
|
even={even}
|
|
99
|
+
events={events}
|
|
95
100
|
key={columnIdentifier(column)}
|
|
96
101
|
model={model}
|
|
97
102
|
table={table}
|
|
98
103
|
tableSettingColumn={tableSettingColumn}
|
|
99
|
-
width={width}
|
|
100
104
|
/>
|
|
101
105
|
)
|
|
102
106
|
}
|
|
@@ -87,6 +87,7 @@ export default memo(shapeComponent(class ColumnRow extends BaseComponent {
|
|
|
87
87
|
const {table, tableSettingColumn} = this.p
|
|
88
88
|
|
|
89
89
|
await tableSettingColumn.update({visible: this.checked})
|
|
90
|
-
|
|
90
|
+
|
|
91
|
+
table.events.emit("columnVisibilityUpdated", {tableSettingColumn})
|
|
91
92
|
}
|
|
92
93
|
}))
|
package/src/table/table.jsx
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import {digg, digs} from "diggerize"
|
|
2
|
-
import {
|
|
2
|
+
import React, {createContext, useContext, useMemo, useRef} from "react"
|
|
3
|
+
import {Animated, Pressable, View} from "react-native"
|
|
3
4
|
import BaseComponent from "../base-component"
|
|
4
5
|
import Card from "../bootstrap/card"
|
|
5
6
|
import classNames from "classnames"
|
|
6
7
|
import Collection from "../collection"
|
|
7
8
|
import columnVisible from "./column-visible.mjs"
|
|
8
9
|
import debounce from "debounce"
|
|
10
|
+
import DraggableSort from "../draggable-sort/index.jsx"
|
|
11
|
+
import EventEmitter from "events"
|
|
9
12
|
import Filters from "./filters"
|
|
10
13
|
import FlatList from "./components/flat-list"
|
|
11
14
|
import FontAwesomeIcon from "react-native-vector-icons/FontAwesome"
|
|
@@ -20,7 +23,6 @@ import ModelRow from "./model-row"
|
|
|
20
23
|
import Paginate from "../bootstrap/paginate"
|
|
21
24
|
import Params from "../params"
|
|
22
25
|
import PropTypes from "prop-types"
|
|
23
|
-
import React, {createContext, useContext, useMemo, useRef} from "react"
|
|
24
26
|
import Row from "./components/row"
|
|
25
27
|
import selectCalculator from "./select-calculator"
|
|
26
28
|
import Select from "../inputs/select"
|
|
@@ -32,6 +34,7 @@ import uniqunize from "uniqunize"
|
|
|
32
34
|
import useBreakpoint from "../use-breakpoint"
|
|
33
35
|
import useCollection from "../use-collection"
|
|
34
36
|
import useI18n from "i18n-on-steroids/src/use-i18n.mjs"
|
|
37
|
+
import useEventEmitter from "../use-event-emitter.mjs"
|
|
35
38
|
import useModelEvent from "../use-model-event.js"
|
|
36
39
|
import useQueryParams from "on-location-changed/src/use-query-params.js"
|
|
37
40
|
import Widths from "./widths"
|
|
@@ -40,43 +43,55 @@ const paginationOptions = [30, 60, 90, ["All", "all"]]
|
|
|
40
43
|
const WorkerPluginsCheckAllCheckbox = React.lazy(() => import("./worker-plugins-check-all-checkbox"))
|
|
41
44
|
const TableContext = createContext()
|
|
42
45
|
|
|
43
|
-
const ListHeaderComponent = memo((
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
46
|
+
const ListHeaderComponent = memo(shapeComponent(class ListHeaderComponent extends BaseComponent {
|
|
47
|
+
setup() {
|
|
48
|
+
this.useStates({
|
|
49
|
+
lastUpdate: new Date()
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
render() {
|
|
54
|
+
const {mdUp} = useBreakpoint()
|
|
55
|
+
const tableContextValue = useContext(TableContext)
|
|
56
|
+
const table = tableContextValue.table
|
|
57
|
+
const {collection, events, queryWithoutPagination, t} = table.tt
|
|
58
|
+
const {query} = digs(collection, "query")
|
|
59
|
+
|
|
60
|
+
useEventEmitter(events, "columnVisibilityUpdated", this.tt.onColumnVisibilityUpdated)
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Row dataSet={{class: "api-maker/table/header-row"}} style={table.styleForRowHeader()}>
|
|
64
|
+
{table.p.workplace && table.s.currentWorkplace &&
|
|
65
|
+
<Header style={table.styleForHeader({style: {width: mdUp ? 41 : undefined}})}>
|
|
66
|
+
<WorkerPluginsCheckAllCheckbox
|
|
67
|
+
currentWorkplace={table.s.currentWorkplace}
|
|
68
|
+
query={queryWithoutPagination}
|
|
69
|
+
style={{marginHorizontal: "auto"}}
|
|
70
|
+
/>
|
|
71
|
+
{!mdUp &&
|
|
72
|
+
<Text style={{marginLeft: 3}}>
|
|
73
|
+
{t(".select_all_found", {defaultValue: "Select all found"})}
|
|
74
|
+
</Text>
|
|
75
|
+
}
|
|
76
|
+
</Header>
|
|
77
|
+
}
|
|
78
|
+
{!mdUp &&
|
|
79
|
+
<Header style={table.styleForHeader({style: {}})}>
|
|
80
|
+
<HeaderSelect preparedColumns={table.s.preparedColumns} query={query} table={table} />
|
|
81
|
+
</Header>
|
|
82
|
+
}
|
|
83
|
+
{mdUp &&
|
|
84
|
+
<>
|
|
85
|
+
{table.headersContentFromColumns()}
|
|
86
|
+
<Header style={table.styleForHeader({style: {}, type: "actions"})} />
|
|
87
|
+
</>
|
|
88
|
+
}
|
|
89
|
+
</Row>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
onColumnVisibilityUpdated = () => this.setState({lastUpdate: new Date()})
|
|
94
|
+
}))
|
|
80
95
|
|
|
81
96
|
export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
82
97
|
static defaultProps = {
|
|
@@ -132,7 +147,9 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
132
147
|
workplace: PropTypes.bool.isRequired
|
|
133
148
|
}
|
|
134
149
|
|
|
135
|
-
|
|
150
|
+
draggableSortEvents = new EventEmitter()
|
|
151
|
+
events = new EventEmitter()
|
|
152
|
+
tableSettings = null
|
|
136
153
|
|
|
137
154
|
setup() {
|
|
138
155
|
const {t} = useI18n({namespace: "js.api_maker.table"})
|
|
@@ -151,14 +168,15 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
151
168
|
|
|
152
169
|
if (!queryName) queryName = collectionKey
|
|
153
170
|
|
|
154
|
-
const columnsAsArray = this.columnsAsArray()
|
|
155
171
|
const querySName = `${queryName}_s`
|
|
156
172
|
|
|
157
173
|
this.useStates({
|
|
158
|
-
columns: columnsAsArray,
|
|
174
|
+
columns: () => this.columnsAsArray(),
|
|
159
175
|
currentWorkplace: undefined,
|
|
160
176
|
currentWorkplaceCount: null,
|
|
161
177
|
filterForm: null,
|
|
178
|
+
columnsToShow: null,
|
|
179
|
+
draggedColumn: null,
|
|
162
180
|
identifier: () => this.props.identifier || `${collectionKey}-default`,
|
|
163
181
|
lastUpdate: () => new Date(),
|
|
164
182
|
preload: undefined,
|
|
@@ -181,9 +199,10 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
181
199
|
() => ({
|
|
182
200
|
cacheKey: this.s.tableSettingFullCacheKey,
|
|
183
201
|
lastUpdate: this.s.lastUpdate,
|
|
202
|
+
resizing: this.s.resizing,
|
|
184
203
|
table: this
|
|
185
204
|
}),
|
|
186
|
-
[this.s.lastUpdate, this.s.tableSettingFullCacheKey]
|
|
205
|
+
[this.s.lastUpdate, this.s.resizing, this.s.tableSettingFullCacheKey]
|
|
187
206
|
)
|
|
188
207
|
|
|
189
208
|
useMemo(() => {
|
|
@@ -195,7 +214,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
195
214
|
}, [this.p.currentUser?.id()])
|
|
196
215
|
|
|
197
216
|
useMemo(() => {
|
|
198
|
-
if (!this.tt.
|
|
217
|
+
if (!this.tt.tableSettings && this.s.width) {
|
|
199
218
|
this.loadTableSetting()
|
|
200
219
|
}
|
|
201
220
|
}, [this.p.currentUser?.id(), this.s.width])
|
|
@@ -235,8 +254,16 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
235
254
|
() => this.collection?.query?.clone()?.except("page"),
|
|
236
255
|
[this.collection.query]
|
|
237
256
|
)
|
|
257
|
+
|
|
258
|
+
useEventEmitter(this.tt.draggableSortEvents, "onDragStart", this.tt.onDragStart)
|
|
259
|
+
useEventEmitter(this.tt.draggableSortEvents, "onDragEndAnimation", this.tt.onDragEndAnimation)
|
|
260
|
+
useEventEmitter(this.tt.events, "columnVisibilityUpdated", this.tt.onColumnVisibilityUpdated)
|
|
238
261
|
}
|
|
239
262
|
|
|
263
|
+
onColumnVisibilityUpdated = () => this.setState({columnsToShow: this.getColumnsToShow(this.s.columns), lastUpdate: new Date()})
|
|
264
|
+
onDragStart = ({item}) => item.animatedZIndex.setValue(9999)
|
|
265
|
+
onDragEndAnimation = ({item}) => item.animatedZIndex.setValue(0)
|
|
266
|
+
|
|
240
267
|
async loadCurrentWorkplace() {
|
|
241
268
|
const Workplace = modelClassRequire("Workplace")
|
|
242
269
|
const result = await Workplace.current()
|
|
@@ -257,6 +284,12 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
257
284
|
this.setState({currentWorkplaceCount})
|
|
258
285
|
}
|
|
259
286
|
|
|
287
|
+
getColumnsToShow(columns) {
|
|
288
|
+
return columns
|
|
289
|
+
.filter(({column, tableSettingColumn}) => columnVisible(column, tableSettingColumn))
|
|
290
|
+
.sort((a, b) => a.tableSettingColumn.position() - b.tableSettingColumn.position())
|
|
291
|
+
}
|
|
292
|
+
|
|
260
293
|
async loadTableSetting() {
|
|
261
294
|
this.tableSettings = new TableSettings({table: this})
|
|
262
295
|
|
|
@@ -264,8 +297,11 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
264
297
|
const {columns, preload} = this.tableSettings.preparedColumns(tableSetting)
|
|
265
298
|
const {width} = this.s
|
|
266
299
|
const widths = new Widths({columns, table: this, width})
|
|
300
|
+
const columnsToShow = this.getColumnsToShow(columns)
|
|
267
301
|
|
|
268
302
|
this.setState({
|
|
303
|
+
columns,
|
|
304
|
+
columnsToShow,
|
|
269
305
|
preparedColumns: columns,
|
|
270
306
|
preload: this.mergedPreloads(preload),
|
|
271
307
|
tableSetting,
|
|
@@ -450,7 +486,11 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
450
486
|
<TableContext.Provider value={this.tt.tableContextValue}>
|
|
451
487
|
<FlatList
|
|
452
488
|
data={models}
|
|
453
|
-
dataSet={{
|
|
489
|
+
dataSet={{
|
|
490
|
+
class: classNames("api-maker--table", className),
|
|
491
|
+
cacheKey: this.s.tableSettingFullCacheKey,
|
|
492
|
+
lastUpdate: this.s.lastUpdate
|
|
493
|
+
}}
|
|
454
494
|
extraData={this.s.lastUpdate}
|
|
455
495
|
keyExtractor={this.tt.keyExtrator}
|
|
456
496
|
ListHeaderComponent={ListHeaderComponent}
|
|
@@ -575,8 +615,6 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
575
615
|
}
|
|
576
616
|
|
|
577
617
|
renderItem = ({index, item: model}) => {
|
|
578
|
-
const {preparedColumns, tableSettingFullCacheKey} = this.s
|
|
579
|
-
|
|
580
618
|
if (!this.s.tableSettingLoaded) {
|
|
581
619
|
return (
|
|
582
620
|
<View>
|
|
@@ -590,13 +628,14 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
590
628
|
return (
|
|
591
629
|
<ModelRow
|
|
592
630
|
cacheKey={model.cacheKey()}
|
|
631
|
+
columns={this.s.columnsToShow}
|
|
593
632
|
columnWidths={this.columnWidths()}
|
|
633
|
+
events={this.tt.events}
|
|
594
634
|
index={index}
|
|
595
635
|
key={model.id()}
|
|
596
636
|
model={model}
|
|
597
|
-
preparedColumns={preparedColumns}
|
|
598
637
|
table={this}
|
|
599
|
-
tableSettingFullCacheKey={tableSettingFullCacheKey}
|
|
638
|
+
tableSettingFullCacheKey={this.s.tableSettingFullCacheKey}
|
|
600
639
|
/>
|
|
601
640
|
)
|
|
602
641
|
}
|
|
@@ -611,7 +650,7 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
611
650
|
|
|
612
651
|
if (styleUI) {
|
|
613
652
|
Object.assign(defaultStyle, {
|
|
614
|
-
backgroundColor: even ? "#f5f5f5" :
|
|
653
|
+
backgroundColor: even ? "#f5f5f5" : "#fff"
|
|
615
654
|
})
|
|
616
655
|
}
|
|
617
656
|
|
|
@@ -648,10 +687,6 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
648
687
|
defaultStyle.borderRight = "1px solid #dbdbdb"
|
|
649
688
|
}
|
|
650
689
|
|
|
651
|
-
if (mdUp) {
|
|
652
|
-
|
|
653
|
-
}
|
|
654
|
-
|
|
655
690
|
const actualStyle = Object.assign(
|
|
656
691
|
defaultStyle,
|
|
657
692
|
style
|
|
@@ -798,17 +833,60 @@ export default memo(shapeComponent(class ApiMakerTable extends BaseComponent {
|
|
|
798
833
|
return columnWidths
|
|
799
834
|
}
|
|
800
835
|
|
|
801
|
-
headersContentFromColumns = () =>
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
836
|
+
headersContentFromColumns = () => {
|
|
837
|
+
return (
|
|
838
|
+
<DraggableSort
|
|
839
|
+
data={this.s.columnsToShow}
|
|
840
|
+
events={this.tt.draggableSortEvents}
|
|
841
|
+
horizontal
|
|
842
|
+
keyExtractor={this.tt.dragListkeyExtractor}
|
|
843
|
+
onItemMoved={this.tt.onItemMoved}
|
|
844
|
+
onReordered={this.tt.onReordered}
|
|
845
|
+
renderItem={this.tt.dragListRenderItemContent}
|
|
846
|
+
/>
|
|
847
|
+
)
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
dragListCacheKeyExtractor = (item) => `${item.tableSettingColumn.identifier()}-${this.s.resizing}`
|
|
851
|
+
dragListkeyExtractor = (item) => item.tableSettingColumn.identifier()
|
|
852
|
+
|
|
853
|
+
onItemMoved = ({animationArgs, itemIndex, x, y}) => {
|
|
854
|
+
const animatedPosition = digg(this, "s", "columnsToShow", itemIndex, "animatedPosition")
|
|
855
|
+
|
|
856
|
+
if (animationArgs) {
|
|
857
|
+
Animated.timing(animatedPosition, animationArgs).start()
|
|
858
|
+
} else {
|
|
859
|
+
animatedPosition.setValue({x, y})
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
onReordered = async ({fromItem, fromPosition, toItem, toPosition}) => {
|
|
864
|
+
if (fromPosition == toPosition) return // Only do requests and queries if changed
|
|
865
|
+
|
|
866
|
+
const TableSettingColumn = fromItem.tableSettingColumn.constructor
|
|
867
|
+
const toColumn = await TableSettingColumn.find(toItem.tableSettingColumn.id()) // Need to load latest position because ActsAsList might have changed it
|
|
868
|
+
|
|
869
|
+
await fromItem.tableSettingColumn.update({position: toColumn.position()})
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
dragListRenderItemContent = ({isActive, item, touchProps}) => {
|
|
873
|
+
const {animatedWidth, animatedZIndex, column, tableSettingColumn} = item
|
|
874
|
+
|
|
875
|
+
return (
|
|
876
|
+
<HeaderColumn
|
|
877
|
+
active={isActive}
|
|
878
|
+
animatedWidth={animatedWidth}
|
|
879
|
+
animatedZIndex={animatedZIndex}
|
|
880
|
+
column={column}
|
|
881
|
+
key={tableSettingColumn.identifier()}
|
|
882
|
+
resizing={this.s.resizing}
|
|
883
|
+
table={this}
|
|
884
|
+
tableSettingColumn={tableSettingColumn}
|
|
885
|
+
touchProps={touchProps}
|
|
886
|
+
widths={this.s.widths}
|
|
887
|
+
/>
|
|
888
|
+
)
|
|
889
|
+
}
|
|
812
890
|
|
|
813
891
|
headerClassNameForColumn(column) {
|
|
814
892
|
const classNames = []
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {Animated, Easing} from "react-native"
|
|
1
2
|
import {digg} from "diggerize"
|
|
2
3
|
|
|
3
4
|
export default class TableWidths {
|
|
@@ -19,7 +20,15 @@ export default class TableWidths {
|
|
|
19
20
|
const column = this.columns[columnIndex]
|
|
20
21
|
const tableSettingColumn = column.tableSettingColumn
|
|
21
22
|
|
|
23
|
+
if (column.animatedPosition) throw new Error("Column already had an animated position")
|
|
24
|
+
|
|
25
|
+
column.animatedPosition = new Animated.ValueXY()
|
|
26
|
+
column.animatedZIndex = new Animated.Value(0)
|
|
27
|
+
|
|
22
28
|
if (tableSettingColumn.hasWidth()) {
|
|
29
|
+
if (column.animatedWidth) throw new Error("Column already had an animated width")
|
|
30
|
+
|
|
31
|
+
column.animatedWidth = new Animated.Value(tableSettingColumn.width())
|
|
23
32
|
column.width = tableSettingColumn.width()
|
|
24
33
|
|
|
25
34
|
widthLeft -= tableSettingColumn.width()
|
|
@@ -44,6 +53,7 @@ export default class TableWidths {
|
|
|
44
53
|
|
|
45
54
|
if (newWidth < 200) newWidth = 200
|
|
46
55
|
|
|
56
|
+
column.animatedWidth = new Animated.Value(newWidth)
|
|
47
57
|
column.width = newWidth
|
|
48
58
|
|
|
49
59
|
updateData << {
|
|
@@ -72,7 +82,6 @@ export default class TableWidths {
|
|
|
72
82
|
if (!column) throw new Error(`No such column: ${identifier}`)
|
|
73
83
|
|
|
74
84
|
column.width = width
|
|
75
|
-
|
|
76
|
-
this.table.setState({lastUpdate: new Date()})
|
|
85
|
+
column.animatedWidth.setValue(width)
|
|
77
86
|
}
|
|
78
87
|
}
|