UNPKG

primeng

Version:

PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,

1,286 lines (1,280 loc) 102 kB
export * from 'primeng/types/inputcolor'; import * as i0 from '@angular/core'; import { InjectionToken, inject, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, input, booleanAttribute, effect, Directive, Injectable, forwardRef, signal, output, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { SharedModule } from 'primeng/api'; import { BaseComponent, PARENT_INSTANCE } from 'primeng/basecomponent'; import * as i1 from 'primeng/bind'; import { Bind } from 'primeng/bind'; import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common'; import { ButtonDirective, ButtonIcon } from 'primeng/button'; import * as i1$1 from 'primeng/inputtext'; import { InputText } from 'primeng/inputtext'; import { style } from '@primeuix/styles/inputcolor'; import { BaseStyle } from 'primeng/base'; function clamp(value, min, max) { return Math.min(Math.max(value, min), max); } function round(value, decimals = 0) { const factor = Math.pow(10, decimals); return Math.round(value * factor) / factor; } function multiplyMatrices(matrix, vector) { return [matrix[0] * vector[0] + matrix[1] * vector[1] + matrix[2] * vector[2], matrix[3] * vector[0] + matrix[4] * vector[1] + matrix[5] * vector[2], matrix[6] * vector[0] + matrix[7] * vector[1] + matrix[8] * vector[2]]; } function mod(n, m) { return ((n % m) + m) % m; } /** * Snaps a value to the nearest step increment within min/max bounds. * @example snap(23.7, 0, 100, 5) => 25 * @example snap(0.234, 0, 1, 0.01) => 0.23 */ function snapValue(value, min, max, step) { const clamped = clamp(value, min, max); const offset = clamped - min; const steps = Math.round(offset / step); const snapped = min + steps * step; const precision = (step.toString().split('.')[1] || '').length; return parseFloat(snapped.toFixed(precision)); } class Color { get alpha() { return this.getChannelValue('alpha'); } getSpaceAxes(xyChannels) { const { xChannel, yChannel } = xyChannels; if (xChannel === yChannel) { throw new Error('xChannel and yChannel cannot be the same'); } const zChannel = this.getChannels().find((channel) => channel !== xChannel && channel !== yChannel); if (!zChannel) { throw new Error('zChannel not found'); } return { xChannel, yChannel, zChannel: zChannel }; } incChannelValue(channel, step) { const range = this.getChannelRange(channel); const currentValue = this.getChannelValue(channel); const newValue = snapValue(clamp(currentValue + step, range.minValue, range.maxValue), range.minValue, range.maxValue, range.step); return this.setChannelValue(channel, newValue); } decChannelValue(channel, step) { return this.incChannelValue(channel, -step); } toHex() { const rgb = this.toRGB(); const r = Math.round(rgb.red).toString(16).padStart(2, '0'); const g = Math.round(rgb.green).toString(16).padStart(2, '0'); const b = Math.round(rgb.blue).toString(16).padStart(2, '0'); return `#${r}${g}${b}`; } toHexa() { const hex = this.toHex(); if (this.alpha < 1) { const a = Math.round(this.alpha * 255) .toString(16) .padStart(2, '0'); return `${hex}${a}`; } return hex; } toHexInt() { const rgb = this.toRGB(); return (Math.round(rgb.red) << 16) | (Math.round(rgb.green) << 8) | Math.round(rgb.blue); } toRgbString() { const rgb = this.toRGB(); const r = Math.round(rgb.red); const g = Math.round(rgb.green); const b = Math.round(rgb.blue); if (this.alpha < 1) { return `rgba(${r}, ${g}, ${b}, ${round(this.alpha, 2)})`; } return `rgb(${r}, ${g}, ${b})`; } toHslString() { const hsl = this.toHSL(); const h = Math.round(hsl.hue) % 360; const s = Math.round(hsl.saturation); const l = Math.round(hsl.lightness); if (this.alpha < 1) { return `hsla(${h}, ${s}%, ${l}%, ${round(this.alpha, 2)})`; } return `hsl(${h}, ${s}%, ${l}%)`; } toHsbString() { const hsb = this.toHSB(); const h = Math.round(hsb.hue) % 360; const s = Math.round(hsb.saturation); const b = Math.round(hsb.brightness); if (this.alpha < 1) { return `hsba(${h}, ${s}%, ${b}%, ${round(this.alpha, 2)})`; } return `hsb(${h}, ${s}%, ${b}%)`; } toString(format) { const f = format || this.colorSpace; switch (f) { case 'hex': return this.toHex(); case 'hexa': return this.toHexa(); case 'rgb': case 'rgba': return this.toRgbString(); case 'hsl': case 'hsla': return this.toHslString(); case 'hsb': case 'hsba': return this.toHsbString(); case 'oklch': return this.toOKLCH().toString('oklch'); case 'oklcha': return this.toOKLCH().toString('oklcha'); case 'css': return this.toHex(); default: return this.toHex(); } } toFormat(format) { switch (format) { case 'hsba': return this.toHSB(); case 'hsla': return this.toHSL(); case 'rgba': return this.toRGB(); case 'hexa': return this.toRGB(); case 'oklch': return this.toOKLCH(); default: return this.toHSB(); } } } class HSBColor extends Color { hue; saturation; brightness; _alpha; colorSpace = 'hsba'; constructor(hue, saturation, brightness, _alpha = 1) { super(); this.hue = hue; this.saturation = saturation; this.brightness = brightness; this._alpha = _alpha; this.hue = hue >= 0 && hue <= 360 ? hue : mod(hue, 360); this.saturation = clamp(saturation, 0, 100); this.brightness = clamp(brightness, 0, 100); this._alpha = clamp(_alpha, 0, 1); } getChannelValue(channel) { switch (channel) { case 'hue': return this.hue; case 'saturation': return this.saturation; case 'brightness': return this.brightness; case 'alpha': return this._alpha; case 'lightness': return this.toHSL().getChannelValue(channel); case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': return this.toOKLCH().getChannelValue(channel); default: return this.toRGB().getChannelValue(channel); } } setChannelValue(channel, value) { switch (channel) { case 'hue': return new HSBColor(value, this.saturation, this.brightness, this._alpha); case 'saturation': return new HSBColor(this.hue, value, this.brightness, this._alpha); case 'brightness': return new HSBColor(this.hue, this.saturation, value, this._alpha); case 'alpha': return new HSBColor(this.hue, this.saturation, this.brightness, value); case 'lightness': { const hsl = this.toHSL().setChannelValue(channel, value); return hsl.toHSB(); } case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': { const oklch = this.toOKLCH().setChannelValue(channel, value); return oklch.toHSB(); } default: { const rgb = this.toRGB().setChannelValue(channel, value); return rgb.toHSB(); } } } toHSB() { return this.clone(); } toHSL() { const h = this.hue; const s = this.saturation / 100; const b = this.brightness / 100; const l = b * (1 - s / 2); const sl = l === 0 || l === 1 ? 0 : ((b - l) / Math.min(l, 1 - l)) * 100; return new HSLColor(h, sl, l * 100, this._alpha); } toRGB() { const h = this.hue / 360; const s = this.saturation / 100; const b = this.brightness / 100; let r, g, bl; const i = Math.floor(h * 6); const f = h * 6 - i; const p = b * (1 - s); const q = b * (1 - f * s); const t = b * (1 - (1 - f) * s); switch (i % 6) { case 0: r = b; g = t; bl = p; break; case 1: r = q; g = b; bl = p; break; case 2: r = p; g = b; bl = t; break; case 3: r = p; g = q; bl = b; break; case 4: r = t; g = p; bl = b; break; case 5: r = b; g = p; bl = q; break; default: r = 0; g = 0; bl = 0; } return new RGBColor(r * 255, g * 255, bl * 255, this._alpha); } toOKLCH() { return this.toRGB().toOKLCH(); } clone() { return new HSBColor(this.hue, this.saturation, this.brightness, this._alpha); } toJSON() { return { hue: this.hue, saturation: this.saturation, brightness: this.brightness, alpha: this._alpha }; } getFormat() { return 'hsba'; } getChannels() { return ['hue', 'saturation', 'brightness']; } getChannelRange(channel) { switch (channel) { case 'hue': return { minValue: 0, maxValue: 360, step: 1, pageStep: 15 }; case 'saturation': case 'brightness': return { minValue: 0, maxValue: 100, step: 1, pageStep: 10 }; case 'alpha': return { minValue: 0, maxValue: 1, step: 0.01, pageStep: 0.1 }; case 'lightness': return this.toHSL().getChannelRange(channel); case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': return this.toOKLCH().getChannelRange(channel); case 'red': case 'green': case 'blue': return this.toRGB().getChannelRange(channel); default: throw new Error(`Unknown color channel: ${channel}`); } } } class HSLColor extends Color { hue; saturation; lightness; _alpha; colorSpace = 'hsla'; constructor(hue, saturation, lightness, _alpha = 1) { super(); this.hue = hue; this.saturation = saturation; this.lightness = lightness; this._alpha = _alpha; this.hue = hue >= 0 && hue <= 360 ? hue : mod(hue, 360); this.saturation = clamp(saturation, 0, 100); this.lightness = clamp(lightness, 0, 100); this._alpha = clamp(_alpha, 0, 1); } getChannelValue(channel) { switch (channel) { case 'hue': return this.hue; case 'saturation': return this.saturation; case 'lightness': return this.lightness; case 'alpha': return this._alpha; case 'brightness': return this.toHSB().getChannelValue(channel); case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': return this.toOKLCH().getChannelValue(channel); default: return this.toRGB().getChannelValue(channel); } } setChannelValue(channel, value) { switch (channel) { case 'hue': return new HSLColor(value, this.saturation, this.lightness, this._alpha); case 'saturation': return new HSLColor(this.hue, value, this.lightness, this._alpha); case 'lightness': return new HSLColor(this.hue, this.saturation, value, this._alpha); case 'alpha': return new HSLColor(this.hue, this.saturation, this.lightness, value); case 'brightness': { const hsb = this.toHSB().setChannelValue(channel, value); return hsb.toHSL(); } case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': { const oklch = this.toOKLCH().setChannelValue(channel, value); return oklch.toHSL(); } default: { const rgb = this.toRGB().setChannelValue(channel, value); return rgb.toHSL(); } } } toHSB() { const h = this.hue; const s = this.saturation / 100; const l = this.lightness / 100; const b = l + s * Math.min(l, 1 - l); const sb = b === 0 ? 0 : 2 * (1 - l / b); return new HSBColor(h, sb * 100, b * 100, this._alpha); } toHSL() { return this.clone(); } toRGB() { const h = this.hue; const s = this.saturation / 100; const l = this.lightness / 100; const a = s * Math.min(l, 1 - l); const f = (n) => { const k = (n + h / 30) % 12; return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); }; return new RGBColor(f(0) * 255, f(8) * 255, f(4) * 255, this._alpha); } toOKLCH() { return this.toRGB().toOKLCH(); } clone() { return new HSLColor(this.hue, this.saturation, this.lightness, this._alpha); } toJSON() { return { hue: this.hue, saturation: this.saturation, lightness: this.lightness, alpha: this._alpha }; } getFormat() { return 'hsla'; } getChannels() { return ['hue', 'saturation', 'lightness']; } getChannelRange(channel) { switch (channel) { case 'hue': return { minValue: 0, maxValue: 360, step: 1, pageStep: 15 }; case 'saturation': case 'lightness': return { minValue: 0, maxValue: 100, step: 1, pageStep: 10 }; case 'alpha': return { minValue: 0, maxValue: 1, step: 0.01, pageStep: 0.1 }; case 'brightness': return this.toHSB().getChannelRange(channel); case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': return this.toOKLCH().getChannelRange(channel); case 'red': case 'green': case 'blue': return this.toRGB().getChannelRange(channel); default: throw new Error(`Unknown color channel: ${channel}`); } } } class RGBColor extends Color { red; green; blue; _alpha; colorSpace = 'rgba'; constructor(red, green, blue, _alpha = 1) { super(); this.red = red; this.green = green; this.blue = blue; this._alpha = _alpha; this.red = clamp(red, 0, 255); this.green = clamp(green, 0, 255); this.blue = clamp(blue, 0, 255); this._alpha = clamp(_alpha, 0, 1); } getChannelValue(channel) { switch (channel) { case 'red': return this.red; case 'green': return this.green; case 'blue': return this.blue; case 'alpha': return this._alpha; case 'hue': case 'saturation': case 'brightness': return this.toHSB().getChannelValue(channel); case 'lightness': return this.toHSL().getChannelValue(channel); case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': return this.toOKLCH().getChannelValue(channel); default: return this.toHSB().getChannelValue(channel); } } setChannelValue(channel, value) { switch (channel) { case 'red': return new RGBColor(value, this.green, this.blue, this._alpha); case 'green': return new RGBColor(this.red, value, this.blue, this._alpha); case 'blue': return new RGBColor(this.red, this.green, value, this._alpha); case 'alpha': return new RGBColor(this.red, this.green, this.blue, value); case 'hue': case 'saturation': case 'brightness': { const hsb = this.toHSB().setChannelValue(channel, value); return hsb.toRGB(); } case 'lightness': { const hsl = this.toHSL().setChannelValue(channel, value); return hsl.toRGB(); } case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': { const oklch = this.toOKLCH().setChannelValue(channel, value); return oklch.toRGB(); } default: { const hsb = this.toHSB().setChannelValue(channel, value); return hsb.toRGB(); } } } toHSB() { const r = this.red / 255; const g = this.green / 255; const b = this.blue / 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); const d = max - min; let h = 0; const s = max === 0 ? 0 : d / max; const v = max; if (d !== 0) { switch (max) { case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break; case g: h = ((b - r) / d + 2) / 6; break; case b: h = ((r - g) / d + 4) / 6; break; } } return new HSBColor(h * 360, s * 100, v * 100, this._alpha); } toHSL() { const r = this.red / 255; const g = this.green / 255; const b = this.blue / 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); const d = max - min; const l = (max + min) / 2; let h = 0; let s = 0; if (d !== 0) { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break; case g: h = ((b - r) / d + 2) / 6; break; case b: h = ((r - g) / d + 4) / 6; break; } } return new HSLColor(h * 360, s * 100, l * 100, this._alpha); } toRGB() { return this.clone(); } toOKLCH() { const rgb = [this.red / 255, this.green / 255, this.blue / 255]; const rgbLinear = rgb.map((c) => (Math.abs(c) <= 0.04045 ? c / 12.92 : (c < 0 ? -1 : 1) * ((Math.abs(c) + 0.055) / 1.055) ** 2.4)); const xyz = multiplyMatrices([0.41239079926595934, 0.357584339383878, 0.1804807884018343, 0.21263900587151027, 0.715168678767756, 0.07219231536073371, 0.01933081871559182, 0.11919477979462598, 0.9505321522496607], rgbLinear); const LMS = multiplyMatrices([0.819022437996703, 0.3619062600528904, -0.1288737815209879, 0.0329836539323885, 0.9292868615863434, 0.0361446663506424, 0.0481771893596242, 0.2642395317527308, 0.6335478284694309], xyz); const LMSg = LMS.map((val) => Math.cbrt(val)); const [L, a, b] = multiplyMatrices([0.210454268309314, 0.7936177747023054, -0.0040720430116193, 1.9779985324311684, -2.4285922420485799, 0.450593709617411, 0.0259040424655478, 0.7827717124575296, -0.8086757549230774], LMSg); const C = Math.sqrt(a ** 2 + b ** 2); const H = Math.abs(a) < 0.0002 && Math.abs(b) < 0.0002 ? NaN : ((((Math.atan2(b, a) * 180) / Math.PI) % 360) + 360) % 360; const outL = Number(Math.min(1, Math.max(0, L)).toFixed(4)); const outC = Number(C.toFixed(4)); const outH = Number.isNaN(H) ? NaN : Number(H.toFixed(2)); return new OKLCHColor(outL, outC, outH, Number(this._alpha.toFixed(2))); } clone() { return new RGBColor(this.red, this.green, this.blue, this._alpha); } toJSON() { return { red: this.red, green: this.green, blue: this.blue, alpha: this._alpha }; } getFormat() { return 'rgba'; } getChannels() { return ['red', 'green', 'blue']; } getChannelRange(channel) { switch (channel) { case 'red': case 'green': case 'blue': return { minValue: 0, maxValue: 255, step: 1, pageStep: 17 }; case 'alpha': return { minValue: 0, maxValue: 1, step: 0.01, pageStep: 0.1 }; case 'hue': case 'saturation': case 'brightness': return this.toHSB().getChannelRange(channel); case 'lightness': return this.toHSL().getChannelRange(channel); case 'L': case 'C': case 'H': case 'oklchLightness': case 'oklchChroma': case 'oklchHue': return this.toOKLCH().getChannelRange(channel); default: throw new Error(`Unknown color channel: ${channel}`); } } } class OKLCHColor extends Color { L; C; H; _alpha; colorSpace = 'oklch'; constructor(L, C, H, _alpha = 1) { super(); this.L = L; this.C = C; this.H = H; this._alpha = _alpha; this.L = clamp(L, 0, 1); this.C = clamp(C, 0, 0.4); this.H = Number.isNaN(H) ? NaN : H >= 0 && H <= 360 ? H : mod(H, 360); this._alpha = clamp(_alpha, 0, 1); } getChannelValue(channel) { switch (channel) { case 'L': case 'oklchLightness': return this.L; case 'C': case 'oklchChroma': return this.C; case 'H': case 'oklchHue': return this.H; case 'alpha': return this._alpha; default: return this.toRGB().getChannelValue(channel); } } setChannelValue(channel, value) { switch (channel) { case 'L': case 'oklchLightness': return new OKLCHColor(value, this.C, this.H, this._alpha); case 'C': case 'oklchChroma': return new OKLCHColor(this.L, value, this.H, this._alpha); case 'H': case 'oklchHue': return new OKLCHColor(this.L, this.C, value, this._alpha); case 'alpha': return new OKLCHColor(this.L, this.C, this.H, value); default: { const rgb = this.toRGB().setChannelValue(channel, value); return rgb.toOKLCH(); } } } toHSB() { return this.toRGB().toHSB(); } toHSL() { return this.toRGB().toHSL(); } toRGB() { const hRad = (this.H * Math.PI) / 180; const a = Number.isNaN(this.H) ? 0 : this.C * Math.cos(hRad); const b = Number.isNaN(this.H) ? 0 : this.C * Math.sin(hRad); const l_ = this.L + 0.3963377774 * a + 0.2158037573 * b; const m_ = this.L - 0.1055613458 * a - 0.0638541728 * b; const s_ = this.L - 0.0894841775 * a - 1.291485548 * b; const l = l_ * l_ * l_; const m = m_ * m_ * m_; const s = s_ * s_ * s_; const lr = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s; const lg = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s; const lb = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s; const toSrgb = (c) => { if (c <= 0.0031308) return c * 12.92; return 1.055 * Math.pow(c, 1 / 2.4) - 0.055; }; return new RGBColor(clamp(toSrgb(lr) * 255, 0, 255), clamp(toSrgb(lg) * 255, 0, 255), clamp(toSrgb(lb) * 255, 0, 255), this._alpha); } toOKLCH() { return this.clone(); } toString(format) { const f = format || this.colorSpace; switch (f) { case 'oklch': { const l = Number.isNaN(this.L) ? 0 : Number((this.L * 100).toFixed(2)); const c = Number.isNaN(this.C) ? 0 : Number(this.C.toFixed(4)); const h = Number.isNaN(this.H) ? 0 : Number(this.H.toFixed(2)); return `oklch(${l}% ${c} ${h})`; } case 'oklcha': case 'css': { const l = Number.isNaN(this.L) ? 0 : Number((this.L * 100).toFixed(2)); const c = Number.isNaN(this.C) ? 0 : Number(this.C.toFixed(4)); const h = Number.isNaN(this.H) ? 0 : Number(this.H.toFixed(2)); const a = Number.isNaN(this._alpha) ? 1 : Number(this._alpha.toFixed(2)); return `oklch(${l}% ${c} ${h} / ${a})`; } default: return super.toString(f); } } clone() { return new OKLCHColor(this.L, this.C, this.H, this._alpha); } toJSON() { return { L: this.L, C: this.C, H: this.H, alpha: this._alpha }; } getFormat() { return 'oklch'; } getChannels() { return ['L', 'C', 'H']; } getChannelRange(channel) { switch (channel) { case 'L': case 'oklchLightness': return { minValue: 0, maxValue: 1, step: 0.01, pageStep: 0.1 }; case 'C': case 'oklchChroma': return { minValue: 0, maxValue: 0.4, step: 0.01, pageStep: 0.05 }; case 'H': case 'oklchHue': return { minValue: 0, maxValue: 360, step: 1, pageStep: 15 }; case 'alpha': return { minValue: 0, maxValue: 1, step: 0.01, pageStep: 0.1 }; case 'hue': case 'saturation': case 'brightness': return this.toHSB().getChannelRange(channel); case 'lightness': return this.toHSL().getChannelRange(channel); case 'red': case 'green': case 'blue': return this.toRGB().getChannelRange(channel); default: throw new Error(`Unknown color channel: ${channel}`); } } } function parseColor(value) { if (!value) return null; if (value instanceof Color) { return value; } if (typeof value !== 'string') return null; const str = value.trim(); const hexMatch = str.match(/^#?([0-9a-f]{3,8})$/i); if (hexMatch) { let hex = hexMatch[1]; if (hex.length === 3) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } else if (hex.length === 4) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]; } if (hex.length === 6) { const r = parseInt(hex.substring(0, 2), 16); const g = parseInt(hex.substring(2, 4), 16); const b = parseInt(hex.substring(4, 6), 16); return new RGBColor(r, g, b, 1); } if (hex.length === 8) { const r = parseInt(hex.substring(0, 2), 16); const g = parseInt(hex.substring(2, 4), 16); const b = parseInt(hex.substring(4, 6), 16); const a = parseInt(hex.substring(6, 8), 16) / 255; return new RGBColor(r, g, b, a); } } const rgbMatch = str.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)$/i); if (rgbMatch) { return new RGBColor(parseInt(rgbMatch[1]), parseInt(rgbMatch[2]), parseInt(rgbMatch[3]), rgbMatch[4] !== undefined ? parseFloat(rgbMatch[4]) : 1); } const hslMatch = str.match(/^hsla?\(\s*([\d.]+)\s*,\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*(?:,\s*([\d.]+))?\s*\)$/i); if (hslMatch) { return new HSLColor(parseFloat(hslMatch[1]), parseFloat(hslMatch[2]), parseFloat(hslMatch[3]), hslMatch[4] !== undefined ? parseFloat(hslMatch[4]) : 1); } const hsbMatch = str.match(/^hsba?\(\s*([\d.]+)\s*,\s*([\d.]+)%?\s*,\s*([\d.]+)%?\s*(?:,\s*([\d.]+))?\s*\)$/i); if (hsbMatch) { return new HSBColor(parseFloat(hsbMatch[1]), parseFloat(hsbMatch[2]), parseFloat(hsbMatch[3]), hsbMatch[4] !== undefined ? parseFloat(hsbMatch[4]) : 1); } const oklchMatch = str.match(/^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)\s*(?:\/\s*([\d.]+))?\s*\)$/i); if (oklchMatch) { const lVal = parseFloat(oklchMatch[1]); const l = oklchMatch[2] === '%' ? lVal / 100 : lVal; return new OKLCHColor(l, parseFloat(oklchMatch[3]), parseFloat(oklchMatch[4]), oklchMatch[5] !== undefined ? parseFloat(oklchMatch[5]) : 1); } return null; } function getChannelRange(channel) { switch (channel) { case 'hue': return { minValue: 0, maxValue: 360, step: 1, pageStep: 15 }; case 'H': case 'oklchHue': return { minValue: 0, maxValue: 360, step: 1, pageStep: 15 }; case 'saturation': case 'brightness': case 'lightness': return { minValue: 0, maxValue: 100, step: 1, pageStep: 10 }; case 'red': case 'green': case 'blue': return { minValue: 0, maxValue: 255, step: 1, pageStep: 17 }; case 'alpha': return { minValue: 0, maxValue: 1, step: 0.01, pageStep: 0.1 }; case 'L': case 'oklchLightness': return { minValue: 0, maxValue: 1, step: 0.01, pageStep: 0.1 }; case 'C': case 'oklchChroma': return { minValue: 0, maxValue: 0.4, step: 0.01, pageStep: 0.05 }; default: return { minValue: 0, maxValue: 100, step: 1, pageStep: 10 }; } } function getInputChannelRange(channel) { if (channel === 'hex') { return { minValue: 0, maxValue: 0xffffff, step: 1, pageStep: 1 }; } return getChannelRange(channel); } function getChannelGradient(color, channel, orientation = 'horizontal') { const range = getChannelRange(channel); const direction = orientation === 'horizontal' ? 'right' : 'top'; switch (channel) { case 'hue': case 'H': case 'oklchHue': return `linear-gradient(to ${direction}, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0) 33%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 83%, rgb(255, 0, 0) 100%)`; case 'lightness': case 'L': case 'oklchLightness': { const start = color.setChannelValue(channel, range.minValue).toRgbString(); const middle = color.setChannelValue(channel, (range.maxValue - range.minValue) / 2).toRgbString(); const end = color.setChannelValue(channel, range.maxValue).toRgbString(); return `linear-gradient(to ${direction}, ${start}, ${middle}, ${end})`; } case 'alpha': { const start = color.setChannelValue('alpha', range.minValue).toRgbString(); const end = color.setChannelValue('alpha', range.maxValue).toRgbString(); return `linear-gradient(to ${direction}, ${start}, ${end})`; } default: { const start = color.setChannelValue(channel, range.minValue).toRgbString(); const end = color.setChannelValue(channel, range.maxValue).toRgbString(); return `linear-gradient(to ${direction}, ${start}, ${end})`; } } } const channelGenerators = { hue: (color) => [0, 60, 120, 180, 240, 300, 360].map((h) => color.setChannelValue('hue', h).toRgbString()).join(', '), saturation: (color) => `${color.setChannelValue('saturation', 0).toRgbString()}, transparent`, lightness: () => 'black, transparent, white', brightness: () => 'black, transparent' }; function getAreaGradient(color, xChannel, yChannel, format) { const axes3d = getDefault3DAxes(format); const zChannel = axes3d.zChannel; const zValue = color.getChannelValue(zChannel); const isHSL = format === 'hsla'; let base; if (isHSL) { base = parseColor('hsl(0, 100%, 50%)').setChannelValue(zChannel, zValue); } else { base = parseColor('hsb(0, 100%, 100%)').setChannelValue(zChannel, zValue); } const channels = [xChannel, yChannel]; const direction = (c) => (c === xChannel ? 'right' : 'top'); const layers = channels .map((c) => { const gen = channelGenerators[c]; if (!gen) return null; return `linear-gradient(to ${direction(c)}, ${gen(base)})`; }) .filter(Boolean) .reverse(); const isHueZ = zChannel === 'hue' || zChannel === 'H' || zChannel === 'oklchHue'; if (isHueZ) { layers.push(base.toRgbString()); } return layers.join(', '); } function getChannelColor(color, channel) { switch (channel) { case 'hue': return parseColor(`hsl(${color.getChannelValue('hue')}, 100%, 50%)`); case 'red': case 'green': case 'blue': case 'lightness': case 'brightness': case 'saturation': return color.setChannelValue('alpha', 1); case 'alpha': return color; default: return color.setChannelValue('alpha', 1); } } function toCssString(color, format) { const a = round(color.alpha, 2); switch (format) { case 'rgba': case 'hexa': { const rgb = color.toRGB(); return `rgba(${Math.round(rgb.red)}, ${Math.round(rgb.green)}, ${Math.round(rgb.blue)}, ${a})`; } case 'hsla': { const hsl = color.toHSL(); return `hsla(${Math.round(hsl.hue) % 360}, ${hsl.saturation.toFixed(2)}%, ${hsl.lightness.toFixed(2)}%, ${a})`; } case 'hsba': { // CSS doesn't support hsb, convert to hsl const hsl = color.toHSL(); return `hsla(${Math.round(hsl.hue) % 360}, ${hsl.saturation.toFixed(2)}%, ${hsl.lightness.toFixed(2)}%, ${a})`; } case 'oklch': { return color.toOKLCH().toString('css'); } default: return color.toOKLCH().toString('css'); } } function getInputChannelValue(color, channel, format = 'hsba') { if (channel === 'hex') { const alphaRange = getChannelRange('alpha'); if (color.alpha < alphaRange.maxValue) { return color.toHexa(); } return color.toHex(); } if (channel === 'css') { return toCssString(color, format); } const value = color.getChannelValue(channel); if (Number.isNaN(value)) return 'NaN'; const range = getChannelRange(channel); if (channel === 'H' || channel === 'oklchHue') { const rounded = round(value, 2); return rounded.toString(); } if (channel === 'hue') { const rounded = Math.round(value); return rounded.toString(); } if (range.step >= 1) { return Math.round(value).toString(); } return round(value, 4).toString(); } function getDefault2DAxes(format) { switch (format) { case 'hsla': return { xChannel: 'saturation', yChannel: 'lightness' }; case 'hsba': case 'rgba': case 'oklch': default: return { xChannel: 'saturation', yChannel: 'brightness' }; } } function getDefault3DAxes(format) { switch (format) { case 'hsla': return { xChannel: 'saturation', yChannel: 'lightness', zChannel: 'hue' }; case 'hsba': case 'rgba': case 'oklch': default: return { xChannel: 'saturation', yChannel: 'brightness', zChannel: 'hue' }; } } const INPUT_COLOR_INSTANCE = new InjectionToken('INPUT_COLOR_INSTANCE'); const INPUT_COLOR_SLIDER_INSTANCE = new InjectionToken('INPUT_COLOR_SLIDER_INSTANCE'); /** * InputColorArea is a helper component for InputColor component. * @group Components */ class InputColorArea extends BaseComponent { componentName = 'InputColorArea'; bindDirectiveInstance = inject(Bind, { self: true }); $pc = inject(INPUT_COLOR_INSTANCE); $xChannel = computed(() => this.$pc.$axes().xChannel, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$xChannel" }] : /* istanbul ignore next */ [])); $yChannel = computed(() => this.$pc.$axes().yChannel, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$yChannel" }] : /* istanbul ignore next */ [])); $areaGradient = computed(() => { const color = this.$pc.$color(); const xCh = this.$xChannel(); const yCh = this.$yChannel(); const format = this.$pc.format(); return getAreaGradient(color, xCh, yCh, format); }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$areaGradient" }] : /* istanbul ignore next */ [])); $handleBackground = computed(() => this.$pc.$color().setChannelValue('alpha', 1).toRgbString(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$handleBackground" }] : /* istanbul ignore next */ [])); $handleLeft = computed(() => { const xCh = this.$xChannel(); const range = getChannelRange(xCh); const value = this.$pc.$color().getChannelValue(xCh); const pct = ((value - range.minValue) / (range.maxValue - range.minValue)) * 100; return `${pct}%`; }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$handleLeft" }] : /* istanbul ignore next */ [])); $handleTop = computed(() => { const yCh = this.$yChannel(); const range = getChannelRange(yCh); const value = this.$pc.$color().getChannelValue(yCh); const pct = (1 - (value - range.minValue) / (range.maxValue - range.minValue)) * 100; return `${pct}%`; }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$handleTop" }] : /* istanbul ignore next */ [])); dragging = false; dragOffset = { x: 0, y: 0 }; cleanupDrag = null; onAfterViewChecked() { this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root'])); } onPointerDown(event) { if (this.$pc.$disabled()) return; event.preventDefault(); this.dragging = true; const el = this.el.nativeElement; el.setPointerCapture(event.pointerId); const handle = event.target?.closest('[data-pc-section="areahandle"], .p-inputcolor-area-handle'); if (handle) { const handleRect = handle.getBoundingClientRect(); this.dragOffset = { x: event.clientX - (handleRect.left + handleRect.width / 2), y: event.clientY - (handleRect.top + handleRect.height / 2) }; } else { this.dragOffset = { x: 0, y: 0 }; } this.updateFromPointer(event); const onMove = (e) => { if (!this.dragging) return; e.preventDefault(); this.updateFromPointer(e); }; const cleanup = () => { this.dragging = false; this.cleanupDrag = null; el.removeEventListener('pointermove', onMove); el.removeEventListener('pointerup', onUp); el.removeEventListener('pointercancel', onCancel); el.removeEventListener('lostpointercapture', onLostCapture); }; this.cleanupDrag = cleanup; const onUp = (e) => { if (!this.dragging) return; this.updateFromPointer(e, true); this.dragOffset = { x: 0, y: 0 }; cleanup(); }; const onCancel = () => { cleanup(); }; const onLostCapture = () => { cleanup(); }; el.addEventListener('pointermove', onMove); el.addEventListener('pointerup', onUp); el.addEventListener('pointercancel', onCancel); el.addEventListener('lostpointercapture', onLostCapture); } ngOnDestroy() { this.cleanupDrag?.(); } updateFromPointer(event, isEnd = false) { const el = this.el.nativeElement; const rect = el.getBoundingClientRect(); const xPercent = Math.max(0, Math.min(1, (event.clientX - this.dragOffset.x - rect.left) / rect.width)); const yPercent = Math.max(0, Math.min(1, (event.clientY - this.dragOffset.y - rect.top) / rect.height)); const xCh = this.$xChannel(); const yCh = this.$yChannel(); const xRange = getChannelRange(xCh); const yRange = getChannelRange(yCh); const xValue = snapValue(xRange.minValue + xPercent * (xRange.maxValue - xRange.minValue), xRange.minValue, xRange.maxValue, xRange.step); const yValue = snapValue(yRange.maxValue - yPercent * (yRange.maxValue - yRange.minValue), yRange.minValue, yRange.maxValue, yRange.step); const nativeColor = this.$pc.toChannelNativeFormat(this.$pc.$color(), xCh); let color = nativeColor.setChannelValue(xCh, xValue); color = color.setChannelValue(yCh, yValue); this.$pc.updateColor(color, event, isEnd); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: InputColorArea, deps: null, target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: InputColorArea, isStandalone: true, selector: "p-inputcolor-area", host: { listeners: { "pointerdown": "onPointerDown($event)" }, properties: { "class": "$pc.cx(\"area\")", "style.--px-area-gradient": "$areaGradient()", "style.--px-handle-background": "$handleBackground()", "style.--px-handle-position-left": "$handleLeft()", "style.--px-handle-position-top": "$handleTop()" } }, providers: [{ provide: PARENT_INSTANCE, useExisting: InputColorArea }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: InputColorArea, decorators: [{ type: Component, args: [{ selector: 'p-inputcolor-area', standalone: true, template: `<ng-content></ng-content>`, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { '[class]': '$pc.cx("area")', '[style.--px-area-gradient]': '$areaGradient()', '[style.--px-handle-background]': '$handleBackground()', '[style.--px-handle-position-left]': '$handleLeft()', '[style.--px-handle-position-top]': '$handleTop()', '(pointerdown)': 'onPointerDown($event)' }, providers: [{ provide: PARENT_INSTANCE, useExisting: InputColorArea }], hostDirectives: [Bind] }] }] }); /** * InputColorAreaBackground is a helper component for InputColor component. * @group Components */ class InputColorAreaBackground extends BaseComponent { componentName = 'InputColorAreaBackground'; bindDirectiveInstance = inject(Bind, { self: true }); $pc = inject(INPUT_COLOR_INSTANCE); onAfterViewChecked() { this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root'])); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: InputColorAreaBackground, deps: null, target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: InputColorAreaBackground, isStandalone: true, selector: "p-inputcolor-area-background", host: { properties: { "class": "$pc.cx(\"areaBackground\")" } }, providers: [{ provide: PARENT_INSTANCE, useExisting: InputColorAreaBackground }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: InputColorAreaBackground, decorators: [{ type: Component, args: [{ selector: 'p-inputcolor-area-background', standalone: true, template: `<ng-content></ng-content>`, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { '[class]': '$pc.cx("areaBackground")' }, providers: [{ provide: PARENT_INSTANCE, useExisting: InputColorAreaBackground }], hostDirectives: [Bind] }] }] }); /** * InputColorAreaHandle is a helper component for InputColor component. * @group Components */ class InputColorAreaHandle extends BaseComponent { componentName = 'InputColorAreaHandle'; bindDirectiveInstance = inject(Bind, { self: true }); $pc = inject(INPUT_COLOR_INSTANCE); $xChannel = computed(() => this.$pc.$axes().xChannel, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$xChannel" }] : /* istanbul ignore next */ [])); $yChannel = computed(() => this.$pc.$axes().yChannel, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$yChannel" }] : /* istanbul ignore next */ [])); $xRange = computed(() => getChannelRange(this.$xChannel()), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$xRange" }] : /* istanbul ignore next */ [])); $yRange = computed(() => getChannelRange(this.$yChannel()), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$yRange" }] : /* istanbul ignore next */ [])); $xValue = computed(() => this.$pc.$color().getChannelValue(this.$xChannel()), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$xValue" }] : /* istanbul ignore next */ [])); $yValue = computed(() => this.$pc.$color().getChannelValue(this.$yChannel()), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$yValue" }] : /* istanbul ignore next */ [])); $xMin = computed(() => this.$xRange().minValue, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$xMin" }] : /* istanbul ignore next */ [])); $xMax = computed(() => this.$xRange().maxValue, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$xMax" }] : /* istanbul ignore next */ [])); $tabindex = computed(() => (this.$pc.$disabled() ? -1 : 0), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$tabindex" }] : /* istanbul ignore next */ [])); $ariaDisabled = computed(() => this.$pc.$disabled() || undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$ariaDisabled" }] : /* istanbul ignore next */ [])); $ariaValueText = computed(() => { const xCh = this.$xChannel(); const yCh = this.$yChannel(); return `${xCh} ${this.$xValue()}, ${yCh} ${this.$yValue()}`; }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$ariaValueText" }] : /* istanbul ignore next */ [])); onAfterViewChecked() { this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root'])); } onKeyDown(event) { if (this.$pc.$disabled()) return; const xCh = this.$xChannel(); const yCh = this.$yChannel(); const xRange = this.$xRange(); const yRange = this.$yRange(); let xVal = this.$xValue(); let yVal = this.$yValue(); let handled = false; switch (event.key) { case 'ArrowRight': xVal = Math.min(xVal + xRange.step, xRange.maxValue); handled = true; break; case 'ArrowLeft': xVal = Math.max(xVal - xRange.step, xRange.minValue); handled = true; break; case 'ArrowUp': yVal = Math.min(yVal + yRange.step, yRange.maxValue); handled = true; break; case 'ArrowDown': yVal = Math.max(yVal - yRange.step, yRange.minValue); handled = true;