Skip to content

Commit

Permalink
Almost done with blending mode without PASS_THROUGH and opacities case.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikhin committed Nov 9, 2023
1 parent 40652c7 commit f0a8408
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 115 deletions.
1 change: 1 addition & 0 deletions src/api/services/figma/nodes/create-polychrom-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const createPolychromNode = (
const parents = collectNodeParents(node);

return {
blendMode: 'blendMode' in node ? node.blendMode : 'PASS_THROUGH',
children: [],
fills: fills.map((fill) => {
if (fill.type === 'SOLID') {
Expand Down
48 changes: 22 additions & 26 deletions src/api/services/figma/nodes/has-only-valid-blend-modes.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
// import { type PolychromNode, type FigmaPaint } from '~types/figma.ts';
// import { isEmpty, notEmpty } from '~utils/not-empty.ts';
//
// // PLUS_LIGHTER is LINEAR_DODGE
// // PLUS_DARKER is LINEAR_BURN
// const unprocessedBlendModes = ['LINEAR_BURN', 'LINEAR_DODGE'];
//
// const isVisibleSolidFill = (fill: FigmaPaint): boolean =>
// fill.visible === true &&
// (notEmpty(fill.opacity) ? fill.opacity > 0 : true) &&
// fill.type === 'SOLID';
//
// const hasValidBlendMode = (fill: FigmaPaint): boolean => {
// if (isEmpty(fill.blendMode)) return true;
//
// return !unprocessedBlendModes.includes(fill.blendMode);
// };
//
// export const hasOnlyValidBlendModes = (nodes: PolychromNode[]): boolean =>
// nodes.every(
// (node) =>
// node.fills
// .filter((fill) => isVisibleSolidFill(fill))
// .every(hasValidBlendMode) &&
// !unprocessedBlendModes.includes(node.blendMode)
// );
import { type FigmaPaint, type PolychromNode } from '~types/figma.ts';
import { flattenPolychromNodesTree } from '~utils/figma/flatten-polychrom-nodes-tree.ts';
import { isVisibleSolidFill } from '~utils/figma/is-visible-solid-fill.ts';
import { isEmpty } from '~utils/not-empty.ts';

// PLUS_DARKER is LINEAR_BURN
const unprocessedBlendModes = ['LINEAR_BURN'];

const hasValidBlendMode = (fill: FigmaPaint): boolean => {
if (isEmpty(fill.blendMode)) return true;

return !unprocessedBlendModes.includes(fill.blendMode);
};

export const hasOnlyValidBlendModes = (nodes: PolychromNode): boolean =>
flattenPolychromNodesTree(nodes).every(
(node) =>
node.fills
.filter((fill) => isVisibleSolidFill(fill))
.every(hasValidBlendMode) &&
!unprocessedBlendModes.includes(node.blendMode)
);
2 changes: 0 additions & 2 deletions src/api/services/figma/nodes/map-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ export const mapPolychromNodeTree = (
node: PolychromNode,
transform: (node: PolychromNode) => PolychromNode
): PolychromNode => {
// Apply the transformation to the current node
const newNode = transform(node);

// Recursively map the children
newNode.children = node.children.map((child) =>
mapPolychromNodeTree(child, transform)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('createPolychromNode', () => {
const result = createPolychromNode(node);

expect(result).toEqual({
blendMode: 'PASS_THROUGH',
children: [],
fills: [],
id: '123',
Expand Down
26 changes: 15 additions & 11 deletions src/api/services/payload/build-general-selection-payload.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getIntersectingNodes } from '~api/services/figma/intersections/get-intersecting-nodes.ts';
// import { hasOnlyValidBlendModes } from '~api/services/figma/nodes/has-only-valid-blend-modes.ts';
import { hasOnlyValidBlendModes } from '~api/services/figma/nodes/has-only-valid-blend-modes.ts';
import { isValidForBackground } from '~api/services/figma/nodes/is-valid-for-background.ts';
import { isValidForSelection } from '~api/services/figma/nodes/is-valid-for-selection.ts';
import { type PolychromNode } from '~types/figma.ts';
Expand All @@ -17,7 +17,11 @@ enum PairState {
const isValidSelection = (
pair: PairState | PolychromNode
): pair is PolychromNode => {
return notEmpty(pair) && pair !== PairState.InvalidBackground;
return (
notEmpty(pair) &&
pair !== PairState.InvalidBackground &&
pair !== PairState.InvalidBlendMode
);
};

export const buildGeneralSelectionPayload = (
Expand All @@ -28,9 +32,9 @@ export const buildGeneralSelectionPayload = (
.map((selectedNode) => {
const intersectingNodesTree = getIntersectingNodes(selectedNode);

// if (!hasOnlyValidBlendModes([selectedPolychromNode, ...intersectingNodesTree])) {
// return PairState.InvalidBlendMode;
// }
if (!hasOnlyValidBlendModes(intersectingNodesTree)) {
return PairState.InvalidBlendMode;
}

if (isValidForBackground(intersectingNodesTree)) {
return intersectingNodesTree;
Expand All @@ -53,12 +57,12 @@ export const buildGeneralSelectionPayload = (
};
}

// if (selectedNodePairs.some((pair) => pair === PairState.InvalidBlendMode)) {
// return {
// colorSpace: figma.root.documentColorProfile,
// text: SelectionMessageTypes.unprocessedBlendModes,
// };
// }
if (selectedNodePairs.some((pair) => pair === PairState.InvalidBlendMode)) {
return {
colorSpace: figma.root.documentColorProfile,
text: SelectionMessageTypes.unprocessedBlendModes,
};
}

return {
colorSpace: figma.root.documentColorProfile,
Expand Down
15 changes: 8 additions & 7 deletions src/api/services/payload/build-pair-selection-payload.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getIntersectingNodes } from '~api/services/figma/intersections/get-intersecting-nodes.ts';
import { createPolychromNode } from '~api/services/figma/nodes/create-polychrom-node.ts';
// import { hasOnlyValidBlendModes } from '~api/services/figma/nodes/has-only-valid-blend-modes.ts';
import { hasOnlyValidBlendModes } from '~api/services/figma/nodes/has-only-valid-blend-modes.ts';
import { isValidForBackground } from '~api/services/figma/nodes/is-valid-for-background.ts';
import { isValidForSelection } from '~api/services/figma/nodes/is-valid-for-selection.ts';
import { mapPolychromNodeTree } from '~api/services/figma/nodes/map-tree.ts';
Expand Down Expand Up @@ -48,12 +48,12 @@ export const buildPairSelectionPayload = (
};
}

// if (!hasOnlyValidBlendModes([bg, fg])) {
// return {
// colorSpace: figma.root.documentColorProfile,
// text: SelectionMessageTypes.unprocessedBlendModes,
// };
// }
if (!hasOnlyValidBlendModes(bg) || !hasOnlyValidBlendModes(fg)) {
return {
colorSpace: figma.root.documentColorProfile,
text: SelectionMessageTypes.unprocessedBlendModes,
};
}

if (!isValidForSelection(fgSceneNode))
return {
Expand All @@ -67,6 +67,7 @@ export const buildPairSelectionPayload = (
colorSpace: figma.root.documentColorProfile,
selectedNodePairs: [
{
blendMode: 'NORMAL',
children: [
mapPolychromNodeTree(getIntersectingNodes(bgSceneNode), (node) => ({
...node,
Expand Down
1 change: 1 addition & 0 deletions src/types/figma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { type UIColor } from '~types/common.ts';
export type FigmaPaint = Paint | (SolidPaint & UIColor);

export interface PolychromNode {
blendMode: BlendMode;
children: PolychromNode[];
fills: FigmaPaint[];
id: string;
Expand Down
7 changes: 6 additions & 1 deletion src/ui/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ export const App: React.FC = () => {
{isP3 && (
<Tooltip>
<TooltipTrigger>
<div className="flex items-center">
<div
style={{
mixBlendMode: 'difference',
}}
className="flex items-center"
>
<p className="mr-3 rounded border-0.5 border-secondary-75 p-1 text-xxxs font-medium leading-[8px] text-secondary-75">
P3
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const UnprocessedBlendModesSelectionMessage = (): ReactElement => {
}}
className="mx-auto flex h-[200px] w-[250px] select-none items-end justify-center bg-[length:180px_180px] bg-center bg-no-repeat pt-2 text-center font-martianMono text-xxs text-secondary-75"
>
The blending modes Plus Lighter and Plus Darker are not supported
The blending mode Plus Darker is not supported
</p>
);
};
18 changes: 10 additions & 8 deletions src/ui/services/blend-modes/map-figma-blend-to-canvas.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { notEmpty } from '~utils/not-empty.ts';
import { type CSSProperties } from 'react';

export const mapFigmaBlendToCanvas = (
figmaBlend: BlendMode
): GlobalCompositeOperation => {
const mapping: Record<BlendMode, GlobalCompositeOperation> = {
figmaBlend?: BlendMode
): CSSProperties['mixBlendMode'] => {
const mapping: Record<BlendMode, CSSProperties['mixBlendMode']> = {
COLOR: 'color',
COLOR_BURN: 'color-burn',
COLOR_DODGE: 'color-dodge',
Expand All @@ -13,18 +16,17 @@ export const mapFigmaBlendToCanvas = (
LIGHTEN: 'lighten',
// unsupported
LINEAR_BURN: 'color-burn',
// unsupported
LINEAR_DODGE: 'lighter',
LINEAR_DODGE: 'plus-lighter',
LUMINOSITY: 'luminosity',
MULTIPLY: 'multiply',
NORMAL: 'source-over',
NORMAL: 'normal',
OVERLAY: 'overlay',
// only for layers, not for fills
PASS_THROUGH: 'source-over',
PASS_THROUGH: undefined,
SATURATION: 'saturation',
SCREEN: 'screen',
SOFT_LIGHT: 'soft-light',
};

return mapping[figmaBlend];
return notEmpty(figmaBlend) ? mapping[figmaBlend] : undefined;
};
4 changes: 2 additions & 2 deletions src/ui/services/blend/blend-colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getFillFromCtx } from '~ui/services/canvas/get-fill-from-ctx.ts';
import { renderSvgOnCanvas } from '~ui/services/canvas/render-svg-on-canvas.ts';
import { findFgAndBgNodes } from '~ui/services/figma/find-fg-and-bg-nodes.ts';
import { formatPolychromNodeId } from '~ui/services/figma/format-figma-node-id.ts';
import { drawFillsOnSvg } from '~ui/services/svg/draw-fills-on-svg.ts';
import { drawNodesOnSvg } from '~ui/services/svg/draw-nodes-on-svg.ts';
import { type ContrastConclusion } from '~ui/types';
import { calculateApcaScore } from '~utils/apca/calculate-apca-score.ts';
import { getActualFill } from '~utils/figma/get-actual-fill.ts';
Expand Down Expand Up @@ -122,7 +122,7 @@ const drawNodesOnContext = async (
svg.setAttribute('width', `${BACKGROUND_BOX.width}`);
svg.setAttribute('height', `${BACKGROUND_BOX.height}`);

drawFillsOnSvg(svg, pair, FOREGROUND_BOX, BACKGROUND_BOX, colorSpace);
drawNodesOnSvg(svg, pair, FOREGROUND_BOX, BACKGROUND_BOX, colorSpace);

await renderSvgOnCanvas(ctx, svg);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { type ColorSpace } from '~types/common.ts';
import { type FigmaPaint } from '~types/figma.ts';
import { mapFigmaBlendToCanvas } from '~ui/services/blend-modes/map-figma-blend-to-canvas.ts';
import { determineFillStyle } from '~ui/services/blend/determine-fill-style.ts';
import { isEmpty } from '~utils/not-empty.ts';
import { isEmpty, notEmpty } from '~utils/not-empty.ts';

export interface CanvasRect {
height: number;
width: number;
}

export const drawRect = (
export const drawFillAsRect = (
fill: FigmaPaint,
rectBox: CanvasRect,
colorSpace: ColorSpace
Expand All @@ -21,16 +22,23 @@ export const drawRect = (
svgRect.setAttribute('width', String(rectBox.width));
svgRect.setAttribute('height', String(rectBox.height));

if (notEmpty(fill.blendMode)) {
const mappedBlendMode = mapFigmaBlendToCanvas(fill.blendMode);

if (notEmpty(mappedBlendMode)) {
svgRect.setAttribute('style', `mix-blend-mode: ${mappedBlendMode};`);
}
}

const fillStyle = determineFillStyle(fill, colorSpace);

if (isEmpty(fillStyle)) return null;

// if (notEmpty(fill.blendMode)) {
// ctx.globalCompositeOperation = mapFigmaBlendToCanvas(fill.blendMode);
// }

svgRect.setAttribute('fill', fillStyle);
svgRect.setAttribute('opacity', `${fill.opacity?.toFixed(2) ?? 1}`);

if (fill.opacity !== 1) {
svgRect.setAttribute('opacity', `${fill.opacity?.toFixed(2) ?? 1}`);
}

return svgRect;
};
49 changes: 0 additions & 49 deletions src/ui/services/svg/draw-fills-on-svg.ts

This file was deleted.

Loading

0 comments on commit f0a8408

Please sign in to comment.