muigui 0.0.6 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +19 -4
- package/src/controllers/ColorChooser.js +43 -3
- package/src/controllers/Container.js +8 -2
- package/src/controllers/Controller.js +3 -0
- package/src/controllers/PopDownController.js +14 -13
- package/src/controllers/ValueController.js +15 -7
- package/src/controllers/Vec2.js +0 -1
- package/src/layout/Layout.js +0 -1
- package/src/libs/color-utils.js +252 -12
- package/src/libs/elem.js +6 -1
- package/src/libs/keyboard.js +2 -2
- package/src/libs/touch.js +6 -6
- package/src/libs/utils.js +31 -0
- package/src/libs/wheel.js +1 -1
- package/src/muigui.js +75 -12
- package/src/styles/muigui.css.js +78 -4
- package/src/views/CheckboxView.js +3 -1
- package/src/views/ColorChooserView.js +128 -35
- package/src/views/RadioGridView.js +3 -2
- package/src/views/RangeView.js +10 -4
- package/src/views/{View.js → View.ts} +15 -13
- /package/src/{esm.js → esm.ts} +0 -0
package/src/muigui.js
CHANGED
|
@@ -5,16 +5,22 @@ import {
|
|
|
5
5
|
mapRange,
|
|
6
6
|
makeRangeConverters,
|
|
7
7
|
makeRangeOptions,
|
|
8
|
+
makeMinMaxPair,
|
|
8
9
|
} from './libs/utils.js';
|
|
9
10
|
import {
|
|
10
11
|
converters
|
|
11
12
|
} from './libs/conversions.js';
|
|
13
|
+
import {
|
|
14
|
+
hasAlpha,
|
|
15
|
+
guessFormat,
|
|
16
|
+
} from './libs/color-utils.js';
|
|
12
17
|
import Canvas from './controllers/Canvas.js';
|
|
13
18
|
import Color from './controllers/Color.js';
|
|
14
19
|
import Divider from './controllers/Divider.js';
|
|
15
20
|
import Folder from './controllers/Folder.js';
|
|
16
21
|
import Label from './controllers/Label.js';
|
|
17
22
|
import Controller from './controllers/Controller.js';
|
|
23
|
+
import ColorChooser from './controllers/ColorChooser.js';
|
|
18
24
|
|
|
19
25
|
import Column from './layout/Column.js';
|
|
20
26
|
import Frame from './layout/Frame.js';
|
|
@@ -28,9 +34,6 @@ export {
|
|
|
28
34
|
Row,
|
|
29
35
|
};
|
|
30
36
|
|
|
31
|
-
let stylesInjected = false;
|
|
32
|
-
const styleElem = createElem('style');
|
|
33
|
-
|
|
34
37
|
export class GUIFolder extends Folder {
|
|
35
38
|
add(object, property, ...args) {
|
|
36
39
|
const controller = object instanceof Controller
|
|
@@ -41,8 +44,13 @@ export class GUIFolder extends Folder {
|
|
|
41
44
|
addCanvas(name) {
|
|
42
45
|
return this.addController(new Canvas(name));
|
|
43
46
|
}
|
|
44
|
-
addColor(object, property,
|
|
45
|
-
|
|
47
|
+
addColor(object, property, options = {}) {
|
|
48
|
+
const value = object[property];
|
|
49
|
+
if (hasAlpha(options.format || guessFormat(value))) {
|
|
50
|
+
return this.addController(new ColorChooser(object, property, options));
|
|
51
|
+
} else {
|
|
52
|
+
return this.addController(new Color(object, property, options));
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
addDivider() {
|
|
48
56
|
return this.addController(new Divider());
|
|
@@ -55,11 +63,50 @@ export class GUIFolder extends Folder {
|
|
|
55
63
|
}
|
|
56
64
|
}
|
|
57
65
|
|
|
66
|
+
class MuiguiElement extends HTMLElement {
|
|
67
|
+
constructor() {
|
|
68
|
+
super();
|
|
69
|
+
this.shadow = this.attachShadow({mode: 'open'});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
customElements.define('muigui-element', MuiguiElement);
|
|
74
|
+
|
|
75
|
+
const baseStyleSheet = new CSSStyleSheet();
|
|
76
|
+
baseStyleSheet.replaceSync(css.default);
|
|
77
|
+
const userStyleSheet = new CSSStyleSheet();
|
|
78
|
+
|
|
79
|
+
function makeStyleSheetUpdater(styleSheet) {
|
|
80
|
+
let newCss;
|
|
81
|
+
let newCssPromise;
|
|
82
|
+
|
|
83
|
+
function updateStyle() {
|
|
84
|
+
if (newCss && !newCssPromise) {
|
|
85
|
+
const s = newCss;
|
|
86
|
+
newCss = undefined;
|
|
87
|
+
newCssPromise = styleSheet.replace(s).then(() => {
|
|
88
|
+
newCssPromise = undefined;
|
|
89
|
+
updateStyle();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return function updateStyleSheet(css) {
|
|
95
|
+
newCss = css;
|
|
96
|
+
updateStyle();
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const updateBaseStyle = makeStyleSheetUpdater(baseStyleSheet);
|
|
101
|
+
const updateUserStyle = makeStyleSheetUpdater(userStyleSheet);
|
|
102
|
+
|
|
58
103
|
export class GUI extends GUIFolder {
|
|
59
104
|
static converters = converters;
|
|
60
105
|
static mapRange = mapRange;
|
|
61
106
|
static makeRangeConverters = makeRangeConverters;
|
|
62
107
|
static makeRangeOptions = makeRangeOptions;
|
|
108
|
+
static makeMinMaxPair = makeMinMaxPair;
|
|
109
|
+
#localStyleSheet = new CSSStyleSheet();
|
|
63
110
|
|
|
64
111
|
constructor(options = {}) {
|
|
65
112
|
super('Controls', 'muigui-root');
|
|
@@ -70,16 +117,11 @@ export class GUI extends GUIFolder {
|
|
|
70
117
|
autoPlace = true,
|
|
71
118
|
width,
|
|
72
119
|
title = 'Controls',
|
|
73
|
-
injectStyles = true,
|
|
74
120
|
} = options;
|
|
75
121
|
let {
|
|
76
122
|
parent,
|
|
77
123
|
} = options;
|
|
78
|
-
|
|
79
|
-
stylesInjected = true;
|
|
80
|
-
(document.head || document.documentElement).appendChild(styleElem);
|
|
81
|
-
styleElem.textContent = css;
|
|
82
|
-
}
|
|
124
|
+
|
|
83
125
|
if (width) {
|
|
84
126
|
this.domElement.style.width = /^\d+$/.test(width) ? `${width}px` : width;
|
|
85
127
|
}
|
|
@@ -88,13 +130,34 @@ export class GUI extends GUIFolder {
|
|
|
88
130
|
this.domElement.classList.add('muigui-auto-place');
|
|
89
131
|
}
|
|
90
132
|
if (parent) {
|
|
91
|
-
|
|
133
|
+
const muiguiElement = createElem('muigui-element');
|
|
134
|
+
muiguiElement.shadowRoot.adoptedStyleSheets = [baseStyleSheet, userStyleSheet, this.#localStyleSheet];
|
|
135
|
+
muiguiElement.shadow.appendChild(this.domElement);
|
|
136
|
+
parent.appendChild(muiguiElement);
|
|
92
137
|
}
|
|
93
138
|
if (title) {
|
|
94
139
|
this.title(title);
|
|
95
140
|
}
|
|
96
141
|
this.domElement.classList.add('muigui', 'muigui-colors');
|
|
97
142
|
}
|
|
143
|
+
setStyle(css) {
|
|
144
|
+
this.#localStyleSheet.replace(css);
|
|
145
|
+
}
|
|
146
|
+
static setBaseStyles(css) {
|
|
147
|
+
updateBaseStyle(css);
|
|
148
|
+
}
|
|
149
|
+
static getBaseStyleSheet() {
|
|
150
|
+
return baseStyleSheet;
|
|
151
|
+
}
|
|
152
|
+
static setUserStyles(css) {
|
|
153
|
+
updateUserStyle(css);
|
|
154
|
+
}
|
|
155
|
+
static getUserStyleSheet() {
|
|
156
|
+
return userStyleSheet;
|
|
157
|
+
}
|
|
158
|
+
static setTheme(name) {
|
|
159
|
+
GUI.setBaseStyles(`${css.default}\n${css.themes[name] || ''}`);
|
|
160
|
+
}
|
|
98
161
|
}
|
|
99
162
|
|
|
100
163
|
export default GUI;
|
package/src/styles/muigui.css.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export default
|
|
2
|
-
|
|
1
|
+
export default {
|
|
2
|
+
default: `
|
|
3
|
+
.muigui {
|
|
3
4
|
--bg-color: #ddd;
|
|
4
5
|
--color: #222;
|
|
6
|
+
--contrast-color: #eee;
|
|
5
7
|
--value-color: #145 ;
|
|
6
8
|
--value-bg-color: #eeee;
|
|
7
9
|
--disabled-color: #999;
|
|
@@ -24,9 +26,10 @@ export default `
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
@media (prefers-color-scheme: dark) {
|
|
27
|
-
.muigui
|
|
29
|
+
.muigui {
|
|
28
30
|
--bg-color: #222222;
|
|
29
31
|
--color: #dddddd;
|
|
32
|
+
--contrast-color: #000;
|
|
30
33
|
--value-color: #43e5f7;
|
|
31
34
|
--value-bg-color: #444444;
|
|
32
35
|
--disabled-color: #666666;
|
|
@@ -667,6 +670,17 @@ export default `
|
|
|
667
670
|
}
|
|
668
671
|
*/
|
|
669
672
|
|
|
673
|
+
.muigui-checkered-background {
|
|
674
|
+
background-color: #404040;
|
|
675
|
+
background-image:
|
|
676
|
+
linear-gradient(45deg, #808080 25%, transparent 25%),
|
|
677
|
+
linear-gradient(-45deg, #808080 25%, transparent 25%),
|
|
678
|
+
linear-gradient(45deg, transparent 75%, #808080 75%),
|
|
679
|
+
linear-gradient(-45deg, transparent 75%, #808080 75%);
|
|
680
|
+
background-size: 16px 16px;
|
|
681
|
+
background-position: 0 0, 0 8px, 8px -8px, -8px 0px;
|
|
682
|
+
}
|
|
683
|
+
|
|
670
684
|
/* ---------------------------------------------------------- */
|
|
671
685
|
|
|
672
686
|
/* needs to be at bottom to take precedence */
|
|
@@ -678,5 +692,65 @@ export default `
|
|
|
678
692
|
z-index: 100001;
|
|
679
693
|
}
|
|
680
694
|
|
|
681
|
-
|
|
695
|
+
`,
|
|
696
|
+
themes: {
|
|
697
|
+
default: '',
|
|
698
|
+
float: `
|
|
699
|
+
:root {
|
|
700
|
+
color-scheme: light dark,
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.muigui {
|
|
704
|
+
--width: 400px;
|
|
705
|
+
--bg-color: initial;
|
|
706
|
+
--label-width: 25%;
|
|
707
|
+
--number-width: 20%;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
input,
|
|
711
|
+
.muigui-label-controller>label {
|
|
712
|
+
text-shadow:
|
|
713
|
+
-1px -1px 0 var(--contrast-color),
|
|
714
|
+
1px -1px 0 var(--contrast-color),
|
|
715
|
+
-1px 1px 0 var(--contrast-color),
|
|
716
|
+
1px 1px 0 var(--contrast-color);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.muigui-controller > label:nth-child(1) {
|
|
720
|
+
place-content: center end;
|
|
721
|
+
margin-right: 1em;
|
|
722
|
+
}
|
|
682
723
|
|
|
724
|
+
.muigui-value > :nth-child(2) {
|
|
725
|
+
margin-left: 1em;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.muigui-root>*:nth-child(1) {
|
|
729
|
+
display: none;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.muigui-range input[type=range]::-webkit-slider-thumb {
|
|
733
|
+
border-radius: 1em;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.muigui-range input[type=range]::-webkit-slider-runnable-track {
|
|
737
|
+
-webkit-appearance: initial;
|
|
738
|
+
appearance: none;
|
|
739
|
+
border: 1px solid rgba(0, 0, 0, 0.25);
|
|
740
|
+
height: 2px;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.muigui-colors {
|
|
744
|
+
--value-color: var(--color );
|
|
745
|
+
--value-bg-color: rgba(0, 0, 0, 0.1);
|
|
746
|
+
--disabled-color: #cccccc;
|
|
747
|
+
--menu-bg-color: rgba(0, 0, 0, 0.1);
|
|
748
|
+
--menu-sep-color: #bbbbbb;
|
|
749
|
+
--hover-bg-color: rgba(0, 0, 0, 0);
|
|
750
|
+
--invalid-color: #FF0000;
|
|
751
|
+
--selected-color: rgba(0, 0, 0, 0.3);
|
|
752
|
+
--range-color: rgba(0, 0, 0, 0.125);
|
|
753
|
+
}
|
|
754
|
+
`,
|
|
755
|
+
},
|
|
756
|
+
};
|
|
@@ -2,6 +2,7 @@ import { createElem } from '../libs/elem.js';
|
|
|
2
2
|
import EditView from './EditView.js';
|
|
3
3
|
|
|
4
4
|
export default class CheckboxView extends EditView {
|
|
5
|
+
#checkboxElem;
|
|
5
6
|
constructor(setter, id) {
|
|
6
7
|
const checkboxElem = createElem('input', {
|
|
7
8
|
type: 'checkbox',
|
|
@@ -14,8 +15,9 @@ export default class CheckboxView extends EditView {
|
|
|
14
15
|
},
|
|
15
16
|
});
|
|
16
17
|
super(createElem('label', {}, [checkboxElem]));
|
|
18
|
+
this.#checkboxElem = checkboxElem;
|
|
17
19
|
}
|
|
18
20
|
updateDisplay(v) {
|
|
19
|
-
this.
|
|
21
|
+
this.#checkboxElem.checked = v;
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -1,36 +1,38 @@
|
|
|
1
|
-
import { createElem } from '../libs/elem.js';
|
|
1
|
+
import { createElem, getNewId } from '../libs/elem.js';
|
|
2
2
|
import { addTouchEvents } from '../libs/touch.js';
|
|
3
|
+
import { identity } from '../libs/conversions.js';
|
|
3
4
|
import { clamp } from '../libs/utils.js';
|
|
4
5
|
import EditView from './EditView.js';
|
|
5
6
|
import {
|
|
6
|
-
hexToUint8RGB,
|
|
7
7
|
hexToFloatRGB,
|
|
8
|
-
|
|
8
|
+
hexToFloatRGBA,
|
|
9
9
|
hsv01ToRGBFloat,
|
|
10
|
+
hsva01ToRGBAFloat,
|
|
10
11
|
rgbFloatToHSV01,
|
|
11
|
-
|
|
12
|
+
rgbaFloatToHSVA01,
|
|
12
13
|
floatRGBToHex,
|
|
13
|
-
|
|
14
|
+
floatRGBAToHex,
|
|
15
|
+
rgbaFloatToHsla01,
|
|
14
16
|
} from '../libs/color-utils.js';
|
|
17
|
+
import { copyExistingProperties } from '../libs/utils.js';
|
|
15
18
|
|
|
16
19
|
const svg = `
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
<linearGradient id="muigui-color-chooser-light-dark" x1="0" x2="0" y1="0" y2="1">
|
|
20
|
+
<svg class="muigui-checkered-background" tabindex="0" viewBox="0 0 64 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
|
|
21
|
+
<linearGradient data-src="muigui-color-chooser-light-dark" x1="0" x2="0" y1="0" y2="1">
|
|
20
22
|
<stop stop-color="rgba(0,0,0,0)" offset="0%"/>
|
|
21
23
|
<stop stop-color="#000" offset="100%"/>
|
|
22
24
|
</linearGradient>
|
|
23
|
-
<linearGradient
|
|
24
|
-
<stop stop-color="hsl(60
|
|
25
|
-
<stop stop-color="hsl(60
|
|
25
|
+
<linearGradient data-src="muigui-color-chooser-hue">
|
|
26
|
+
<stop stop-color="hsl(60 0% 100% / 1)" offset="0%"/>
|
|
27
|
+
<stop stop-color="hsl(60 100% 50% / 1)" offset="100%"/>
|
|
26
28
|
</linearGradient>
|
|
27
29
|
|
|
28
|
-
<rect width="64" height="48"
|
|
29
|
-
<rect width="64" height="48"
|
|
30
|
+
<rect width="64" height="48" data-target="muigui-color-chooser-hue"/>
|
|
31
|
+
<rect width="64" height="48" data-target="muigui-color-chooser-light-dark"/>
|
|
30
32
|
<circle r="4" class="muigui-color-chooser-circle"/>
|
|
31
33
|
</svg>
|
|
32
34
|
<svg tabindex="0" viewBox="0 0 64 6" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
|
|
33
|
-
<linearGradient
|
|
35
|
+
<linearGradient data-src="muigui-color-chooser-hues" x1="0" x2="1" y1="0" y2="0">
|
|
34
36
|
<stop stop-color="hsl(0,100%,50%)" offset="0%"/>
|
|
35
37
|
<stop stop-color="hsl(60,100%,50%)" offset="16.666%"/>
|
|
36
38
|
<stop stop-color="hsl(120,100%,50%)" offset="33.333%"/>
|
|
@@ -39,48 +41,108 @@ const svg = `
|
|
|
39
41
|
<stop stop-color="hsl(300,100%,50%)" offset="83.333%"/>
|
|
40
42
|
<stop stop-color="hsl(360,100%,50%)" offset="100%"/>
|
|
41
43
|
</linearGradient>
|
|
42
|
-
<rect y="1" width="64" height="4"
|
|
43
|
-
<g class="muigui-color-chooser-cursor">
|
|
44
|
+
<rect y="1" width="64" height="4" data-target="muigui-color-chooser-hues"/>
|
|
45
|
+
<g class="muigui-color-chooser-hue-cursor">
|
|
46
|
+
<rect x="-3" width="6" height="6" />
|
|
47
|
+
</g>
|
|
48
|
+
</svg>
|
|
49
|
+
<svg class="muigui-checkered-background" tabindex="0" viewBox="0 0 64 6" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
|
|
50
|
+
<linearGradient data-src="muigui-color-chooser-alpha" x1="0" x2="1" y1="0" y2="0">
|
|
51
|
+
<stop stop-color="hsla(0,100%,100%,0)" offset="0%"/>
|
|
52
|
+
<stop stop-color="hsla(0,100%,100%,1)" offset="100%"/>
|
|
53
|
+
</linearGradient>
|
|
54
|
+
<rect y="1" width="64" height="4" data-target="muigui-color-chooser-alpha"/>
|
|
55
|
+
<g class="muigui-color-chooser-alpha-cursor">
|
|
44
56
|
<rect x="-3" width="6" height="6" />
|
|
45
57
|
</g>
|
|
46
58
|
</svg>
|
|
47
59
|
`;
|
|
48
60
|
|
|
61
|
+
function connectFillTargets(elem) {
|
|
62
|
+
elem.querySelectorAll('[data-src]').forEach(srcElem => {
|
|
63
|
+
const id = getNewId();
|
|
64
|
+
srcElem.id = id;
|
|
65
|
+
elem.querySelectorAll(`[data-target=${srcElem.dataset.src}]`).forEach(targetElem => {
|
|
66
|
+
targetElem.setAttribute('fill', `url(#${id})`);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
return elem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Was originally going to make alpha an option. Issue is
|
|
73
|
+
// hard coded conversions?
|
|
49
74
|
export default class ColorChooserView extends EditView {
|
|
75
|
+
#to;
|
|
76
|
+
#from;
|
|
50
77
|
#satLevelElem;
|
|
51
|
-
#hueUIElem;
|
|
52
78
|
#circleElem;
|
|
79
|
+
#hueUIElem;
|
|
53
80
|
#hueElem;
|
|
54
81
|
#hueCursorElem;
|
|
55
|
-
#
|
|
82
|
+
#alphaUIElem;
|
|
83
|
+
#alphaElem;
|
|
84
|
+
#alphaCursorElem;
|
|
85
|
+
#hsva;
|
|
56
86
|
#skipHueUpdate;
|
|
57
87
|
#skipSatLevelUpdate;
|
|
88
|
+
#skipAlphaUpdate;
|
|
89
|
+
#options = {
|
|
90
|
+
converters: identity,
|
|
91
|
+
alpha: false,
|
|
92
|
+
};
|
|
93
|
+
#convertInternalToHex;
|
|
94
|
+
#convertHexToInternal;
|
|
58
95
|
|
|
59
|
-
constructor(setter) {
|
|
96
|
+
constructor(setter, options) {
|
|
60
97
|
super(createElem('div', {
|
|
61
98
|
innerHTML: svg,
|
|
62
99
|
className: 'muigui-no-scroll',
|
|
63
100
|
}));
|
|
64
101
|
this.#satLevelElem = this.domElement.children[0];
|
|
65
102
|
this.#hueUIElem = this.domElement.children[1];
|
|
103
|
+
this.#alphaUIElem = this.domElement.children[2];
|
|
104
|
+
connectFillTargets(this.#satLevelElem);
|
|
105
|
+
connectFillTargets(this.#hueUIElem);
|
|
106
|
+
connectFillTargets(this.#alphaUIElem);
|
|
66
107
|
this.#circleElem = this.$('.muigui-color-chooser-circle');
|
|
67
|
-
this.#hueElem = this.$('
|
|
68
|
-
this.#hueCursorElem = this.$('.muigui-color-chooser-cursor');
|
|
108
|
+
this.#hueElem = this.$('[data-src=muigui-color-chooser-hue]');
|
|
109
|
+
this.#hueCursorElem = this.$('.muigui-color-chooser-hue-cursor');
|
|
110
|
+
this.#alphaElem = this.$('[data-src=muigui-color-chooser-alpha]');
|
|
111
|
+
this.#alphaCursorElem = this.$('.muigui-color-chooser-alpha-cursor');
|
|
69
112
|
|
|
70
113
|
const handleSatLevelChange = (e) => {
|
|
71
114
|
const s = clamp(e.nx, 0, 1);
|
|
72
115
|
const v = clamp(e.ny, 0, 1);
|
|
73
|
-
this.#
|
|
74
|
-
this.#
|
|
116
|
+
this.#hsva[1] = s;
|
|
117
|
+
this.#hsva[2] = (1 - v);
|
|
75
118
|
this.#skipHueUpdate = true;
|
|
76
|
-
|
|
119
|
+
this.#skipAlphaUpdate = true;
|
|
120
|
+
const [valid, newV] = this.#from(this.#convertInternalToHex(this.#hsva));
|
|
121
|
+
if (valid) {
|
|
122
|
+
setter.setValue(newV);
|
|
123
|
+
}
|
|
77
124
|
};
|
|
78
125
|
|
|
79
126
|
const handleHueChange = (e) => {
|
|
80
127
|
const h = clamp(e.nx, 0, 1);
|
|
81
|
-
this.#
|
|
128
|
+
this.#hsva[0] = h;
|
|
82
129
|
this.#skipSatLevelUpdate = true;
|
|
83
|
-
|
|
130
|
+
this.#skipAlphaUpdate = true;
|
|
131
|
+
const [valid, newV] = this.#from(this.#convertInternalToHex(this.#hsva));
|
|
132
|
+
if (valid) {
|
|
133
|
+
setter.setValue(newV);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleAlphaChange = (e) => {
|
|
138
|
+
const a = clamp(e.nx, 0, 1);
|
|
139
|
+
this.#hsva[3] = a;
|
|
140
|
+
this.#skipHueUpdate = true;
|
|
141
|
+
this.#skipSatLevelUpdate = true;
|
|
142
|
+
const [valid, newV] = this.#from(this.#convertInternalToHex(this.#hsva));
|
|
143
|
+
if (valid) {
|
|
144
|
+
setter.setValue(newV);
|
|
145
|
+
}
|
|
84
146
|
};
|
|
85
147
|
|
|
86
148
|
addTouchEvents(this.#satLevelElem, {
|
|
@@ -91,29 +153,45 @@ export default class ColorChooserView extends EditView {
|
|
|
91
153
|
onDown: handleHueChange,
|
|
92
154
|
onMove: handleHueChange,
|
|
93
155
|
});
|
|
156
|
+
addTouchEvents(this.#alphaUIElem, {
|
|
157
|
+
onDown: handleAlphaChange,
|
|
158
|
+
onMove: handleAlphaChange,
|
|
159
|
+
});
|
|
160
|
+
this.setOptions(options);
|
|
94
161
|
}
|
|
95
162
|
updateDisplay(newV) {
|
|
96
|
-
if (!this.#
|
|
97
|
-
this.#
|
|
163
|
+
if (!this.#hsva) {
|
|
164
|
+
this.#hsva = this.#convertHexToInternal(this.#to(newV));
|
|
98
165
|
}
|
|
99
166
|
{
|
|
100
|
-
const [h, s, v] =
|
|
167
|
+
const [h, s, v, a = 1] = this.#convertHexToInternal(this.#to(newV));
|
|
101
168
|
// Don't copy the hue if it was un-computable.
|
|
102
169
|
if (!this.#skipHueUpdate) {
|
|
103
|
-
this.#
|
|
170
|
+
this.#hsva[0] = s > 0.001 && v > 0.001 ? h : this.#hsva[0];
|
|
104
171
|
}
|
|
105
172
|
if (!this.#skipSatLevelUpdate) {
|
|
106
|
-
this.#
|
|
107
|
-
this.#
|
|
173
|
+
this.#hsva[1] = s;
|
|
174
|
+
this.#hsva[2] = v;
|
|
175
|
+
}
|
|
176
|
+
if (!this.#skipAlphaUpdate) {
|
|
177
|
+
this.#hsva[3] = a;
|
|
108
178
|
}
|
|
109
179
|
}
|
|
110
180
|
{
|
|
111
|
-
const [h, s, v] = this.#
|
|
181
|
+
const [h, s, v, a] = this.#hsva;
|
|
182
|
+
const [hue, sat, lum] = rgbaFloatToHsla01(hsva01ToRGBAFloat(this.#hsva));
|
|
183
|
+
|
|
112
184
|
if (!this.#skipHueUpdate) {
|
|
113
185
|
this.#hueCursorElem.setAttribute('transform', `translate(${h * 64}, 0)`);
|
|
114
|
-
this.#hueElem.children[0].setAttribute('stop-color', `hsl(${h * 360}, 0%, 100%)`);
|
|
115
|
-
this.#hueElem.children[1].setAttribute('stop-color', `hsl(${h * 360}, 100%, 50%)`);
|
|
116
186
|
}
|
|
187
|
+
this.#hueElem.children[0].setAttribute('stop-color', `hsl(${hue * 360} 0% 100% / ${a})`);
|
|
188
|
+
this.#hueElem.children[1].setAttribute('stop-color', `hsl(${hue * 360} 100% 50% / ${a})`);
|
|
189
|
+
if (!this.#skipAlphaUpdate) {
|
|
190
|
+
this.#alphaCursorElem.setAttribute('transform', `translate(${a * 64}, 0)`);
|
|
191
|
+
}
|
|
192
|
+
this.#alphaElem.children[0].setAttribute('stop-color', `hsl(${hue * 360} ${sat * 100}% ${lum * 100}% / 0)`);
|
|
193
|
+
this.#alphaElem.children[1].setAttribute('stop-color', `hsl(${hue * 360} ${sat * 100}% ${lum * 100}% / 1)`);
|
|
194
|
+
|
|
117
195
|
if (!this.#skipSatLevelUpdate) {
|
|
118
196
|
this.#circleElem.setAttribute('cx', `${s * 64}`);
|
|
119
197
|
this.#circleElem.setAttribute('cy', `${(1 - v) * 48}`);
|
|
@@ -121,5 +199,20 @@ export default class ColorChooserView extends EditView {
|
|
|
121
199
|
}
|
|
122
200
|
this.#skipHueUpdate = false;
|
|
123
201
|
this.#skipSatLevelUpdate = false;
|
|
202
|
+
this.#skipAlphaUpdate = false;
|
|
203
|
+
}
|
|
204
|
+
setOptions(options) {
|
|
205
|
+
copyExistingProperties(this.#options, options);
|
|
206
|
+
const {converters: {to, from}, alpha} = this.#options;
|
|
207
|
+
this.#alphaUIElem.style.display = alpha ? '' : 'none';
|
|
208
|
+
this.#convertInternalToHex = alpha
|
|
209
|
+
? v => floatRGBAToHex(hsva01ToRGBAFloat(v))
|
|
210
|
+
: v => floatRGBToHex(hsv01ToRGBFloat(v));
|
|
211
|
+
this.#convertHexToInternal = alpha
|
|
212
|
+
? v => rgbaFloatToHSVA01(hexToFloatRGBA(v))
|
|
213
|
+
: v => rgbFloatToHSV01(hexToFloatRGB(v));
|
|
214
|
+
this.#to = to;
|
|
215
|
+
this.#from = from;
|
|
216
|
+
return this;
|
|
124
217
|
}
|
|
125
218
|
}
|
|
@@ -15,7 +15,7 @@ export default class RadioGridView extends EditView {
|
|
|
15
15
|
type: 'radio',
|
|
16
16
|
name,
|
|
17
17
|
value: ndx,
|
|
18
|
-
onChange: function() {
|
|
18
|
+
onChange: function () {
|
|
19
19
|
if (this.checked) {
|
|
20
20
|
setter.setFinalValue(that.#values[this.value]);
|
|
21
21
|
}
|
|
@@ -24,12 +24,13 @@ export default class RadioGridView extends EditView {
|
|
|
24
24
|
createElem('button', {
|
|
25
25
|
type: 'button',
|
|
26
26
|
textContent: key,
|
|
27
|
-
onClick: function() {
|
|
27
|
+
onClick: function () {
|
|
28
28
|
this.previousElementSibling.click();
|
|
29
29
|
},
|
|
30
30
|
}),
|
|
31
31
|
]);
|
|
32
32
|
})));
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
33
34
|
const that = this;
|
|
34
35
|
this.#values = values;
|
|
35
36
|
this.cols(cols);
|
package/src/views/RangeView.js
CHANGED
|
@@ -22,16 +22,22 @@ export default class RangeView extends EditView {
|
|
|
22
22
|
type: 'range',
|
|
23
23
|
onInput: () => {
|
|
24
24
|
this.#skipUpdate = true;
|
|
25
|
-
const
|
|
25
|
+
const {min, max, step} = this.#options;
|
|
26
|
+
const v = parseFloat(this.domElement.value);
|
|
27
|
+
const newV = clamp(stepify(v, v => v, step), min, max);
|
|
28
|
+
const [valid, validV] = this.#from(newV);
|
|
26
29
|
if (valid) {
|
|
27
|
-
setter.setValue(
|
|
30
|
+
setter.setValue(validV);
|
|
28
31
|
}
|
|
29
32
|
},
|
|
30
33
|
onChange: () => {
|
|
31
34
|
this.#skipUpdate = true;
|
|
32
|
-
const
|
|
35
|
+
const {min, max, step} = this.#options;
|
|
36
|
+
const v = parseFloat(this.domElement.value);
|
|
37
|
+
const newV = clamp(stepify(v, v => v, step), min, max);
|
|
38
|
+
const [valid, validV] = this.#from(newV);
|
|
33
39
|
if (valid) {
|
|
34
|
-
setter.setFinalValue(
|
|
40
|
+
setter.setFinalValue(validV);
|
|
35
41
|
}
|
|
36
42
|
},
|
|
37
43
|
onWheel: e => {
|
|
@@ -1,56 +1,58 @@
|
|
|
1
1
|
import { removeArrayElem } from '../libs/utils.js';
|
|
2
2
|
|
|
3
3
|
export default class View {
|
|
4
|
-
|
|
5
|
-
#views = [];
|
|
4
|
+
domElement: HTMLElement;
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
#childDestElem: HTMLElement;
|
|
7
|
+
#views: View[] = [];
|
|
8
|
+
|
|
9
|
+
constructor(elem: HTMLElement) {
|
|
8
10
|
this.domElement = elem;
|
|
9
11
|
this.#childDestElem = elem;
|
|
10
12
|
}
|
|
11
|
-
addElem(elem) {
|
|
13
|
+
addElem(elem: HTMLElement) {
|
|
12
14
|
this.#childDestElem.appendChild(elem);
|
|
13
15
|
return elem;
|
|
14
16
|
}
|
|
15
|
-
removeElem(elem) {
|
|
17
|
+
removeElem(elem: HTMLElement) {
|
|
16
18
|
this.#childDestElem.removeChild(elem);
|
|
17
19
|
return elem;
|
|
18
20
|
}
|
|
19
|
-
pushSubElem(elem) {
|
|
21
|
+
pushSubElem(elem: HTMLElement) {
|
|
20
22
|
this.#childDestElem.appendChild(elem);
|
|
21
23
|
this.#childDestElem = elem;
|
|
22
24
|
}
|
|
23
25
|
popSubElem() {
|
|
24
|
-
this.#childDestElem = this.#childDestElem.parentElement
|
|
26
|
+
this.#childDestElem = this.#childDestElem.parentElement!;
|
|
25
27
|
}
|
|
26
|
-
add(view) {
|
|
28
|
+
add(view: View) {
|
|
27
29
|
this.#views.push(view);
|
|
28
30
|
this.addElem(view.domElement);
|
|
29
31
|
return view;
|
|
30
32
|
}
|
|
31
|
-
remove(view) {
|
|
33
|
+
remove(view: View) {
|
|
32
34
|
this.removeElem(view.domElement);
|
|
33
35
|
removeArrayElem(this.#views, view);
|
|
34
36
|
return view;
|
|
35
37
|
}
|
|
36
|
-
pushSubView(view) {
|
|
38
|
+
pushSubView(view: View) {
|
|
37
39
|
this.pushSubElem(view.domElement);
|
|
38
40
|
}
|
|
39
41
|
popSubView() {
|
|
40
42
|
this.popSubElem();
|
|
41
43
|
}
|
|
42
|
-
setOptions(options) {
|
|
44
|
+
setOptions(options: any) {
|
|
43
45
|
for (const view of this.#views) {
|
|
44
46
|
view.setOptions(options);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
|
-
updateDisplayIfNeeded(newV, ignoreCache) {
|
|
49
|
+
updateDisplayIfNeeded(newV: any, ignoreCache?: boolean) {
|
|
48
50
|
for (const view of this.#views) {
|
|
49
51
|
view.updateDisplayIfNeeded(newV, ignoreCache);
|
|
50
52
|
}
|
|
51
53
|
return this;
|
|
52
54
|
}
|
|
53
|
-
$(selector) {
|
|
55
|
+
$(selector: string) {
|
|
54
56
|
return this.domElement.querySelector(selector);
|
|
55
57
|
}
|
|
56
58
|
}
|
/package/src/{esm.js → esm.ts}
RENAMED
|
File without changes
|