feat: feature/999 I did it
This commit is contained in:
parent
2a7995c363
commit
4fc02ca68b
@ -3,7 +3,7 @@ import { Box } from "@chakra-ui/react"
|
||||
|
||||
import { useThingtime } from "../Thingtime/useThingtime"
|
||||
|
||||
export const MagicInput = (props) => {
|
||||
export const MagicInput = React.forwardRef((props, ref) => {
|
||||
const { thingtime, setThingtime, loading } = useThingtime()
|
||||
|
||||
const [inputValue, setInputValue] = React.useState()
|
||||
@ -92,9 +92,10 @@ export const MagicInput = (props) => {
|
||||
(args) => {
|
||||
const { value } = args
|
||||
props?.onValueChange?.({ value })
|
||||
props?.onChange?.({ value })
|
||||
// updateContentEditableValue(value)
|
||||
},
|
||||
[props?.onValueChange]
|
||||
[props?.onValueChange, props?.onChange]
|
||||
)
|
||||
|
||||
const updateValue = React.useCallback(
|
||||
@ -115,20 +116,36 @@ export const MagicInput = (props) => {
|
||||
[props?.onFocus]
|
||||
)
|
||||
|
||||
const maybeUpdateValue = React.useCallback(
|
||||
(e) => {
|
||||
const { key } = e
|
||||
if (key === "Enter") {
|
||||
if (props?.onEnter) {
|
||||
e?.preventDefault?.()
|
||||
}
|
||||
props?.onEnter?.({ value: inputValue })
|
||||
}
|
||||
},
|
||||
[inputValue, props?.onEnter]
|
||||
)
|
||||
|
||||
const dangerouslySetInnerHTML = React.useMemo(() => {
|
||||
if (!props?.readonly) {
|
||||
return { __html: contentEditableValue }
|
||||
}
|
||||
// return { __html: contentEditableValue }
|
||||
}, [contentEditableValue, props?.readonly])
|
||||
|
||||
return (
|
||||
<Box
|
||||
position="relative"
|
||||
width="100%"
|
||||
transition={props?.transition}
|
||||
{...(props?.chakras || {})}
|
||||
ref={ref}
|
||||
>
|
||||
<Box
|
||||
className="magic-input-focusable"
|
||||
ref={contentEditableRef}
|
||||
width="100%"
|
||||
border="none"
|
||||
@ -146,6 +163,7 @@ export const MagicInput = (props) => {
|
||||
updateValue({ value: innerText })
|
||||
}
|
||||
}}
|
||||
onKeyDown={maybeUpdateValue}
|
||||
>
|
||||
{props?.readonly ? props?.value : null}
|
||||
</Box>
|
||||
@ -171,4 +189,4 @@ export const MagicInput = (props) => {
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
@ -40,6 +40,8 @@ export const Thingtime = (props) => {
|
||||
|
||||
const [circular, setCircular] = React.useState(props?.circular)
|
||||
|
||||
const thingtimeRef = React.useRef()
|
||||
|
||||
const editValueRef = React.useRef({})
|
||||
|
||||
const depth = React.useMemo(() => {
|
||||
@ -304,13 +306,9 @@ export const Thingtime = (props) => {
|
||||
}
|
||||
|
||||
return keys
|
||||
}, [hasChakraChildren, keys])
|
||||
}, [keys, renderChakra])
|
||||
// const keysToUse = flattenedKeys
|
||||
|
||||
const template1Modes = React.useMemo(() => {
|
||||
return ["view", "edit"]
|
||||
}, [])
|
||||
|
||||
const AtomicWrapper = React.useCallback((args) => {
|
||||
return (
|
||||
<Flex
|
||||
@ -652,6 +650,59 @@ export const Thingtime = (props) => {
|
||||
return humanPath
|
||||
}, [humanPath, props?.edit])
|
||||
|
||||
const updatePath = React.useCallback(
|
||||
(args) => {
|
||||
if (typeof args?.value === "string") {
|
||||
try {
|
||||
const parentKeys = Object.keys(parent)
|
||||
// create new object with new key order
|
||||
const newObject = {}
|
||||
|
||||
parentKeys.forEach((key) => {
|
||||
if (key === path) {
|
||||
newObject[args.value] = parent[key]
|
||||
return
|
||||
}
|
||||
newObject[key] = parent[key]
|
||||
})
|
||||
// set new object
|
||||
setThingtime(parentPath, newObject)
|
||||
|
||||
// focus next input
|
||||
const focusableNodeList = thingtimeRef?.current?.querySelectorAll?.(
|
||||
".magic-input-focusable"
|
||||
)
|
||||
|
||||
// convert focusable to array
|
||||
const focusable = Array.from(focusableNodeList)
|
||||
|
||||
const pathMagicInputFocusable = pathRef?.current?.querySelector?.(
|
||||
".magic-input-focusable"
|
||||
)
|
||||
|
||||
const nearestMagicInput = focusable?.find((input) => {
|
||||
if (input !== pathMagicInputFocusable) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if (nearestMagicInput && nearestMagicInput?.focus) {
|
||||
nearestMagicInput.focus()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"Thingtime:657 Something went wrong reassigning path",
|
||||
err
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
[parent, path, parentPath, setThingtime]
|
||||
)
|
||||
|
||||
const pathRef = React.useRef(null)
|
||||
|
||||
const pathDom = React.useMemo(() => {
|
||||
if (chakras) {
|
||||
return <></>
|
||||
@ -661,8 +712,10 @@ export const Thingtime = (props) => {
|
||||
return (
|
||||
<>
|
||||
<MagicInput
|
||||
ref={pathRef}
|
||||
value={renderedPath}
|
||||
readonly={!props?.edit}
|
||||
onEnter={updatePath}
|
||||
chakras={{
|
||||
maxWidth: "100%",
|
||||
paddingLeft: props?.pathPl || pl,
|
||||
@ -720,9 +773,10 @@ export const Thingtime = (props) => {
|
||||
return (
|
||||
<Safe {...props} depth={depth} uuid={uuid}>
|
||||
<Flex
|
||||
ref={thingtimeRef}
|
||||
position="relative"
|
||||
flexDirection="column"
|
||||
// width="500px"
|
||||
flexDirection="column"
|
||||
rowGap={2}
|
||||
width={width}
|
||||
maxWidth="100%"
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from "react"
|
||||
import { Flex } from "@chakra-ui/react"
|
||||
// import { Sticky, StickyContainer } from "react-sticky"
|
||||
import Sticky from "react-sticky-el"
|
||||
import { Box, Flex } from "@chakra-ui/react"
|
||||
import { useLocation, useMatches } from "@remix-run/react"
|
||||
|
||||
import { Thingtime } from "./Thingtime"
|
||||
@ -58,14 +60,51 @@ export const ThingtimeURL = (props) => {
|
||||
return false
|
||||
}, [pathname])
|
||||
|
||||
const containerRef = React.useRef(null)
|
||||
const editorRef = React.useRef(null)
|
||||
|
||||
React.useEffect(() => {
|
||||
const scrollListener = () => {
|
||||
if (containerRef?.current?.getBoundingClientRect) {
|
||||
const { top } = containerRef?.current?.getBoundingClientRect()
|
||||
|
||||
editorRef.current.style.top = `${-top}px`
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("scroll", scrollListener)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", scrollListener)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Flex
|
||||
ref={containerRef}
|
||||
// position="sticky"
|
||||
position="relative"
|
||||
alignItems={inEditorMode ? "flex-start" : "center"}
|
||||
justifyContent="center"
|
||||
// overflow="scroll"
|
||||
// height="auto"
|
||||
flexDirection={inEditorMode ? "row" : "column"}
|
||||
maxWidth="100%"
|
||||
// maxHeight="100vh"
|
||||
>
|
||||
{inEditorMode && (
|
||||
<Box
|
||||
ref={editorRef}
|
||||
position="relative"
|
||||
// position="sticky"
|
||||
// top={200}
|
||||
// alignSelf="flex-start"
|
||||
// overflow="scroll"
|
||||
width="600px"
|
||||
// width="100%"
|
||||
maxHeight="100vh"
|
||||
paddingY={2}
|
||||
>
|
||||
<Thingtime
|
||||
path={path}
|
||||
thing={thing}
|
||||
@ -73,6 +112,7 @@ export const ThingtimeURL = (props) => {
|
||||
chakras={{ marginY: 200 }}
|
||||
width="600px"
|
||||
></Thingtime>
|
||||
</Box>
|
||||
)}
|
||||
<Thingtime
|
||||
edit={inEditMode}
|
||||
|
@ -30,6 +30,9 @@
|
||||
"react-contenteditable": "^3.3.7",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-sticky": "^6.0.3",
|
||||
"react-sticky-el": "^2.1.0",
|
||||
"react-visibility-sensor": "^5.1.1",
|
||||
"tinygradient": "^1.1.5",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
|
@ -74,6 +74,15 @@ dependencies:
|
||||
react-icons:
|
||||
specifier: ^4.10.1
|
||||
version: 4.10.1(react@18.2.0)
|
||||
react-sticky:
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3(react-dom@18.2.0)(react@18.2.0)
|
||||
react-sticky-el:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(react-dom@18.2.0)(react@18.2.0)
|
||||
react-visibility-sensor:
|
||||
specifier: ^5.1.1
|
||||
version: 5.1.1(react-dom@18.2.0)(react@18.2.0)
|
||||
tinygradient:
|
||||
specifier: ^1.1.5
|
||||
version: 1.1.5
|
||||
@ -8301,6 +8310,10 @@ packages:
|
||||
through2: 2.0.5
|
||||
dev: true
|
||||
|
||||
/performance-now@2.1.0:
|
||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
||||
dev: false
|
||||
|
||||
/periscopic@3.1.0:
|
||||
resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
|
||||
dependencies:
|
||||
@ -8587,6 +8600,12 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/raf@3.4.1:
|
||||
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
|
||||
dependencies:
|
||||
performance-now: 2.1.0
|
||||
dev: false
|
||||
|
||||
/randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
dependencies:
|
||||
@ -8746,6 +8765,28 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-sticky-el@2.1.0(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-oo+a2GedF4QMfCfm20e9gD+RuuQp/ngvwGMUXAXpST+h4WnmKhuv7x6MQ4X/e3AHiLYgE0zDyJo1Pzo8m51KpA==}
|
||||
peerDependencies:
|
||||
react: '>=16.3.0'
|
||||
react-dom: '>=16.3.0'
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/react-sticky@6.0.3(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-LNH4UJlRatOqo29/VHxDZOf6fwbgfgcHO4mkEFvrie5FuaZCSTGtug5R8NGqJ0kSnX8gHw8qZN37FcvnFBJpTQ==}
|
||||
peerDependencies:
|
||||
react: '>=15'
|
||||
react-dom: '>=15'
|
||||
dependencies:
|
||||
prop-types: 15.8.1
|
||||
raf: 3.4.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/react-style-singleton@2.2.1(@types/react@17.0.62)(react@18.2.0):
|
||||
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
|
||||
engines: {node: '>=10'}
|
||||
@ -8763,6 +8804,17 @@ packages:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/react-visibility-sensor@5.1.1(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-cTUHqIK+zDYpeK19rzW6zF9YfT4486TIgizZW53wEZ+/GPBbK7cNS0EHyJVyHYacwFEvvHLEKfgJndbemWhB/w==}
|
||||
peerDependencies:
|
||||
react: '>=16.0.0'
|
||||
react-dom: '>=16.0.0'
|
||||
dependencies:
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/react@18.2.0:
|
||||
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
Loading…
Reference in New Issue
Block a user