Cleaned up tests and lint errors. Upgraded npm packages.
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
latest=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
|
||||
IFS='.' read -r major minor patch <<< "${latest#v}"
|
||||
|
||||
case ${1:-patch} in
|
||||
major) new="v$((major+1)).0.0" ;;
|
||||
minor) new="v${major}.$((minor+1)).0" ;;
|
||||
patch) new="v${major}.${minor}.$((patch+1))" ;;
|
||||
*) echo "Usage: bump.sh [major|minor|patch]" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
git tag -a "$new"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
code2prompt -c -e package-lock.json -e example.json -e "colorlib/*"
|
||||
+16
-2
@@ -167,6 +167,21 @@ impl Color {
|
||||
Component::HCL_L => Color::from_hcl(self.hcl.h, self.hcl.c, value),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if two Color objects are equal
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```
|
||||
/// use colorlib::Color;
|
||||
///
|
||||
/// let color1 = Color::from_hex("FF0000");
|
||||
/// let color2 = Color::from_hex("FF0000");
|
||||
/// assert!(color1.equals(&color2));
|
||||
/// ```
|
||||
pub fn equals(&self, other: &Color) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -252,8 +267,7 @@ mod tests {
|
||||
fn color_from_hcl() {
|
||||
let hex_code = "4B964B";
|
||||
let (hr, hg, hb) = (75u8, 150u8, 75u8);
|
||||
let (r, g, b) =
|
||||
(75.19744022437494, 150.3948804487499, 75.19744022437494);
|
||||
let (r, g, b) = (75.19744022437494, 150.3948804487499, 75.19744022437494);
|
||||
let (h1, s, v) = (120.0, 0.5, 0.5897838448970584);
|
||||
let (h2, c, l) = (120.0, 0.5, 0.49);
|
||||
|
||||
|
||||
@@ -85,6 +85,21 @@ impl HCL {
|
||||
let c = calc::chroma(h, s, l);
|
||||
HCL::new(h, c, l)
|
||||
}
|
||||
|
||||
/// Checks if two HCL colors are equal
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```
|
||||
/// use colorlib::hcl::HCL;
|
||||
///
|
||||
/// let hcl1 = HCL::new(0.0, 1.0, 0.55);
|
||||
/// let hcl2 = HCL::new(0.0, 1.0, 0.55);
|
||||
/// assert!(hcl1.equals(&hcl2));
|
||||
/// ```
|
||||
pub fn equals(&self, other: &HCL) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -185,15 +200,7 @@ mod tests {
|
||||
0.864996,
|
||||
0.521301
|
||||
);
|
||||
from_hsv!(
|
||||
from_hsv_dark_magenta,
|
||||
300.0,
|
||||
0.9,
|
||||
0.5,
|
||||
300.0,
|
||||
0.9,
|
||||
0.323601
|
||||
);
|
||||
from_hsv!(from_hsv_dark_magenta, 300.0, 0.9, 0.5, 300.0, 0.9, 0.323601);
|
||||
from_hsv!(
|
||||
from_hsv_light_magenta,
|
||||
300.0,
|
||||
|
||||
@@ -138,6 +138,21 @@ impl Hex {
|
||||
b: decoded[2],
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if two Hex colors are equal
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```
|
||||
/// use colorlib::hex::Hex;
|
||||
///
|
||||
/// let hex1 = Hex::from_code("FF0000");
|
||||
/// let hex2 = Hex::from_code("FF0000");
|
||||
/// assert!(hex1.equals(&hex2));
|
||||
/// ```
|
||||
pub fn equals(&self, other: &Hex) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -114,6 +114,21 @@ impl HSV {
|
||||
let v = calc::value(h, s, l);
|
||||
HSV::new(h, s, v)
|
||||
}
|
||||
|
||||
/// Checks if two HSV colors are equal
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```
|
||||
/// use colorlib::hsv::HSV;
|
||||
///
|
||||
/// let hsv1 = HSV::new(0.0, 1.0, 1.0);
|
||||
/// let hsv2 = HSV::new(0.0, 1.0, 1.0);
|
||||
/// assert!(hsv1.equals(&hsv2));
|
||||
/// ```
|
||||
pub fn equals(&self, other: &HSV) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -93,6 +93,21 @@ impl RGB {
|
||||
let hsv = HSV::from_hcl(h, c, l);
|
||||
RGB::from_hsv(hsv.h, hsv.s, hsv.v)
|
||||
}
|
||||
|
||||
/// Checks if two RGB colors are equal
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```
|
||||
/// use colorlib::rgb::RGB;
|
||||
///
|
||||
/// let rgb1 = RGB::new(255.0, 0.0, 0.0);
|
||||
/// let rgb2 = RGB::new(255.0, 0.0, 0.0);
|
||||
/// assert!(rgb1.equals(&rgb2));
|
||||
/// ```
|
||||
pub fn equals(&self, other: &RGB) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
git tag -a "$(cat VERSION)" -m "Version $(cat VERSION)"
|
||||
Generated
+811
-962
File diff suppressed because it is too large
Load Diff
+3
-5
@@ -7,7 +7,8 @@
|
||||
"build:wasm": "wasm-pack build colorlib -t bundler -d pkg --release",
|
||||
"check": "tsc --noEmit -p tsconfig.app.json",
|
||||
"clean": "rm -rf dist colorlib/pkg*",
|
||||
"cypress": "1>/dev/null 2>/dev/null cypress open -d &",
|
||||
"cypress:component": "cypress run --component",
|
||||
"cypress:open": "1>/dev/null 2>/dev/null cypress open -d &",
|
||||
"dev": "vite",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
@@ -20,10 +21,7 @@
|
||||
"test:e2e:firefox": "cypress run --e2e -b firefox"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^7.0.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^7.0.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.0.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.3",
|
||||
"lucide-react": "^0.542.0",
|
||||
"motion": "^12.23.12",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0"
|
||||
|
||||
@@ -6,7 +6,7 @@ import { memory } from "colorlib/colorlib_bg.wasm";
|
||||
import { useSmoothAnimation } from "@/hooks/animation";
|
||||
import type { Setter } from "@/hooks/color";
|
||||
import { useSlider } from "@/hooks/slider";
|
||||
import { useResize } from "@/hooks/window";
|
||||
import { onResize } from "@/hooks/window";
|
||||
import type { CartesianSpace } from "@/types";
|
||||
import { Direction } from "@/types";
|
||||
import { setMeasurements } from "@/util";
|
||||
@@ -56,7 +56,7 @@ function ColorBar({
|
||||
refreshColorBar(canvasRef.current!, colorBar);
|
||||
});
|
||||
}
|
||||
}, [hue, luminance, colorBar]);
|
||||
}, [hue, luminance, colorBar, smoothAnimation]);
|
||||
|
||||
// Get measurements
|
||||
useEffect(() => {
|
||||
@@ -64,10 +64,10 @@ function ColorBar({
|
||||
setMeasurements(containerRef, setOrigin, setDimensions);
|
||||
}
|
||||
|
||||
return useResize(() =>
|
||||
return onResize(() =>
|
||||
setMeasurements(containerRef, setOrigin, setDimensions),
|
||||
);
|
||||
}, [containerRef.current]);
|
||||
}, [containerRef]);
|
||||
|
||||
// Resize color bar
|
||||
useEffect(() => {
|
||||
@@ -87,7 +87,14 @@ function ColorBar({
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [containerRef.current, canvasRef.current, parentDimensions]);
|
||||
}, [
|
||||
containerRef,
|
||||
canvasRef,
|
||||
parentDimensions,
|
||||
hue,
|
||||
luminance,
|
||||
smoothAnimation,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={styles.colorBarWrapper} ref={containerRef}>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from "react";
|
||||
import * as colorlib from "colorlib";
|
||||
|
||||
import type { ColorActions } from "@/hooks/color";
|
||||
import { useResize } from "@/hooks/window";
|
||||
import { onResize } from "@/hooks/window";
|
||||
import { Direction } from "@/types";
|
||||
import type { CartesianSpace } from "@/types";
|
||||
import { formatCssRgb, setMeasurements } from "@/util";
|
||||
@@ -25,7 +25,7 @@ function ColorPicker({
|
||||
const hueRange = { min: 0, max: 359 };
|
||||
const lumRange = { min: 0, max: 1 };
|
||||
|
||||
const [_origin, setOrigin] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [, setOrigin] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [dimensions, setDimensions] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
|
||||
// Get measurements
|
||||
@@ -34,10 +34,10 @@ function ColorPicker({
|
||||
setMeasurements(containerRef, setOrigin, setDimensions);
|
||||
}
|
||||
|
||||
return useResize(() => {
|
||||
return onResize(() => {
|
||||
setMeasurements(containerRef, setOrigin, setDimensions);
|
||||
});
|
||||
}, [containerRef.current]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={styles.container} ref={containerRef}>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useSmoothAnimation } from "@/hooks/animation";
|
||||
import type { HCLColorActions } from "@/hooks/color";
|
||||
import { useCrosshair } from "@/hooks/crosshair";
|
||||
import { useScroll } from "@/hooks/scroll";
|
||||
import { useResize } from "@/hooks/window";
|
||||
import { onResize } from "@/hooks/window";
|
||||
import type { CartesianSpace } from "@/types";
|
||||
import { setMeasurements } from "@/util";
|
||||
|
||||
@@ -62,12 +62,12 @@ function ColorSquare({
|
||||
refreshColorSquare(canvasRef.current!, colorSquare);
|
||||
});
|
||||
}
|
||||
}, [chroma, colorSquare]);
|
||||
}, [chroma, colorSquare, smoothAnimation]);
|
||||
|
||||
// Add event listeners
|
||||
useEffect(() => {
|
||||
if (canvasRef.current) addScrollListener();
|
||||
}, []);
|
||||
}, [addScrollListener]);
|
||||
|
||||
// Get measurements
|
||||
useEffect(() => {
|
||||
@@ -75,10 +75,10 @@ function ColorSquare({
|
||||
setMeasurements(containerRef, setOrigin, setDimensions);
|
||||
}
|
||||
|
||||
return useResize(() =>
|
||||
return onResize(() =>
|
||||
setMeasurements(containerRef, setOrigin, setDimensions),
|
||||
);
|
||||
}, [containerRef.current, parentDimensions]);
|
||||
}, [containerRef, parentDimensions]);
|
||||
|
||||
// Resize square
|
||||
useEffect(() => {
|
||||
@@ -97,7 +97,7 @@ function ColorSquare({
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [containerRef.current, canvasRef.current, parentDimensions]);
|
||||
}, [containerRef, canvasRef, parentDimensions, chroma, smoothAnimation]);
|
||||
|
||||
return (
|
||||
<div className={styles.colorSquareWrapper} ref={containerRef}>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import * as colorlib from "colorlib";
|
||||
|
||||
import { useResize } from "@/hooks/window";
|
||||
import { onResize } from "@/hooks/window";
|
||||
import type { CartesianSpace } from "@/types";
|
||||
import { formatCssRgb, setMeasurements, valueToPosition } from "@/util";
|
||||
|
||||
@@ -19,7 +19,7 @@ export function SquareCrosshair({
|
||||
hex: colorlib.Hex;
|
||||
parentDimensions: CartesianSpace;
|
||||
}) {
|
||||
const [_origin, setOrigin] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [, setOrigin] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [dimensions, setDimensions] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [darkCrosshairs, setDarkCrosshairs] = useState(true);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -32,10 +32,10 @@ export function SquareCrosshair({
|
||||
|
||||
useEffect(() => {
|
||||
setMeasurements(containerRef, setOrigin, setDimensions);
|
||||
return useResize(() =>
|
||||
return onResize(() =>
|
||||
setMeasurements(containerRef, setOrigin, setDimensions),
|
||||
);
|
||||
}, [containerRef.current, parentDimensions]);
|
||||
}, [containerRef, parentDimensions]);
|
||||
|
||||
return (
|
||||
<div className={styles.crosshairWrapper} ref={containerRef}>
|
||||
@@ -86,7 +86,7 @@ export function BarCrosshair({
|
||||
hex: colorlib.Hex;
|
||||
parentDimensions: CartesianSpace;
|
||||
}) {
|
||||
const [_origin, setOrigin] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [, setOrigin] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [dimensions, setDimensions] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [darkCrosshairs, setDarkCrosshairs] = useState(true);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -98,10 +98,10 @@ export function BarCrosshair({
|
||||
|
||||
useEffect(() => {
|
||||
setMeasurements(containerRef, setOrigin, setDimensions);
|
||||
return useResize(() =>
|
||||
return onResize(() =>
|
||||
setMeasurements(containerRef, setOrigin, setDimensions),
|
||||
);
|
||||
}, [containerRef.current, parentDimensions]);
|
||||
}, [containerRef, parentDimensions]);
|
||||
|
||||
return (
|
||||
<div className={styles.crosshairWrapper} ref={containerRef}>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
||||
|
||||
import type { Setter } from "@/hooks/color";
|
||||
import { useSlider } from "@/hooks/slider";
|
||||
import { useResize } from "@/hooks/window";
|
||||
import { onResize } from "@/hooks/window";
|
||||
import { Direction } from "@/types";
|
||||
import type { CartesianSpace, Range } from "@/types";
|
||||
import {
|
||||
@@ -49,10 +49,8 @@ function GripSlider({
|
||||
setMeasurements(sliderRef, setOrigin, setDimensions);
|
||||
}
|
||||
|
||||
return useResize(() =>
|
||||
setMeasurements(sliderRef, setOrigin, setDimensions),
|
||||
);
|
||||
}, [sliderRef.current, parentDimensions]);
|
||||
return onResize(() => setMeasurements(sliderRef, setOrigin, setDimensions));
|
||||
}, [sliderRef, parentDimensions]);
|
||||
|
||||
const upArrowStyle = {
|
||||
borderLeft: "12px solid transparent",
|
||||
|
||||
@@ -74,6 +74,9 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import type { ChangeEvent, KeyboardEvent, RefObject } from "react";
|
||||
|
||||
import {
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import clsx from "clsx";
|
||||
import * as colorlib from "colorlib";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
|
||||
import type { HexColorActions } from "@/hooks/color";
|
||||
import { useScroll } from "@/hooks/scroll";
|
||||
import { useSlider } from "@/hooks/slider";
|
||||
import { useResize } from "@/hooks/window";
|
||||
import { onResize } from "@/hooks/window";
|
||||
import type { CartesianSpace, Range, Setter, Timeout } from "@/types";
|
||||
import { Direction } from "@/types";
|
||||
import { minmax, roundTo, setMeasurements, valueToPosition } from "@/util";
|
||||
@@ -89,9 +84,7 @@ export function ValueEditor({
|
||||
// Set component dimensions for slider hook
|
||||
useEffect(() => {
|
||||
setMeasurements(sliderRef, setOrigin, setDimensions);
|
||||
return useResize(() =>
|
||||
setMeasurements(sliderRef, setOrigin, setDimensions),
|
||||
);
|
||||
return onResize(() => setMeasurements(sliderRef, setOrigin, setDimensions));
|
||||
}, [sliderRef, setOrigin, setDimensions]);
|
||||
|
||||
return (
|
||||
@@ -209,7 +202,7 @@ function Button({
|
||||
}) {
|
||||
const isIncrease = direction === "increase";
|
||||
const label = isIncrease ? "Increase" : "Decrease";
|
||||
const icon = isIncrease ? faChevronRight : faChevronLeft;
|
||||
const Icon = isIncrease ? ChevronRight : ChevronLeft;
|
||||
const dataCy = `${componentSymbol}-${isIncrease ? "increment" : "decrement"}-button`;
|
||||
|
||||
const step = isIncrease ? 1 : -1;
|
||||
@@ -234,7 +227,7 @@ function Button({
|
||||
data-cy={dataCy}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<FontAwesomeIcon icon={icon} transform="shrink-2 down-1" />
|
||||
<Icon size={18} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
@@ -338,8 +331,8 @@ function useLongPressRepeat(
|
||||
onMouseLeave: stop,
|
||||
onTouchStart: start,
|
||||
onTouchEnd: stop,
|
||||
// Intentional 'any' to avoid overly complex typing
|
||||
onContextMenu: (e: Event | any) => e.preventDefault(),
|
||||
// @ts-expect-error: Avoid overly complex typing
|
||||
onContextMenu: (e) => e.preventDefault(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -385,7 +378,7 @@ export function HexEditor({
|
||||
|
||||
useEffect(() => {
|
||||
setInputValue(formatHexString(color, isShortHex));
|
||||
}, [color]);
|
||||
}, [color, isShortHex]);
|
||||
|
||||
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
/* Large - Landscape Tablets / Desktops */
|
||||
/* Medium - Portrait Tablets */
|
||||
/* Horizontal layout, vertically scrolling picker and palette content */
|
||||
@media (min-width: 992px),
|
||||
(min-width: 568px) and (max-width: 991px) and (orientation: portrait) {
|
||||
.paletteEditor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Medium - Landscape Phones */
|
||||
/* Horizontal layout, side menu, vertical tabbed picker */
|
||||
@media (min-width: 568px) and (max-width: 991px) and (orientation: landscape) {
|
||||
.actionBar {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
/* Small - Portrait Phones*/
|
||||
/* Vertical layout, side menu, horizontal tabbed picker */
|
||||
@media (max-width: 567px) {
|
||||
.cardWrapper {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 4fr;
|
||||
grid-template-rows: 40px 1fr;
|
||||
grid-template-areas:
|
||||
". . card-header"
|
||||
"preview selection palette";
|
||||
}
|
||||
|
||||
.cardHeader {
|
||||
grid-area: card-header;
|
||||
}
|
||||
|
||||
.pickerColor {
|
||||
grid-area: preview;
|
||||
}
|
||||
|
||||
.paletteColor {
|
||||
grid-area: selection;
|
||||
}
|
||||
|
||||
.palette {
|
||||
grid-area: palette;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useReducer } from "react";
|
||||
|
||||
import { Color } from "colorlib";
|
||||
|
||||
import { HexEditor } from "@/components/ColorValues/ValueEditor";
|
||||
import { colorReducer, createColorActions } from "@/hooks/color";
|
||||
|
||||
import PaletteEditor from "./PaletteEditor";
|
||||
|
||||
const initialState = {
|
||||
color: Color.from_hex("000"),
|
||||
};
|
||||
|
||||
function TestWrapper() {
|
||||
const [state, dispatch] = useReducer(colorReducer, initialState);
|
||||
const actions = createColorActions(dispatch);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ width: "100%", height: 400 }}>
|
||||
<PaletteEditor
|
||||
pickerColor={state.color.hex}
|
||||
setPickerColor={actions.hex.setHex}
|
||||
/>
|
||||
</div>
|
||||
<HexEditor color={state.color.hex} actions={actions.hex} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
describe("palette editor tests", () => {
|
||||
beforeEach(() => {
|
||||
cy.mount(<TestWrapper />);
|
||||
});
|
||||
|
||||
it("renders the palette editor", () => {
|
||||
cy.dataCy("palette-editor").should("exist");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import { Hex as HexColor } from "colorlib";
|
||||
|
||||
import styles from "./PaletteEditor.module.css";
|
||||
|
||||
function PaletteEditor({
|
||||
pickerColor,
|
||||
setPickerColor,
|
||||
}: {
|
||||
pickerColor: HexColor;
|
||||
setPickerColor: (hex: HexColor) => void;
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.paletteEditor} data-cy="palette-editor">
|
||||
<ActionBar />
|
||||
<PaletteCard />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ActionBar() {
|
||||
return <div className={styles.actionBar}>actions</div>;
|
||||
}
|
||||
|
||||
function PaletteCard() {
|
||||
return (
|
||||
<div className={styles.cardWrapper}>
|
||||
<CardHeader />
|
||||
<PickerColor />
|
||||
<PaletteColor />
|
||||
<Palette />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CardHeader() {
|
||||
return <div className={styles.cardHeader}>header</div>;
|
||||
}
|
||||
|
||||
function PickerColor() {
|
||||
return <div className={styles.pickerColor}>picker color</div>;
|
||||
}
|
||||
|
||||
function PaletteColor() {
|
||||
return <div className={styles.paletteColor}>palette color</div>;
|
||||
}
|
||||
|
||||
function Palette() {
|
||||
return <div className={styles.palette}>palette</div>;
|
||||
}
|
||||
|
||||
export default PaletteEditor;
|
||||
|
||||
+7
-7
@@ -24,34 +24,34 @@ export function colorReducer(
|
||||
state: ColorState,
|
||||
action: ColorAction,
|
||||
): ColorState {
|
||||
let comp;
|
||||
let comp, rgb, hsv, hcl, hex, valOrFn, prev;
|
||||
|
||||
switch (action.type) {
|
||||
case "SET_COLOR":
|
||||
return { ...state, color: action.payload };
|
||||
|
||||
case "SET_RGB":
|
||||
let rgb = action.payload;
|
||||
rgb = action.payload;
|
||||
return { ...state, color: colorlib.Color.from_rgb(rgb.r, rgb.g, rgb.b) };
|
||||
|
||||
case "SET_HSV":
|
||||
let hsv = action.payload;
|
||||
hsv = action.payload;
|
||||
return { ...state, color: colorlib.Color.from_hsv(hsv.h, hsv.s, hsv.v) };
|
||||
|
||||
case "SET_HCL":
|
||||
let hcl = action.payload;
|
||||
hcl = action.payload;
|
||||
return { ...state, color: colorlib.Color.from_hcl(hcl.h, hcl.c, hcl.l) };
|
||||
|
||||
case "SET_HEX":
|
||||
let hex = action.payload;
|
||||
hex = action.payload;
|
||||
return { ...state, color: colorlib.Color.from_hex(hex.to_code()) };
|
||||
|
||||
case "SET_VALUE":
|
||||
comp = action.component;
|
||||
let valOrFn = action.payload;
|
||||
valOrFn = action.payload;
|
||||
|
||||
if (typeof valOrFn === "function") {
|
||||
let prev = state.color.get(comp);
|
||||
prev = state.color.get(comp);
|
||||
return { ...state, color: state.color.update(comp, valOrFn(prev)) };
|
||||
} else {
|
||||
return { ...state, color: state.color.update(comp, valOrFn) };
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { useSmoothAnimation } from "./animation";
|
||||
|
||||
if (typeof TouchEvent === "undefined") {
|
||||
// @ts-ignore - intentionally creating global
|
||||
// @ts-expect-error - intentionally creating global
|
||||
window.TouchEvent = window.MouseEvent;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,8 @@ export function useCrosshair({
|
||||
yValueRangeRef.current = yValueRange;
|
||||
}, [xValueRange, yValueRange]);
|
||||
|
||||
const calculatePositions = useCallback((event: MouseEvent | TouchEvent) => {
|
||||
const calculatePositions = useCallback(
|
||||
(event: MouseEvent | TouchEvent) => {
|
||||
const orig = originRef.current;
|
||||
const dims = dimensionsRef.current;
|
||||
const xRange = xValueRangeRef.current;
|
||||
@@ -84,14 +85,16 @@ export function useCrosshair({
|
||||
|
||||
setXValueRef.current(newXValue);
|
||||
setYValueRef.current(newYValue);
|
||||
}, []);
|
||||
},
|
||||
[invertX, invertY],
|
||||
);
|
||||
|
||||
const handleMove = useCallback(
|
||||
(event: MouseEvent | TouchEvent) => {
|
||||
event.preventDefault();
|
||||
smoothAnimation(() => calculatePositions(event));
|
||||
},
|
||||
[calculatePositions],
|
||||
[calculatePositions, smoothAnimation],
|
||||
);
|
||||
|
||||
const handleEnd = useCallback(
|
||||
|
||||
+24
-11
@@ -22,9 +22,11 @@ interface DragState<T> {
|
||||
}
|
||||
|
||||
function reducer<T>(state: DragState<T>, action: DragAction<T>) {
|
||||
let items, cursor, rects, newTargetIndex, newPreviewItems, movedItem;
|
||||
|
||||
switch (action.type) {
|
||||
case "resetItems":
|
||||
const items = action.items;
|
||||
items = action.items;
|
||||
return {
|
||||
...state,
|
||||
items: [...items],
|
||||
@@ -44,8 +46,9 @@ function reducer<T>(state: DragState<T>, action: DragAction<T>) {
|
||||
case "processMove":
|
||||
if (!state.isDragging) return state;
|
||||
|
||||
const { cursor, rects } = action;
|
||||
let newTargetIndex = state.targetIndex;
|
||||
cursor = action.cursor;
|
||||
rects = action.rects;
|
||||
newTargetIndex = state.targetIndex;
|
||||
|
||||
for (let i = 0; i < rects.length; i++) {
|
||||
const rect = rects[i];
|
||||
@@ -62,8 +65,8 @@ function reducer<T>(state: DragState<T>, action: DragAction<T>) {
|
||||
|
||||
if (newTargetIndex === state.targetIndex) return state;
|
||||
|
||||
const newPreviewItems = [...state.items];
|
||||
const [movedItem] = newPreviewItems.splice(state.sourceIndex, 1);
|
||||
newPreviewItems = [...state.items];
|
||||
[movedItem] = newPreviewItems.splice(state.sourceIndex, 1);
|
||||
newPreviewItems.splice(newTargetIndex, 0, movedItem);
|
||||
|
||||
return {
|
||||
@@ -136,18 +139,21 @@ export function useDragAndDrop<T extends { id: string }>({
|
||||
return itemElement;
|
||||
}
|
||||
|
||||
function getItemIndex(el: HTMLElement) {
|
||||
const getItemIndex = useCallback(
|
||||
(el: HTMLElement) => {
|
||||
const itemId = el.dataset.itemId;
|
||||
const index = items.findIndex((item) => item.id === itemId);
|
||||
return index;
|
||||
}
|
||||
},
|
||||
[items],
|
||||
);
|
||||
|
||||
function captureItemBoundaries() {
|
||||
const captureItemBoundaries = useCallback(() => {
|
||||
itemBoundingRects.current = items.map((item) => {
|
||||
const el = itemRefs.current[item.id]?.current;
|
||||
return el ? el.getBoundingClientRect() : new DOMRect();
|
||||
});
|
||||
}
|
||||
}, [itemRefs, items]);
|
||||
|
||||
const handleDragMove = useCallback(
|
||||
(event: MouseEvent | TouchEvent) => {
|
||||
@@ -195,7 +201,14 @@ export function useDragAndDrop<T extends { id: string }>({
|
||||
document.addEventListener("touchend", handleDragEnd);
|
||||
document.addEventListener("touchcancel", handleDragEnd);
|
||||
},
|
||||
[items, dispatch, handleDragEnd, handleDragMove],
|
||||
[
|
||||
items,
|
||||
dispatch,
|
||||
handleDragEnd,
|
||||
handleDragMove,
|
||||
captureItemBoundaries,
|
||||
getItemIndex,
|
||||
],
|
||||
);
|
||||
|
||||
// Set/cleanup event handlers
|
||||
@@ -221,7 +234,7 @@ export function useDragAndDrop<T extends { id: string }>({
|
||||
});
|
||||
};
|
||||
}
|
||||
}, [items, handleDragStart, disabled]);
|
||||
}, [items, handleDragStart, disabled, itemRefs]);
|
||||
|
||||
return {
|
||||
containerRef,
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import type { Dispatch } from "react";
|
||||
|
||||
export interface PaletteColor {
|
||||
id: string;
|
||||
name: string;
|
||||
hex: string;
|
||||
}
|
||||
|
||||
export interface PaletteCard {
|
||||
id: string;
|
||||
name: string;
|
||||
colors: PaletteColor[];
|
||||
selectedColorId: string | null;
|
||||
inToolkitMode: boolean;
|
||||
}
|
||||
|
||||
export interface PaletteCardState {
|
||||
present: PaletteCard;
|
||||
history: PaletteCard[];
|
||||
future: PaletteCard[];
|
||||
}
|
||||
|
||||
export type PaletteCardAction =
|
||||
| { type: "SET_CARD_NAME"; payload: string }
|
||||
| { type: "SET_SELECTED_COLOR"; payload: string | null }
|
||||
| { type: "ADD_COLOR" }
|
||||
| { type: "DELETE_SELECTED_COLOR" }
|
||||
| { type: "DUPLICATE_SELECTED_COLOR" }
|
||||
| { type: "REORDER_COLORS"; payload: PaletteColor[] }
|
||||
| { type: "TOGGLE_TOOLKIT_MODE" }
|
||||
| { type: "UNDO" }
|
||||
| { type: "REDO" };
|
||||
|
||||
export function paletteCardReducer(
|
||||
state: PaletteCardState,
|
||||
action: PaletteCardAction,
|
||||
): PaletteCardState {
|
||||
const pushToHistory = (state: PaletteCardState, newPresent: PaletteCard) => {
|
||||
return {
|
||||
...state,
|
||||
history: [state.present, ...state.history],
|
||||
future: [],
|
||||
present: newPresent,
|
||||
};
|
||||
};
|
||||
|
||||
switch (action.type) {
|
||||
case "SET_CARD_NAME":
|
||||
state = pushToHistory(state, { ...state.present, name: action.payload });
|
||||
return state;
|
||||
|
||||
case "SET_SELECTED_COLOR":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
case "ADD_COLOR":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
case "DELETE_SELECTED_COLOR":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
case "DUPLICATE_SELECTED_COLOR":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
case "REORDER_COLORS":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
case "TOGGLE_TOOLKIT_MODE":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
case "UNDO":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
case "REDO":
|
||||
// TODO: Implement
|
||||
return state;
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export interface PaletteCardActions {
|
||||
setCardName: (name: string) => void;
|
||||
setSelectedColor: (id: string | null) => void;
|
||||
addColor: () => void;
|
||||
deleteSelectedColor: () => void;
|
||||
duplicateSelectedColor: () => void;
|
||||
reorderColors: (colors: PaletteColor[]) => void;
|
||||
toggleToolkitMode: () => void;
|
||||
undo: () => void;
|
||||
redo: () => void;
|
||||
}
|
||||
|
||||
export function createPaletteCardActions(
|
||||
dispatch: Dispatch<PaletteCardAction>,
|
||||
): PaletteCardActions {
|
||||
return {
|
||||
setCardName: (name) => dispatch({ type: "SET_CARD_NAME", payload: name }),
|
||||
setSelectedColor: (id) =>
|
||||
dispatch({ type: "SET_SELECTED_COLOR", payload: id }),
|
||||
addColor: () => dispatch({ type: "ADD_COLOR" }),
|
||||
deleteSelectedColor: () => dispatch({ type: "DELETE_SELECTED_COLOR" }),
|
||||
duplicateSelectedColor: () =>
|
||||
dispatch({ type: "DUPLICATE_SELECTED_COLOR" }),
|
||||
reorderColors: (colors) =>
|
||||
dispatch({ type: "REORDER_COLORS", payload: colors }),
|
||||
toggleToolkitMode: () => dispatch({ type: "TOGGLE_TOOLKIT_MODE" }),
|
||||
undo: () => dispatch({ type: "UNDO" }),
|
||||
redo: () => dispatch({ type: "REDO" }),
|
||||
};
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import { useSmoothAnimation } from "./animation";
|
||||
import { useScroll } from "./scroll";
|
||||
|
||||
if (typeof TouchEvent === "undefined") {
|
||||
// @ts-ignore - intentionally creating global
|
||||
// @ts-expect-error - intentionally creating global
|
||||
window.TouchEvent = window.MouseEvent;
|
||||
}
|
||||
|
||||
@@ -79,11 +79,11 @@ export function useSlider({
|
||||
maxPosition.current,
|
||||
valueRangeRef.current,
|
||||
);
|
||||
}, [direction, origin, dimensions]);
|
||||
}, [direction, origin, dimensions, value]);
|
||||
|
||||
useEffect(() => {
|
||||
valueRangeRef.current = valueRange;
|
||||
}, [valueRangeRef]);
|
||||
}, [valueRange, valueRangeRef]);
|
||||
|
||||
useEffect(() => {
|
||||
setValueRef.current = setValue;
|
||||
@@ -94,7 +94,8 @@ export function useSlider({
|
||||
}, [position]);
|
||||
|
||||
// Setup drag handlers
|
||||
const calculatePosition = useCallback((event: MouseEvent | TouchEvent) => {
|
||||
const calculatePosition = useCallback(
|
||||
(event: MouseEvent | TouchEvent) => {
|
||||
const dir = directionRef.current;
|
||||
const orig = originRef.current;
|
||||
const dims = dimensionsRef.current;
|
||||
@@ -116,14 +117,16 @@ export function useSlider({
|
||||
}
|
||||
|
||||
setValueRef.current(newValue);
|
||||
}, []);
|
||||
},
|
||||
[invert],
|
||||
);
|
||||
|
||||
const handleMove = useCallback(
|
||||
(event: MouseEvent | TouchEvent) => {
|
||||
event.preventDefault();
|
||||
smoothAnimation(() => calculatePosition(event));
|
||||
},
|
||||
[calculatePosition],
|
||||
[calculatePosition, smoothAnimation],
|
||||
);
|
||||
|
||||
const handleEnd = useCallback(() => {
|
||||
|
||||
@@ -1,44 +1,11 @@
|
||||
import * as colorlib from "colorlib";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { expectEqualColor, mockUseReducer } from "@/testUtil";
|
||||
|
||||
import { colorReducer, createColorActions } from "../color";
|
||||
import type { ColorAction, ColorActions, ColorState } from "../color";
|
||||
|
||||
const mockUseReducer = <T extends object, U>(
|
||||
reducer: (state: T, action: U) => T,
|
||||
initialArg: T,
|
||||
): [T, (value: U) => void] => {
|
||||
let currentState = initialArg;
|
||||
|
||||
const state = new Proxy({} as T, {
|
||||
get: (_, prop) => currentState[prop as keyof T],
|
||||
});
|
||||
|
||||
const dispatch = (value: U) => {
|
||||
const nextState = reducer(currentState, value);
|
||||
currentState = nextState;
|
||||
};
|
||||
return [state, dispatch];
|
||||
};
|
||||
|
||||
const expectRGB = (value: colorlib.RGB, expected: colorlib.RGB) => {
|
||||
expect(value.r).toBe(expected.r);
|
||||
expect(value.g).toBe(expected.g);
|
||||
expect(value.b).toBe(expected.b);
|
||||
};
|
||||
|
||||
const expectHSV = (value: colorlib.HSV, expected: colorlib.HSV) => {
|
||||
expect(value.h).toBe(expected.h);
|
||||
expect(value.s).toBe(expected.s);
|
||||
expect(value.v).toBe(expected.v);
|
||||
};
|
||||
|
||||
const expectHCL = (value: colorlib.HCL, expected: colorlib.HCL) => {
|
||||
expect(value.h).toBe(expected.h);
|
||||
expect(value.c).toBe(expected.c);
|
||||
expect(value.l).toBe(expected.l);
|
||||
};
|
||||
|
||||
describe("color reducer", () => {
|
||||
const initialState = { color: colorlib.Color.from_hex("000") };
|
||||
|
||||
@@ -61,7 +28,7 @@ describe("color reducer", () => {
|
||||
payload: nextColor,
|
||||
});
|
||||
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("set hsv", () => {
|
||||
@@ -71,7 +38,7 @@ describe("color reducer", () => {
|
||||
payload: nextColor,
|
||||
});
|
||||
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("set hcl", () => {
|
||||
@@ -81,7 +48,7 @@ describe("color reducer", () => {
|
||||
payload: nextColor,
|
||||
});
|
||||
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("set hex", () => {
|
||||
@@ -104,7 +71,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_R,
|
||||
payload: nextColor.r,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("set rgb g", () => {
|
||||
@@ -114,7 +81,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_G,
|
||||
payload: nextColor.g,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("set rgb b", () => {
|
||||
@@ -124,7 +91,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_B,
|
||||
payload: nextColor.b,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -136,7 +103,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_H,
|
||||
payload: nextColor.h,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("set hsv s", () => {
|
||||
@@ -146,7 +113,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_S,
|
||||
payload: nextColor.s,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("set hsv v", () => {
|
||||
@@ -156,7 +123,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_V,
|
||||
payload: nextColor.v,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -168,7 +135,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_H,
|
||||
payload: nextColor.h,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("set hcl c", () => {
|
||||
@@ -178,7 +145,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_C,
|
||||
payload: nextColor.c,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("set hcl l", () => {
|
||||
@@ -188,7 +155,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_L,
|
||||
payload: nextColor.l,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -202,7 +169,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_R,
|
||||
payload: (prev) => prev + 100,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
|
||||
nextColor = colorlib.RGB.new(50, 0, 0);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -210,7 +177,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_R,
|
||||
payload: (prev) => prev - 50,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("adjust rgb g", () => {
|
||||
@@ -220,7 +187,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_G,
|
||||
payload: (prev) => prev + 100,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
|
||||
nextColor = colorlib.RGB.new(0, 50, 0);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -228,7 +195,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_G,
|
||||
payload: (prev) => prev - 50,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("adjust rgb b", () => {
|
||||
@@ -238,7 +205,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_B,
|
||||
payload: (prev) => prev + 100,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
|
||||
nextColor = colorlib.RGB.new(0, 0, 50);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -246,7 +213,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.RGB_B,
|
||||
payload: (prev) => prev - 50,
|
||||
});
|
||||
expectRGB(nextState.color.rgb, nextColor);
|
||||
expectEqualColor(nextState.color.rgb, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -258,7 +225,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_H,
|
||||
payload: (prev) => prev + 100,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
|
||||
nextColor = colorlib.HSV.new(50, 0, 0);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -266,7 +233,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_H,
|
||||
payload: (prev) => prev - 50,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hsv s", () => {
|
||||
@@ -276,7 +243,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_S,
|
||||
payload: (prev) => prev + 1,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
|
||||
nextColor = colorlib.HSV.new(0, 0.5, 0);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -284,7 +251,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_S,
|
||||
payload: (prev) => prev - 0.5,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hsv v", () => {
|
||||
@@ -294,7 +261,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_V,
|
||||
payload: (prev) => prev + 1,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
|
||||
nextColor = colorlib.HSV.new(0, 0, 0.5);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -302,7 +269,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HSV_V,
|
||||
payload: (prev) => prev - 0.5,
|
||||
});
|
||||
expectHSV(nextState.color.hsv, nextColor);
|
||||
expectEqualColor(nextState.color.hsv, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -314,7 +281,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_H,
|
||||
payload: (prev) => prev + 100,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
|
||||
nextColor = colorlib.HCL.new(50, 0, 0);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -322,7 +289,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_H,
|
||||
payload: (prev) => prev - 50,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hcl c", () => {
|
||||
@@ -332,7 +299,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_C,
|
||||
payload: (prev) => prev + 1,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
|
||||
nextColor = colorlib.HCL.new(0, 0.5, 0);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -340,7 +307,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_C,
|
||||
payload: (prev) => prev - 0.5,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hcl l", () => {
|
||||
@@ -350,7 +317,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_L,
|
||||
payload: (prev) => prev + 1,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
|
||||
nextColor = colorlib.HCL.new(0, 0, 0.5);
|
||||
nextState = colorReducer(nextState, {
|
||||
@@ -358,7 +325,7 @@ describe("color reducer", () => {
|
||||
component: colorlib.Component.HCL_L,
|
||||
payload: (prev) => prev - 0.5,
|
||||
});
|
||||
expectHCL(nextState.color.hcl, nextColor);
|
||||
expectEqualColor(nextState.color.hcl, nextColor);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -388,19 +355,19 @@ describe("color actions", () => {
|
||||
test("set rgb", () => {
|
||||
const nextColor = colorlib.RGB.new(1, 2, 3);
|
||||
actions.rgb.setRGB(nextColor);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("set hsv", () => {
|
||||
const nextColor = colorlib.HSV.new(1, 2, 3);
|
||||
actions.hsv.setHSV(nextColor);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("set hcl", () => {
|
||||
const nextColor = colorlib.HCL.new(1, 2, 3);
|
||||
actions.hcl.setHCL(nextColor);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("set hex", () => {
|
||||
@@ -415,19 +382,19 @@ describe("color actions", () => {
|
||||
test("set rgb r", () => {
|
||||
const nextColor = colorlib.RGB.new(100, 0, 0);
|
||||
actions.rgb.setR(nextColor.r);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("set rgb g", () => {
|
||||
const nextColor = colorlib.RGB.new(0, 100, 0);
|
||||
actions.rgb.setG(nextColor.g);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("set rgb b", () => {
|
||||
const nextColor = colorlib.RGB.new(0, 0, 100);
|
||||
actions.rgb.setB(nextColor.b);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -435,19 +402,19 @@ describe("color actions", () => {
|
||||
test("set hsv h", () => {
|
||||
const nextColor = colorlib.HSV.new(100, 0, 0);
|
||||
actions.hsv.setH(nextColor.h);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("set hsv s", () => {
|
||||
const nextColor = colorlib.HSV.new(0, 0.5, 0);
|
||||
actions.hsv.setS(nextColor.s);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("set hsv v", () => {
|
||||
const nextColor = colorlib.HSV.new(0, 0, 0.5);
|
||||
actions.hsv.setV(nextColor.v);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -455,19 +422,19 @@ describe("color actions", () => {
|
||||
test("set hcl h", () => {
|
||||
const nextColor = colorlib.HCL.new(100, 0, 0);
|
||||
actions.hcl.setH(nextColor.h);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("set hcl c", () => {
|
||||
const nextColor = colorlib.HCL.new(0, 0.5, 0);
|
||||
actions.hcl.setC(nextColor.c);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("set hcl l", () => {
|
||||
const nextColor = colorlib.HCL.new(0, 0, 0.5);
|
||||
actions.hcl.setL(nextColor.l);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -477,31 +444,31 @@ describe("color actions", () => {
|
||||
test("adjust rgb r", () => {
|
||||
let nextColor = colorlib.RGB.new(100, 0, 0);
|
||||
actions.rgb.setR((prev) => prev + 100);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
|
||||
nextColor = colorlib.RGB.new(50, 0, 0);
|
||||
actions.rgb.setR((prev) => prev - 50);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("adjust rgb g", () => {
|
||||
let nextColor = colorlib.RGB.new(0, 100, 0);
|
||||
actions.rgb.setG((prev) => prev + 100);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
|
||||
nextColor = colorlib.RGB.new(0, 50, 0);
|
||||
actions.rgb.setG((prev) => prev - 50);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
});
|
||||
|
||||
test("adjust rgb b", () => {
|
||||
let nextColor = colorlib.RGB.new(0, 0, 100);
|
||||
actions.rgb.setB((prev) => prev + 100);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
|
||||
nextColor = colorlib.RGB.new(0, 0, 50);
|
||||
actions.rgb.setB((prev) => prev - 50);
|
||||
expectRGB(state.color.rgb, nextColor);
|
||||
expectEqualColor(state.color.rgb, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -509,31 +476,31 @@ describe("color actions", () => {
|
||||
test("adjust hsv h", () => {
|
||||
let nextColor = colorlib.HSV.new(100, 0, 0);
|
||||
actions.hsv.setH((prev) => prev + 100);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
|
||||
nextColor = colorlib.HSV.new(50, 0, 0);
|
||||
actions.hsv.setH((prev) => prev - 50);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hsv s", () => {
|
||||
let nextColor = colorlib.HSV.new(0, 1, 0);
|
||||
actions.hsv.setS((prev) => prev + 1);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
|
||||
nextColor = colorlib.HSV.new(0, 0.5, 0);
|
||||
actions.hsv.setS((prev) => prev - 0.5);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hsv v", () => {
|
||||
let nextColor = colorlib.HSV.new(0, 0, 1);
|
||||
actions.hsv.setV((prev) => prev + 1);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
|
||||
nextColor = colorlib.HSV.new(0, 0, 0.5);
|
||||
actions.hsv.setV((prev) => prev - 0.5);
|
||||
expectHSV(state.color.hsv, nextColor);
|
||||
expectEqualColor(state.color.hsv, nextColor);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -541,31 +508,31 @@ describe("color actions", () => {
|
||||
test("adjust hcl h", () => {
|
||||
let nextColor = colorlib.HCL.new(100, 0, 0);
|
||||
actions.hcl.setH((prev) => prev + 100);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
|
||||
nextColor = colorlib.HCL.new(50, 0, 0);
|
||||
actions.hcl.setH((prev) => prev - 50);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hcl c", () => {
|
||||
let nextColor = colorlib.HCL.new(0, 1, 0);
|
||||
actions.hcl.setC((prev) => prev + 1);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
|
||||
nextColor = colorlib.HCL.new(0, 0.5, 0);
|
||||
actions.hcl.setC((prev) => prev - 0.5);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
});
|
||||
|
||||
test("adjust hcl l", () => {
|
||||
let nextColor = colorlib.HCL.new(0, 0, 1);
|
||||
actions.hcl.setL((prev) => prev + 1);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
|
||||
nextColor = colorlib.HCL.new(0, 0, 0.5);
|
||||
actions.hcl.setL((prev) => prev - 0.5);
|
||||
expectHCL(state.color.hcl, nextColor);
|
||||
expectEqualColor(state.color.hcl, nextColor);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import type { CartesianSpace } from "@/types";
|
||||
import { valueToPosition } from "@/util";
|
||||
@@ -12,8 +12,8 @@ function TestSquare() {
|
||||
const [dimensions, setDimensions] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [xValue, setXValue] = useState(0);
|
||||
const [yValue, setYValue] = useState(0);
|
||||
const xValueRange = { min: 0, max: 100 };
|
||||
const yValueRange = { min: 0, max: 100 };
|
||||
const xValueRange = useMemo(() => ({ min: 0, max: 100 }), []);
|
||||
const yValueRange = useMemo(() => ({ min: 0, max: 100 }), []);
|
||||
const [xPosition, setXPosition] = useState(0);
|
||||
const [yPosition, setYPosition] = useState(0);
|
||||
|
||||
@@ -46,7 +46,7 @@ function TestSquare() {
|
||||
const newYPos = valueToPosition(yValue, dimensions.y - 1, yValueRange);
|
||||
setXPosition(newXPos);
|
||||
setYPosition(newYPos);
|
||||
}, [xValue, yValue]);
|
||||
}, [xValue, yValue, dimensions.x, dimensions.y, xValueRange, yValueRange]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { useState } from "react";
|
||||
|
||||
import clsx from "clsx";
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Hex as HexColor } from "colorlib";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { mockUseReducer } from "@/testUtil";
|
||||
|
||||
import type {
|
||||
PaletteCard,
|
||||
PaletteCardAction,
|
||||
PaletteCardActions,
|
||||
PaletteCardState,
|
||||
} from "../paletteCard";
|
||||
import { createPaletteCardActions, paletteCardReducer } from "../paletteCard";
|
||||
|
||||
const createPaletteState = (
|
||||
present: PaletteCard,
|
||||
history: PaletteCard[] = [],
|
||||
future: PaletteCard[] = [],
|
||||
) => ({ present: { ...present }, history, future });
|
||||
|
||||
const testPaletteCard = {
|
||||
id: "palette_id",
|
||||
name: "Test Palette",
|
||||
colors: [],
|
||||
selectedColorId: null,
|
||||
inToolkitMode: false,
|
||||
};
|
||||
const testState = createPaletteState(testPaletteCard);
|
||||
|
||||
const WHITE = HexColor.from_code("#fff");
|
||||
const GREY = HexColor.from_code("#777");
|
||||
const BLACK = HexColor.from_code("#000");
|
||||
|
||||
describe("palette card actions", () => {
|
||||
let state: PaletteCardState;
|
||||
let dispatch: (value: PaletteCardAction) => void;
|
||||
let actions: PaletteCardActions;
|
||||
|
||||
beforeEach(() => {
|
||||
[state, dispatch] = mockUseReducer(paletteCardReducer, testState);
|
||||
actions = createPaletteCardActions(dispatch);
|
||||
});
|
||||
|
||||
test("sets card name", () => {
|
||||
actions.setCardName("New Name");
|
||||
expect(state.present.name).toBe("New Name");
|
||||
|
||||
expect(state.history.length).toBe(1);
|
||||
expect(state.future.length).toBe(0);
|
||||
|
||||
expect(state.history[0].name).toBe("Test Palette");
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import type { CartesianSpace } from "@/types";
|
||||
import { Direction } from "@/types";
|
||||
@@ -17,7 +17,7 @@ function TestSlider({
|
||||
const [dimensions, setDimensions] = useState<CartesianSpace>({ x: 0, y: 0 });
|
||||
const [value, setValue] = useState(0);
|
||||
const [position, setPosition] = useState(0);
|
||||
const valueRange = { min: 0, max: 100 };
|
||||
const valueRange = useMemo(() => ({ min: 0, max: 100 }), []);
|
||||
const { sliderRef, isDragging } = useSlider({
|
||||
direction,
|
||||
origin,
|
||||
@@ -51,7 +51,7 @@ function TestSlider({
|
||||
} else {
|
||||
setValue(0);
|
||||
}
|
||||
}, [dimensions, direction]);
|
||||
}, [dimensions, direction, position]);
|
||||
|
||||
useEffect(() => {
|
||||
const maxPosition = chooseValueByDirection(
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export function useResize(callback: () => void): () => void {
|
||||
export function onResize(callback: () => void): () => void {
|
||||
window.addEventListener("resize", callback);
|
||||
return () => window.removeEventListener("resize", callback);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,7 @@
|
||||
import { createContext, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
enum ViewportMode {
|
||||
DESKTOP = "desktop",
|
||||
MOBILE_LANDSCAPE = "mobile-landscape",
|
||||
MOBILE_PORTRAIT = "mobile-portrait",
|
||||
}
|
||||
|
||||
interface MediaQueryContextType {
|
||||
viewportMode: ViewportMode;
|
||||
isDesktop: boolean;
|
||||
isMobileLandscape: boolean;
|
||||
isMobilePortrait: boolean;
|
||||
}
|
||||
|
||||
export const MediaQueryContext = createContext<
|
||||
MediaQueryContextType | undefined
|
||||
>(undefined);
|
||||
import { MediaQueryContext, ViewportMode } from "./context";
|
||||
|
||||
export const MediaQueryProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [viewportMode, setViewportMode] = useState<ViewportMode>(
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
import { createContext, useReducer } from "react";
|
||||
import { useReducer } from "react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import * as colorlib from "colorlib";
|
||||
|
||||
import { colorReducer, createColorActions } from "@/hooks/color";
|
||||
import type { ColorActions } from "@/hooks/color";
|
||||
|
||||
interface SelectedColorContextType {
|
||||
selectedColor: colorlib.Color;
|
||||
selectedColorActions: ColorActions;
|
||||
}
|
||||
|
||||
export const SelectedColorContext = createContext<
|
||||
SelectedColorContextType | undefined
|
||||
>(undefined);
|
||||
import { SelectedColorContext } from "./context";
|
||||
|
||||
export const SelectedColorProvider = ({
|
||||
children,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { createContext } from "react";
|
||||
|
||||
import * as colorlib from "colorlib";
|
||||
|
||||
import type { ColorActions } from "@/hooks/color";
|
||||
|
||||
export enum ViewportMode {
|
||||
DESKTOP = "desktop",
|
||||
MOBILE_LANDSCAPE = "mobile-landscape",
|
||||
MOBILE_PORTRAIT = "mobile-portrait",
|
||||
}
|
||||
|
||||
interface MediaQueryContextType {
|
||||
viewportMode: ViewportMode;
|
||||
isDesktop: boolean;
|
||||
isMobileLandscape: boolean;
|
||||
isMobilePortrait: boolean;
|
||||
}
|
||||
|
||||
export const MediaQueryContext = createContext<
|
||||
MediaQueryContextType | undefined
|
||||
>(undefined);
|
||||
|
||||
interface SelectedColorContextType {
|
||||
selectedColor: colorlib.Color;
|
||||
selectedColorActions: ColorActions;
|
||||
}
|
||||
|
||||
export const SelectedColorContext = createContext<
|
||||
SelectedColorContextType | undefined
|
||||
>(undefined);
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Color, HCL, HSV, Hex, RGB } from "colorlib";
|
||||
import { expect } from "vitest";
|
||||
|
||||
export const mockUseReducer = <T extends object, U>(
|
||||
reducer: (state: T, action: U) => T,
|
||||
initialArg: T,
|
||||
): [T, (value: U) => void] => {
|
||||
let currentState = initialArg;
|
||||
|
||||
const state = new Proxy({} as T, {
|
||||
get: (_, prop) => currentState[prop as keyof T],
|
||||
});
|
||||
|
||||
const dispatch = (value: U) => {
|
||||
const nextState = reducer(currentState, value);
|
||||
currentState = nextState;
|
||||
};
|
||||
return [state, dispatch];
|
||||
};
|
||||
|
||||
export const expectEqualColor = <T extends { equals(other: T): boolean }>(
|
||||
value: T,
|
||||
expected: T,
|
||||
) => {
|
||||
if (!value.equals(expected)) {
|
||||
if (value instanceof Color && expected instanceof Color) {
|
||||
expect(value.hex.to_code()).toBe(expected.hex.to_code());
|
||||
} else if (value instanceof HCL && expected instanceof HCL) {
|
||||
expect(value.h).toBe(expected.h);
|
||||
expect(value.c).toBe(expected.c);
|
||||
expect(value.l).toBe(expected.l);
|
||||
} else if (value instanceof HSV && expected instanceof HSV) {
|
||||
expect(value.h).toBe(expected.h);
|
||||
expect(value.s).toBe(expected.s);
|
||||
expect(value.v).toBe(expected.v);
|
||||
} else if (
|
||||
(value instanceof RGB && expected instanceof RGB) ||
|
||||
(value instanceof Hex && expected instanceof Hex)
|
||||
) {
|
||||
expect(value.r).toBe(expected.r);
|
||||
expect(value.g).toBe(expected.g);
|
||||
expect(value.b).toBe(expected.b);
|
||||
}
|
||||
}
|
||||
expect(value.equals(expected)).toBe(true);
|
||||
};
|
||||
@@ -1,9 +1,15 @@
|
||||
import * as path from "path";
|
||||
import topLevelAwait from "vite-plugin-top-level-await";
|
||||
import wasm from "vite-plugin-wasm";
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [wasm(), topLevelAwait()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
environment: "jsdom",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user