Skip to content

Commit

Permalink
feat: color picker redesign (excalidraw#6216)
Browse files Browse the repository at this point in the history
Co-authored-by: Maielo <[email protected]>
Co-authored-by: dwelle <[email protected]>
Co-authored-by: Aakansha Doshi <[email protected]>
  • Loading branch information
4 people authored May 18, 2023
1 parent 6977c32 commit 5b75965
Show file tree
Hide file tree
Showing 55 changed files with 4,013 additions and 2,702 deletions.
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
save-exact=true
legacy-peer-deps=true
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
]
},
"dependencies": {
"@radix-ui/react-popover": "1.0.3",
"@radix-ui/react-tabs": "1.0.2",
"@sentry/browser": "6.2.5",
"@sentry/integrations": "6.2.5",
Expand Down
32 changes: 15 additions & 17 deletions src/actions/actionCanvas.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ColorPicker } from "../components/ColorPicker";
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
import { ZoomInIcon, ZoomOutIcon } from "../components/icons";
import { ToolButton } from "../components/ToolButton";
import { CURSOR_TYPE, MIN_ZOOM, THEME, ZOOM_STEP } from "../constants";
Expand All @@ -19,6 +19,7 @@ import {
isEraserActive,
isHandToolActive,
} from "../appState";
import { DEFAULT_CANVAS_BACKGROUND_PICKS } from "../colors";

export const actionChangeViewBackgroundColor = register({
name: "changeViewBackgroundColor",
Expand All @@ -35,24 +36,21 @@ export const actionChangeViewBackgroundColor = register({
commitToHistory: !!value.viewBackgroundColor,
};
},
PanelComponent: ({ elements, appState, updateData }) => {
PanelComponent: ({ elements, appState, updateData, appProps }) => {
// FIXME move me to src/components/mainMenu/DefaultItems.tsx
return (
<div style={{ position: "relative" }}>
<ColorPicker
label={t("labels.canvasBackground")}
type="canvasBackground"
color={appState.viewBackgroundColor}
onChange={(color) => updateData({ viewBackgroundColor: color })}
isActive={appState.openPopup === "canvasColorPicker"}
setActive={(active) =>
updateData({ openPopup: active ? "canvasColorPicker" : null })
}
data-testid="canvas-background-picker"
elements={elements}
appState={appState}
/>
</div>
<ColorPicker
palette={null}
topPicks={DEFAULT_CANVAS_BACKGROUND_PICKS}
label={t("labels.canvasBackground")}
type="canvasBackground"
color={appState.viewBackgroundColor}
onChange={(color) => updateData({ viewBackgroundColor: color })}
data-testid="canvas-background-picker"
elements={elements}
appState={appState}
updateData={updateData}
/>
);
},
});
Expand Down
6 changes: 3 additions & 3 deletions src/actions/actionFlip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from "../element/bounds";
import { isLinearElement } from "../element/typeChecks";
import { LinearElementEditor } from "../element/linearElementEditor";
import { KEYS } from "../keys";
import { CODES, KEYS } from "../keys";

const enableActionFlipHorizontal = (
elements: readonly ExcalidrawElement[],
Expand Down Expand Up @@ -48,7 +48,7 @@ export const actionFlipHorizontal = register({
commitToHistory: true,
};
},
keyTest: (event) => event.shiftKey && event.code === "KeyH",
keyTest: (event) => event.shiftKey && event.code === CODES.H,
contextItemLabel: "labels.flipHorizontal",
predicate: (elements, appState) =>
enableActionFlipHorizontal(elements, appState),
Expand All @@ -65,7 +65,7 @@ export const actionFlipVertical = register({
};
},
keyTest: (event) =>
event.shiftKey && event.code === "KeyV" && !event[KEYS.CTRL_OR_CMD],
event.shiftKey && event.code === CODES.V && !event[KEYS.CTRL_OR_CMD],
contextItemLabel: "labels.flipVertical",
predicate: (elements, appState) =>
enableActionFlipVertical(elements, appState),
Expand Down
26 changes: 15 additions & 11 deletions src/actions/actionProperties.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { AppState } from "../../src/types";
import {
DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE,
DEFAULT_ELEMENT_BACKGROUND_PICKS,
DEFAULT_ELEMENT_STROKE_COLOR_PALETTE,
DEFAULT_ELEMENT_STROKE_PICKS,
} from "../colors";
import { trackEvent } from "../analytics";
import { ButtonIconSelect } from "../components/ButtonIconSelect";
import { ColorPicker } from "../components/ColorPicker";
import { ColorPicker } from "../components/ColorPicker/ColorPicker";
import { IconPicker } from "../components/IconPicker";
// TODO barnabasmolnar/editor-redesign
// TextAlignTopIcon, TextAlignBottomIcon,TextAlignMiddleIcon,
Expand Down Expand Up @@ -226,10 +232,12 @@ export const actionChangeStrokeColor = register({
commitToHistory: !!value.currentItemStrokeColor,
};
},
PanelComponent: ({ elements, appState, updateData }) => (
PanelComponent: ({ elements, appState, updateData, appProps }) => (
<>
<h3 aria-hidden="true">{t("labels.stroke")}</h3>
<ColorPicker
topPicks={DEFAULT_ELEMENT_STROKE_PICKS}
palette={DEFAULT_ELEMENT_STROKE_COLOR_PALETTE}
type="elementStroke"
label={t("labels.stroke")}
color={getFormValue(
Expand All @@ -239,12 +247,9 @@ export const actionChangeStrokeColor = register({
appState.currentItemStrokeColor,
)}
onChange={(color) => updateData({ currentItemStrokeColor: color })}
isActive={appState.openPopup === "strokeColorPicker"}
setActive={(active) =>
updateData({ openPopup: active ? "strokeColorPicker" : null })
}
elements={elements}
appState={appState}
updateData={updateData}
/>
</>
),
Expand All @@ -269,10 +274,12 @@ export const actionChangeBackgroundColor = register({
commitToHistory: !!value.currentItemBackgroundColor,
};
},
PanelComponent: ({ elements, appState, updateData }) => (
PanelComponent: ({ elements, appState, updateData, appProps }) => (
<>
<h3 aria-hidden="true">{t("labels.background")}</h3>
<ColorPicker
topPicks={DEFAULT_ELEMENT_BACKGROUND_PICKS}
palette={DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE}
type="elementBackground"
label={t("labels.background")}
color={getFormValue(
Expand All @@ -282,12 +289,9 @@ export const actionChangeBackgroundColor = register({
appState.currentItemBackgroundColor,
)}
onChange={(color) => updateData({ currentItemBackgroundColor: color })}
isActive={appState.openPopup === "backgroundColorPicker"}
setActive={(active) =>
updateData({ openPopup: active ? "backgroundColorPicker" : null })
}
elements={elements}
appState={appState}
updateData={updateData}
/>
</>
),
Expand Down
30 changes: 21 additions & 9 deletions src/actions/actionStyles.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import ExcalidrawApp from "../excalidraw-app";
import { t } from "../i18n";
import { CODES } from "../keys";
import { API } from "../tests/helpers/api";
import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
import { fireEvent, render, screen } from "../tests/test-utils";
import {
act,
fireEvent,
render,
screen,
togglePopover,
} from "../tests/test-utils";
import { copiedStyles } from "./actionStyles";

const { h } = window;
Expand All @@ -14,7 +19,14 @@ describe("actionStyles", () => {
beforeEach(async () => {
await render(<ExcalidrawApp />);
});
it("should copy & paste styles via keyboard", () => {

afterEach(async () => {
// https://github.com/floating-ui/floating-ui/issues/1908#issuecomment-1301553793
// affects node v16+
await act(async () => {});
});

it("should copy & paste styles via keyboard", async () => {
UI.clickTool("rectangle");
mouse.down(10, 10);
mouse.up(20, 20);
Expand All @@ -24,10 +36,10 @@ describe("actionStyles", () => {
mouse.up(20, 20);

// Change some styles of second rectangle
UI.clickLabeledElement("Stroke");
UI.clickLabeledElement(t("colors.c92a2a"));
UI.clickLabeledElement("Background");
UI.clickLabeledElement(t("colors.e64980"));
togglePopover("Stroke");
UI.clickOnTestId("color-red");
togglePopover("Background");
UI.clickOnTestId("color-blue");
// Fill style
fireEvent.click(screen.getByTitle("Cross-hatch"));
// Stroke width
Expand Down Expand Up @@ -60,8 +72,8 @@ describe("actionStyles", () => {

const firstRect = API.getSelectedElement();
expect(firstRect.id).toBe(h.elements[0].id);
expect(firstRect.strokeColor).toBe("#c92a2a");
expect(firstRect.backgroundColor).toBe("#e64980");
expect(firstRect.strokeColor).toBe("#e03131");
expect(firstRect.backgroundColor).toBe("#a5d8ff");
expect(firstRect.fillStyle).toBe("cross-hatch");
expect(firstRect.strokeWidth).toBe(2); // Bold: 2
expect(firstRect.strokeStyle).toBe("dotted");
Expand Down
4 changes: 2 additions & 2 deletions src/appState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import oc from "open-color";
import { COLOR_PALETTE } from "./colors";
import {
DEFAULT_ELEMENT_PROPS,
DEFAULT_FONT_FAMILY,
Expand Down Expand Up @@ -84,7 +84,7 @@ export const getDefaultAppState = (): Omit<
startBoundElement: null,
suggestedBindings: [],
toast: null,
viewBackgroundColor: oc.white,
viewBackgroundColor: COLOR_PALETTE.white,
zenModeEnabled: false,
zoom: {
value: 1 as NormalizedZoomValue,
Expand Down
32 changes: 24 additions & 8 deletions src/charts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import colors from "./colors";
import { DEFAULT_FONT_SIZE, ENV } from "./constants";
import {
COLOR_PALETTE,
DEFAULT_CHART_COLOR_INDEX,
getAllColorsSpecificShade,
} from "./colors";
import {
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE,
ENV,
VERTICAL_ALIGN,
} from "./constants";
import { newElement, newLinearElement, newTextElement } from "./element";
import { NonDeletedExcalidrawElement } from "./element/types";
import { randomId } from "./random";
Expand Down Expand Up @@ -153,15 +162,22 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => {
return result;
};

const bgColors = colors.elementBackground.slice(
2,
colors.elementBackground.length,
);
const bgColors = getAllColorsSpecificShade(DEFAULT_CHART_COLOR_INDEX);

// Put all the common properties here so when the whole chart is selected
// the properties dialog shows the correct selected values
const commonProps = {
strokeColor: colors.elementStroke[0],
fillStyle: "hachure",
fontFamily: DEFAULT_FONT_FAMILY,
fontSize: DEFAULT_FONT_SIZE,
opacity: 100,
roughness: 1,
strokeColor: COLOR_PALETTE.black,
roundness: null,
strokeStyle: "solid",
strokeWidth: 1,
verticalAlign: VERTICAL_ALIGN.MIDDLE,
locked: false,
} as const;

const getChartDimentions = (spreadsheet: Spreadsheet) => {
Expand Down Expand Up @@ -322,7 +338,7 @@ const chartBaseElements = (
y: y - chartHeight,
width: chartWidth,
height: chartHeight,
strokeColor: colors.elementStroke[0],
strokeColor: COLOR_PALETTE.black,
fillStyle: "solid",
opacity: 6,
})
Expand Down
20 changes: 14 additions & 6 deletions src/clients.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import colors from "./colors";
import {
DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX,
DEFAULT_ELEMENT_STROKE_COLOR_INDEX,
getAllColorsSpecificShade,
} from "./colors";
import { AppState } from "./types";

const BG_COLORS = getAllColorsSpecificShade(
DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX,
);
const STROKE_COLORS = getAllColorsSpecificShade(
DEFAULT_ELEMENT_STROKE_COLOR_INDEX,
);

export const getClientColors = (clientId: string, appState: AppState) => {
if (appState?.collaborators) {
const currentUser = appState.collaborators.get(clientId);
Expand All @@ -11,12 +22,9 @@ export const getClientColors = (clientId: string, appState: AppState) => {
// Naive way of getting an integer out of the clientId
const sum = clientId.split("").reduce((a, str) => a + str.charCodeAt(0), 0);

// Skip transparent & gray colors
const backgrounds = colors.elementBackground.slice(3);
const strokes = colors.elementStroke.slice(3);
return {
background: backgrounds[sum % backgrounds.length],
stroke: strokes[sum % strokes.length],
background: BG_COLORS[sum % BG_COLORS.length],
stroke: STROKE_COLORS[sum % STROKE_COLORS.length],
};
};

Expand Down
Loading

0 comments on commit 5b75965

Please sign in to comment.