feat: feature/mvp-sprint-1 Progress commit on editable text

This commit is contained in:
Nikolaj Frey 2023-08-03 20:56:42 +10:00
parent 804f356adc
commit b20c4eb091
5 changed files with 223 additions and 94 deletions

View File

@ -5,6 +5,9 @@ settings:
excludeLinksFromLockfile: false
dependencies:
react-contenteditable:
specifier: ^3.3.7
version: 3.3.7(react@18.2.0)
smarts:
specifier: 2.0.0
version: 2.0.0
@ -351,6 +354,10 @@ packages:
engines: {node: '>=0.8.0'}
dev: false
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: false
/gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@ -386,6 +393,13 @@ packages:
hasBin: true
dev: false
/loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
dependencies:
js-tokens: 4.0.0
dev: false
/lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
dependencies:
@ -400,6 +414,11 @@ packages:
resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==}
dev: false
/object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
dev: false
/picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
dev: false
@ -410,6 +429,35 @@ packages:
hasBin: true
dev: false
/prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
react-is: 16.13.1
dev: false
/react-contenteditable@3.3.7(react@18.2.0):
resolution: {integrity: sha512-GA9NbC0DkDdpN3iGvib/OMHWTJzDX2cfkgy5Tt98JJAbA3kLnyrNbBIpsSpPpq7T8d3scD39DHP+j8mAM7BIfQ==}
peerDependencies:
react: '>=16.3'
dependencies:
fast-deep-equal: 3.1.3
prop-types: 15.8.1
react: 18.2.0
dev: false
/react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: false
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
dependencies:
loose-envify: 1.4.0
dev: false
/regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
dev: false

View File

@ -156,15 +156,19 @@ export const Commander = (props) => {
}, [inputValue])
const suggestions = React.useMemo(() => {
const fuse = new Fuse(paths)
try {
const fuse = new Fuse(paths)
const results = fuse.search(inputValue)
const results = fuse.search(inputValue)
const mappedResults = results?.map((result) => {
return result?.item
})
const mappedResults = results?.map((result) => {
return result?.item
})
return mappedResults
return mappedResults
} catch (err) {
console.error("nik fuse error", err)
}
}, [inputValue, paths])
const selectSuggestion = React.useCallback(
@ -230,96 +234,101 @@ export const Commander = (props) => {
else if (e?.code === "Escape") {
closeCommander()
}
// if arrow keys then move selection
else if (e?.code === "ArrowUp") {
// move selection up
const curSuggestionIdx =
typeof hoveredSuggestion === "number"
? hoveredSuggestion
: suggestions?.length
const newSuggestionIdx = curSuggestionIdx - 1
if (newSuggestionIdx >= 0) {
setHoveredSuggestion(newSuggestionIdx)
} else {
setHoveredSuggestion(suggestions?.length - 1)
}
} else if (e?.code === "ArrowDown") {
// move selection down
const curSuggestionIdx =
typeof hoveredSuggestion === "number" ? hoveredSuggestion : -1
const newSuggestionIdx = curSuggestionIdx + 1
if (newSuggestionIdx < suggestions?.length) {
setHoveredSuggestion(newSuggestionIdx)
} else {
setHoveredSuggestion(0)
}
} else if (e?.code === "Enter") {
// if selection is active then select it
const curSuggestionIdx = hoveredSuggestion
if (curSuggestionIdx !== null) {
selectSuggestion(curSuggestionIdx)
}
if (commanderActive) {
try {
// console.log("nik Commander onEnter")
// console.log("nik commandIsAction", commandIsAction)
// console.log("nik commandContainsPath", commandContainsPath)
// console.log("nik onEnter commandPath", commandPath)
// only run these if commander active
if (commandIsAction) {
// nothing
const prevVal = getThingtime(commandPath)
const parentPath = getParentPath(commandPath) || "thingtime"
try {
// first try to execute literal javscript
const fn = `() => { return ${commandValue} }`
const evalFn = eval(fn)
const realVal = evalFn()
// console.log("nik realVal", realVal)
// console.log("nik prevVal", prevVal)
// console.log("nik parentPath", parentPath)
// console.log("nik commandPath", commandPath)
setThingtime(commandPath, realVal)
} catch (err) {
console.log(
"Caught error after trying to execute literal javascript",
err
)
if (commanderActive) {
// if arrow keys then move selection
if (e?.code === "ArrowUp") {
// move selection up
const curSuggestionIdx =
typeof hoveredSuggestion === "number"
? hoveredSuggestion
: suggestions?.length
const newSuggestionIdx = curSuggestionIdx - 1
if (newSuggestionIdx >= 0) {
setHoveredSuggestion(newSuggestionIdx)
} else {
setHoveredSuggestion(suggestions?.length - 1)
}
} else if (e?.code === "ArrowDown") {
// move selection down
const curSuggestionIdx =
typeof hoveredSuggestion === "number" ? hoveredSuggestion : -1
const newSuggestionIdx = curSuggestionIdx + 1
if (newSuggestionIdx < suggestions?.length) {
setHoveredSuggestion(newSuggestionIdx)
} else {
setHoveredSuggestion(0)
}
} else if (e?.code === "Enter") {
// if selection is active then select it
const curSuggestionIdx = hoveredSuggestion
if (curSuggestionIdx !== null) {
selectSuggestion(curSuggestionIdx)
}
if (commanderActive) {
try {
// console.log("nik Commander onEnter")
// console.log("nik commandIsAction", commandIsAction)
// console.log("nik commandContainsPath", commandContainsPath)
// likely literaly javascript wasn't valid
// console.log("nik onEnter commandPath", commandPath)
if (commandIsAction) {
// nothing
const prevVal = getThingtime(commandPath)
const parentPath = getParentPath(commandPath) || "thingtime"
try {
const fn = `() => { return ${escapedCommandValue} }`
// first try to execute literal javscript
const fn = `() => { return ${commandValue} }`
const evalFn = eval(fn)
const realVal = evalFn()
const prevVal = getThingtime(commandPath)
const parentPath = getParentPath(commandPath)
// console.log("nik realVal", realVal)
// console.log("nik prevVal", prevVal)
// console.log("nik parentPath", parentPath)
// console.log("nik commandPath", commandPath)
setThingtime(commandPath, realVal)
} catch {
// something very bad went wrong
} catch (err) {
console.log(
"Caught error after trying to execute escaped literal javascript",
"Caught error after trying to execute literal javascript",
err
)
// likely literaly javascript wasn't valid
try {
const fn = `() => { return ${escapedCommandValue} }`
const evalFn = eval(fn)
const realVal = evalFn()
const prevVal = getThingtime(commandPath)
const parentPath = getParentPath(commandPath)
setThingtime(commandPath, realVal)
} catch {
// something very bad went wrong
console.log(
"Caught error after trying to execute escaped literal javascript",
err
)
}
}
if (!prevVal) {
setContextPath(commandPath)
setShowContext(true, "commandIsAction check")
}
}
if (!prevVal) {
// if (commandContainsPath)
else {
// const prevValue = getThingtime(commandPath)
// const newValue = setThingtime(commandPath, prevValue)
console.log("Setting context path", commandPath)
setContextPath(commandPath)
setShowContext(true, "commandIsAction check")
setShowContext(true, "commandContainsPath check")
}
} catch (err) {
console.error("Caught error on commander onEnter", err)
}
// if (commandContainsPath)
else {
// const prevValue = getThingtime(commandPath)
// const newValue = setThingtime(commandPath, prevValue)
console.log("Setting context path", commandPath)
setContextPath(commandPath)
setShowContext(true, "commandContainsPath check")
}
} catch (err) {
console.error("Caught error on commander onEnter", err)
}
}
}
@ -334,7 +343,6 @@ export const Commander = (props) => {
thingtimeRef,
commanderActive,
commandIsAction,
commandContainsPath,
commandPath,
commandValue,
escapedCommandValue,
@ -439,16 +447,18 @@ export const Commander = (props) => {
)
})}
</Flex>
<Flex
display={showContext ? "flex" : "none"}
maxWidth="100%"
background="grey"
borderRadius="12px"
pointerEvents="all"
paddingY={3}
>
<Thingtime path={contextPath} thing={contextValue}></Thingtime>
</Flex>
{showContext && (
<Flex
display={showContext ? "flex" : "none"}
maxWidth="100%"
background="grey"
borderRadius="12px"
pointerEvents="all"
paddingY={3}
>
<Thingtime path={contextPath} thing={contextValue}></Thingtime>
</Flex>
)}
</Flex>
</Flex>
<Center

View File

@ -1,4 +1,5 @@
import React from "react"
import ContentEditable from "react-contenteditable"
import {
Box,
Flex,
@ -27,6 +28,8 @@ export const Thingtime = (props) => {
const [circular, setCircular] = React.useState(props?.circular)
const contentEditableRef = React.useRef(null)
const depth = React.useMemo(() => {
return props?.depth || 1
}, [props?.depth])
@ -221,6 +224,7 @@ export const Thingtime = (props) => {
mode,
circular,
seen,
fullPath,
depth,
thing,
props,
@ -236,6 +240,7 @@ export const Thingtime = (props) => {
<Flex
flexDirection="row"
flexShrink={1}
width="100%"
paddingLeft={pl}
fontSize="20px"
border="none"
@ -251,6 +256,22 @@ export const Thingtime = (props) => {
[pl]
)
const updatedRef = React.useRef(false)
const [contentEditableThing, setContentEditableThing] = React.useState(thing)
React.useEffect(() => {
console.log("nik detected thing changed")
console.log("nik thing", thing)
console.log("nik contentEditableThing", contentEditableThing)
console.log("nik updatedRef?.current", updatedRef?.current)
if (!updatedRef?.current && contentEditableThing !== thing) {
console.log("nik setting content editable thing", thing)
setContentEditableThing(thing)
}
updatedRef.current = false
}, [thing, updatedRef, contentEditableThing, contentEditableRef])
const updateValue = React.useCallback(
(args) => {
const { value } = args
@ -259,11 +280,13 @@ export const Thingtime = (props) => {
console.log("nik props?.fullPath", fullPath)
setThingtime(fullPath, value)
updatedRef.current = true
},
[fullPath, setThingtime]
)
const atomicValue = React.useMemo(() => {
console.log("nik contentEditableThing", contentEditableThing)
if (props?.edit) {
if (type === "boolean") {
return (
@ -321,9 +344,41 @@ export const Thingtime = (props) => {
</AtomicWrapper>
)
}
if (type === "string") {
return (
<AtomicWrapper>
<Box
ref={contentEditableRef}
width="100%"
border="none"
outline="none"
contentEditable={true}
onInput={(value) => {
console.log("nik value", value)
const innerText = value?.target?.innerText
if (typeof innerText === "string") {
updateValue({ value: innerText })
}
}}
>
{contentEditableThing}
</Box>
</AtomicWrapper>
)
}
}
return <AtomicWrapper>{renderableValue}</AtomicWrapper>
}, [renderableValue, AtomicWrapper, type, props?.edit, thing, updateValue])
}, [
renderableValue,
contentEditableThing,
AtomicWrapper,
type,
props?.edit,
thing,
updateValue,
])
const contextMenu = (
<Flex

View File

@ -25,6 +25,7 @@
"lodash-es": "^4.17.21",
"react": "^18.2.0",
"react-click-away-listener": "^2.2.3",
"react-contenteditable": "^3.3.7",
"react-dom": "^18.2.0",
"react-icons": "^4.10.1",
"tinygradient": "^1.1.5",
@ -50,6 +51,9 @@
"eslint-plugin-unused-imports": "^2.0.0",
"typescript": "^4.9.3"
},
"resolutions": {
"@types/react": "^17.0.2"
},
"engines": {
"node": ">=14"
}

View File

@ -56,6 +56,9 @@ dependencies:
react-click-away-listener:
specifier: ^2.2.3
version: 2.2.3(react-dom@18.2.0)(react@18.2.0)
react-contenteditable:
specifier: ^3.3.7
version: 3.3.7(react@18.2.0)
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
@ -6017,7 +6020,6 @@ packages:
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
@ -8536,6 +8538,16 @@ packages:
react: 18.2.0
dev: false
/react-contenteditable@3.3.7(react@18.2.0):
resolution: {integrity: sha512-GA9NbC0DkDdpN3iGvib/OMHWTJzDX2cfkgy5Tt98JJAbA3kLnyrNbBIpsSpPpq7T8d3scD39DHP+j8mAM7BIfQ==}
peerDependencies:
react: '>=16.3'
dependencies:
fast-deep-equal: 3.1.3
prop-types: 15.8.1
react: 18.2.0
dev: false
/react-dom@18.2.0(react@18.2.0):
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
peerDependencies: