From b20c4eb0917ebaef8ba20c1487e080c6d4e1c0ae Mon Sep 17 00:00:00 2001 From: Nikolaj Frey Date: Thu, 3 Aug 2023 20:56:42 +1000 Subject: [PATCH] feat: feature/mvp-sprint-1 Progress commit on editable text --- pnpm-lock.yaml | 48 +++++ remix/app/components/Commander/Commander.tsx | 194 ++++++++++--------- remix/app/components/Thingtime/Thingtime.tsx | 57 +++++- remix/package.json | 4 + remix/pnpm-lock.yaml | 14 +- 5 files changed, 223 insertions(+), 94 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36ad807..b1a4283 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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 diff --git a/remix/app/components/Commander/Commander.tsx b/remix/app/components/Commander/Commander.tsx index e3069a8..8f39678 100644 --- a/remix/app/components/Commander/Commander.tsx +++ b/remix/app/components/Commander/Commander.tsx @@ -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) => { ) })} - - - + {showContext && ( + + + + )}
{ 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) => { { [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) => { ) } + if (type === "string") { + return ( + + { + console.log("nik value", value) + + const innerText = value?.target?.innerText + + if (typeof innerText === "string") { + updateValue({ value: innerText }) + } + }} + > + {contentEditableThing} + + + ) + } } return {renderableValue} - }, [renderableValue, AtomicWrapper, type, props?.edit, thing, updateValue]) + }, [ + renderableValue, + contentEditableThing, + AtomicWrapper, + type, + props?.edit, + thing, + updateValue, + ]) const contextMenu = ( =14" } diff --git a/remix/pnpm-lock.yaml b/remix/pnpm-lock.yaml index e63cc1d..69556bb 100644 --- a/remix/pnpm-lock.yaml +++ b/remix/pnpm-lock.yaml @@ -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: