mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Makes the hex value editable in the color select
Summary: - reuses the textInput form the editableLabel module - adds a isValidHex utility function to gutil Test Plan: - Adds test to the project test Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2744
This commit is contained in:
parent
92ef1f400c
commit
5e5bf3af9d
@ -1,6 +1,8 @@
|
||||
import { darker, lighter } from "app/client/ui2018/ColorPalette";
|
||||
import { colors, testId, vars } from 'app/client/ui2018/cssVars';
|
||||
import { textInput } from "app/client/ui2018/editableLabel";
|
||||
import { icon } from "app/client/ui2018/icons";
|
||||
import { isValidHex } from "app/common/gutil";
|
||||
import { Computed, Disposable, dom, DomArg, Observable, onKeyDown, styled } from "grainjs";
|
||||
import { defaultMenuOptions, IOpenController, setPopupToCreateDom } from "popweasel";
|
||||
|
||||
@ -84,7 +86,11 @@ function buildColorPicker(ctl: IOpenController, textColor: Observable<string>, f
|
||||
onKeyDown({
|
||||
Escape: () => { revert(); },
|
||||
Enter: () => { ctl.close(); },
|
||||
})
|
||||
}),
|
||||
|
||||
// Set focus when `focusout` is bubbling from a children element. This is to allow to receive
|
||||
// keyboard event again after user interacted with the hex box text input.
|
||||
dom.on('focusout', (ev, elem) => (ev.target !== elem) && elem.focus()),
|
||||
);
|
||||
}
|
||||
|
||||
@ -150,12 +156,13 @@ class PickerComponent extends Disposable {
|
||||
testId(`${title}-input`),
|
||||
),
|
||||
),
|
||||
// TODO: make it possible to type in hex value.
|
||||
cssHexBox(
|
||||
dom.attr('value', this._color),
|
||||
{readonly: true},
|
||||
dom.on('click', (ev, e) => e.select()),
|
||||
this._color,
|
||||
async (val) => { if (isValidHex(val)) {this._model.setValue(val); }},
|
||||
testId(`${title}-hex`),
|
||||
// select the hex value on click. Doing it using settimeout allows to avoid some
|
||||
// sporadically losing the selection just after the click.
|
||||
dom.on('click', (ev, elem) => setTimeout(() => elem.select(), 0)),
|
||||
)
|
||||
),
|
||||
title,
|
||||
@ -275,7 +282,7 @@ const cssContent = styled('div', `
|
||||
align-items: center;
|
||||
`);
|
||||
|
||||
const cssHexBox = styled('input', `
|
||||
const cssHexBox = styled(textInput, `
|
||||
border: 1px solid #D9D9D9;
|
||||
border-left: none;
|
||||
font-size: ${vars.smallFontSize};
|
||||
@ -285,6 +292,8 @@ const cssHexBox = styled('input', `
|
||||
width: 56px;
|
||||
outline: none;
|
||||
padding: 0 3px;
|
||||
height: unset;
|
||||
border-radius: unset;
|
||||
`);
|
||||
|
||||
const cssLightBorder = styled('div', `
|
||||
|
@ -10,7 +10,7 @@
|
||||
* TODO: Consider merging this into grainjs's input widget.
|
||||
*/
|
||||
import { colors } from 'app/client/ui2018/cssVars';
|
||||
import { dom, DomElementArg, styled } from 'grainjs';
|
||||
import { dom, DomArg, styled } from 'grainjs';
|
||||
import { Observable } from 'grainjs';
|
||||
import noop = require('lodash/noop');
|
||||
|
||||
@ -69,7 +69,7 @@ type SaveFunc = (value: string) => Promise<void>;
|
||||
* cancels editing. Label grows in size with typed input. Validation logic (if any) should happen in
|
||||
* the save function, to reject a value simply throw an error, this will revert to the saved one .
|
||||
*/
|
||||
export function editableLabel(label: Observable<string>, save: SaveFunc, ...args: DomElementArg[]) {
|
||||
export function editableLabel(label: Observable<string>, save: SaveFunc, ...args: Array<DomArg<HTMLInputElement>>) {
|
||||
let input: HTMLInputElement;
|
||||
let sizer: HTMLSpanElement;
|
||||
|
||||
@ -92,7 +92,7 @@ export function editableLabel(label: Observable<string>, save: SaveFunc, ...args
|
||||
* of focus. Escape cancels editing. Validation logic (if any) should happen in the save function,
|
||||
* to reject a value simply throw an error, this will revert to the the saved one.
|
||||
*/
|
||||
export function textInput(label: Observable<string>, save: SaveFunc, ...args: DomElementArg[]) {
|
||||
export function textInput(label: Observable<string>, save: SaveFunc, ...args: Array<DomArg<HTMLInputElement>>) {
|
||||
return rawTextInput(label, save, noop, dom.cls(cssTextInput.className), ...args);
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ export function textInput(label: Observable<string>, save: SaveFunc, ...args: Do
|
||||
* A helper that implements all the saving logic for both editableLabel and textInput.
|
||||
*/
|
||||
export function rawTextInput(value: Observable<string>, save: SaveFunc, onChange: () => void,
|
||||
...args: DomElementArg[]) {
|
||||
...args: Array<DomArg<HTMLInputElement>>) {
|
||||
let status: Status = Status.NORMAL;
|
||||
let inputEl: HTMLInputElement;
|
||||
|
||||
|
@ -777,6 +777,15 @@ export function isColorDark(hexColor: string, isDarkBelow: number = 220): boolea
|
||||
return luma < isDarkBelow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if val is a valid hex color value. For instance: #aabbaa is valid, #aabba is not. Do
|
||||
* not accept neither short notation nor hex with transparency, ie: #aab, #aabb and #aabbaabb are
|
||||
* invalid.
|
||||
*/
|
||||
export function isValidHex(val: string): boolean {
|
||||
return /^#([0-9A-F]{6})$/i.test(val);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a promise that resolves to true if promise takes longer than timeoutMsec to resolve. If not
|
||||
|
Loading…
Reference in New Issue
Block a user