OWL
inputs
Custom Color Picker
Odoo 19 OWL component — Custom Color Picker (core)
Live preview
Interactive
Source excerpt
web/static/src/core/color_picker/custom_color_picker/custom_color_picker.js
import { getActiveHotkey } from "@web/core/hotkeys/hotkey_service";
import { _t } from "@web/core/l10n/translation";
import {
convertCSSColorToRgba,
convertHslToRgb,
convertRgbaToCSSColor,
convertRgbToHsl,
normalizeCSSColor,
} from "@web/core/utils/colors";
import { uniqueId } from "@web/core/utils/functions";
import { clamp } from "@web/core/utils/numbers";
import { debounce, useThrottleForAnimation } from "@web/core/utils/timing";
import { Component, onMounted, onWillUpdateProps, useExternalListener, useRef } from "@odoo/owl";
const ARROW_KEYS = ["arrowup", "arrowdown", "arrowleft", "arrowright"];
const SLIDER_KEYS = [...ARROW_KEYS, "pageup", "pagedown", "home", "end"];
const DEFAULT_COLOR = "#FF0000";
export class CustomColorPicker extends Component {
static template = "web.CustomColorPicker";
static props = {
document: { type: true, optional: true },
defaultColor: { type: String, optional: true },
selectedColor: { type: String, optional: true },
noTransparency: { type: Boolean, optional: true },
stopClickPropagation: { type: Boolean, optional: true },
onColorSelect: { type: Function, optional: true },
onColorPreview: { type: Function, optional: true },
onInputEnter: { type: Function, optional: true },
defaultOpacity: { type: Number, optional: true },
setOnCloseCallback: { type: Function, optional: true },
setOperationCallbacks: { type: Function, optional: true },
};
static defaultProps = {
document: window.document,
defaultColor: DEFAULT_COLOR,
defaultOpacity: 100,
noTransparency: false,
stopClickPropagation: false,
onColorSelect: () => {},
onColorPreview: () => {},
onInputEnter: () => {},
};
setup() {
this.pickerFlag = false;
this.sliderFlag = false;
this.opacitySliderFlag = false;
if (this.props.defaultOpacity > 0 && this.props.defaultOpacity <= 1) {
this.props.defaultOpacity *= 100;
}
if (this.props.defaultColor.length <= 7) {
const opacityHex = Math.round((this.props.defaultOpacity / 100) * 255)
.toString(16)
.padStart(2, "0");
this.props.defaultColor += opacityHex;
}
this.colorComponents = {};
this.uniqueId = uniqueId("colorpicker");
this.selectedHexValue = "";
this.shouldSetSelectedColor = false;
this.lastFocusedSliderEl = undefined;
if (!this.props.selectedColor) {
this.props.selectedColor = this.props.defaultColor;
}
this.debouncedOnChangeInputs = debounce(this.onChangeInputs.bind(this), 10, true);
this.elRef = useRef("el");
this.colorPickerAreaRef = useRef("colorPickerArea");
this.colorPickerPointerRef = useRef("colorPickerPointer");
this.colorSliderRef = useRef("colorSlider");
this.colorSliderPointerRef = useRef("colorSliderPointer");
this.opacitySliderRef = useRef("opacitySlider");
this.opacitySliderPointerRef = useRef("opacitySliderPointer");
// Need to be bound on all documents to work in all possible cases (we
// have to be able to start dragging/moving from the colorpicker to
// anywhere on the screen, crossing iframes).
const documents = [
window.top,
...Array.from(window.top.frames).filter((frame) => {
try {
const document = frame.document;
return !!document;
} catch {
// We cannot access the document (cross origin).
return false;
}
}),
].map((w) => w.document);
this.throttleOnPointerMove = useThrottleForAnimation((ev) => {
this.onPointerMovePicker(ev);
this.onPointerMoveSlider(ev);
this.onPointerMoveOpacitySlider(ev);
});
for (const doc of documents) {
useExternalListener(doc, "pointermove", this.throttleOnPointerMove);
useExternalListener(doc, "pointerup", this.onPointerUp.bind(this));
useExternalListener(doc, "keydown", this.onEscapeKeydown.bind(this), { capture: true });
}
// Apply the previewed custom color when the popover is closed.
this.props.setOnCloseCallback?.(() => {
if (this.shouldSetSelectedColor) {
this._colorSelected();
}
});
this.props.setOperationCallbacks?.({
getPreviewColor: () => {
if (this.shouldSetSelectedColor) {
return this.colorComponents.hex;
}
},
onApplyCallback: () => {
this.shouldSetSelectedColor = false;
},
// Reapply the current custom color preview after reverting a preview.
// Typical usecase: 1) modify the custom color, 2) hover one of the
Registry / API
- Registry name
CustomColorPicker- Category
—- Module
web- Slug
custom-color-picker- Nav group
inputs