zeplin-extension-style-kit
Version:
Models and utilities to generate CSS-like style code in Zeplin extensions.
84 lines (67 loc) • 2.74 kB
text/typescript
import { ColorStop } from "@zeplin/extension-model";
import { ColorNameResolver, ColorParams, StyleValue } from "../../common.js";
import { Percent } from "../percent.js";
import { LinearColorStop } from "./linearColorStop.js";
interface Point {
x: number;
y: number;
}
export class RadialGradient implements StyleValue {
center: Point;
colorStops: LinearColorStop[];
constructor(
colorStops: ColorStop[],
from: Point,
to: Point,
width: number,
height: number
) {
this.center = from;
/*
* Convert the relative `from` and `to` positions on a layer to absolute positions
* by multiplying them with the width and height of the layer
*/
const x1 = from.x * width;
const y1 = from.y * height;
const x2 = to.x * width;
const y2 = to.y * height;
// The length of the gradient line between `from` (center) and `to` points
const gradientDistance = Math.hypot(x1 - x2, y1 - y2);
let farthestDistance = 0;
const corners = [
{ x: 0, y: 0 },
{ x: width, y: 0 },
{ x: width, y: height },
{ x: 0, y: height }
];
corners.forEach(corner => {
const distance = Math.hypot(x1 - corner.x, y1 - corner.y);
if (distance > farthestDistance) {
farthestDistance = distance;
}
});
const distanceRatio = gradientDistance / farthestDistance;
this.colorStops = colorStops.map(({ color, position: p }) => {
// Convert the position coming from design tool to position on the actual gradient line
const position = p * distanceRatio;
return new LinearColorStop({ color, position });
});
}
valueOf(): string {
const { center, colorStops } = this;
return `radialGradient::cx:${center.x}:cy:${center.y}:${colorStops.map(cs => cs.valueOf()).join(":")}`;
}
equals(other: RadialGradient): boolean {
return (
this.center.x === other.center.x &&
this.center.y === other.center.y &&
this.colorStops.length === other.colorStops.length &&
this.colorStops.every((stop, i) => stop.equals(other.colorStops[i]))
);
}
toStyleValue({ colorFormat }: ColorParams, colorNameResolver: ColorNameResolver) {
const { center, colorStops } = this;
const colorStopStyle = colorStops.map(cs => cs.toStyleValue({ colorFormat }, colorNameResolver)).join(", ");
return `radial-gradient(circle at ${new Percent(center.x).toStyleValue()} ${new Percent(center.y).toStyleValue()}, ${colorStopStyle})`;
}
}