How to get slate indentation with increasing depth - reactjs

how to get numbered list when Tab key press on slate editor currently i get only one numbered list ?
export const toggleBlock = (editor, format) => {
const isActive = isBlockActive(editor, format);
const isList = LIST_TYPES.includes(format);
Transforms.unwrapNodes(editor, {
match: (n) =>
LIST_TYPES.includes(
!Editor.isEditor(n) && SlateElement.isElement(n) && n.type
),
split: true,
});
const newProperties = {
type: isActive ? 'paragraph' : isList ? 'list-item' : format,
};
Transforms.setNodes(editor, newProperties);
if (!isActive && isList) {
const block = { type: format, children: [] };
Transforms.wrapNodes(editor, block);
}
};

Related

react-beautiful-dnd: Prevent flicker when drag and drop a lists with API call

I'm using this react-beautiful-dnd library to be able to reorder lists. However, even though I'm able to drag and drop and re-order, there is a flicker when I try to move a card from one list to another list I call API when a card is dragged to the destination list
const onDragEnd = (result: any) => {
if (!result.destination) {
return;
}
const listCopy: any = { ...elements };
const sourceList = listCopy[result.source.droppableId];
const [removedElement, newSourceList] = removeFromList(
sourceList,
result.source.index
);
listCopy[result.source.droppableId] = newSourceList;
const destinationList = listCopy[result.destination.droppableId];
listCopy[result.destination.droppableId] = addToList(
result.destination.droppableId,
destinationList || [],
result.destination.index,
removedElement,
result.source.droppableId
);
setElements(listCopy)};
and in addToList function I am calling API to update order on server
const addToList = (
changedList: string,
list: any[],
index: number,
element: any,
currentListId: string
) => {
let cardOrder;
const result = Array.from(list);
result.splice(index, 0, element);
const cardCurrentIndex = result.findIndex((item) => item.id === element.id);
if (list.length === 0) {
cardOrder = DEFAULT_PIPELINE_ORDER;
} else if (cardCurrentIndex === 0 && result.length !== 0) {
const nextCardOrder = result[1];
cardOrder = nextCardOrder.current_stage_order - STAGE_INCREMENT_AMOUNT;
} else if (cardCurrentIndex === result.length - 1) {
const nextCardOrder = result[result.length - 2];
cardOrder = nextCardOrder.current_stage_order + STAGE_INCREMENT_AMOUNT;
} else if (
Boolean(result[cardCurrentIndex - 1]) &&
Boolean(result[cardCurrentIndex + 1])
) {
cardOrder = Math.round(
(result[cardCurrentIndex - 1].current_stage_order +
result[cardCurrentIndex + 1].current_stage_order) /
2
);
}
let candidatesData: any = elements;
if (candidatesData) {
if (currentListId === changedList) {
candidatesData[changedList as any] = result as unknown as elementsType;
setElements([...candidatesData]);
} else {
candidatesData[currentListId as any] = candidatesData[
currentListId as any
]?.filter((item: any) => item.id !== element.id);
candidatesData[changedList as any] = result as unknown as elementsType;
setElements([...candidatesData]);
console.log("[...candidatesData]", [...candidatesData]);
}
}
const stageId = stagePipeLineLanes?.find(
(item) => item.id.toString() === changedList.toLowerCase()
)?.id;
if (
changedList === "applied" ||
changedList === "sourcing" ||
changedList === "interviewing"
) {
const changedDestination = changedList;
const destinationStages = positionDetails?.candidate_stages.filter(
(item) =>
item.pipeline.toLowerCase() === changedDestination.toLowerCase()
);
const stage = destinationStages.find((item) => item.is_default === true);
mutate(
{
candidateId: element.id.toString(),
data: compressObject({
stage: stage?.id.toString(),
}),
},
{
onSuccess: (response) => {
if (response) {
toast.success(
`Candidate moved to ${capitalizeFirstLetter(
changedDestination
)}`
);
}
},
}
);
} else {
mutate({
candidateId: element.id.toString(),
data: compressObject({
stage: stageId?.toString() || "",
current_stage_order: cardOrder?.toString() || "",
}),
});
}
return result;
};

React setting state using function not merging like objects

This function is called whenever MUI's data grid pro column width has been changed. I am trying to capture the "field" and "width" from the "params" and create an array of objects for all the columns that had changed width. My issue is that it just keeps adding the same object instead of merging them. For instance below I changed the width of the "wave" column two times and it just added the second change to the array.
I need help merging them properly
const handleColumnSizeChange = useCallback(
(params) => {
setColumnDefinitions((columnDefinitions) => {
return [
...columnDefinitions,
{ field: params.colDef.field, width: params.colDef.width },
];
});
},
[columnDefinitions]
);
console.log(columnDefinitions);
UPDATE:
I figured it out. I thought there was an easier way just using the spread in my previous function.
const handleColumnSizeChange = useCallback(
(params) => {
const { field, width } = params.colDef;
const check = columnDefinitions.some((e) => e.field === field);
if (check) {
const updatedDefs = columnDefinitions.map((column) => {
if (column.field === field) {
return { ...column, width: width };
}
return column;
});
setColumnDefinitions(updatedDefs);
} else {
// setColumnDefinitions((columnDefinitions) => {
// return [...columnDefinitions, { field: field, width: width }];
// });
setColumnDefinitions([
...columnDefinitions,
{ field: field, width: width },
]);
}
},
[columnDefinitions]
);
const handleColumnSizeChange = useCallback(
(params) => {
const { field, width } = params.colDef;
const check = columnDefinitions.some((e) => e.field === field);
if (check) {
const updatedDefs = columnDefinitions.map((column) => {
if (column.field === field) {
return { ...column, width: width };
}
return column;
});
setColumnDefinitions(updatedDefs);
} else {
setColumnDefinitions((columnDefinitions) => {
return [...columnDefinitions, { field: field, width: width }];
});
}
},
[columnDefinitions]
);

Failing to Compile React Native Application

I am building the ABP.IO react-front end(with no modifications other than Environment.js) to deploy however it is failing. I have already tried installing the packages according to some other posts such as.
I am running expo build:web --no-pwa and get the following:
Failed to compile.
C:/Users/INeedHelpPlz/Desktop/myProject/react-native/node_modules/#codler/react-native-keyboard-aware-scroll-view/lib/KeyboardAwareHOC.js 13:12
Module parse failed: Unexpected token (13:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| } from 'react-native'
| import { isIphoneX } from 'react-native-iphone-x-helper'
> import type { KeyboardAwareInterface } from './KeyboardAwareInterface'
|
| const _KAM_DEFAULT_TAB_BAR_HEIGHT: number = isIphoneX() ? 83 : 49
Error: C:/Users/INeedHelpPlz/Desktop/myProject/react-native/node_modules/#codler/react-native-keyboard-aware-scroll-view/lib/KeyboardAwareHOC.js 13:12
Module parse failed: Unexpected token (13:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| } from 'react-native'
| import { isIphoneX } from 'react-native-iphone-x-helper'
> import type { KeyboardAwareInterface } from './KeyboardAwareInterface'
|
| const _KAM_DEFAULT_TAB_BAR_HEIGHT: number = isIphoneX() ? 83 : 49
at C:\#expo\xdl#59.0.14\src\Webpack.ts:280:23
at finalCallback (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\webpack\lib\Compiler.js:257:39)
at C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\webpack\lib\Compiler.js:273:13
at AsyncSeriesHook.eval [as callAsync] (eval at create (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:33:1)
at AsyncSeriesHook.lazyCompileHook (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\Hook.js:154:20)
at onCompiled (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\webpack\lib\Compiler.js:271:21)
at C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\webpack\lib\Compiler.js:681:15
at AsyncSeriesHook.eval [as callAsync] (eval at create (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
at AsyncSeriesHook.lazyCompileHook (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\Hook.js:154:20)
at C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\webpack\lib\Compiler.js:678:31
at AsyncSeriesHook.eval [as callAsync] (eval at create (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:9:1)
at AsyncSeriesHook.lazyCompileHook (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\Hook.js:154:20)
at C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\webpack\lib\Compilation.js:1423:35
at AsyncSeriesHook.eval [as callAsync] (eval at create (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:9:1)
at AsyncSeriesHook.lazyCompileHook (C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\tapable\lib\Hook.js:154:20)
at C:\Users\INeedHelpPlz\AppData\Roaming\npm\node_modules\expo-cli\node_modules\webpack\lib\Compilation.js:1414:32
Edit, adding code for KeyboardAwareHOC.js
/* #flow */
import React from 'react'
import {
Keyboard,
Platform,
UIManager,
TextInput,
findNodeHandle,
Animated
} from 'react-native'
import { isIphoneX } from 'react-native-iphone-x-helper'
import type { KeyboardAwareInterface } from './KeyboardAwareInterface'
const _KAM_DEFAULT_TAB_BAR_HEIGHT: number = isIphoneX() ? 83 : 49
const _KAM_KEYBOARD_OPENING_TIME: number = 250
const _KAM_EXTRA_HEIGHT: number = 75
const supportedKeyboardEvents = [
'keyboardWillShow',
'keyboardDidShow',
'keyboardWillHide',
'keyboardDidHide',
'keyboardWillChangeFrame',
'keyboardDidChangeFrame'
]
const keyboardEventToCallbackName = (eventName: string) =>
'on' + eventName[0].toUpperCase() + eventName.substring(1)
const keyboardAwareHOCTypeEvents = supportedKeyboardEvents.reduce(
(acc: Object, eventName: string) => ({
...acc,
[keyboardEventToCallbackName(eventName)]: Function
}),
{}
)
export type KeyboardAwareHOCProps = {
viewIsInsideTabBar?: boolean,
resetScrollToCoords?: {
x: number,
y: number
},
enableResetScrollToCoords?: boolean,
enableAutomaticScroll?: boolean,
extraHeight?: number,
extraScrollHeight?: number,
keyboardOpeningTime?: number,
onScroll?: Function,
update?: Function,
contentContainerStyle?: any,
enableOnAndroid?: boolean,
innerRef?: Function,
...keyboardAwareHOCTypeEvents
}
export type KeyboardAwareHOCState = {
keyboardSpace: number
}
export type ElementLayout = {
x: number,
y: number,
width: number,
height: number
}
export type ContentOffset = {
x: number,
y: number
}
export type ScrollPosition = {
x: number,
y: number,
animated: boolean
}
export type ScrollIntoViewOptions = ?{
getScrollPosition?: (
parentLayout: ElementLayout,
childLayout: ElementLayout,
contentOffset: ContentOffset
) => ScrollPosition
}
export type KeyboardAwareHOCOptions = ?{
enableOnAndroid: boolean,
contentContainerStyle: ?Object,
enableAutomaticScroll: boolean,
extraHeight: number,
extraScrollHeight: number,
enableResetScrollToCoords: boolean,
keyboardOpeningTime: number,
viewIsInsideTabBar: boolean,
refPropName: string,
extractNativeRef: Function
}
function getDisplayName(WrappedComponent: React$Component) {
return (
(WrappedComponent &&
(WrappedComponent.displayName || WrappedComponent.name)) ||
'Component'
)
}
const ScrollIntoViewDefaultOptions: KeyboardAwareHOCOptions = {
enableOnAndroid: false,
contentContainerStyle: undefined,
enableAutomaticScroll: true,
extraHeight: _KAM_EXTRA_HEIGHT,
extraScrollHeight: 0,
enableResetScrollToCoords: true,
keyboardOpeningTime: _KAM_KEYBOARD_OPENING_TIME,
viewIsInsideTabBar: false,
// The ref prop name that will be passed to the wrapped component to obtain a ref
// If your ScrollView is already wrapped, maybe the wrapper permit to get a ref
// For example, with glamorous-native ScrollView, you should use "innerRef"
refPropName: 'ref',
// Sometimes the ref you get is a ref to a wrapped view (ex: Animated.ScrollView)
// We need access to the imperative API of a real native ScrollView so we need extraction logic
extractNativeRef: (ref: Object) => {
// getNode() permit to support Animated.ScrollView automatically
// see https://github.com/facebook/react-native/issues/19650
// see https://stackoverflow.com/questions/42051368/scrollto-is-undefined-on-animated-scrollview/48786374
if (ref.getNode) {
return ref.getNode()
} else {
return ref
}
}
}
function KeyboardAwareHOC(
ScrollableComponent: React$Component,
userOptions: KeyboardAwareHOCOptions = {}
) {
const hocOptions: KeyboardAwareHOCOptions = {
...ScrollIntoViewDefaultOptions,
...userOptions
}
return class
extends React.Component<KeyboardAwareHOCProps, KeyboardAwareHOCState>
implements KeyboardAwareInterface {
_rnkasv_keyboardView: any
keyboardWillShowEvent: ?Function
keyboardWillHideEvent: ?Function
position: ContentOffset
defaultResetScrollToCoords: ?{ x: number, y: number }
mountedComponent: boolean
handleOnScroll: Function
state: KeyboardAwareHOCState
static displayName = `KeyboardAware${getDisplayName(ScrollableComponent)}`
// HOC options are used to init default props, so that these options can be overriden with component props
static defaultProps = {
enableAutomaticScroll: hocOptions.enableAutomaticScroll,
extraHeight: hocOptions.extraHeight,
extraScrollHeight: hocOptions.extraScrollHeight,
enableResetScrollToCoords: hocOptions.enableResetScrollToCoords,
keyboardOpeningTime: hocOptions.keyboardOpeningTime,
viewIsInsideTabBar: hocOptions.viewIsInsideTabBar,
enableOnAndroid: hocOptions.enableOnAndroid
}
constructor(props: KeyboardAwareHOCProps) {
super(props)
this.keyboardWillShowEvent = undefined
this.keyboardWillHideEvent = undefined
this.callbacks = {}
this.position = { x: 0, y: 0 }
this.defaultResetScrollToCoords = null
const keyboardSpace: number = props.viewIsInsideTabBar
? _KAM_DEFAULT_TAB_BAR_HEIGHT
: 0
this.state = { keyboardSpace }
}
componentDidMount() {
this.mountedComponent = true
// Keyboard events
if (Platform.OS === 'ios') {
this.keyboardWillShowEvent = Keyboard.addListener(
'keyboardWillShow',
this._updateKeyboardSpace
)
this.keyboardWillHideEvent = Keyboard.addListener(
'keyboardWillHide',
this._resetKeyboardSpace
)
} else if (Platform.OS === 'android' && this.props.enableOnAndroid) {
this.keyboardWillShowEvent = Keyboard.addListener(
'keyboardDidShow',
this._updateKeyboardSpace
)
this.keyboardWillHideEvent = Keyboard.addListener(
'keyboardDidHide',
this._resetKeyboardSpace
)
}
supportedKeyboardEvents.forEach((eventName: string) => {
const callbackName = keyboardEventToCallbackName(eventName)
if (this.props[callbackName]) {
this.callbacks[eventName] = Keyboard.addListener(
eventName,
this.props[callbackName]
)
}
})
}
componentDidUpdate(prevProps: KeyboardAwareHOCProps) {
if (this.props.viewIsInsideTabBar !== prevProps.viewIsInsideTabBar) {
const keyboardSpace: number = this.props.viewIsInsideTabBar
? _KAM_DEFAULT_TAB_BAR_HEIGHT
: 0
if (this.state.keyboardSpace !== keyboardSpace) {
this.setState({ keyboardSpace })
}
}
}
componentWillUnmount() {
this.mountedComponent = false
this.keyboardWillShowEvent && this.keyboardWillShowEvent.remove()
this.keyboardWillHideEvent && this.keyboardWillHideEvent.remove()
Object.values(this.callbacks).forEach((callback: Object) =>
callback.remove()
)
}
getScrollResponder = () => {
return (
this._rnkasv_keyboardView &&
this._rnkasv_keyboardView.getScrollResponder &&
this._rnkasv_keyboardView.getScrollResponder()
)
}
scrollToPosition = (x: number, y: number, animated: boolean = true) => {
const responder = this.getScrollResponder()
responder && responder.scrollResponderScrollTo({ x, y, animated })
}
scrollToEnd = (animated?: boolean = true) => {
const responder = this.getScrollResponder()
responder && responder.scrollResponderScrollToEnd({ animated })
}
scrollForExtraHeightOnAndroid = (extraHeight: number) => {
this.scrollToPosition(0, this.position.y + extraHeight, true)
}
/**
* #param keyboardOpeningTime: takes a different keyboardOpeningTime in consideration.
* #param extraHeight: takes an extra height in consideration.
*/
scrollToFocusedInput = (
reactNode: any,
extraHeight?: number,
keyboardOpeningTime?: number
) => {
if (extraHeight === undefined) {
extraHeight = this.props.extraHeight || 0
}
if (keyboardOpeningTime === undefined) {
keyboardOpeningTime = this.props.keyboardOpeningTime || 0
}
setTimeout(() => {
if (!this.mountedComponent) {
return
}
const responder = this.getScrollResponder()
responder &&
responder.scrollResponderScrollNativeHandleToKeyboard(
reactNode,
extraHeight,
true
)
}, keyboardOpeningTime)
}
scrollIntoView = async (
element: React.Element<*>,
options: ScrollIntoViewOptions = {}
) => {
if (!this._rnkasv_keyboardView || !element) {
return
}
const [parentLayout, childLayout] = await Promise.all([
this._measureElement(this._rnkasv_keyboardView),
this._measureElement(element)
])
const getScrollPosition =
options.getScrollPosition || this._defaultGetScrollPosition
const { x, y, animated } = getScrollPosition(
parentLayout,
childLayout,
this.position
)
this.scrollToPosition(x, y, animated)
}
_defaultGetScrollPosition = (
parentLayout: ElementLayout,
childLayout: ElementLayout,
contentOffset: ContentOffset
): ScrollPosition => {
return {
x: 0,
y: Math.max(0, childLayout.y - parentLayout.y + contentOffset.y),
animated: true
}
}
_measureElement = (element: React.Element<*>): Promise<ElementLayout> => {
const node = findNodeHandle(element)
return new Promise((resolve: ElementLayout => void) => {
UIManager.measureInWindow(
node,
(x: number, y: number, width: number, height: number) => {
resolve({ x, y, width, height })
}
)
})
}
// Keyboard actions
_updateKeyboardSpace = (frames: Object) => {
// Automatically scroll to focused TextInput
if (this.props.enableAutomaticScroll) {
let keyboardSpace: number =
frames.endCoordinates.height + this.props.extraScrollHeight
if (this.props.viewIsInsideTabBar) {
keyboardSpace -= _KAM_DEFAULT_TAB_BAR_HEIGHT
}
this.setState({ keyboardSpace })
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
const responder = this.getScrollResponder()
if (!currentlyFocusedField || !responder) {
return
}
UIManager.viewIsDescendantOf(
currentlyFocusedField,
responder.getInnerViewNode(),
(isAncestor: boolean) => {
if (isAncestor) {
// Check if the TextInput will be hidden by the keyboard
UIManager.measureInWindow(
currentlyFocusedField,
(x: number, y: number, width: number, height: number) => {
const textInputBottomPosition = y + height
const keyboardPosition = frames.endCoordinates.screenY
const totalExtraHeight =
this.props.extraScrollHeight + this.props.extraHeight
if (Platform.OS === 'ios') {
if (
textInputBottomPosition >
keyboardPosition - totalExtraHeight
) {
this._scrollToFocusedInputWithNodeHandle(
currentlyFocusedField
)
}
} else {
// On android, the system would scroll the text input just
// above the keyboard so we just neet to scroll the extra
// height part
if (textInputBottomPosition > keyboardPosition) {
// Since the system already scrolled the whole view up
// we should reduce that amount
keyboardSpace =
keyboardSpace -
(textInputBottomPosition - keyboardPosition)
this.setState({ keyboardSpace })
this.scrollForExtraHeightOnAndroid(totalExtraHeight)
} else if (
textInputBottomPosition >
keyboardPosition - totalExtraHeight
) {
this.scrollForExtraHeightOnAndroid(
totalExtraHeight -
(keyboardPosition - textInputBottomPosition)
)
}
}
}
)
}
}
)
}
if (!this.props.resetScrollToCoords) {
if (!this.defaultResetScrollToCoords) {
this.defaultResetScrollToCoords = this.position
}
}
}
_resetKeyboardSpace = () => {
const keyboardSpace: number = this.props.viewIsInsideTabBar
? _KAM_DEFAULT_TAB_BAR_HEIGHT
: 0
this.setState({ keyboardSpace })
// Reset scroll position after keyboard dismissal
if (this.props.enableResetScrollToCoords === false) {
this.defaultResetScrollToCoords = null
return
} else if (this.props.resetScrollToCoords) {
this.scrollToPosition(
this.props.resetScrollToCoords.x,
this.props.resetScrollToCoords.y,
true
)
} else {
if (this.defaultResetScrollToCoords) {
this.scrollToPosition(
this.defaultResetScrollToCoords.x,
this.defaultResetScrollToCoords.y,
true
)
this.defaultResetScrollToCoords = null
} else {
this.scrollToPosition(0, 0, true)
}
}
}
_scrollToFocusedInputWithNodeHandle = (
nodeID: number,
extraHeight?: number,
keyboardOpeningTime?: number
) => {
if (extraHeight === undefined) {
extraHeight = this.props.extraHeight
}
const reactNode = findNodeHandle(nodeID)
this.scrollToFocusedInput(
reactNode,
extraHeight + this.props.extraScrollHeight,
keyboardOpeningTime !== undefined
? keyboardOpeningTime
: this.props.keyboardOpeningTime || 0
)
}
_handleOnScroll = (
e: SyntheticEvent<*> & { nativeEvent: { contentOffset: number } }
) => {
this.position = e.nativeEvent.contentOffset
}
_handleRef = (ref: React.Component<*>) => {
this._rnkasv_keyboardView = ref ? hocOptions.extractNativeRef(ref) : ref
if (this.props.innerRef) {
this.props.innerRef(this._rnkasv_keyboardView)
}
}
update = () => {
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
const responder = this.getScrollResponder()
if (!currentlyFocusedField || !responder) {
return
}
this._scrollToFocusedInputWithNodeHandle(currentlyFocusedField)
}
render() {
const { enableOnAndroid, contentContainerStyle, onScroll } = this.props
let newContentContainerStyle
if (Platform.OS === 'android' && enableOnAndroid) {
newContentContainerStyle = [].concat(contentContainerStyle).concat({
paddingBottom:
((contentContainerStyle || {}).paddingBottom || 0) +
this.state.keyboardSpace
})
}
const refProps = { [hocOptions.refPropName]: this._handleRef }
return (
<ScrollableComponent
{...refProps}
keyboardDismissMode='interactive'
contentInset={{ bottom: this.state.keyboardSpace }}
automaticallyAdjustContentInsets={false}
showsVerticalScrollIndicator={true}
scrollEventThrottle={1}
{...this.props}
contentContainerStyle={
newContentContainerStyle || contentContainerStyle
}
keyboardSpace={this.state.keyboardSpace}
getScrollResponder={this.getScrollResponder}
scrollToPosition={this.scrollToPosition}
scrollToEnd={this.scrollToEnd}
scrollForExtraHeightOnAndroid={this.scrollForExtraHeightOnAndroid}
scrollToFocusedInput={this.scrollToFocusedInput}
scrollIntoView={this.scrollIntoView}
resetKeyboardSpace={this._resetKeyboardSpace}
handleOnScroll={this._handleOnScroll}
update={this.update}
onScroll={Animated.forkEvent(onScroll, this._handleOnScroll)}
/>
)
}
}
}
// Allow to pass options, without breaking change, and curried for composition
// listenToKeyboardEvents(ScrollView);
// listenToKeyboardEvents(options)(Comp);
const listenToKeyboardEvents = (configOrComp: any) => {
if (typeof configOrComp === 'object' && !configOrComp.displayName) {
return (Comp: Function) => KeyboardAwareHOC(Comp, configOrComp)
} else {
return KeyboardAwareHOC(configOrComp)
}
}
export default listenToKeyboardEvents

Leaflet GeoJSON Turf: × Error: Invalid LatLng object: (undefined, undefined)

I set the return to null for the component and condition in question to check the data I'm returning and I couldn't find any issues in the coordinates arrays.
I get data as an array of geometry collections containing linestrings that make borders (from OSM's Overpass). Leaflet seems to only accept shapes, features, and featurecollections as inputs. As such, I wrote something to convert each geometry collection to a feature containing a multipolygon and added in a name and ID properties then made it into a featurecollection.
Example of OSM request body
[out:json];relation["name"="Mount Rainier National Park"]["type"="boundary"]; convert item ::=::,::geom=geom(),_osm_type=type(); out geom;
State
// Get boundaries for national lands in state X
const getBoundaries = async (st) => {
try {
// Fetch boundaries
const usStates = new UsaStates({ includeTerritories: true });
// Convert full state/territory name to two character abbrieviation.
let abbr = null;
usStates.states.map((row) => {
if (row.name === st) {
abbr = row.abbreviation;
}
});
// Build array of national land names
let lands = [];
state.locations.map((loc) => {
if (loc.states.includes(abbr)) {
lands.push(loc.fullName);
}
});
// Build Overpass query for boundaries
let query = "[out:json];";
lands.map((location) => {
query += `relation["name"="${location}"]["type"="boundary"]; convert item ::=::,::geom=geom(),_osm_type=type(); out geom;`;
});
const osmRes = await axios.post(
"https://lz4.overpass-api.de/api/interpreter",
query
);
dispatch({
type: GET_BOUNDARIES,
payload: osmRes.data,
});
} catch (err) {
dispatch({
type: TOAST_ERROR,
payload: err,
});
}
};
Reducer
case GET_BOUNDARIES:
let b = [];
let t = null;
action.payload.elements.map((boundary) => {
let a = [];
t = polygonize(boundary.geometry);
t.features.map((feature) => {
a.push(feature.geometry.coordinates[0]);
});
b.push(multiPolygon(a));
b[b.length - 1].properties = {
name: boundary.tags.name,
id: short.generate(),
};
});
b = featureCollection(b);
console.log("Reducer");
return {
...state,
boundaries: b,
loading: false,
};
Component
import React, { useContext} from "react";
import ParksContext from "../context/parks/ParksContext";
import { GeoJSON } from "react-leaflet";
const Boundaries = () => {
const parksContext = useContext(ParksContext);
const { boundaries, target, locations, states } = parksContext;
return target === null &&
Object.keys(states).length > 0 &&
states.constructor === Object ? (
<GeoJSON data={states} key={states}></GeoJSON>
) : target && locations.find((location) => location.id === target) ? (
<GeoJSON
data={
boundaries[
locations.find((location) => location.id === target).fullName
]
}
/>
) : Object.keys(boundaries).length > 0 &&
boundaries.constructor === Object ? (
<GeoJSON data={boundaries} key={boundaries}></GeoJSON>
) : null;
};
export default Boundaries;
I used geojsonlint.com and found an error in my geojson. My coordinates array of arrays had to be in another array. The outermost array allows for a second element: holes.
case GET_BOUNDARIES:
let b = [];
let t = null;
action.payload.elements.map((boundary) => {
let a = [];
t = polygonize(boundary.geometry);
t.features.map((feature) => {
a.push(feature.geometry.coordinates[0]);
});
b.push(multiPolygon([a])); <-- Here
b[b.length - 1].properties = {
name: boundary.tags.name,
id: short.generate(),
};

typescript Promise - persist change in mapped array of objects

I am trying to replace the value (file paths) of the key/value entries in an array of objects upon the if-condition, that a file/ or files exist in the file directory Documents ( ios capacitor ionic ); else, just return the array unchanged.
Arrays
const currentItems = this.data;
const filenames = [val, val, ...];
// for loop
for (let filename of filenames) {
// capacitor FileSystem API; promise
Plugins.Filesystem.stat({
path:filename+'.jpeg',
directory: FilesystemDirectory.Documents
}).then((result) => {
// return path to file in Documents directory ( simplified)
const result.uri = this.imagepath;
// map array
const newItems = this.currentItems.map(e => {
// if entries match set the value for key 'linethree'
if (e.lineone === filename) {
return {
...e,
linethree: this.imagepath
}
}
// else, return e unchanged
else
return { ...e,}
});
}).catch( reason => {
console.error( 'onRejected : ' + reason );
})
}
The problem:
on every iteration - filename of filenames - the original array is mapped again - with its original values; thus each iteration overwrites the change from the previous iteration.
How can it be achieved that the value entry at key 'linethree' for each match - e.lineone === filename - persists ?
Desired replacement:
const filenames = ["uncle"];
[{"lineone":"nagybácsi","linetwo":"uncle","linethree":"./assets/imgs/logo.png"}]
[{"lineone":"nagybácsi","linetwo":"uncle","linethree":"_capacitor_/var/mobile/Containers/Data/Application/D95D4DEF-A933-43F1-8507-4258475E1414/Documents/nagybácsi.jpeg"}]
If i understand well you need something like this:
Solution with Array#Filter, Array#Some and Array#Map
const wantedImagePath = '_capacitor_/var/mobile/Containers/Data/Application/D95D4DEF-A933-43F1-8507-4258475E1414/Documents/nagybácsi.jpeg';
const fileNames = ["uncle"];
const someData = [
{
"lineone":"ikertestvérek; ikrek",
"linetwo":"twins",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nagybácsi",
"linetwo":"uncle",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nőtlen (man)",
"linetwo":"unmarried",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone": "bar",
"linetwo": "foo",
"linethree": "./some/demo/path/logo.png"
}
];
const modifed = someData.filter(x => fileNames.some(y => y === x.linetwo)).map(z => ({ ...z, linethree: wantedImagePath }));
console.log(modifed)
Update:
Solution if you want to keep current data and modify matched:
const wantedImagePath = '_capacitor_/var/mobile/Containers/Data/Application/D95D4DEF-A933-43F1-8507-4258475E1414/Documents/nagybácsi.jpeg';
const fileNames = ["uncle"];
const someData = [
{
"lineone":"ikertestvérek; ikrek",
"linetwo":"twins",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nagybácsi",
"linetwo":"uncle",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nőtlen (man)",
"linetwo":"unmarried",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone": "bar",
"linetwo": "foo",
"linethree": "./some/demo/path/logo.png"
}
];
const modified = someData.map(x => {
let match = fileNames.find(y => x.linetwo === y);
return match !== undefined ? ({ ...x, linethree: wantedImagePath }) : x;
});
console.log(modified)

Resources