mami/src/mami.js/colpick/picker.jsx

198 lines
6.6 KiB
JavaScript

#include args.js
#include colour.js
#include utility.js
#include controls/tabs.js
#include colpick/tgrid.jsx
#include colpick/tpresets.jsx
#include colpick/tsliders.jsx
#include colpick/vhex.jsx
#include colpick/vraw.jsx
const MamiColourPicker = function(options) {
options = MamiArgs('options', options, define => {
define('colour').default(0).filter(value => Math.min(0xFFFFFF, Math.max(0, value))).done();
define('posX').default(-1).done();
define('posY').default(-1).done();
define('presets').default([]).constraint(value => Array.isArray(value)).done();
define('showPresetsTab').default(true).done();
define('showGridTab').default(true).done();
define('showSlidersTab').default(true).done();
define('showHexValue').default(true).done();
define('showRawValue').default(true).done();
define('showDialogButtons').default(true).done();
});
let colour;
const needsColour = [];
let promiseResolve;
const runResolve = () => {
if(promiseResolve !== undefined)
promiseResolve(colour);
close();
};
let promiseReject;
const runReject = () => {
if(promiseReject !== undefined)
promiseReject();
close();
};
let tabsElem, tabsContainer, tabsList;
let values, buttons;
const html = <form class="colpick" style={{ zIndex: '9001' }} onsubmit={ev => { ev.preventDefault(); runResolve(); return false; }}>
{tabsElem = <div class="colpick-tabbed">
{tabsContainer = <div class="colpick-tabbed-container"/>}
{tabsList = <div class="colpick-tabbed-list"/>}
</div>}
<div class="colpick-middle-row">
<div class="colpick-colour-preview-container">
<div class="colpick-colour-preview"/>
</div>
{values = <div class="colpick-values-container"/>}
</div>
<div class="colpick-buttons-container">
{buttons = <div class="colpick-buttons-container-inner"/>}
</div>
</form>;
const close = () => html.parentNode.removeChild(html);
const setColour = (raw, mask) => {
raw = typeof raw === 'number' ? (parseInt(raw) & 0xFFFFFF) : 0;
mask = typeof mask === 'number' ? parseInt(mask) : ~0;
colour = (colour & ~mask) | (raw & mask);
const text = MamiColour.text(colour);
html.style.setProperty('--colpick-colour', MamiColour.hex(colour));
html.style.setProperty('--colpick-text', MamiColour.hex(text));
for(const info of needsColour)
if('updateColour' in info)
info.updateColour(colour, text);
};
const setPosition = pos => {
if(typeof pos !== 'object')
throw 'pos must be an object';
html.style.top = 'y' in pos && pos.y >= 0 ? `${pos.y}px` : null;
html.style.left = 'x' in pos && pos.x >= 0 ? `${pos.x}px` : '';
};
const tabs = new MamiTabsControl({
onAdd: ctx => {
const name = ctx.info.getName(),
containerName = `colpick-tab-${name}-container`,
buttonName = `colpick-tab-${name}-button`;
needsColour.push(ctx.info);
ctx.info.onChange(setColour);
ctx.elem.className = `colpick-tab-container ${containerName} colpick-tab-container-inactive`;
tabsContainer.appendChild(ctx.elem);
tabsList.appendChild(<input type="button" value={ctx.title}
class={['colpick-tab-button', buttonName]}
onclick={ctx.onClick}/>);
},
onRemove: ctx => {
const name = ctx.info.getName();
$rq(`.colpick-tab-${name}-button`);
$rq(`.colpick-tab-${name}-container`);
},
onSwitch: ctx => {
if(ctx.from !== undefined) {
ctx.from.elem.classList.toggle('colpick-tab-container-inactive', true);
$q(`.colpick-tab-${ctx.from.info.getName()}-button`).classList.toggle('colpick-tab-button-active', false);
}
ctx.elem.classList.toggle('colpick-tab-container-inactive', false);
$q(`.colpick-tab-${ctx.info.getName()}-button`).classList.toggle('colpick-tab-button-active', true);
},
});
if(options.showPresetsTab && options.presets.length > 0)
tabs.add(new MamiColourPickerPresetsTab(options.presets));
if(options.showGridTab)
tabs.add(new MamiColourPickerGridTab);
if(options.showSlidersTab)
tabs.add(new MamiColourPickerSlidersTab);
if(tabs.count() < 1)
html.removeChild(tabsElem);
const addValue = (id, name, valueInfo) => {
needsColour.push(valueInfo);
valueInfo.onChange(setColour);
values.appendChild(<label class={['colpick-values-child', `colpick-${id}-value`]}>
<div class={['colpick-values-child-label', `colpick-${id}-value-label`]}>{name}</div>
{valueInfo}
</label>);
};
if(options.showHexValue)
addValue('hex', 'Hex', new MamiColourPickerValueHex);
if(options.showRawValue)
addValue('raw', 'Raw', new MamiColourPickerValueRaw);
const addButton = (id, name, action) => {
const button = <input class={['colpick-buttons-button', `colpick-buttons-${id}-button`]} value={name}/>;
if(action === undefined) {
button.classList.add('colpick-buttons-button-submit');
button.type = 'submit';
} else {
button.onclick = () => action();
button.type = 'button';
}
buttons.appendChild(button);
};
if(options.showDialogButtons) {
addButton('cancel', 'Cancel', runReject);
addButton('apply', 'Apply');
}
setPosition({ x: options.posX, y: options.posY });
setColour(options.colour);
return {
getElement: () => html,
getColour: () => colour,
setColour: setColour,
setPosition: setPosition,
close: close,
dialog: pos => {
if(pos !== undefined)
setPosition(pos);
return new Promise((resolve, reject) => {
promiseResolve = resolve;
promiseReject = reject;
});
},
suggestPosition: mouseEvent => {
let x = 10, y = 10;
if(html.parentNode.clientWidth > 340) {
x = mouseEvent.clientX;
y = mouseEvent.clientY;
const bb = html.getBoundingClientRect();
if(y > bb.height + 20)
y -= bb.height;
if(x > html.parentNode.clientWidth - bb.width - 20)
x -= bb.width;
}
return { x: x, y: y };
},
};
};