angular-material-palette-generator
Version:
This package lets you refine the color palettes to be integrated into Sass theme files generated by the Angular CLI (`ng generate @angular/material:theme-color`).
857 lines (838 loc) • 156 kB
JavaScript
import { CdkDrag } from '@angular/cdk/drag-drop';
import * as i0 from '@angular/core';
import { inject, DOCUMENT, signal, computed, effect, Injectable, ElementRef, input, afterRenderEffect, Directive, viewChildren, output, ViewEncapsulation, Component, booleanAttribute, Pipe, model, viewChild, untracked, Injector, RendererFactory2, DestroyRef } from '@angular/core';
import * as i1$3 from '@angular/forms';
import { FormGroup, FormControl, Validators, NgControl, ReactiveFormsModule } from '@angular/forms';
import * as i3 from '@angular/material/tooltip';
import { MatTooltipModule } from '@angular/material/tooltip';
import Color from 'colorjs.io';
import * as i1 from '@angular/material/core';
import { MAT_RIPPLE_GLOBAL_OPTIONS, MatRipple } from '@angular/material/core';
import { BreakpointObserver } from '@angular/cdk/layout';
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
import * as i1$1 from '@angular/material/button';
import { MatButtonModule } from '@angular/material/button';
import * as i2 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import * as i3$3 from '@angular/material/sidenav';
import { MatSidenavModule } from '@angular/material/sidenav';
import { startWith, filter, map, shareReplay } from 'rxjs';
import { TitleCasePipe } from '@angular/common';
import * as i1$2 from '@angular/material/button-toggle';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import * as i3$2 from '@angular/material/dialog';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { contrastRatio } from 'wcag-contrast-utils';
import * as i6 from '@angular/material/form-field';
import { MatFormFieldModule } from '@angular/material/form-field';
import * as i3$1 from '@angular/material/select';
import { MatSelectModule } from '@angular/material/select';
import * as i2$1 from '@angular/material/checkbox';
import { MatCheckboxModule } from '@angular/material/checkbox';
import * as i4 from '@angular/material/input';
import { MatInputModule } from '@angular/material/input';
import * as i6$1 from '@angular/material/slider';
import { MatSliderModule } from '@angular/material/slider';
import * as i7 from '@angular/cdk/text-field';
import * as i2$2 from '@angular/material/badge';
import { MatBadgeModule } from '@angular/material/badge';
import * as i5 from '@angular/material/chips';
import { MatChipsModule } from '@angular/material/chips';
import * as i9 from '@angular/material/progress-bar';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import * as i10 from '@angular/material/radio';
import { MatRadioModule } from '@angular/material/radio';
import * as i11 from '@angular/material/slide-toggle';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import * as i12 from '@angular/material/tabs';
import { MatTabsModule } from '@angular/material/tabs';
import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
const HEX_COLOR_REGEXP = /^#?([0-9abcdef]{3}|[0-9abcdef]{6})$/i;
const HEX_COLOR_ERROR_KEY = 'hexColor';
const hexColorValidator = (control) => control.value?.match(HEX_COLOR_REGEXP) ? null : { [HEX_COLOR_ERROR_KEY]: true };
const getDefaultParams = () => ({ p1x: 0, p1y: 0, p2x: 1, p2y: 1 });
const getPaletteGenForm = () => new FormGroup({
color: new FormControl('', [Validators.required, hexColorValidator]),
start: new FormControl(0, [Validators.required]),
end: new FormControl(100, [Validators.required]),
params: new FormControl(getDefaultParams()),
reverse: new FormControl(false),
neutral: new FormControl(false),
});
const parsePaletteGenFormValue = (value) => {
try {
const formValue = JSON.parse(value);
getPaletteGenForm().setValue(formValue); // This will throw an error if the JSON is invalid
return formValue;
}
catch {
return null;
}
};
const paletteGenFormValuesEqual = (a, b) => a.color === b.color &&
a.start === b.start &&
a.end === b.end &&
a.reverse === b.reverse &&
a.neutral === b.neutral &&
a.params.p1x === b.params.p1x &&
a.params.p1y === b.params.p1y &&
a.params.p2x === b.params.p2x &&
a.params.p2y === b.params.p2y;
/* eslint-disable @typescript-eslint/no-explicit-any */
// ----
// NOTE
// ----
// Since the "bezier-easing" package is NOT ESM, we have copied/pasted the source code directly.
// - `module.exports` has been replaced by `export default`, and `var` by `const`.
// - Some types has been inferred.
/**
* https://github.com/gre/bezier-easing
* BezierEasing - use bezier curve for transition easing function
* by Gaëtan Renaudeau 2014 - 2015 – MIT License
*/
// These values are established by empiricism with tests (tradeoff: performance VS precision)
const NEWTON_ITERATIONS = 4;
const NEWTON_MIN_SLOPE = 0.001;
const SUBDIVISION_PRECISION = 0.0000001;
const SUBDIVISION_MAX_ITERATIONS = 10;
const kSplineTableSize = 11;
const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
const float32ArraySupported = typeof Float32Array === 'function';
function A(aA1, aA2) {
return 1.0 - 3.0 * aA2 + 3.0 * aA1;
}
function B(aA1, aA2) {
return 3.0 * aA2 - 6.0 * aA1;
}
function C(aA1) {
return 3.0 * aA1;
}
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function calcBezier(aT, aA1, aA2) {
return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
}
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function getSlope(aT, aA1, aA2) {
return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
}
function binarySubdivide(aX, aA, aB, mX1, mX2) {
let currentX, currentT, i = 0;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
if (currentX > 0.0) {
aB = currentT;
}
else {
aA = currentT;
}
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
return currentT;
}
function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
for (let i = 0; i < NEWTON_ITERATIONS; ++i) {
const currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) {
return aGuessT;
}
const currentX = calcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
function LinearEasing(x) {
return x;
}
function bezier(mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
throw new Error('bezier x values must be in [0, 1] range');
}
if (mX1 === mY1 && mX2 === mY2) {
return LinearEasing;
}
// Precompute samples table
const sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
for (let i = 0; i < kSplineTableSize; ++i) {
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
function getTForX(aX) {
let intervalStart = 0.0;
let currentSample = 1;
const lastSample = kSplineTableSize - 1;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
intervalStart += kSampleStepSize;
}
--currentSample;
// Interpolate to provide an initial guess for t
const dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
const guessForT = intervalStart + dist * kSampleStepSize;
const initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= NEWTON_MIN_SLOPE) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
}
else if (initialSlope === 0.0) {
return guessForT;
}
else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
}
}
return function BezierEasing(x) {
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
if (x === 0 || x === 1) {
return x;
}
return calcBezier(getTForX(x), mY1, mY2);
};
}
const cubicBezierFactory = ({ p1x, p1y, p2x, p2y }) => {
const cubicBezier = bezier(p1x, p1y, p2x, p2y);
return (x) => cubicBezier(x);
};
const buildPaletteGenFormValue = (color, params = { p1x: 0, p1y: 0, p2x: 1, p2y: 1 }, neutral = false) => ({
color,
start: 0,
end: 100,
params,
reverse: false,
neutral,
});
const percentageToRgbFactory = ({ color, params, reverse, }) => {
const cubicBezier = cubicBezierFactory(params);
const lightness = reverse
? (percent) => 1 - cubicBezier(percent / 100)
: (percent) => cubicBezier(percent / 100);
const _color = new Color(color);
return (percent) => {
_color.oklch['l'] = lightness(percent);
const hex = _color.toString({ format: 'hex' });
if (hex.length === 4) {
const [, r, g, b] = hex.split('');
return `#${r}${r}${g}${g}${b}${b}`;
}
return hex;
};
};
const buildPaletteGenData = (formValue) => {
if (!formValue) {
return { list: [], colorMap: {} };
}
const { color, start, end, params, reverse, neutral } = formValue;
const percentages = MATERIAL_PALETTE_PERCENTAGES_MAP[neutral ? 'neutral' : 'default'];
const percentageToRgb = percentageToRgbFactory({ color, params, reverse });
const list = percentages
.map((percentage) => ({
percentage,
adjustedPercentage: start + (percentage / 100) * (end - start),
}))
.map(({ percentage, adjustedPercentage }) => ({ percentage, color: percentageToRgb(adjustedPercentage) }));
const colorMap = list.reduce((map, { percentage, color }) => {
map[percentage] = color;
return map;
}, {});
return { list, colorMap };
};
const buildSassMapStringified = (formValue, dataList) => {
const settings = ` // ${JSON.stringify(formValue)}\n`;
const sassMap = dataList.map(({ percentage, color }) => ` ${percentage}: ${color},\n`).join('');
return settings + sassMap;
};
const PALETTE_FORM_CONTROL_SIZE_DEFAULT = 200;
const MATERIAL_PALETTE_PERCENTAGES_MAP = {
// Works for Material `primary`, `secondary`, `tertiary`, `neutral-variant` and `error` palettes
default: [0, 10, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 95, 98, 99, 100],
// Works for Material `neutral` palette
neutral: [0, 4, 6, 10, 12, 17, 20, 22, 24, 25, 30, 35, 40, 50, 60, 70, 80, 87, 90, 92, 94, 95, 96, 98, 99, 100],
};
// Match `$azure-palette` from https://github.com/angular/components/blob/main/src/material/core/theming/_palettes.scss
const FORM_VALUE_MAP_DEFAULT = {
primary: buildPaletteGenFormValue('#005cbb', { p1x: 0, p1y: 0.21, p2x: 1, p2y: 1 }),
secondary: buildPaletteGenFormValue('#565e71', { p1x: 0, p1y: 0.2, p2x: 1, p2y: 1 }),
tertiary: buildPaletteGenFormValue('#343dff', { p1x: 0, p1y: 0.26, p2x: 1, p2y: 1 }),
neutral: buildPaletteGenFormValue('#5e5e62', { p1x: 0, p1y: 0.2, p2x: 1, p2y: 1 }, true),
'neutral-variant': buildPaletteGenFormValue('#5b5e66', { p1x: 0, p1y: 0.2, p2x: 1, p2y: 1 }),
error: buildPaletteGenFormValue('#ba1a1a', { p1x: 0, p1y: 0.16, p2x: 0.88, p2y: 1 }),
};
const PALETTE_MODES = ['light', 'dark'];
const PALETTE_NAMES = ['primary', 'secondary', 'tertiary', 'neutral', 'neutral-variant', 'error'];
// TODO: need to refactor this service...
// TODO: add a global import...
class PaletteGenService {
document = inject(DOCUMENT);
localStorage = this.document.defaultView?.localStorage;
paletteMode = signal('light');
paletteName = signal('primary');
formValueMap = PALETTE_NAMES.reduce((map, paletteName) => {
map[paletteName] = signal(FORM_VALUE_MAP_DEFAULT[paletteName]);
return map;
}, {});
formValue = computed(() => this.formValueMap[this.paletteName()]);
dataMap = PALETTE_NAMES.reduce((map, paletteName) => {
map[paletteName] = computed(() => buildPaletteGenData(this.formValueMap[paletteName]()));
return map;
}, {});
formValueSnapshotsMap = PALETTE_NAMES.reduce((map, paletteName) => {
map[paletteName] = signal([]);
return map;
}, {});
reset() {
PALETTE_NAMES.forEach((name) => {
this.formValueMap[name].set(FORM_VALUE_MAP_DEFAULT[name]);
this.formValueSnapshotsMap[name].set([]);
});
}
controlSize = signal(PALETTE_FORM_CONTROL_SIZE_DEFAULT);
refreshCanvas;
refreshCanvasOn(trigger) {
this.refreshCanvas = trigger;
}
constructor() {
this.restoreFormValueMap();
effect(() => this.storeFormValueMap());
this.restorePaletteState();
effect(() => this.storePaletteState());
this.restoreFormValueSnapshotsMap();
effect(() => this.storeFormValueSnapshotsMap());
}
sassMapsToClipboard() {
const text = Object.entries(this.dataMap)
.map(([paletteName, data]) => {
const paletteMap = buildSassMapStringified(this.formValueMap[paletteName](), data().list);
return `${paletteName}: (\n${paletteMap}),`;
})
.join('\n');
this.document.defaultView?.navigator.clipboard?.writeText(text);
}
// ----- FormValueMap storage -----
formValueMapStorageKey = 'pg-palette-gen-service.form-value-map';
restoreFormValueMap() {
const value = this.localStorage?.getItem(this.formValueMapStorageKey);
if (!value) {
return;
}
try {
const formValueMap = JSON.parse(value);
const form = getPaletteGenForm();
Object.entries(formValueMap).forEach(([paletteName, formValue]) => {
form.setValue(formValue); // Validate each `formValue`
this.formValueMap[paletteName].set(formValue);
});
}
catch (err) {
this.localStorage?.removeItem(this.formValueMapStorageKey);
console.error('PaletteGenService: unable to restore FormValueMap', value, err);
}
}
storeFormValueMap() {
const formValueMap = Object.entries(this.formValueMap).reduce((map, [paletteName, formValue]) => {
map[paletteName] = formValue();
return map;
}, {});
this.localStorage?.setItem(this.formValueMapStorageKey, JSON.stringify(formValueMap));
}
// ----- FormValueSnapshotsMap storage -----
formValueMapSnapshotsStorageKey = 'pg-palette-gen-service.form-value-snapshots-map';
restoreFormValueSnapshotsMap() {
const value = this.localStorage?.getItem(this.formValueMapSnapshotsStorageKey);
if (!value) {
return;
}
try {
const formValueSnapshotsMap = JSON.parse(value);
const form = getPaletteGenForm();
Object.entries(formValueSnapshotsMap).forEach(([paletteName, snapshots]) => {
snapshots.forEach((snapshot) => form.setValue(JSON.parse(snapshot.value))); // Validate each `snapshot`
this.formValueSnapshotsMap[paletteName].set(snapshots);
});
}
catch (err) {
this.localStorage?.removeItem(this.formValueMapSnapshotsStorageKey);
console.error('PaletteGenService: unable to restore FormValueSnapshotsMap', value, err);
}
}
storeFormValueSnapshotsMap() {
const formValueSnapshotsMap = Object.entries(this.formValueSnapshotsMap).reduce((map, [paletteName, snapshots]) => {
map[paletteName] = snapshots();
return map;
}, {});
this.localStorage?.setItem(this.formValueMapSnapshotsStorageKey, JSON.stringify(formValueSnapshotsMap));
}
// ----- PaletteState storage -----
paletteStateStorageKey = 'pg-palette-gen-service.palette-state';
restorePaletteState() {
const value = this.localStorage?.getItem(this.paletteStateStorageKey);
if (!value) {
return;
}
try {
const { mode, name } = JSON.parse(value);
if (PALETTE_MODES.includes(mode) && PALETTE_NAMES.includes(name)) {
this.paletteMode.set(mode);
this.paletteName.set(name);
}
else {
throw new Error('Invalid palette mode and/or name');
}
}
catch (err) {
this.localStorage?.removeItem(this.paletteStateStorageKey);
console.error('PaletteGenService: unable to restore PaletteState', value, err);
}
}
storePaletteState() {
const paletteState = {
mode: this.paletteMode(),
name: this.paletteName(),
};
this.localStorage?.setItem(this.paletteStateStorageKey, JSON.stringify(paletteState));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: PaletteGenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: PaletteGenService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: PaletteGenService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [] });
class CubicBezierControlColorsDirective {
host = inject(ElementRef).nativeElement;
service = inject(PaletteGenService);
cssVarName = input.required({ alias: 'pgCubicBezierControlColors' });
rgbColor = signal(undefined); // Part of the public directive API
constructor() {
afterRenderEffect(() => {
this.service.refreshCanvas?.();
this.cssVarName();
const rgbColor = this.host.computedStyleMap().get('color')?.toString();
this.rgbColor.set(rgbColor);
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlColorsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.0", type: CubicBezierControlColorsDirective, isStandalone: true, selector: "[pgCubicBezierControlColors]", inputs: { cssVarName: { classPropertyName: "cssVarName", publicName: "pgCubicBezierControlColors", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style.color": "\"var(\" + cssVarName() + \")\"" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlColorsDirective, decorators: [{
type: Directive,
args: [{
selector: '[pgCubicBezierControlColors]',
host: {
'[style.color]': '"var(" + cssVarName() + ")"',
},
}]
}], ctorParameters: () => [] });
class CubicBezierControlColorsComponent {
cssVarConfig = input.required();
cssVarNames = computed(() => Object.values(this.cssVarConfig()));
cssVarItems = viewChildren(CubicBezierControlColorsDirective);
colorMap = computed(() => {
const keys = Object.keys(this.cssVarConfig());
return this.cssVarItems().reduce((map, item, index) => {
const rgbColor = item.rgbColor();
if (rgbColor) {
map[keys[index]] = rgbColor;
}
return map;
}, {});
});
colorMapChange = output();
constructor() {
effect(() => this.colorMapChange.emit(this.colorMap()));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlColorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: CubicBezierControlColorsComponent, isStandalone: true, selector: "pg-cubic-bezier-control-colors", inputs: { cssVarConfig: { classPropertyName: "cssVarConfig", publicName: "cssVarConfig", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { colorMapChange: "colorMapChange" }, host: { properties: { "attr.role": "\"presentation\"" }, classAttribute: ".pg-cubic-bezier-control-colors" }, viewQueries: [{ propertyName: "cssVarItems", predicate: CubicBezierControlColorsDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@for (cssVarName of cssVarNames(); track $index) {\n <i [pgCubicBezierControlColors]=\"cssVarName\"></i>\n}\n", styles: [".pg-cubic-bezier-control-colors{position:absolute;left:-99999px}\n"], dependencies: [{ kind: "directive", type: CubicBezierControlColorsDirective, selector: "[pgCubicBezierControlColors]", inputs: ["pgCubicBezierControlColors"] }], encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlColorsComponent, decorators: [{
type: Component,
args: [{ selector: 'pg-cubic-bezier-control-colors', host: {
class: '.pg-cubic-bezier-control-colors',
'[attr.role]': '"presentation"',
}, imports: [CubicBezierControlColorsDirective], encapsulation: ViewEncapsulation.None, template: "@for (cssVarName of cssVarNames(); track $index) {\n <i [pgCubicBezierControlColors]=\"cssVarName\"></i>\n}\n", styles: [".pg-cubic-bezier-control-colors{position:absolute;left:-99999px}\n"] }]
}], ctorParameters: () => [] });
class CubicBezierControlDirectionDirective {
direction = output({ alias: 'pgCubicBezierControlDirection' });
emit(event, direction) {
event.preventDefault();
this.direction.emit(direction);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlDirectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.0", type: CubicBezierControlDirectionDirective, isStandalone: true, selector: "[pgCubicBezierControlDirection]", outputs: { direction: "pgCubicBezierControlDirection" }, host: { listeners: { "keydown.ArrowUp": "emit($event, \"up\")", "keydown.ArrowRight": "emit($event, \"right\")", "keydown.ArrowDown": "emit($event, \"down\")", "keydown.ArrowLeft": "emit($event, \"left\")" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlDirectionDirective, decorators: [{
type: Directive,
args: [{
selector: '[pgCubicBezierControlDirection]',
host: {
'(keydown.ArrowUp)': 'emit($event, "up")',
'(keydown.ArrowRight)': 'emit($event, "right")',
'(keydown.ArrowDown)': 'emit($event, "down")',
'(keydown.ArrowLeft)': 'emit($event, "left")',
},
}]
}] });
class CubicBezierControlRippleDirective {
globalRippleDisabled = inject(MAT_RIPPLE_GLOBAL_OPTIONS, { optional: true })?.disabled === true;
matRipple = inject(MatRipple, { self: true });
rippleRef;
enabled = input(true, { transform: booleanAttribute, alias: 'pgCubicBezierControlRipple' });
constructor() {
this.matRipple.disabled = true; // Prevent the first self-triggered ripple
this.matRipple.color = 'rgb(from var(--mat-sys-primary) r g b / 0.24)';
this.matRipple.centered = true;
this.matRipple.unbounded = true;
this.matRipple.radius = 24;
}
launch() {
if (this.globalRippleDisabled || !this.enabled()) {
return;
}
this.matRipple.disabled = false;
this.rippleRef = this.matRipple.launch({ persistent: true });
}
fadeOut() {
if (!this.rippleRef) {
return;
}
this.rippleRef.fadeOut();
this.matRipple.disabled = true;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlRippleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.0", type: CubicBezierControlRippleDirective, isStandalone: true, selector: "[pgCubicBezierControlRipple]", inputs: { enabled: { classPropertyName: "enabled", publicName: "pgCubicBezierControlRipple", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focus": "launch()", "blur": "fadeOut()" } }, hostDirectives: [{ directive: i1.MatRipple }], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlRippleDirective, decorators: [{
type: Directive,
args: [{
selector: '[pgCubicBezierControlRipple]',
hostDirectives: [MatRipple],
host: {
'(focus)': 'launch()',
'(blur)': 'fadeOut()',
},
}]
}], ctorParameters: () => [] });
const cubicBezierParamsToPoints = ({ params: { p1x, p1y, p2x, p2y }, size, }) => {
const func = (x, y) => ({ x: x * size, y: y * size });
return {
p1: func(p1x, p1y),
p2: func(p2x, p2y),
};
};
const pointToCubicBezierParam = ({ point, container, size }) => {
const func = (_point, _container) => Math.round((1000 * (_point - _container)) / size) / 1000;
return {
x: func(point.x, container.x),
y: func(point.y, container.y),
};
};
// --------------------
class CanvasHandler {
ctx;
canvasSize;
colors;
constructor(ctx, canvasSize, colors) {
this.ctx = ctx;
this.canvasSize = canvasSize;
this.colors = colors;
}
clear() {
this.ctx.clearRect(0, 0, this.canvasSize, this.canvasSize);
return this;
}
linear() {
this.ctx.beginPath();
this.ctx.moveTo(0, 0);
this.ctx.lineWidth = 4;
this.ctx.lineTo(this.canvasSize, this.canvasSize);
this.ctx.strokeStyle = this.colors.linearColor;
this.ctx.stroke();
return this;
}
curve(interpolate) {
this.ctx.beginPath();
this.ctx.moveTo(0, 0);
this.ctx.lineWidth = 4;
this.ctx.lineJoin = 'round';
for (let step = 0; step <= this.canvasSize; step += 1) {
this.ctx.lineTo(step, interpolate(step / this.canvasSize) * this.canvasSize);
}
this.ctx.strokeStyle = this.colors.curveColor;
this.ctx.stroke();
return this;
}
sticks(params) {
this.ctx.beginPath();
this.ctx.lineWidth = 1;
this.ctx.lineCap = 'round';
this.ctx.moveTo(0, 0);
this.ctx.lineTo(this.canvasSize * params.p1x, this.canvasSize * params.p1y);
this.ctx.moveTo(this.canvasSize, this.canvasSize);
this.ctx.lineTo(this.canvasSize * params.p2x, this.canvasSize * params.p2y);
this.ctx.strokeStyle = this.colors.stickColor;
this.ctx.stroke();
return this;
}
}
// --------------------
const movePoint = ([x, y], direction, delta) => {
const more = (coord) => Math.round(Math.min(coord + delta, 1) * 100) / 100;
const less = (coord) => Math.round(Math.max(0, coord - delta) * 100) / 100;
switch (direction) {
case 'up':
return [x, less(y)];
case 'right':
return [more(x), y];
case 'down':
return [x, more(y)];
case 'left':
return [less(x), y];
}
};
const moveCubicBezierParams = ({ p1x, p1y, p2x, p2y }, p, direction, delta = 0.01) => {
if (p === 'p1') {
const [x, y] = movePoint([p1x, p1y], direction, delta);
return { p1x: x, p1y: y, p2x, p2y };
}
else {
const [x, y] = movePoint([p2x, p2y], direction, delta);
return { p1x, p1y, p2x: x, p2y: y };
}
};
class CubicBezierParamsPipe {
transform({ p1x, p1y, p2x, p2y }, p) {
let x;
let y;
if (p === 'p1') {
x = p1x;
y = p1y;
}
else {
x = p2x;
y = p2y;
}
return `x: ${x.toFixed(2)} - y: ${y.toFixed(2)}`;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierParamsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierParamsPipe, isStandalone: true, name: "cubicBezierParams" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierParamsPipe, decorators: [{
type: Pipe,
args: [{
name: 'cubicBezierParams',
}]
}] });
class CubicBezierControlComponent {
container = inject(ElementRef).nativeElement;
params = model({ p1x: 0, p1y: 0, p2x: 1, p2y: 1 });
cubicBezier = computed(() => cubicBezierFactory(this.params()));
canvasRef = viewChild.required('canvas');
canvasHandler = computed(() => {
const ctx = this.canvasRef().nativeElement.getContext('2d');
return ctx ? new CanvasHandler(ctx, this.canvasSize(), this.colorMap()) : undefined;
});
canvasSize = input(PALETTE_FORM_CONTROL_SIZE_DEFAULT);
p1 = viewChild.required('p1');
p2 = viewChild.required('p2');
disabled = model(false);
skipNextPointsUpdate = false;
cdkDrags = viewChildren(CdkDrag);
constructor() {
afterRenderEffect(() => this.updatePoints());
afterRenderEffect(() => this.updateCanvas());
const ngControl = inject(NgControl, { optional: true, self: true });
if (ngControl) {
ngControl.valueAccessor = this;
}
}
updatePoints() {
const params = this.params();
const size = this.canvasSize();
if (this.skipNextPointsUpdate) {
this.skipNextPointsUpdate = false;
return;
}
const { p1, p2 } = cubicBezierParamsToPoints({ params, size });
const [p1Drag, p2Drag] = untracked(() => this.cdkDrags());
p1Drag.setFreeDragPosition(p1);
p2Drag.setFreeDragPosition(p2);
}
updateParam(p) {
const point = this[p]().nativeElement.getBoundingClientRect();
const container = this.container.getBoundingClientRect();
const size = this.canvasSize();
this.skipNextPointsUpdate = true;
this.params.update((params) => {
const { x, y } = pointToCubicBezierParam({ point, container, size });
const newParams = { ...params };
if (p === 'p1') {
newParams.p1x = x;
newParams.p1y = y;
}
else {
newParams.p2x = x;
newParams.p2y = y;
}
return newParams;
});
this.onChange(this.params());
this.onTouched();
}
moveParams(p, direction) {
this.params.update((params) => moveCubicBezierParams(params, p, direction));
this.onChange(this.params());
this.onTouched();
}
updateCanvas() {
const canvasHandler = this.canvasHandler();
if (!canvasHandler) {
console.warn('ColorGenBezierComponent: canvas is not supported');
return;
}
canvasHandler.clear().linear().curve(this.cubicBezier()).sticks(this.params());
}
// ----- ControlValueAccessor -----
onChange = () => undefined;
onTouched = () => undefined;
registerOnChange(onChange) {
this.onChange = onChange;
}
registerOnTouched(onTouched) {
this.onTouched = onTouched;
}
writeValue(params) {
this.params.set(params ?? { p1x: 0, p1y: 0, p2x: 1, p2y: 1 });
}
setDisabledState(disabled) {
this.disabled.set(disabled);
}
// ----- Material colors in RGB (for the canvas configuration) -----
cssVarConfig = {
linearColor: '--mat-sys-surface-container-highest',
curveColor: '--mat-sys-primary',
stickColor: '--mat-sys-on-surface-variant',
};
colorMap = signal({
linearColor: 'grey',
curveColor: 'grey',
stickColor: 'grey',
});
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.0", type: CubicBezierControlComponent, isStandalone: true, selector: "pg-cubic-bezier-control", inputs: { params: { classPropertyName: "params", publicName: "params", isSignal: true, isRequired: false, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { params: "paramsChange", disabled: "disabledChange" }, host: { properties: { "class.pg-cubic-bezier-control--disabled": "disabled()", "style.--pg-cubic-bezier-control-canvas-size": "canvasSize() + \"px\"" }, classAttribute: "pg-cubic-bezier-control" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }, { propertyName: "p1", first: true, predicate: ["p1"], descendants: true, isSignal: true }, { propertyName: "p2", first: true, predicate: ["p2"], descendants: true, isSignal: true }, { propertyName: "cdkDrags", predicate: CdkDrag, descendants: true, isSignal: true }], ngImport: i0, template: "<canvas #canvas [width]=\"canvasSize()\" [height]=\"canvasSize()\" class=\"pg-cubic-bezier-control__canvas\"></canvas>\n\n<div\n class=\"pg-cubic-bezier-control__point\"\n cdkDrag\n cdkDragBoundary=\".pg-cubic-bezier-control\"\n [cdkDragDisabled]=\"disabled()\"\n (cdkDragMoved)=\"updateParam('p1')\"\n #p1\n>\n <button\n [matTooltip]=\"params() | cubicBezierParams: 'p1'\"\n matTooltipPosition=\"left\"\n [pgCubicBezierControlRipple]=\"!disabled()\"\n (pgCubicBezierControlDirection)=\"moveParams('p1', $event)\"\n >\n p1\n </button>\n</div>\n\n<div\n class=\"pg-cubic-bezier-control__point\"\n cdkDrag\n cdkDragBoundary=\".pg-cubic-bezier-control\"\n [cdkDragDisabled]=\"disabled()\"\n (cdkDragMoved)=\"updateParam('p2')\"\n #p2\n>\n <button\n [matTooltip]=\"params() | cubicBezierParams: 'p2'\"\n matTooltipPosition=\"right\"\n [pgCubicBezierControlRipple]=\"!disabled()\"\n (pgCubicBezierControlDirection)=\"moveParams('p2', $event)\"\n >\n p2\n </button>\n</div>\n\n<pg-cubic-bezier-control-colors [cssVarConfig]=\"cssVarConfig\" (colorMapChange)=\"colorMap.set($event)\" />\n", styles: [".pg-cubic-bezier-control{position:relative;display:block;width:var(--pg-cubic-bezier-control-canvas-size);height:var(--pg-cubic-bezier-control-canvas-size);transition:opacity ease .12s;text-align:left}.pg-cubic-bezier-control--disabled{opacity:.5}.pg-cubic-bezier-control__canvas{position:absolute;z-index:1;width:100%;height:100%;border-radius:.25rem;background-color:rgb(from var(--mat-sys-surface-variant) r g b/.24)}.pg-cubic-bezier-control__point{position:absolute!important;z-index:2;top:0;left:0;width:0;height:0}.pg-cubic-bezier-control__point button{content:\"\";cursor:pointer;outline:none;position:absolute;top:-.625rem;left:-.625rem;width:1.25rem;height:1.25rem;margin:0;padding:0;border-radius:99px;border:none;background:var(--mat-sys-primary);color:transparent;line-height:inherit;text-align:inherit;font:inherit;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: CubicBezierControlColorsComponent, selector: "pg-cubic-bezier-control-colors", inputs: ["cssVarConfig"], outputs: ["colorMapChange"] }, { kind: "directive", type: CubicBezierControlDirectionDirective, selector: "[pgCubicBezierControlDirection]", outputs: ["pgCubicBezierControlDirection"] }, { kind: "directive", type: CubicBezierControlRippleDirective, selector: "[pgCubicBezierControlRipple]", inputs: ["pgCubicBezierControlRipple"] }, { kind: "pipe", type: CubicBezierParamsPipe, name: "cubicBezierParams" }], encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: CubicBezierControlComponent, decorators: [{
type: Component,
args: [{ selector: 'pg-cubic-bezier-control', host: {
class: 'pg-cubic-bezier-control',
'[class.pg-cubic-bezier-control--disabled]': 'disabled()',
'[style.--pg-cubic-bezier-control-canvas-size]': 'canvasSize() + "px"',
}, imports: [
CdkDrag,
MatTooltipModule,
CubicBezierControlColorsComponent,
CubicBezierControlDirectionDirective,
CubicBezierControlRippleDirective,
CubicBezierParamsPipe,
], encapsulation: ViewEncapsulation.None, template: "<canvas #canvas [width]=\"canvasSize()\" [height]=\"canvasSize()\" class=\"pg-cubic-bezier-control__canvas\"></canvas>\n\n<div\n class=\"pg-cubic-bezier-control__point\"\n cdkDrag\n cdkDragBoundary=\".pg-cubic-bezier-control\"\n [cdkDragDisabled]=\"disabled()\"\n (cdkDragMoved)=\"updateParam('p1')\"\n #p1\n>\n <button\n [matTooltip]=\"params() | cubicBezierParams: 'p1'\"\n matTooltipPosition=\"left\"\n [pgCubicBezierControlRipple]=\"!disabled()\"\n (pgCubicBezierControlDirection)=\"moveParams('p1', $event)\"\n >\n p1\n </button>\n</div>\n\n<div\n class=\"pg-cubic-bezier-control__point\"\n cdkDrag\n cdkDragBoundary=\".pg-cubic-bezier-control\"\n [cdkDragDisabled]=\"disabled()\"\n (cdkDragMoved)=\"updateParam('p2')\"\n #p2\n>\n <button\n [matTooltip]=\"params() | cubicBezierParams: 'p2'\"\n matTooltipPosition=\"right\"\n [pgCubicBezierControlRipple]=\"!disabled()\"\n (pgCubicBezierControlDirection)=\"moveParams('p2', $event)\"\n >\n p2\n </button>\n</div>\n\n<pg-cubic-bezier-control-colors [cssVarConfig]=\"cssVarConfig\" (colorMapChange)=\"colorMap.set($event)\" />\n", styles: [".pg-cubic-bezier-control{position:relative;display:block;width:var(--pg-cubic-bezier-control-canvas-size);height:var(--pg-cubic-bezier-control-canvas-size);transition:opacity ease .12s;text-align:left}.pg-cubic-bezier-control--disabled{opacity:.5}.pg-cubic-bezier-control__canvas{position:absolute;z-index:1;width:100%;height:100%;border-radius:.25rem;background-color:rgb(from var(--mat-sys-surface-variant) r g b/.24)}.pg-cubic-bezier-control__point{position:absolute!important;z-index:2;top:0;left:0;width:0;height:0}.pg-cubic-bezier-control__point button{content:\"\";cursor:pointer;outline:none;position:absolute;top:-.625rem;left:-.625rem;width:1.25rem;height:1.25rem;margin:0;padding:0;border-radius:99px;border:none;background:var(--mat-sys-primary);color:transparent;line-height:inherit;text-align:inherit;font:inherit;-webkit-user-select:none;user-select:none}\n"] }]
}], ctorParameters: () => [] });
class PreferBlackForgroundColorPipe {
transform(backgroundColor) {
return contrastRatio(backgroundColor, '#fff') < contrastRatio(backgroundColor, '#000');
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: PreferBlackForgroundColorPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.0", ngImport: i0, type: PreferBlackForgroundColorPipe, isStandalone: true, name: "preferBlackForgroundColor" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: PreferBlackForgroundColorPipe, decorators: [{
type: Pipe,
args: [{
name: 'preferBlackForgroundColor',
}]
}] });
class PaletteGenOverviewComponent {
service = inject(PaletteGenService);
percentages = MATERIAL_PALETTE_PERCENTAGES_MAP.default;
overview = computed(() => {
return Object.entries(this.service.dataMap).reduce((acc, [paletteName, data]) => {
acc.push({ paletteName: paletteName, dataList: data().list });
return acc;
}, []);
});
compact = input(false);
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: PaletteGenOverviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: PaletteGenOverviewComponent, isStandalone: true, selector: "pg-palette-gen-overview", inputs: { compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "pg-palette-gen-overview" }, ngImport: i0, template: "@for (overviewItem of overview(); track $index) {\n <h2 class=\"pg-palette-gen-overview__name\">{{ overviewItem.paletteName | titlecase }}</h2>\n\n <div class=\"pg-palette-gen-overview__list\">\n @for (dataListItem of overviewItem.dataList; track $index) {\n @if (percentages.includes(dataListItem.percentage)) {\n <span\n [matTooltip]=\"dataListItem.color\"\n class=\"pg-palette-gen-overview__item\"\n [class.pg-palette-gen-overview__item--prefer-black]=\"dataListItem.color | preferBlackForgroundColor\"\n [class.pg-palette-gen-overview__item--compact]=\"compact()\"\n [style.background-color]=\"dataListItem.color\"\n >\n {{ dataListItem.percentage }}\n </span>\n }\n }\n </div>\n}\n", styles: [".pg-palette-gen-overview__name{margin:1rem 0 .5rem;font:var(--mat-sys-title-medium);letter-spacing:var(--mat-sys-title-medium-tracking)}.pg-palette-gen-overview__list{display:flex}.pg-palette-gen-overview__item{height:4rem;line-height:4rem;flex-basis:3rem;text-align:center;font-size:var(--pl-font-size-monospace, .85rem);font-family:var(--pl-font-family-monospace, monospace);font-optical-sizing:auto;font-weight:400;font-style:normal;border:1px solid rgba(255,255,255,.1);border-width:0 0 0 1px;color:#fff;transition:all ease .1s;transform-origin:center 3.5rem}.pg-palette-gen-overview__item--prefer-black{border:1px solid rgba(0,0,0,.05);border-width:0 0 0 1px;color:#000}.pg-palette-gen-overview__item:first-child{border-radius:.25rem 0 0 .25rem}.pg-palette-gen-overview__item:last-child{border-radius:0 .25rem .25rem 0}.pg-palette-gen-overview__item:hover{z-index:1;border-radius:.25rem;border-width:1px;transform:scale(1.5)}.pg-palette-gen-overview__item--compact{height:3rem;line-height:3rem;transform-origin:center 2.5rem}\n"], dependencies: [{ kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: PreferBlackForgroundColorPipe, name: "preferBlackForgroundColor" }], encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: PaletteGenOverviewComponent, decorators: [{
type: Component,
args: [{ selector: 'pg-palette-gen-overview', host: { class: 'pg-palette-gen-overview' }, imports: [TitleCasePipe, MatTooltipModule, PreferBlackForgroundColorPipe], encapsulation: ViewEncapsulation.None, template: "@for (overviewItem of overview(); track $index) {\n <h2 class=\"pg-palette-gen-overview__name\">{{ overviewItem.paletteName | titlecase }}</h2>\n\n <div class=\"pg-palette-gen-overview__list\">\n @for (dataListItem of overviewItem.dataList; track $index) {\n @if (percentages.includes(dataListItem.percentage)) {\n <span\n [matTooltip]=\"dataListItem.color\"\n class=\"pg-palette-gen-overview__item\"\n [class.pg-palette-gen-overview__item--prefer-black]=\"dataListItem.color | preferBlackForgroundColor\"\n [class.pg-palette-gen-overview__item--compact]=\"compact()\"\n [style.background-color]=\"dataListItem.color\"\n >\n {{ dataListItem.percentage }}\n </span>\n }\n }\n </div>\n}\n", styles: [".pg-palette-gen-overview__name{margin:1rem 0 .5rem;font:var(--mat-sys-title-medium);letter-spacing:var(--mat-sys-title-medium-tracking)}.pg-palette-gen-overview__list{display:flex}.pg-palette-gen-overview__item{height:4rem;line-height:4rem;flex-basis:3rem;text-align:center;font-size:var(--pl-font-size-monospace, .85rem);font-family:var(--pl-font-family-monospace, monospace);font-optical-sizing:auto;font-weight:400;font-style:normal;border:1px solid rgba(255,255,255,.1);border-width:0 0 0 1px;color:#fff;transition:all ease .1s;transform-origin:center 3.5rem}.pg-palette-gen-overview__item--prefer-black{border:1px solid rgba(0,0,0,.05);border-width:0 0 0 1px;color:#000}.pg-palette-gen-overview__item:first-child{border-radius:.25rem 0 0 .25rem}.pg-palette-gen-overview__item:last-child{border-radius:0 .25rem .25rem 0}.pg-palette-gen-overview__item:hover{z-index:1;border-radius:.25rem;border-width:1px;transform:scale(1.5)}.pg-palette-gen-overview__item--compact{height:3rem;line-height:3rem;transform-origin:center 2.5rem}\n"] }]
}] });
// According to WCAG 2.1 guidelines, the required contrast ratios for normal text are:
// - AA: 4.5
// - AAA: 7
class WcagContrastRatioCompliancePipe {
transform(colorA, colorB) {
if (!colorB) {
return undefined;
}
const ratio = contrastRatio(colorA, colorB);
if (ratio >= 7) {
return { icon: 'done_all', label: 'WCAG 2 AAA Compliant' };
}
if (ratio >= 4.5) {
return { icon: 'check', label: 'WCAG 2 AA Compliant' };
}
return { icon: 'warning', label: 'Not WCAG Compliant' };
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: WcagContrastRatioCompliancePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.0", ngImport: i0, type: WcagContrastRatioCompliancePipe, isStandalone: true, name: "wcagContrastRatioCompliance" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: WcagContrastRatioCompliancePipe, decorators: [{
type: Pipe,
args: [{
name: 'wcagContrastRatioCompliance',
}]
}] });
// DO NOT MODIFY THE FOLLOWING OBJECTS MANUALLY
// --------------------------------------------
// The content of following objects has been generated from the script:
// `<rootDir>/palette-matching/palette-matching.script.ts`
const PALETTE_TOKEN_MATCHING_MAP = {
primary: {
light: {
'10': ['on-primary-container', 'on-primary-fixed'],
'30': ['on-primary-fixed-variant'],
'40': ['primary', 'surface-tint'],
'80': ['inverse-primary', 'primary-fixed-dim'],
'90': ['primary-container', 'primary-fixed'],
'100': ['on-primary'],
},
dark: {
'10': ['on-primary-fixed'],
'20': ['on-primary'],
'30': ['primary-container', 'on-primary-fixed-variant'],
'40': ['inverse-primary'],
'80': ['primary', 'primary-fixed-dim', 'surface-tint'],
'90': ['on-primary-container', 'primary-fixed'],
},
},
secondary: {
light: {
'10': ['on-secondary-container', 'on-secondary-fixed'],
'30': ['on-secondary-fixed-variant'],
'40': ['secondary'],
'80': ['secondary-fixed-dim'],
'90': ['secondary-container', 'secondary-fixed'],
'100': ['on-secondary'],
},
dark: {
'10': ['on-secondary-fixed'],
'20': ['on-secondary'],
'30': ['secondary-container', 'on-secondary-fixed-variant'],
'80': ['secondary', 'secondary-fixed-dim'],
'90': ['on-secondary-container', 'secondary-fixed'],
},
},
tertiary: {
light: {
'10': ['on-tertiary-container', 'on-tertiary-fixed'],
'30': ['on-tertiary-fixed-variant'],
'40': ['tertiary'],
'80': ['tertiary-fixed-dim'],
'90': ['tertiary-contai