diff --git a/src/components/ActivityButtons.tsx b/src/components/ActivityButtons.tsx
index 6e6b0ddf..f51c1673 100644
--- a/src/components/ActivityButtons.tsx
+++ b/src/components/ActivityButtons.tsx
@@ -1,22 +1,24 @@
import {
Button,
ButtonGroup,
+ ColorPicker,
Flex,
Group,
HStack,
Heading,
Input,
+ Portal,
+ Select,
Stack,
Text,
createListCollection,
parseColor,
- ColorPicker,
- Select,
- Portal,
} from "@chakra-ui/react";
import type { ComponentPropsWithoutRef, FormEvent } from "react";
import { useContext, useLayoutEffect, useState } from "react";
+import { ColorPickerInput } from "./ui/colorpicker-input";
+
import { LuCheck as CheckIcon, LuX as CloseIcon } from "react-icons/lu";
import { Checkbox } from "./ui/checkbox";
import { Field } from "./ui/field";
@@ -213,7 +215,7 @@ function ActivityColor(props: { activity: Activity; onHide: () => void }) {
>
-
+
diff --git a/src/components/ui/colorpicker-input.tsx b/src/components/ui/colorpicker-input.tsx
new file mode 100644
index 00000000..a9ef209d
--- /dev/null
+++ b/src/components/ui/colorpicker-input.tsx
@@ -0,0 +1,53 @@
+import {
+ ColorPicker,
+ parseColor,
+ useColorPickerContext,
+} from "@chakra-ui/react";
+import { forwardRef } from "react";
+
+export const ColorPickerInput = forwardRef<
+ HTMLInputElement,
+ Omit
+>(function ColorHexInput(props, ref) {
+ const { setValue } = useColorPickerContext();
+
+ return (
+ {
+ const input = e.target.value;
+ if (
+ input.length === 6 ||
+ (input.length === 7 && input.startsWith("#"))
+ ) {
+ // parseColor will throw if the value is not a valid hex color
+ try {
+ let caretPositionBefore = e.target.selectionStart;
+ let colorToParse = input;
+ if (!colorToParse.startsWith("#")) {
+ colorToParse = `#${colorToParse}`;
+ caretPositionBefore = caretPositionBefore
+ ? caretPositionBefore + 1
+ : caretPositionBefore;
+ }
+ setValue(parseColor(colorToParse));
+ setTimeout(() => {
+ try {
+ e.target.setSelectionRange(
+ caretPositionBefore,
+ caretPositionBefore,
+ );
+ } catch (error) {
+ console.error("Error setting selection range:", error);
+ }
+ }, 0);
+ } catch {
+ return;
+ }
+ }
+ }}
+ channel="hex"
+ ref={ref}
+ {...props}
+ />
+ );
+});