Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions packages/devextreme/js/__internal/m_color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,27 @@ const standardColorTypes = [
// eslint-disable-next-line @typescript-eslint/naming-convention
const _round = Math.round;

export interface ColorInstance {
baseColor: string | undefined;
r: number;
g: number;
b: number;
a: number;
hsv: { h: number; s: number; v: number };
hsl: { h: number; s: number; l: number };
colorIsInvalid: boolean;
highlight: (step?: number) => string;
darken: (step?: number) => string;
alter: (step: number) => ColorInstance;
blend: (blendColor: ColorInstance | string, opacity: number) => ColorInstance;
toHex: () => string;
getPureColor: () => ColorInstance;
isValidHex: (hex: string) => boolean;
isValidRGB: (r: number | undefined, g: number | undefined, b: number | undefined) => boolean;
isValidAlpha: (a: number) => boolean;
fromHSL: (hsl: { h: number; s: number; l: number }) => ColorInstance;
}

function Color(value?) {
this.baseColor = value;
let color;
Expand Down Expand Up @@ -495,10 +516,10 @@ function isIntegerBetweenMinAndMax(number, min?, max?) {
min = min || 0;
max = max || 255;

if (number % 1 !== 0
if (typeof number !== 'number'
|| number % 1 !== 0
|| number < min
|| number > max
|| typeof number !== 'number'
|| isNaN(number)) {
return false;
}
Expand Down Expand Up @@ -580,4 +601,9 @@ Color.prototype = {
},
};

export default Color;
interface ColorConstructor {
prototype: ColorInstance;
new(value?: string): ColorInstance;
}

export default Color as unknown as ColorConstructor;
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import type { ValueChangedEvent } from '@ts/ui/editor/editor';

import type { PopupProperties } from '../popup/m_popup';
import type Popup from '../popup/m_popup';
import type { ColorViewProperties } from './m_color_view';
import ColorView from './m_color_view';
import type { ColorViewProperties } from './color_view';
import ColorView from './color_view';

const COLOR_BOX_CLASS = 'dx-colorbox';
const COLOR_BOX_INPUT_CLASS = `${COLOR_BOX_CLASS}-input`;
Expand Down Expand Up @@ -219,7 +219,7 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
onValueChanged: ({ event, value: changedValue, previousValue }): void => {
const { applyValueMode: currentValueMode } = this.option();
const isInstantlyMode = currentValueMode === 'instantly';
const isOldValue = colorUtils.makeRgba(changedValue) === previousValue;
const isOldValue = colorUtils.makeRgba(new Color(changedValue)) === previousValue;
const isChangesApplied = isInstantlyMode || this._colorViewEnterKeyPressed;
const isValueCleared = this._shouldSaveEmptyValue;

Expand All @@ -238,7 +238,7 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
_enterKeyHandler(e: KeyboardEvent): boolean | undefined {
const newValue = this._input().val();
const { value, editAlphaChannel } = this.option();
const oldValue = value && editAlphaChannel ? colorUtils.makeRgba(value) : value;
const oldValue = value && editAlphaChannel ? colorUtils.makeRgba(new Color(value)) : value;

if (!newValue) return false;

Expand All @@ -251,7 +251,8 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
if (newValue !== oldValue) {
this._applyColorFromInput(newValue);
this._saveValueChangeEvent(e);
this.option('value', editAlphaChannel ? colorUtils.makeRgba(newValue) : newValue);
this.option('value', editAlphaChannel
? colorUtils.makeRgba(new Color(newValue)) : newValue);
}

if (this._colorView) {
Expand Down Expand Up @@ -281,7 +282,8 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
super._cancelButtonHandler();
}

// needed to be typed in widget.ts
// need to be typed in widget.ts
// eslint-disable-next-line @typescript-eslint/no-explicit-any
_getKeyboardListeners(): any[] {
return super._getKeyboardListeners().concat([this._colorView]);
}
Expand All @@ -303,7 +305,7 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
}

_renderNoColorIcon(): void {
if (!this._$noColorIcon || !this._$noColorIcon.length) {
if (!this._$noColorIcon?.length) {
this._$noColorIcon = $('<i>')
.addClass(`${DX_ICON_CLASS} ${DX_ICON_COLOR_DISMISS}`)
.appendTo(this._$colorResultPreview);
Expand All @@ -312,14 +314,14 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {

_updateNoColorIndicator(): void {
const { value } = this.option();
const hasValue = Boolean(value);
const hasValue = value !== null && value !== undefined && value.length > 0;

this._$colorBoxInputContainer.toggleClass(COLOR_BOX_COLOR_IS_NOT_DEFINED, !hasValue);

if (hasValue) {
this._cleanNoColorIcon();

colorUtils.makeTransparentBackground(this._$colorResultPreview, value);
colorUtils.makeTransparentBackground(this._$colorResultPreview, new Color(value));
} else {
this._$colorResultPreview.removeAttr('style');
this._renderNoColorIcon();
Expand All @@ -344,7 +346,7 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
_renderValue(): DeferredObj<unknown> {
const { value, editAlphaChannel } = this.option();
const shouldConvertToColor = value && editAlphaChannel;
const text = shouldConvertToColor ? colorUtils.makeRgba(value) : value;
const text = shouldConvertToColor ? colorUtils.makeRgba(new Color(value)) : value;

this.option('text', text);

Expand Down Expand Up @@ -388,13 +390,12 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
}

if (editAlphaChannel) {
return colorUtils.makeRgba(value);
return colorUtils.makeRgba(newColor);
}

return value;
}

// eslint-disable-next-line class-methods-use-this
_shouldLogFieldTemplateDeprecationWarning(): boolean {
return true;
}
Expand Down Expand Up @@ -435,7 +436,9 @@ class ColorBox extends DropDownEditor<ColorBoxProperties> {
case 'applyButtonText':
case 'cancelButtonText':
super._optionChanged(args);
this._popup && this._addPopupBottomClasses();
if (this._popup) {
this._addPopupBottomClasses();
}
break;
case 'editAlphaChannel':
case 'keyStep':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import { Guid } from '@ts/core/m_guid';
import { extend } from '@ts/core/utils/m_extend';
import { getHeight, getOuterHeight, getWidth } from '@ts/core/utils/m_size';
import type { OptionChanged } from '@ts/core/widget/types';
import type { SupportedKeys } from '@ts/core/widget/widget';
import type { SupportedKeyHandler, SupportedKeys } from '@ts/core/widget/widget';
import eventsEngine from '@ts/events/core/m_events_engine';
import { name as clickEventName } from '@ts/events/m_click';
import { isCommandKeyPressed } from '@ts/events/utils/index';
import Color from '@ts/m_color';
import Color, { type ColorInstance } from '@ts/m_color';
import Draggable from '@ts/m_draggable';
import type { EditorProperties, ValueChangedEvent } from '@ts/ui/editor/editor';
import Editor from '@ts/ui/editor/editor';
Expand Down Expand Up @@ -85,6 +85,23 @@ export interface ColorViewProperties extends EditorProperties {
target?: string | Element | dxElementWrapper | null;
}

type EditorWithLabelType = new (
element: dxElementWrapper,
options?: object,
) => { registerKeyHandler: (key: string, handler: SupportedKeyHandler) => void };

interface EditorWithLabelOptions {
editorType: EditorWithLabelType;
value: number | string;
onValueChanged: (args: ValueChangedEvent) => void;
labelText: string;
labelAriaText: string;
labelClass: string;
min?: number;
max?: number;
step?: number;
}

class ColorView extends Editor<ColorViewProperties> {
_$palette!: dxElementWrapper;

Expand All @@ -100,8 +117,7 @@ class ColorView extends Editor<ColorViewProperties> {

_updateByDrag?: boolean;

// need typings and correct class in m_color.ts
_currentColor!: any;
_currentColor!: ColorInstance;

_isTopColorHue?: boolean;

Expand Down Expand Up @@ -401,19 +417,11 @@ class ColorView extends Editor<ColorViewProperties> {
this._renderAlphaChannelElements();
}

_makeTransparentBackground($el: dxElementWrapper, color: any): void {
if (!(color instanceof Color)) {
color = new Color(color);
}

_makeTransparentBackground($el: dxElementWrapper, color: ColorInstance): void {
$el.css('backgroundColor', this._makeRgba(color));
}

_makeRgba(color: any): string {
if (!(color instanceof Color)) {
color = new Color(color);
}

_makeRgba(color: ColorInstance): string {
return `rgba(${[color.r, color.g, color.b, color.a].join(', ')})`;
}

Expand All @@ -438,15 +446,12 @@ class ColorView extends Editor<ColorViewProperties> {
if (delta < 0) {
delta = Math.abs(delta);
const rows: dxElementWrapper[] = [];
let i;
for (i = 0; i < delta; i++) {
for (let i = 0; i < delta; i += 1) {
rows.push($('<div>').addClass(COLOR_VIEW_ROW_CLASS));
}

if (renderedRowsCount) {
for (i = 0; i < rows.length; i++) {
$renderedRows.eq(0).after(rows[i]);
}
rows.forEach((row) => { $renderedRows.eq(0).after(row); });
} else {
this._$colorPickerContainer.append(rows);
}
Expand Down Expand Up @@ -539,12 +544,12 @@ class ColorView extends Editor<ColorViewProperties> {

_calculateColorValue(paletteHandlePosition: PaletteHandlePosition): number {
const value = Math.floor(paletteHandlePosition.top + this._paletteHandleHeight / 2);
return 100 - Math.round(value * 100 / this._paletteHeight);
return 100 - Math.round((value * 100) / this._paletteHeight);
}

_calculateColorSaturation(paletteHandlePosition: PaletteHandlePosition): number {
const saturation = Math.floor(paletteHandlePosition.left + this._paletteHandleWidth / 2);
return Math.round(saturation * 100 / this._paletteWidth);
return Math.round((saturation * 100) / this._paletteWidth);
}

_updateColorFromHsv(hue: number, saturation: number, value: number): void {
Expand Down Expand Up @@ -603,7 +608,7 @@ class ColorView extends Editor<ColorViewProperties> {
_placeHueScaleHandle(): void {
const hueScaleHeight = this._hueScaleWrapperHeight;
const handleHeight = this._hueScaleHandleHeight;
let top = (hueScaleHeight - handleHeight) * (360 - this._currentColor.hsv.h) / 360;
let top = ((hueScaleHeight - handleHeight) * (360 - this._currentColor.hsv.h)) / 360;

if (hueScaleHeight < top + handleHeight) {
top = hueScaleHeight - handleHeight;
Expand Down Expand Up @@ -662,7 +667,7 @@ class ColorView extends Editor<ColorViewProperties> {
this._$currentColor = $('<div>').addClass([COLOR_VIEW_COLOR_PREVIEW, COLOR_VIEW_COLOR_PREVIEW_COLOR_NEW].join(' '));
this._$baseColor = $('<div>').addClass([COLOR_VIEW_COLOR_PREVIEW, COLOR_VIEW_COLOR_PREVIEW_COLOR_CURRENT].join(' '));

this._makeTransparentBackground(this._$baseColor, matchValue);
this._makeTransparentBackground(this._$baseColor, new Color(matchValue ?? BLACK_COLOR));
this._makeTransparentBackground(this._$currentColor, this._currentColor);

$colorsPreviewContainerInner.append([this._$baseColor, this._$currentColor]);
Expand Down Expand Up @@ -718,7 +723,7 @@ class ColorView extends Editor<ColorViewProperties> {
];
}

_renderEditorWithLabel(options): dxElementWrapper {
_renderEditorWithLabel(options: EditorWithLabelOptions): dxElementWrapper {
const $editor = $('<div>');
const $label = $('<label>')
.addClass(options.labelClass)
Expand Down Expand Up @@ -747,7 +752,7 @@ class ColorView extends Editor<ColorViewProperties> {
editorOptions.step = options.step || 1;
}

const editor = new EditorConstructor($editor, editorOptions);
const editor = new (EditorConstructor)($editor, editorOptions);

editor.registerKeyHandler('enter', (e) => {
this._fireEnterKeyPressed(e);
Expand All @@ -758,7 +763,7 @@ class ColorView extends Editor<ColorViewProperties> {
return $label;
}

hexInputOptions() {
hexInputOptions(): EditorWithLabelOptions {
return {
editorType: TextBox,
value: this._currentColor.toHex().replace('#', ''),
Expand Down Expand Up @@ -829,7 +834,9 @@ class ColorView extends Editor<ColorViewProperties> {
onValueChanged: (args) => {
let { value } = args;
value = this._currentColor.isValidAlpha(value) ? value : this._currentColor.a;
args.event && this._saveValueChangeEvent(args.event);
if (args.event) {
this._saveValueChangeEvent(args.event);
}
this._updateColorTransparency(value);
this._placeAlphaChannelHandle();
},
Expand Down Expand Up @@ -860,7 +867,8 @@ class ColorView extends Editor<ColorViewProperties> {
onDragMove: ({ event }) => {
this._updateByDrag = true;
const $alphaChannelHandle = this._$alphaChannelHandle;
const alphaChannelHandlePosition = locate($alphaChannelHandle).left + this._alphaChannelHandleWidth / 2;
const alphaChannelHandlePosition = locate($alphaChannelHandle).left
+ this._alphaChannelHandleWidth / 2;
this._saveValueChangeEvent(event);
this._calculateColorTransparencyByScaleWidth(alphaChannelHandlePosition);
},
Expand Down Expand Up @@ -934,15 +942,21 @@ class ColorView extends Editor<ColorViewProperties> {
}

_updateColor(isHex: boolean, args: ValueChangedEvent): void {
let rgba;
let rgba: number[] = [];
let newColor = '';

if (isHex) {
newColor = this._validateHex(`#${this._hexInput.option('value') as string}`);
} else {
rgba = this._validateRgb();
if (this._alphaChannelInput) {
rgba.push(this._alphaChannelInput.option('value'));
const { value: alphaValue } = this._alphaChannelInput.option();
const isValidAlpha = alphaValue !== undefined
&& this._currentColor.isValidAlpha(alphaValue);

const valueToAdd = isValidAlpha ? alphaValue : this._currentColor.a;

rgba.push(valueToAdd);
newColor = `rgba(${rgba.join(', ')})`;
} else {
newColor = `rgb(${rgba.join(', ')})`;
Expand All @@ -958,15 +972,16 @@ class ColorView extends Editor<ColorViewProperties> {
}

_validateHex(hex: string): string {
return this._currentColor.isValidHex(hex) ? hex : this._currentColor.toHex() as string;
return this._currentColor.isValidHex(hex) ? hex : this._currentColor.toHex();
}

_validateRgb(): number[] {
let { value: r } = this._rgbInputs[0].option();
let { value: g } = this._rgbInputs[1].option();
let { value: b } = this._rgbInputs[2].option();

if (!this._currentColor.isValidRGB(r, g, b)) {
const isInvalidRgb = !this._currentColor.isValidRGB(r, g, b);
if (isInvalidRgb) {
r = this._currentColor.r;
g = this._currentColor.g;
b = this._currentColor.b;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@js/ui/select_box';
import '@ts/ui/color_box/m_color_view';
import '@ts/ui/color_box/color_view';
import '@js/ui/number_box';
import '@js/ui/menu';

Expand Down
2 changes: 1 addition & 1 deletion packages/devextreme/js/ui/color_box.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ColorBox from '../__internal/ui/color_box/m_color_box';
import ColorBox from '../__internal/ui/color_box/color_box';
export default ColorBox;

// STYLE colorBox
Expand Down
2 changes: 1 addition & 1 deletion packages/devextreme/js/ui/color_box/color_view.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import ColorView from '../../__internal/ui/color_box/m_color_view';
import ColorView from '../../__internal/ui/color_box/color_view';

export default ColorView;
Loading
Loading