summaryrefslogtreecommitdiff
path: root/client/src/components/entry.jsx
diff options
context:
space:
mode:
authorLieuwe Rooijakkers <lieuwerooijakkers@gmail.com>2025-01-19 22:21:32 +0100
committerLieuwe Rooijakkers <lieuwerooijakkers@gmail.com>2025-01-19 22:21:46 +0100
commit93552152be180766fda08b1bd7ccefc4d26065ff (patch)
treef9f1e19372995729adc7e1c79f16c27acd9625be /client/src/components/entry.jsx
parent6841765fcbfadbd4e3006f5fbcea45194c92e5a1 (diff)
client advancements
Diffstat (limited to 'client/src/components/entry.jsx')
-rw-r--r--client/src/components/entry.jsx76
1 files changed, 76 insertions, 0 deletions
diff --git a/client/src/components/entry.jsx b/client/src/components/entry.jsx
new file mode 100644
index 0000000..637a696
--- /dev/null
+++ b/client/src/components/entry.jsx
@@ -0,0 +1,76 @@
+import {createElement, useLayoutEffect, useRef, useState} from 'react';
+
+import './entry.css';
+
+function TextField({ item, onEnter, onSelect, onRemove, ref }) {
+ const onKeyDown = e => {
+ if (e.keyCode === 38) { // up
+ onSelect(-1);
+ e.preventDefault();
+ return;
+ } else if (e.keyCode === 40) { // down
+ onSelect(+1);
+ e.preventDefault();
+ return;
+ } else if (e.keyCode === 8 && e.target.innerText.length === 0) { // backspace
+ onRemove();
+ e.preventDefault();
+ return;
+ }
+
+ if (e.keyCode !== 13) {
+ return;
+ } else if (e.shiftKey) {
+ return;
+ }
+
+ e.preventDefault();
+
+ onEnter(e.ctrlKey ? 'todo' : 'plain');
+ };
+
+ useLayoutEffect(() => {
+ if (ref.current == null) {
+ return;
+ }
+
+ ref.current.innerText = item.text;
+ }, [item.text]);
+
+ return <div ref={ref} className='text' contentEditable="true" onKeyDown={onKeyDown} onClick={() => onSelect(0)}></div>;
+}
+
+function Plain({ item, onEnter, onSelect, onRemove, ref }) {
+ return <TextField item={item} onEnter={onEnter} onSelect={onSelect} onRemove={onRemove} ref={ref} />;
+}
+
+function Todo({ item, onEnter, onSelect, onRemove, ref }) {
+ return <>
+ <input type="checkbox" />
+ <TextField item={item} onEnter={onEnter} onSelect={onSelect} onRemove={onRemove} ref={ref} />
+ </>;
+}
+
+export default function Entry({ item, onEnter, onSelect, onRemove, isFocused }) {
+ const ref = useRef(null);
+ useLayoutEffect(() => {
+ if (isFocused && ref.current != null && document.activeElement !== ref.current) {
+ ref.current.focus();
+ document.execCommand('selectAll', false, null);
+ document.getSelection().collapseToEnd();
+ }
+ }, [isFocused]);
+
+ const child = createElement(item.type === 'plain' ? Plain : Todo, {
+ ref,
+ item,
+ onEnter,
+ onSelect,
+ onRemove: () => onRemove(true),
+ });
+
+ return <div className={`entry ${isFocused ? 'focus' : ''}`}>
+ <button onClick={() => onRemove(false)}>X</button>
+ {child}
+ </div>
+}