12 changed files with 361 additions and 11 deletions
@ -0,0 +1,26 @@ |
|||
diff --git a/node_modules/@iplab/ngx-color-picker/esm2022/lib/helpers/color.class.mjs b/node_modules/@iplab/ngx-color-picker/esm2022/lib/helpers/color.class.mjs
|
|||
index 6c7f8b1..f390b3b 100644
|
|||
--- a/node_modules/@iplab/ngx-color-picker/esm2022/lib/helpers/color.class.mjs
|
|||
+++ b/node_modules/@iplab/ngx-color-picker/esm2022/lib/helpers/color.class.mjs
|
|||
@@ -173,7 +173,7 @@ export class Color {
|
|||
const s = (color.saturation / 100) * (l <= 1 ? l : 2 - l); |
|||
const value = (l + s) / 2; |
|||
const saturation = (2 * s) / (l + s) || 0; |
|||
- return new Hsva(hue, saturation, value, color.alpha);
|
|||
+ return new Hsva(hue, saturation * 100, value * 100, color.alpha);
|
|||
} |
|||
rgbaToHsva(color) { |
|||
const red = color.red / 255; |
|||
diff --git a/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs b/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
|
|||
index a3b270c..9a9b592 100644
|
|||
--- a/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
|
|||
+++ b/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
|
|||
@@ -505,7 +505,7 @@ class Color {
|
|||
const s = (color.saturation / 100) * (l <= 1 ? l : 2 - l); |
|||
const value = (l + s) / 2; |
|||
const saturation = (2 * s) / (l + s) || 0; |
|||
- return new Hsva(hue, saturation, value, color.alpha);
|
|||
+ return new Hsva(hue, saturation * 100, value * 100, color.alpha);
|
|||
} |
|||
rgbaToHsva(color) { |
|||
const red = color.red / 255; |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016-2026 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
:host { |
|||
.color-input-container { |
|||
display: flex; |
|||
gap: 4px; |
|||
align-items: center; |
|||
} |
|||
.color-input { |
|||
max-width: 72px; |
|||
margin-bottom: 4px; |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,54 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2026 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<div class="color-input-container"> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" [min]="0" [max]="360" [value]="value.getHue()" (inputChange)="onInputChange($event, 'H')"/> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>H</span> |
|||
} |
|||
</div> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" [min]="0" [max]="100" [value]="value.getSaturation()" (inputChange)="onInputChange($event, 'S')" /> |
|||
<span matSuffix>{{suffixValue}}</span> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>S</span> |
|||
} |
|||
</div> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" [min]="0" [max]="100" [value]="value.getLightness()" (inputChange)="onInputChange($event,'L')" /> |
|||
<span matSuffix>{{suffixValue}}</span> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>L</span> |
|||
} |
|||
</div> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput type="number" [min]="0" [max]="100" [value]="alphaValue" (inputChange)="onAlphaInputChange($event)" /> |
|||
<span matSuffix>{{suffixValue}}</span> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>A</span> |
|||
} |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,71 @@ |
|||
///
|
|||
/// Copyright © 2016-2026 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, EventEmitter, Input, Output } from '@angular/core'; |
|||
import { Color } from '@iplab/ngx-color-picker'; |
|||
import { coerceBoolean } from '@shared/decorators/coercion'; |
|||
|
|||
type Channel = 'H' | 'S' | 'L'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-hsla-input', |
|||
templateUrl: './hsla-input.component.html', |
|||
styleUrl: './color-input.base.scss' |
|||
}) |
|||
export class HslaInputComponent { |
|||
|
|||
@Input() |
|||
public color: Color; |
|||
|
|||
@Output() |
|||
public colorChange = new EventEmitter<Color>(false); |
|||
|
|||
@Input() |
|||
@coerceBoolean() |
|||
public labelVisible = false; |
|||
|
|||
@Input() |
|||
public suffixValue = '%'; |
|||
|
|||
public get value() { |
|||
return this.color.getHsla(); |
|||
} |
|||
|
|||
public get alphaValue(): number { |
|||
return this.color ? Math.round(this.color.getHsla().getAlpha() * 100) : 0; |
|||
} |
|||
|
|||
public onAlphaInputChange(inputValue: number): void { |
|||
if (!this.color) return; |
|||
const hsla = this.color.getHsla(); |
|||
const alpha = +inputValue / 100; |
|||
if (hsla.alpha !== alpha) { |
|||
const newColor = new Color().setHsla(hsla.getHue(), hsla.getSaturation(), hsla.getLightness(), alpha); |
|||
this.colorChange.emit(newColor); |
|||
} |
|||
} |
|||
|
|||
public onInputChange(newValue: number, channel: Channel): void { |
|||
if (!this.color) return; |
|||
const hsla = this.value; |
|||
const hue = channel === 'H' ? +newValue : hsla.getHue(); |
|||
const saturation = channel === 'S' ? +newValue : hsla.getSaturation(); |
|||
const lightness = channel === 'L' ? +newValue : hsla.getLightness(); |
|||
if (hue === hsla.getHue() && saturation === hsla.getSaturation() && lightness === hsla.getLightness()) return; |
|||
const newColor = new Color().setHsla(hue, saturation, lightness, hsla.getAlpha()); |
|||
this.colorChange.emit(newColor); |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
///
|
|||
/// Copyright © 2016-2026 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Directive, EventEmitter, HostBinding, HostListener, Input, numberAttribute, Output } from '@angular/core'; |
|||
|
|||
@Directive({ |
|||
selector: '[inputChange]' |
|||
}) |
|||
export class InputChangeDirective { |
|||
|
|||
@Input({transform: numberAttribute}) |
|||
@HostBinding('attr.min') |
|||
min = 0; |
|||
|
|||
@Input({transform: numberAttribute}) |
|||
@HostBinding('attr.max') |
|||
max = 255; |
|||
|
|||
@Output() |
|||
public inputChange = new EventEmitter<number>(); |
|||
|
|||
@HostListener('input', ['$event']) |
|||
public inputChanges(event: any): void { |
|||
const element = event.target as HTMLInputElement || event.srcElement as HTMLInputElement; |
|||
const value = element.value; |
|||
|
|||
const numeric = parseFloat(value); |
|||
if (!isNaN(numeric) && numeric >= this.min && numeric <= this.max) { |
|||
this.inputChange.emit(numeric); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2026 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<div class="color-input-container"> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" subscriptSizing="dynamic" appearance="outline"> |
|||
<input matInput type="number" [min]="0" [max]="255" [value]="value?.getRed()" (inputChange)="onInputChange($event, 'R')" /> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>R</span> |
|||
} |
|||
</div> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" subscriptSizing="dynamic" appearance="outline"> |
|||
<input matInput type="number" [min]="0" [max]="255" [value]="value?.getGreen()" (inputChange)="onInputChange($event, 'G')" /> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>G</span> |
|||
} |
|||
</div> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" subscriptSizing="dynamic" appearance="outline"> |
|||
<input matInput type="number" [min]="0" [max]="255" [value]="value?.getBlue()" (inputChange)="onInputChange($event,'B')" /> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>B</span> |
|||
} |
|||
</div> |
|||
<div class="tb-form-row tb-flex no-gap no-border no-padding column align-center"> |
|||
<mat-form-field class="color-input number" subscriptSizing="dynamic" appearance="outline"> |
|||
<input matInput type="number" [min]="0" [max]="100" [value]="alphaValue" (inputChange)="onAlphaInputChange($event)" /> |
|||
<span matSuffix>{{suffixValue}}</span> |
|||
</mat-form-field> |
|||
@if (labelVisible) { |
|||
<span>A</span> |
|||
} |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,70 @@ |
|||
///
|
|||
/// Copyright © 2016-2026 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, EventEmitter, Input, Output } from '@angular/core'; |
|||
import { Color } from '@iplab/ngx-color-picker'; |
|||
import { coerceBoolean } from '@shared/decorators/coercion'; |
|||
|
|||
type Channel = 'R' | 'G' | 'B' | 'A'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-rgba-input', |
|||
templateUrl: './rgba-input.component.html', |
|||
styleUrl: './color-input.base.scss' |
|||
}) |
|||
export class RgbaInputComponent { |
|||
|
|||
@Input() |
|||
public color: Color; |
|||
|
|||
@Output() |
|||
public colorChange = new EventEmitter<Color>(false); |
|||
|
|||
@Input() |
|||
@coerceBoolean() |
|||
public labelVisible = false; |
|||
|
|||
@Input() |
|||
public suffixValue = '%'; |
|||
|
|||
public get value() { |
|||
return this.color.getRgba(); |
|||
} |
|||
|
|||
public get alphaValue(): string { |
|||
return this.color ? Math.round(this.color.getRgba().getAlpha() * 100).toString() : ''; |
|||
} |
|||
|
|||
public onAlphaInputChange(inputValue: number): void { |
|||
if (!this.color) return; |
|||
const color = this.color.getRgba(); |
|||
const alpha = +inputValue / 100; |
|||
if (color.getAlpha() !== alpha) { |
|||
const newColor = new Color().setRgba(color.getRed(), color.getGreen(), color.getBlue(), alpha).toRgbaString(); |
|||
this.colorChange.emit(new Color(newColor)); |
|||
} |
|||
} |
|||
|
|||
onInputChange(newValue: number, channel: Channel) { |
|||
if (!this.color) return; |
|||
const rgba = this.value; |
|||
const red = channel === 'R' ? newValue : rgba.getRed(); |
|||
const green = channel === 'G' ? newValue : rgba.getGreen(); |
|||
const blue = channel === 'B' ? newValue : rgba.getBlue(); |
|||
if (red === rgba.getRed() && green === rgba.getGreen() && blue === rgba.getBlue()) return; |
|||
this.colorChange.emit(new Color().setRgba(red, green, blue, rgba.alpha)); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue