@onehat/ui 0.4.97 → 0.4.99
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 +1 -1
- package/src/Components/Container/Container.js +90 -37
- package/src/Components/Form/Form.js +1 -0
- package/src/Components/Grid/Grid.js +55 -17
- package/src/Components/Hoc/withPresetButtons.js +5 -0
- package/src/Components/Tree/Tree.js +3 -0
- package/src/Constants/PmStatuses.js +9 -0
- package/src/PlatformImports/Web/Attachments.js +1 -1
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cloneElement, useState, useEffect, useRef, } from 'react';
|
|
1
|
+
import { cloneElement, useState, useEffect, useRef, useCallback, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
BoxNative,
|
|
4
4
|
HStack,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from '../../Constants/UiModes.js';
|
|
17
17
|
import withComponent from '../Hoc/withComponent.js';
|
|
18
18
|
import useForceUpdate from '../../Hooks/useForceUpdate.js';
|
|
19
|
+
import getComponentFromType from '../../Functions/getComponentFromType.js';
|
|
19
20
|
import getSaved from '../../Functions/getSaved.js';
|
|
20
21
|
import setSaved from '../../Functions/setSaved.js';
|
|
21
22
|
import Splitter from './Splitter.js';
|
|
@@ -106,6 +107,8 @@ function Container(props) {
|
|
|
106
107
|
} = props,
|
|
107
108
|
id = props.id || props.self?.path,
|
|
108
109
|
isWeb = CURRENT_MODE === UI_MODE_WEB,
|
|
110
|
+
useWindowSize = getComponentFromType('useWindowSize'),
|
|
111
|
+
windowSize = useWindowSize(),
|
|
109
112
|
forceUpdate = useForceUpdate(),
|
|
110
113
|
centerRef = useRef(null),
|
|
111
114
|
northRef = useRef(null),
|
|
@@ -122,6 +125,36 @@ function Container(props) {
|
|
|
122
125
|
localSouthIsCollapsedRef = useRef(southInitialIsCollapsed),
|
|
123
126
|
localEastIsCollapsedRef = useRef(eastInitialIsCollapsed),
|
|
124
127
|
localWestIsCollapsedRef = useRef(westInitialIsCollapsed),
|
|
128
|
+
onLayout = async (e) => {
|
|
129
|
+
console.log('Container onLayout', e.nativeEvent.layout.width);
|
|
130
|
+
if (id) {
|
|
131
|
+
// save prevScreenSize if changed
|
|
132
|
+
const
|
|
133
|
+
height = parseFloat(e.nativeEvent.layout.height),
|
|
134
|
+
width = parseFloat(e.nativeEvent.layout.width),
|
|
135
|
+
key = id + '-prevScreenSize',
|
|
136
|
+
prevScreenSize = await getSaved(key);
|
|
137
|
+
if (!prevScreenSize || prevScreenSize.width !== width || prevScreenSize.height !== height) {
|
|
138
|
+
await setSaved(key, {
|
|
139
|
+
height,
|
|
140
|
+
width,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// reset all sizes to null, so they recalculate
|
|
144
|
+
setNorthHeight(null);
|
|
145
|
+
setSouthHeight(null);
|
|
146
|
+
setEastWidth(null);
|
|
147
|
+
setWestWidth(null);
|
|
148
|
+
forceUpdate();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
debouncedOnLayout = useCallback(
|
|
153
|
+
_.debounce((e) => {
|
|
154
|
+
onLayout(e);
|
|
155
|
+
}, 2000), // delay is signficant, as all we're trying to do is catch screen size changes
|
|
156
|
+
[]
|
|
157
|
+
),
|
|
125
158
|
setNorthIsCollapsed = (bool) => {
|
|
126
159
|
if (setExternalNorthIsCollapsed) {
|
|
127
160
|
setExternalNorthIsCollapsed(bool);
|
|
@@ -293,53 +326,72 @@ function Container(props) {
|
|
|
293
326
|
|
|
294
327
|
if (id) {
|
|
295
328
|
let key, val;
|
|
296
|
-
key = id + '-northIsCollapsed';
|
|
297
|
-
val = await getSaved(key);
|
|
298
|
-
if (!_.isNil(val)) {
|
|
299
|
-
setNorthIsCollapsed(val);
|
|
300
|
-
}
|
|
301
329
|
|
|
302
|
-
|
|
330
|
+
// does screensize from previous render exist?
|
|
331
|
+
key = id + '-prevScreenSize';
|
|
303
332
|
val = await getSaved(key);
|
|
333
|
+
let prevScreenSize = null;
|
|
304
334
|
if (!_.isNil(val)) {
|
|
305
|
-
|
|
335
|
+
prevScreenSize = val;
|
|
306
336
|
}
|
|
337
|
+
const currentScreenSize = {
|
|
338
|
+
width: windowSize?.width ?? null,
|
|
339
|
+
height: windowSize?.height ?? null,
|
|
340
|
+
};
|
|
341
|
+
if (!prevScreenSize || (prevScreenSize.width === currentScreenSize.width && prevScreenSize.height === currentScreenSize.height)) {
|
|
342
|
+
|
|
343
|
+
// only load these saved settings if the screen size is the same as when they were saved
|
|
344
|
+
key = id + '-northIsCollapsed';
|
|
345
|
+
val = await getSaved(key);
|
|
346
|
+
if (!_.isNil(val)) {
|
|
347
|
+
setNorthIsCollapsed(val);
|
|
348
|
+
}
|
|
307
349
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
350
|
+
key = id + '-southIsCollapsed';
|
|
351
|
+
val = await getSaved(key);
|
|
352
|
+
if (!_.isNil(val)) {
|
|
353
|
+
setSouthIsCollapsed(val);
|
|
354
|
+
}
|
|
313
355
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
356
|
+
key = id + '-eastIsCollapsed';
|
|
357
|
+
val = await getSaved(key);
|
|
358
|
+
if (!_.isNil(val)) {
|
|
359
|
+
setEastIsCollapsed(val);
|
|
360
|
+
}
|
|
319
361
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
362
|
+
key = id + '-westIsCollapsed';
|
|
363
|
+
val = await getSaved(key);
|
|
364
|
+
if (!_.isNil(val)) {
|
|
365
|
+
setWestIsCollapsed(val);
|
|
366
|
+
}
|
|
325
367
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
368
|
+
key = id + '-northHeight';
|
|
369
|
+
val = await getSaved(key);
|
|
370
|
+
if (!_.isNil(val)) {
|
|
371
|
+
setNorthHeight(val);
|
|
372
|
+
}
|
|
331
373
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
374
|
+
key = id + '-southHeight';
|
|
375
|
+
val = await getSaved(key);
|
|
376
|
+
if (!_.isNil(val)) {
|
|
377
|
+
setSouthHeight(val);
|
|
378
|
+
}
|
|
337
379
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
380
|
+
key = id + '-eastWidth';
|
|
381
|
+
val = await getSaved(key);
|
|
382
|
+
if (!_.isNil(val)) {
|
|
383
|
+
setEastWidth(val);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
key = id + '-westWidth';
|
|
387
|
+
val = await getSaved(key);
|
|
388
|
+
if (!_.isNil(val)) {
|
|
389
|
+
setWestWidth(val);
|
|
390
|
+
}
|
|
391
|
+
|
|
342
392
|
}
|
|
393
|
+
|
|
394
|
+
|
|
343
395
|
}
|
|
344
396
|
|
|
345
397
|
if (!isReady) {
|
|
@@ -366,6 +418,7 @@ function Container(props) {
|
|
|
366
418
|
|
|
367
419
|
componentProps._panel.isCollapsible = false;
|
|
368
420
|
componentProps._panel.isDisabled = isDisabled || isComponentsDisabled;
|
|
421
|
+
componentProps.onLayout = debouncedOnLayout;
|
|
369
422
|
centerComponent = cloneElement(center, componentProps);
|
|
370
423
|
if (north) {
|
|
371
424
|
componentProps = { _panel: { ...north.props?._panel }, };
|
|
@@ -208,6 +208,7 @@ function GridComponent(props) {
|
|
|
208
208
|
onRowDrop,
|
|
209
209
|
onDragStart,
|
|
210
210
|
onDragEnd,
|
|
211
|
+
rowLongPressDelayMs,
|
|
211
212
|
|
|
212
213
|
// withComponent
|
|
213
214
|
self,
|
|
@@ -300,6 +301,7 @@ function GridComponent(props) {
|
|
|
300
301
|
[localColumnsConfig, setLocalColumnsConfigRaw] = useState([]),
|
|
301
302
|
[isReorderMode, setIsReorderMode] = useState(false),
|
|
302
303
|
showRowHandle = showSelectHandle || areRowsDragSource || (canRowsReorder && isReorderMode),
|
|
304
|
+
rowLongPressDelay = rowLongPressDelayMs ?? ((areRowsDragSource || canRowsReorder) ? 800 : undefined),
|
|
303
305
|
[lastMeasuredContainerHeight, setLastMeasuredContainerHeight] = useState(0),
|
|
304
306
|
getMeasurementPhase = () => {
|
|
305
307
|
return measurementPhaseRaw.current;
|
|
@@ -469,11 +471,12 @@ function GridComponent(props) {
|
|
|
469
471
|
<Pressable
|
|
470
472
|
dataSet={{ ix: index }}
|
|
471
473
|
{...testProps(getRowTestId ? getRowTestId(row) : ((Repository ? Repository.schema.name : 'GridRow') + '-' + item?.id))}
|
|
474
|
+
delayLongPress={rowLongPressDelay}
|
|
472
475
|
onPress={(e) => {
|
|
473
476
|
if (e.preventDefault && e.cancelable) {
|
|
474
477
|
e.preventDefault();
|
|
475
478
|
}
|
|
476
|
-
if (isHeaderRow
|
|
479
|
+
if (isHeaderRow) {
|
|
477
480
|
return
|
|
478
481
|
}
|
|
479
482
|
if (CURRENT_MODE === UI_MODE_WEB) {
|
|
@@ -485,6 +488,9 @@ function GridComponent(props) {
|
|
|
485
488
|
}
|
|
486
489
|
break;
|
|
487
490
|
case DOUBLE_CLICK:
|
|
491
|
+
if (isReorderMode) {
|
|
492
|
+
return; // don't allow double-clicks while in reorder mode
|
|
493
|
+
}
|
|
488
494
|
if (editorType === EDITOR_TYPE__SIDE) {
|
|
489
495
|
// For side-editors, a double-click just acts like a single click
|
|
490
496
|
if (!getIsEditorShown()) {
|
|
@@ -929,26 +935,58 @@ function GridComponent(props) {
|
|
|
929
935
|
onRowReorderEnd = (item, monitor) => {
|
|
930
936
|
const
|
|
931
937
|
{ ix: dropIx, useBottom, marker, rows, dragIx } = cachedDragElements.current,
|
|
932
|
-
|
|
933
|
-
if (
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
938
|
+
selectionList = item?.getSelection ? item.getSelection() : (dragSelectionRef.current || selection || []);
|
|
939
|
+
if (dropIx === -1) {
|
|
940
|
+
marker.remove();
|
|
941
|
+
cachedDragElements.current = null;
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
const
|
|
946
|
+
// normalize the current selection to ids
|
|
947
|
+
itemsList = Repository ? entities : data,
|
|
948
|
+
dragItem = Repository ? Repository.getByIx(dragIx) : itemsList?.[dragIx],
|
|
949
|
+
selectionIds = _.compact(_.map(selectionList, (selectedItem) => {
|
|
950
|
+
if (!selectedItem) {
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
if (_.isObject(selectedItem)) {
|
|
954
|
+
return Repository ? selectedItem.id : selectedItem[idIx];
|
|
955
|
+
}
|
|
956
|
+
return selectedItem;
|
|
957
|
+
})),
|
|
958
|
+
// decide if we're moving the selected items or just the dragged item
|
|
959
|
+
dragItemId = dragItem ? (Repository ? dragItem.id : dragItem[idIx]) : null,
|
|
960
|
+
useSelection = !!(dragItemId && selectionIds.includes(dragItemId)),
|
|
961
|
+
dragItems = useSelection ? selectionIds : (dragItemId ? [dragItemId] : []),
|
|
962
|
+
// get the indices of the selected items
|
|
963
|
+
selectedIndicesRaw = Repository
|
|
964
|
+
? _.map(dragItems, (id) => itemsList?.findIndex((item) => item?.id === id))
|
|
965
|
+
: _.map(dragItems, (id) => itemsList?.findIndex((item) => item?.[idIx] === id)),
|
|
966
|
+
selectedIndices = _.uniq(_.filter(selectedIndicesRaw, (ix) => ix > -1)).sort((a, b) => a - b),
|
|
967
|
+
selectedIndicesSet = new Set(selectedIndices),
|
|
968
|
+
insertionIndexOriginal = useBottom ? dropIx + 1 : dropIx,
|
|
969
|
+
// get the drop record
|
|
970
|
+
dropRecord = Repository ? Repository.getByIx(dropIx) : itemsList?.[dropIx],
|
|
971
|
+
dropRecordId = dropRecord ? (Repository ? dropRecord.id : dropRecord[idIx]) : null,
|
|
972
|
+
// decide if we should move
|
|
973
|
+
shouldMove = !dropRecordId || !selectionIds.includes(dropRecordId);
|
|
974
|
+
|
|
975
|
+
if (shouldMove && selectedIndices.length) {
|
|
937
976
|
if (Repository) {
|
|
938
977
|
if (!Repository.isDestroyed) {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
if (dropRecord) {
|
|
942
|
-
Repository.reorder(dragRecord, dropRecord, useBottom ? DROP_POSITION_AFTER : DROP_POSITION_BEFORE);
|
|
978
|
+
if (dropRecord && dragItems.length) {
|
|
979
|
+
Repository.reorder(dragItems, dropRecord, useBottom ? DROP_POSITION_AFTER : DROP_POSITION_BEFORE);
|
|
943
980
|
}
|
|
944
981
|
}
|
|
945
|
-
} else {
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
982
|
+
} else if (itemsList && itemsList.length) {
|
|
983
|
+
const
|
|
984
|
+
removedBefore = _.filter(selectedIndices, (ix) => ix < insertionIndexOriginal).length,
|
|
985
|
+
insertionIndex = insertionIndexOriginal - removedBefore,
|
|
986
|
+
selectedItems = _.map(selectedIndices, (ix) => itemsList[ix]),
|
|
987
|
+
remainingItems = _.filter(itemsList, (entry, ix) => !selectedIndicesSet.has(ix));
|
|
988
|
+
remainingItems.splice(insertionIndex, 0, ...selectedItems);
|
|
989
|
+
itemsList.splice(0, itemsList.length, ...remainingItems);
|
|
952
990
|
}
|
|
953
991
|
}
|
|
954
992
|
|
|
@@ -339,6 +339,11 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
339
339
|
case DUPLICATE:
|
|
340
340
|
key = 'duplicateBtn';
|
|
341
341
|
text = 'Duplicate';
|
|
342
|
+
if (model) {
|
|
343
|
+
let inflected = Inflector.singularize(model); // can only add one at a time
|
|
344
|
+
inflected = Inflector.camel2words(Inflector.humanize(Inflector.underscore(inflected))); // Separate with spaces, capitalize each word
|
|
345
|
+
text += ' ' + inflected;
|
|
346
|
+
}
|
|
342
347
|
handler = (parent, e) => {
|
|
343
348
|
onDuplicate();
|
|
344
349
|
};
|
|
@@ -110,6 +110,7 @@ function TreeComponent(props) {
|
|
|
110
110
|
showHeaderToolbar = true,
|
|
111
111
|
showHovers = true,
|
|
112
112
|
showSelectHandle = true,
|
|
113
|
+
nodeLongPressDelayMs,
|
|
113
114
|
isNodeSelectable = true,
|
|
114
115
|
isNodeHoverable = true,
|
|
115
116
|
allowToggleSelection = true, // i.e. single click with no shift key toggles the selection of the node clicked on
|
|
@@ -219,6 +220,7 @@ function TreeComponent(props) {
|
|
|
219
220
|
[highlitedDatum, setHighlitedDatum] = useState(null),
|
|
220
221
|
[treeSearchValue, setTreeSearchValue] = useState(''),
|
|
221
222
|
showNodeHandle = showSelectHandle || areNodesDragSource,
|
|
223
|
+
nodeLongPressDelay = nodeLongPressDelayMs ?? ((areNodesDragSource || canNodesMoveInternally) ? 800 : undefined),
|
|
222
224
|
// state getters & setters
|
|
223
225
|
getTreeNodeData = () => {
|
|
224
226
|
return treeNodeData.current;
|
|
@@ -1092,6 +1094,7 @@ function TreeComponent(props) {
|
|
|
1092
1094
|
return <Pressable
|
|
1093
1095
|
{...testProps((Repository ? Repository.schema.name : 'TreeNode') + '-' + item?.id)}
|
|
1094
1096
|
key={item.hash}
|
|
1097
|
+
delayLongPress={nodeLongPressDelay}
|
|
1095
1098
|
onPress={(e) => {
|
|
1096
1099
|
if (e.preventDefault && e.cancelable) {
|
|
1097
1100
|
e.preventDefault();
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
export const PM_STATUSES__OK = 1;
|
|
2
|
+
export const PM_STATUSES__OK_TEXT = 'OK';
|
|
2
3
|
export const PM_STATUSES__PM_DUE = 2;
|
|
4
|
+
export const PM_STATUSES__PM_DUE_TEXT = 'PM Due';
|
|
3
5
|
export const PM_STATUSES__DELAYED = 3;
|
|
6
|
+
export const PM_STATUSES__DELAYED_TEXT = 'Delayed';
|
|
4
7
|
export const PM_STATUSES__WILL_CALL = 4;
|
|
8
|
+
export const PM_STATUSES__WILL_CALL_TEXT = 'Will Call';
|
|
5
9
|
export const PM_STATUSES__SCHEDULED = 5;
|
|
10
|
+
export const PM_STATUSES__SCHEDULED_TEXT = 'Scheduled';
|
|
6
11
|
export const PM_STATUSES__OVERDUE = 6;
|
|
12
|
+
export const PM_STATUSES__OVERDUE_TEXT = 'Overdue';
|
|
7
13
|
export const PM_STATUSES__COMPLETED = 7;
|
|
14
|
+
export const PM_STATUSES__COMPLETED_TEXT = 'Completed';
|
|
15
|
+
export const PM_STATUSES__DISABLED = 8;
|
|
16
|
+
export const PM_STATUSES__DISABLED_TEXT = 'Disabled';
|
|
@@ -1212,7 +1212,7 @@ function AttachmentsElement(props) {
|
|
|
1212
1212
|
onChangeSelection: (selection) => {
|
|
1213
1213
|
setTreeSelection(selection);
|
|
1214
1214
|
},
|
|
1215
|
-
additionalToolbarButtons: canCrud ? [
|
|
1215
|
+
additionalToolbarButtons: canCrud && treeSelection[0] && !treeSelection[0].isDestroyed ? [
|
|
1216
1216
|
{
|
|
1217
1217
|
key: 'Plus',
|
|
1218
1218
|
text: 'New Directory',
|