@pixerate/editor-react 0.69.0 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -521,6 +521,10 @@ var BrushPanel = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, clas
|
|
|
521
521
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
522
522
|
[controller, brushes, paper, thumbnailWidth, thumbnailHeight]
|
|
523
523
|
);
|
|
524
|
+
const engine = (0, import_paint_editor4.brushEngineControls)(brush);
|
|
525
|
+
const mc = brush.behavior.multicolor;
|
|
526
|
+
const carried = (0, import_paint_editor4.brushLoadColor)(state.mixerLoad);
|
|
527
|
+
const setColors = (colors) => controller.setBrush({ behavior: { multicolor: { colors } } });
|
|
524
528
|
const slug = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "brush";
|
|
525
529
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `${panel} ${className ?? ""}`, "data-testid": "brush-panel", children: [
|
|
526
530
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "grid grid-cols-2 gap-1", role: "listbox", "aria-label": "Brushes", children: brushes.map((b) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -552,6 +556,68 @@ var BrushPanel = ({ controller, thumbnailWidth = 112, thumbnailHeight = 32, clas
|
|
|
552
556
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2", children: [
|
|
553
557
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "checkbox", checked: brush.tip.pressureOpacity, onChange: (e) => controller.setBrush({ tip: { pressureOpacity: e.target.checked } }) }),
|
|
554
558
|
" Pressure \u2192 opacity"
|
|
559
|
+
] }),
|
|
560
|
+
brush.engine === "dab" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center justify-between gap-2", children: [
|
|
561
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Blend" }),
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": "Brush blend", value: brush.tip.blend, onChange: (e) => controller.setBrush({ tip: { blend: e.target.value } }), className: "rounded bg-slate-800 px-1 py-0.5", children: import_paint_editor4.BLEND_MENU_GROUPS.map((g) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("optgroup", { label: g.label, children: g.modes.map((m) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: m.id, title: m.description, children: m.label }, m.id)) }, g.label)) })
|
|
563
|
+
] })
|
|
564
|
+
] }),
|
|
565
|
+
engine && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-1.5", "data-testid": "brush-engine", children: [
|
|
566
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-medium text-slate-300", children: engine.title }),
|
|
567
|
+
engine.sliders.map((c) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PaintSlider, { control: c, value: (0, import_paint_editor4.readPath)(brush, c.path), onChange: (v) => controller.setBrush((0, import_paint_editor4.patchPath)(brush, c.path, v)) }, c.path)),
|
|
568
|
+
engine.mixingPath && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center justify-between gap-2", children: [
|
|
569
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Mixing" }),
|
|
570
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
571
|
+
"select",
|
|
572
|
+
{
|
|
573
|
+
"aria-label": "Brush mixing",
|
|
574
|
+
value: engine.mixingPath === "blender.mixing" ? brush.blender.mixing : engine.mixingPath === "smudge.mixing" ? brush.smudge.mixing : brush.behavior.mixing,
|
|
575
|
+
onChange: (e) => controller.setBrush((0, import_paint_editor4.patchBrushValue)(brush, engine.mixingPath, e.target.value)),
|
|
576
|
+
className: "rounded bg-slate-800 px-1 py-0.5",
|
|
577
|
+
children: [
|
|
578
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "pigment", children: "Pigment" }),
|
|
579
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "rgb", children: "RGB" })
|
|
580
|
+
]
|
|
581
|
+
}
|
|
582
|
+
)
|
|
583
|
+
] }),
|
|
584
|
+
engine.dirty && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center gap-2", title: "Keep the colour the brush picked up for the next stroke (needs Pick-up above 0)", children: [
|
|
585
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "checkbox", "aria-label": "Dirty brush", checked: brush.behavior.dirty, onChange: (e) => controller.setBrush({ behavior: { dirty: e.target.checked } }) }),
|
|
586
|
+
" Dirty brush"
|
|
587
|
+
] }),
|
|
588
|
+
engine.multicolor && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col gap-1.5", "data-testid": "multicolor", children: [
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center justify-between gap-2", children: [
|
|
590
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Multi-colour" }),
|
|
591
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { "aria-label": "Multi-colour", value: mc.mode, onChange: (e) => controller.setBrush({ behavior: { multicolor: { mode: e.target.value } } }), className: "rounded bg-slate-800 px-1 py-0.5", children: [
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "off", children: "Off" }),
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "tip", children: "Across the tip" }),
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "dab", children: "Per dab" })
|
|
595
|
+
] })
|
|
596
|
+
] }),
|
|
597
|
+
mc.mode !== "off" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
598
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center gap-1", "aria-label": "Multi-colour colours", children: [
|
|
599
|
+
mc.colors.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex items-center", children: [
|
|
600
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "color", "aria-label": `Multi-colour ${i + 1}`, value: col, onChange: (e) => setColors(mc.colors.map((x, j) => j === i ? e.target.value : x)), className: "h-5 w-6 rounded bg-transparent" }),
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", "aria-label": `Remove multi-colour ${i + 1}`, className: "px-0.5 text-slate-500 hover:text-white", onClick: () => setColors(mc.colors.filter((_, j) => j !== i)), children: "\xD7" })
|
|
602
|
+
] }, i)),
|
|
603
|
+
mc.colors.length < 8 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: button, "aria-label": "Add multi-colour", onClick: () => setColors([...mc.colors.length ? mc.colors : [state.color, state.secondaryColor], state.color].slice(0, 8)), children: "+" }),
|
|
604
|
+
mc.colors.length < 2 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-[10px] text-slate-500", children: "Uses the paint and second colours" })
|
|
605
|
+
] }),
|
|
606
|
+
mc.mode === "dab" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "flex items-center justify-between gap-2", children: [
|
|
607
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Order" }),
|
|
608
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { "aria-label": "Colour order", value: mc.order, onChange: (e) => controller.setBrush({ behavior: { multicolor: { order: e.target.value } } }), className: "rounded bg-slate-800 px-1 py-0.5", children: [
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "sequence", children: "In order" }),
|
|
610
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "random", children: "Random" })
|
|
611
|
+
] })
|
|
612
|
+
] }),
|
|
613
|
+
(0, import_paint_editor4.multiColorSliders)(mc.mode).map((c) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PaintSlider, { control: c, value: (0, import_paint_editor4.readPath)(brush, c.path), onChange: (v) => controller.setBrush((0, import_paint_editor4.patchPath)(brush, c.path, v)) }, c.path))
|
|
614
|
+
] })
|
|
615
|
+
] }),
|
|
616
|
+
engine.load && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
617
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400", children: "Carries" }),
|
|
618
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-label": "Brush load", title: carried ?? "Clean", className: "h-4 w-4 rounded ring-1 ring-slate-700", style: { background: carried ?? "transparent" } }),
|
|
619
|
+
brush.engine === "mixer" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: button, onClick: () => controller.loadMixerBrush(), children: "Load" }),
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: button, onClick: () => controller.cleanMixerBrush(brush.engine === "mixer"), children: "Clean" })
|
|
555
621
|
] })
|
|
556
622
|
] }),
|
|
557
623
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
@@ -631,6 +697,9 @@ var ColorPanel = ({ controller, wheelSize = 168, mixingPad = true, className })
|
|
|
631
697
|
const [wheel, setWheel] = (0, import_react7.useState)("ryb");
|
|
632
698
|
const [kind, setKind] = (0, import_react7.useState)("complementary");
|
|
633
699
|
const [padTool, setPadTool] = (0, import_react7.useState)("paint");
|
|
700
|
+
const [sample, setSample] = (0, import_react7.useState)(3);
|
|
701
|
+
const [parts, setParts] = (0, import_react7.useState)([1, 1]);
|
|
702
|
+
const [padName, setPadName] = (0, import_react7.useState)("");
|
|
634
703
|
const padPoints = (0, import_react7.useRef)(null);
|
|
635
704
|
const ring = (0, import_react7.useMemo)(() => (0, import_paint_editor6.renderColorWheel)(wheelSize, wheel), [wheelSize, wheel]);
|
|
636
705
|
const color = state.color;
|
|
@@ -742,7 +811,7 @@ var ColorPanel = ({ controller, wheelSize = 168, mixingPad = true, className })
|
|
|
742
811
|
onPointerDown: (e) => {
|
|
743
812
|
const p = padPoint(e);
|
|
744
813
|
if (padTool === "pick") {
|
|
745
|
-
attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true }));
|
|
814
|
+
attempt(() => controller.mixingPadPick(p.x, p.y, { setColor: true, radius: (0, import_paint_editor6.padSampleRadius)(sample) }));
|
|
746
815
|
return;
|
|
747
816
|
}
|
|
748
817
|
padPoints.current = [p];
|
|
@@ -756,7 +825,44 @@ var ColorPanel = ({ controller, wheelSize = 168, mixingPad = true, className })
|
|
|
756
825
|
},
|
|
757
826
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PixelCanvas, { pixels: pad, label: "Mixing pad pixels", className: "w-full rounded", style: { aspectRatio: `${import_paint_editor6.MIXING_PAD_WIDTH} / ${import_paint_editor6.MIXING_PAD_HEIGHT}` } })
|
|
758
827
|
}
|
|
759
|
-
)
|
|
828
|
+
),
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-wrap items-center gap-1", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-400", children: "Sample" }),
|
|
831
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("select", { "aria-label": "Pick sample size", value: sample, onChange: (e) => setSample(Number(e.target.value)), className: "rounded bg-slate-800 px-1 py-0.5", children: import_paint_editor6.PAD_SAMPLE_SIZES.map((n) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: n, children: n === 1 ? "1 px" : `${n}\xD7${n}` }, n)) })
|
|
832
|
+
] }) }),
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "h-4 w-4 rounded ring-1 ring-slate-700", style: { background: color } }),
|
|
835
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "number", "aria-label": "Paint colour parts", min: 0, max: 20, value: parts[0], onChange: (e) => setParts([Number(e.target.value), parts[1]]), className: "w-10 rounded bg-slate-800 px-1 py-0.5" }),
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-slate-500", children: ":" }),
|
|
837
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "number", "aria-label": "Second colour parts", min: 0, max: 20, value: parts[1], onChange: (e) => setParts([parts[0], Number(e.target.value)]), className: "w-10 rounded bg-slate-800 px-1 py-0.5" }),
|
|
838
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "h-4 w-4 rounded ring-1 ring-slate-700", style: { background: state.secondaryColor } }),
|
|
839
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
840
|
+
"button",
|
|
841
|
+
{
|
|
842
|
+
type: "button",
|
|
843
|
+
className: button,
|
|
844
|
+
title: "Mix the paint and second colours in these parts on the pad, and use the mix",
|
|
845
|
+
onClick: () => attempt(
|
|
846
|
+
() => controller.mixOnPad(
|
|
847
|
+
[
|
|
848
|
+
{ color, parts: parts[0] },
|
|
849
|
+
{ color: state.secondaryColor, parts: parts[1] }
|
|
850
|
+
],
|
|
851
|
+
{ setColor: true }
|
|
852
|
+
)
|
|
853
|
+
),
|
|
854
|
+
children: "Mix"
|
|
855
|
+
}
|
|
856
|
+
)
|
|
857
|
+
] }),
|
|
858
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
859
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { value: padName, placeholder: "Pad name", "aria-label": "Pad name", onChange: (e) => setPadName(e.target.value), className: "w-24 rounded bg-slate-800 px-1.5 py-0.5" }),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: button, onClick: () => attempt(() => (controller.saveMixingPad(padName || void 0), setPadName(""))), children: "Keep pad" })
|
|
861
|
+
] }),
|
|
862
|
+
state.savedMixingPads.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "flex flex-col gap-0.5", "aria-label": "Kept pads", children: state.savedMixingPads.map((p) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { className: "flex items-center gap-1", children: [
|
|
863
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: `${button} flex-1 text-left`, onClick: () => attempt(() => controller.loadMixingPad(p.id)), children: p.name }),
|
|
864
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: button, "aria-label": `Remove ${p.name}`, onClick: () => attempt(() => controller.removeMixingPad(p.id)), children: "\xD7" })
|
|
865
|
+
] }, p.id)) })
|
|
760
866
|
] }),
|
|
761
867
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ErrorLine, { error })
|
|
762
868
|
] });
|