muigui 0.0.1 → 0.0.2

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.
Files changed (72) hide show
  1. package/README.md +72 -7
  2. package/package.json +9 -6
  3. package/src/controllers/Button.js +34 -0
  4. package/src/controllers/Canvas.js +17 -0
  5. package/src/controllers/Checkbox.js +11 -0
  6. package/src/controllers/Color.js +31 -0
  7. package/src/controllers/ColorChooser.js +12 -0
  8. package/src/controllers/Container.js +58 -0
  9. package/src/controllers/Controller.js +138 -0
  10. package/src/controllers/Direction.js +23 -0
  11. package/src/controllers/Divider.js +9 -0
  12. package/src/controllers/Folder.js +37 -0
  13. package/src/controllers/Label.js +14 -0
  14. package/src/controllers/LabelController.js +32 -0
  15. package/src/controllers/PopDownController.js +84 -0
  16. package/src/controllers/RadioGrid.js +17 -0
  17. package/src/controllers/Range.js +11 -0
  18. package/src/controllers/Select.js +14 -0
  19. package/src/controllers/Slider.js +12 -0
  20. package/src/controllers/TabHolder.js +36 -0
  21. package/src/controllers/Text.js +10 -0
  22. package/src/controllers/TextNumber.js +18 -0
  23. package/src/controllers/ValueController.js +107 -0
  24. package/src/controllers/Vec2.js +50 -0
  25. package/src/controllers/create-controller.js +43 -0
  26. package/src/layout/Column.js +7 -0
  27. package/src/layout/Frame.js +11 -0
  28. package/src/layout/Grid.js +7 -0
  29. package/src/layout/Layout.js +47 -0
  30. package/src/layout/Row.js +7 -0
  31. package/src/libs/assert.js +5 -0
  32. package/src/libs/color-utils.js +406 -0
  33. package/src/libs/conversions.js +14 -0
  34. package/src/libs/css-utils.js +3 -0
  35. package/src/libs/elem.js +8 -3
  36. package/src/libs/emitter.js +68 -0
  37. package/src/libs/iterable-array.js +57 -0
  38. package/src/libs/key-values.js +25 -0
  39. package/src/libs/keyboard.js +32 -0
  40. package/src/libs/resize-helpers.js +22 -0
  41. package/src/libs/svg.js +33 -0
  42. package/src/libs/taskrunner.js +56 -0
  43. package/src/libs/touch.js +50 -0
  44. package/src/libs/utils.js +38 -2
  45. package/src/libs/wheel.js +10 -0
  46. package/src/muigui.js +79 -19
  47. package/src/styles/muigui.css.js +640 -0
  48. package/src/umd.js +3 -0
  49. package/src/views/CheckboxView.js +21 -0
  50. package/src/views/ColorChooserView.js +124 -0
  51. package/src/views/ColorView.js +50 -0
  52. package/src/views/DirectionView.js +127 -0
  53. package/src/views/EditView.js +100 -0
  54. package/src/views/ElementView.js +8 -0
  55. package/src/views/GridView.js +15 -0
  56. package/src/views/NumberView.js +67 -0
  57. package/src/views/RadioGridView.js +46 -0
  58. package/src/views/RangeView.js +73 -0
  59. package/src/views/SelectView.js +23 -0
  60. package/src/views/SliderView.js +194 -0
  61. package/src/views/TextView.js +49 -0
  62. package/src/views/ValueView.js +11 -0
  63. package/src/views/Vec2View.js +51 -0
  64. package/src/views/View.js +56 -0
  65. package/src/widgets/checkbox.js +0 -0
  66. package/src/widgets/divider.js +0 -0
  67. package/src/widgets/menu.js +0 -0
  68. package/src/widgets/radio.js +0 -0
  69. package/src/widgets/select.js +0 -1
  70. package/src/widgets/slider.js +0 -41
  71. package/src/widgets/text.js +0 -0
  72. package/src/widgets/widget.js +0 -51
package/README.md CHANGED
@@ -1,29 +1,94 @@
1
1
  # muigui
2
2
 
3
- > Nothing to see here...yet?
3
+ # NOT READY for USE
4
+
5
+ <!---
4
6
 
5
7
  <img src="./images/muigui.png" style="max-width: 640px">
6
8
 
7
9
  A simple Web UI library.
8
10
 
9
11
  muigui is a simple UI library in the spirit of
10
- [dat.gui](https://github.com/dataarts/dat.gui).
12
+ [dat.gui](https://github.com/dataarts/dat.gui) and/or [lil-gui](https://github.com/georgealways/).
13
+
14
+ ## Usage
15
+
16
+ ```js
17
+ import GUI from 'https://muigui.org/dist/0.x/muigui.module.js';
18
+ ```
19
+
20
+ or
21
+
22
+ ```html
23
+ <script src="https://muigui.org/dist/0.x/muigui.min.js"></script>
24
+ ```
25
+
26
+ Then
27
+
28
+ ```js
29
+ const s = {
30
+ someNumber: 123,
31
+ someString: "hello",
32
+ someOption: "dog",
33
+ someColor: '#ED3281',
34
+ someFunction: () => console.log('called')
35
+ };
36
+
37
+ const gui = new GUI();
38
+ gui.add(s, 'someNumber', 0, 200); // range 0 to 200
39
+ gui.add(s, 'someString);
40
+ gui.add(s, 'someOption, ['cat', 'bird', 'dog']);
41
+ gui.addColor(s, 'someColor');
42
+ gui.add(s, 'someFunction');
43
+ ```
44
+
45
+ produces
46
+
47
+ <img src="./images/muigui-screenshot.png" style="max-width: 275px">
48
+
49
+ or a shorter version
50
+
51
+ ```js
52
+ const s = {
53
+ someNumber: 123,
54
+ someString: "hello",
55
+ someOption: "dog",
56
+ someColor: '#ED3281',
57
+ someFunction: () => console.log('called')
58
+ };
59
+
60
+ const options = {
61
+ someNumber: [1, 200], // range 0 to 200
62
+ someOption: ['cat', 'bird', 'dog'],
63
+ }
64
+
65
+ const gui = new GUI();
66
+ gui.add(s, options);
67
+ ```
68
+
69
+ ## What
11
70
 
12
71
  It is not a general purpose library for every type of GUI.
13
72
  Rather, it is a small, easy to use library for small apps.
14
73
  Basically I liked how simple it was to use dat.gui to add
15
- a few sliders and options to a demo. What I didn't like is
16
- that dat.gui is very opinionated on style. I thought I'd
17
- try to make a DOM based UI with DOM elements only and then
18
- require CSS to style it and see how far I got.
74
+ a few sliders and options to a demo.
75
+
76
+ I thought I'd try to make a CSS/DOM based UI standard elements
77
+ only and then require CSS to style it and see how far I got.
19
78
 
20
79
  ### Not invented here syndrome
21
80
 
22
81
  It's possible this already exists but if so I couldn't find it.
23
82
  Most UI libraries seem to be giant and require a build step.
24
- I wanted something hopefully not to big and something I could
83
+ I wanted something hopefully not too big and something I could
25
84
  easily add to any example with 1 file (or 2 if you add CSS).
26
85
 
86
+ ## muigui - wat?
87
+
88
+ https://user-images.githubusercontent.com/234804/177000460-3449c2dd-da94-4119-903f-cc7460b46e7b.mp4
89
+
90
+ -->
91
+
27
92
  ## License
28
93
 
29
94
  [MIT](https://github.com/greggman/muigui/blob/main/LICENSE.md)
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "muigui",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "A Simple GUI",
5
5
  "main": "muigui.js",
6
6
  "module": "src/muigui.js",
7
7
  "scripts": {
8
- "build": "rollup -c",
8
+ "build": "npm run build-min",
9
+ "build-normal": "rollup -c",
10
+ "build-min": "rollup -c",
9
11
  "eslint": "eslint \"**/*.js\"",
10
12
  "pre-push": "npm run eslint",
11
13
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -30,11 +32,12 @@
30
32
  ],
31
33
  "homepage": "https://github.com/greggman/muiguiy#readme",
32
34
  "devDependencies": {
33
- "eslint": "^7.5.0",
34
- "eslint-plugin-html": "^6.0.2",
35
+ "@rollup/plugin-node-resolve": "^15.0.1",
36
+ "@rollup/plugin-terser": "^0.4.0",
37
+ "eslint": "^8.20.0",
38
+ "eslint-plugin-html": "^6.2.0",
35
39
  "eslint-plugin-optional-comma-spacing": "0.0.4",
36
40
  "eslint-plugin-require-trailing-comma": "0.0.1",
37
- "rollup": "^2.23.0",
38
- "rollup-plugin-node-resolve": "^5.2.0"
41
+ "rollup": "^2.77.0"
39
42
  }
40
43
  }
@@ -0,0 +1,34 @@
1
+ import {
2
+ createElem,
3
+ } from '../libs/elem.js';
4
+ import { copyExistingProperties } from '../libs/utils.js';
5
+ import Controller from './Controller.js';
6
+
7
+ export default class Button extends Controller {
8
+ #object;
9
+ #property;
10
+ #buttonElem;
11
+ #options = {
12
+ name: '',
13
+ };
14
+
15
+ constructor(object, property, options = {}) {
16
+ super('muigui-button', '');
17
+ this.#object = object;
18
+ this.#property = property;
19
+
20
+ this.#buttonElem = this.addElem(
21
+ createElem('button', {
22
+ type: 'button',
23
+ onClick: () => {
24
+ this.#object[this.#property](this);
25
+ },
26
+ }));
27
+ this.setOptions({name: property, ...options});
28
+ }
29
+ setOptions(options) {
30
+ copyExistingProperties(this.#options, options);
31
+ const {name} = this.#options;
32
+ this.#buttonElem.textContent = name;
33
+ }
34
+ }
@@ -0,0 +1,17 @@
1
+ import ElementView from '../views/ElementView.js';
2
+ import LabelController from './LabelController.js';
3
+
4
+ // TODO: remove this? Should just be user side
5
+ export default class Canvas extends LabelController {
6
+ #canvasElem;
7
+
8
+ constructor() {
9
+ super('muigui-canvas');
10
+ this.#canvasElem = this.add(
11
+ new ElementView('canvas', 'muigui-canvas'),
12
+ ).domElement;
13
+ }
14
+ get canvas() {
15
+ return this.#canvasElem;
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ import CheckboxView from '../views/CheckboxView.js';
2
+ import ValueController from './ValueController.js';
3
+
4
+ export default class Checkbox extends ValueController {
5
+ constructor(object, property) {
6
+ super(object, property, 'muigui-checkbox');
7
+ const id = this.id;
8
+ this.add(new CheckboxView(this, id));
9
+ this.updateDisplay();
10
+ }
11
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ colorFormatConverters,
3
+ guessFormat,
4
+ } from '../libs/color-utils.js';
5
+ import ValueController from './ValueController.js';
6
+ import TextView from '../views/TextView.js';
7
+ import ColorView from '../views/ColorView.js';
8
+
9
+ export default class Color extends ValueController {
10
+ #colorView;
11
+ #textView;
12
+
13
+ constructor(object, property, options = {}) {
14
+ super(object, property, 'muigui-color');
15
+ const format = options.format || guessFormat(this.getValue());
16
+ const {color, text} = colorFormatConverters[format];
17
+ this.#colorView = this.add(new ColorView(this, {converters: color}));
18
+ this.#textView = this.add(new TextView(this, {converters: text}));
19
+ this.updateDisplay();
20
+ }
21
+ setOptions(options) {
22
+ const {format} = options;
23
+ if (format) {
24
+ const {color, text} = colorFormatConverters[format];
25
+ this.#colorView.setOptions({converters: color});
26
+ this.#textView.setOptions({converters: text});
27
+ }
28
+ super.setOptions(options);
29
+ return this;
30
+ }
31
+ }
@@ -0,0 +1,12 @@
1
+ import ColorChooserView from '../views/ColorChooserView.js';
2
+ import TextView from '../views/TextView.js';
3
+ import PopDownController from './PopDownController.js';
4
+
5
+ export default class ColorChooser extends PopDownController {
6
+ constructor(object, property) {
7
+ super(object, property, 'muigui-color-chooser');
8
+ this.addTop(new TextView(this));
9
+ this.addBottom(new ColorChooserView(this));
10
+ this.updateDisplay();
11
+ }
12
+ }
@@ -0,0 +1,58 @@
1
+ import Controller from './Controller.js';
2
+
3
+ export default class Container extends Controller {
4
+ #controllers;
5
+ #childDestController;
6
+
7
+ constructor(className) {
8
+ super(className);
9
+ this.#controllers = [];
10
+ this.#childDestController = this;
11
+ }
12
+ get children() {
13
+ return this.#controllers; // should we return a copy?
14
+ }
15
+ get controllers() {
16
+ return this.#controllers.filter(c => !(c instanceof Container));
17
+ }
18
+ get folders() {
19
+ return this.#controllers.filter(c => c instanceof Container);
20
+ }
21
+ reset(recursive = true) {
22
+ for (const controller of this.#controllers) {
23
+ if (!(controller instanceof Container) || recursive) {
24
+ controller.reset(recursive);
25
+ }
26
+ }
27
+ return this;
28
+ }
29
+ remove(controller) {
30
+ const ndx = this.#controllers.indexOf(controller);
31
+ if (ndx >= 0) {
32
+ const c = this.#controllers.splice(ndx, 1);
33
+ const c0 = c[0];
34
+ const elem = c0.domElement;
35
+ elem.remove();
36
+ c0.setParent(null);
37
+ }
38
+ return this;
39
+ }
40
+ _addControllerImpl(controller) {
41
+ this.domElement.appendChild(controller.domElement);
42
+ this.#controllers.push(controller);
43
+ controller.setParent(this);
44
+ return controller;
45
+ }
46
+ addController(controller) {
47
+ return this.#childDestController._addControllerImpl(controller);
48
+ }
49
+ pushContainer(container) {
50
+ this.addController(container);
51
+ this.#childDestController = container;
52
+ return container;
53
+ }
54
+ popContainer() {
55
+ this.#childDestController = this.#childDestController.parent;
56
+ return this;
57
+ }
58
+ }
@@ -0,0 +1,138 @@
1
+ import { createElem } from '../libs/elem.js';
2
+ import { removeArrayElem } from '../libs/utils.js';
3
+ import View from '../views/View.js';
4
+
5
+ export default class Controller extends View {
6
+ #changeFns;
7
+ #finishChangeFns;
8
+ #parent;
9
+
10
+ constructor(className) {
11
+ super(createElem('div', {className: 'muigui-controller'}));
12
+ this.#changeFns = [];
13
+ this.#finishChangeFns = [];
14
+ // we need the specialization to come last so it takes precedence.
15
+ if (className) {
16
+ this.domElement.classList.add(className);
17
+ }
18
+ }
19
+ get parent() {
20
+ return this.#parent;
21
+ }
22
+ setParent(parent) {
23
+ this.#parent = parent;
24
+ this.enable(!this.disabled());
25
+ }
26
+ show(show = true) {
27
+ this.domElement.classList.toggle('muigui-hide', !show);
28
+ this.domElement.classList.toggle('muigui-show', show);
29
+ return this;
30
+ }
31
+ hide() {
32
+ return this.show(false);
33
+ }
34
+ disabled() {
35
+ return !!this.domElement.closest('.muigui-disabled');
36
+ }
37
+
38
+ enable(enable = true) {
39
+ this.domElement.classList.toggle('muigui-disabled', !enable);
40
+
41
+ // If disabled we need to set the attribute 'disabled=true' to all
42
+ // input/select/button/textarea's below
43
+ //
44
+ // If enabled we need to set the attribute 'disabled=false' to all below
45
+ // until we hit a disabled controller.
46
+ //
47
+ // ATM the problem is we can find the input/select/button/textarea elements
48
+ // but we can't easily find which controller they belong do.
49
+ // But we don't need to? We can just check up if it or parent has
50
+ // '.muigui-disabled'
51
+ ['input', 'button', 'select', 'textarea'].forEach(tag => {
52
+ this.domElement.querySelectorAll(tag).forEach(elem => {
53
+ const disabled = !!elem.closest('.muigui-disabled');
54
+ elem.disabled = disabled;
55
+ });
56
+ });
57
+
58
+ return this;
59
+ }
60
+ disable(disable = true) {
61
+ return this.enable(!disable);
62
+ }
63
+ onChange(fn) {
64
+ this.removeChange(fn);
65
+ this.#changeFns.push(fn);
66
+ return this;
67
+ }
68
+ removeChange(fn) {
69
+ removeArrayElem(this.#changeFns, fn);
70
+ return this;
71
+ }
72
+ onFinishChange(fn) {
73
+ this.removeFinishChange(fn);
74
+ this.#finishChangeFns.push(fn);
75
+ return this;
76
+ }
77
+ removeFinishChange(fn) {
78
+ removeArrayElem(this.#finishChangeFns, fn);
79
+ return this;
80
+ }
81
+ #callListeners(fns, newV) {
82
+ for (const fn of fns) {
83
+ fn.call(this, newV);
84
+ }
85
+ }
86
+ emitChange(value, object, property) {
87
+ this.#callListeners(this.#changeFns, value);
88
+ if (this.#parent) {
89
+ if (object === undefined) {
90
+ this.#parent.emitChange(value);
91
+ } else {
92
+ this.#parent.emitChange({
93
+ object,
94
+ property,
95
+ value,
96
+ controller: this,
97
+ });
98
+ }
99
+ }
100
+ }
101
+ emitFinalChange(value, object, property) {
102
+ this.#callListeners(this.#finishChangeFns, value);
103
+ if (this.#parent) {
104
+ if (object === undefined) {
105
+ this.#parent.emitChange(value);
106
+ } else {
107
+ this.#parent.emitFinalChange({
108
+ object,
109
+ property,
110
+ value,
111
+ controller: this,
112
+ });
113
+ }
114
+ }
115
+ }
116
+ getColors() {
117
+ const toCamelCase = s => s.replace(/-([a-z])/g, (m, m1) => m1.toUpperCase());
118
+ const keys = [
119
+ 'color',
120
+ 'bg-color',
121
+ 'value-color',
122
+ 'value-bg-color',
123
+ 'hover-bg-color',
124
+ 'menu-bg-color',
125
+ 'menu-sep-color',
126
+ 'disabled-color',
127
+ ];
128
+ const div = createElem('div');
129
+ this.domElement.appendChild(div);
130
+ const colors = Object.fromEntries(keys.map(key => {
131
+ div.style.color = `var(--${key})`;
132
+ const s = getComputedStyle(div);
133
+ return [toCamelCase(key), s.color];
134
+ }));
135
+ div.remove();
136
+ return colors;
137
+ }
138
+ }
@@ -0,0 +1,23 @@
1
+ import { identity } from '../libs/conversions.js';
2
+ import DirectionView from '../views/DirectionView.js';
3
+ import NumberView from '../views/NumberView.js';
4
+ // import ValueController from './ValueController.js';
5
+ import PopDownController from './PopDownController.js';
6
+
7
+
8
+ // deg2rad
9
+ // where is 0
10
+ // range (0, 360), (-180, +180), (0,0) Really this is a range
11
+
12
+ export default class Direction extends PopDownController {
13
+ #options;
14
+ constructor(object, property, options) {
15
+ super(object, property, 'muigui-direction');
16
+ this.#options = options; // FIX
17
+ this.addTop(new NumberView(this,
18
+ identity));
19
+ this.addBottom(new DirectionView(this, options));
20
+ this.updateDisplay();
21
+ }
22
+ }
23
+
@@ -0,0 +1,9 @@
1
+ import Controller from './Controller.js';
2
+
3
+ // This feels like it should be something else like
4
+ // gui.addController({className: 'muigui-divider')};
5
+ export default class Divider extends Controller {
6
+ constructor() {
7
+ super('muigui-divider');
8
+ }
9
+ }
@@ -0,0 +1,37 @@
1
+ import { createElem } from '../libs/elem.js';
2
+ import Container from './Container.js';
3
+
4
+ export default class Folder extends Container {
5
+ #labelElem;
6
+
7
+ constructor(name = 'Controls', className = 'muigui-menu') {
8
+ super(className);
9
+ this.#labelElem = createElem('label');
10
+ this.addElem(createElem('button', {
11
+ type: 'button',
12
+ onClick: () => this.toggleOpen(),
13
+ }, [this.#labelElem]));
14
+ this.pushContainer(new Container());
15
+ this.name(name);
16
+ this.open();
17
+ }
18
+ open(open = true) {
19
+ this.domElement.classList.toggle('muigui-closed', !open);
20
+ this.domElement.classList.toggle('muigui-open', open);
21
+ return this;
22
+ }
23
+ close() {
24
+ return this.open(false);
25
+ }
26
+ name(name) {
27
+ this.#labelElem.textContent = name;
28
+ return this;
29
+ }
30
+ title(title) {
31
+ return this.name(title);
32
+ }
33
+ toggleOpen() {
34
+ this.open(!this.domElement.classList.contains('muigui-open'));
35
+ return this;
36
+ }
37
+ }
@@ -0,0 +1,14 @@
1
+ import Controller from './Controller.js';
2
+
3
+ // This feels like it should be something else like
4
+ // gui.addDividing = new Controller()
5
+ export default class Label extends Controller {
6
+ constructor(text) {
7
+ super('muigui-label');
8
+ this.text(text);
9
+ }
10
+ text(text) {
11
+ this.domElement.textContent = text;
12
+ return this;
13
+ }
14
+ }
@@ -0,0 +1,32 @@
1
+ import { createElem } from '../libs/elem.js';
2
+ import { makeId } from '../libs/ids.js';
3
+ import ValueView from '../views/ValueView.js';
4
+ import Controller from './Controller.js';
5
+
6
+ export default class LabelController extends Controller {
7
+ #id;
8
+ #nameElem;
9
+
10
+ constructor(className = '', name = '') {
11
+ super('muigui-label-controller');
12
+ this.#id = makeId();
13
+ this.#nameElem = createElem('label', {for: this.#id});
14
+ this.domElement.appendChild(this.#nameElem);
15
+ this.pushSubView(new ValueView(className));
16
+ this.name(name);
17
+ }
18
+ get id() {
19
+ return this.#id;
20
+ }
21
+ name(name) {
22
+ if (this.#nameElem.title === this.#nameElem.textContent) {
23
+ this.#nameElem.title = name;
24
+ }
25
+ this.#nameElem.textContent = name;
26
+ return this;
27
+ }
28
+ tooltip(tip) {
29
+ this.#nameElem.title = tip;
30
+ }
31
+ }
32
+
@@ -0,0 +1,84 @@
1
+ import ElementView from '../views/ElementView.js';
2
+ import ValueController from './ValueController.js';
3
+ import CheckboxView from '../views/CheckboxView.js';
4
+ import { copyExistingProperties } from '../libs/utils.js';
5
+ import { createElem } from '../libs/elem.js';
6
+ /*
7
+
8
+ holder = new TabHolder
9
+ tab = holder.add(new Tab("name"))
10
+ tab.add(...)
11
+
12
+
13
+ pc = new PopdownController
14
+ top = pc.add(new Row())
15
+ top.add(new Button());
16
+ values = topRow.add(new Div())
17
+ bottom = pc.add(new Row());
18
+
19
+
20
+
21
+ pc = new PopdownController
22
+ pc.addTop
23
+ pc.addTop
24
+
25
+ pc.addBottom
26
+
27
+
28
+ */
29
+
30
+ function makeSetter(object, property) {
31
+ return {
32
+ setValue(v) {
33
+ object[property] = v;
34
+ },
35
+ setFinalValue(v) {
36
+ this.setValue(v);
37
+ },
38
+ };
39
+ }
40
+
41
+ export default class PopDownController extends ValueController {
42
+ #top;
43
+ #valuesView;
44
+ #bottom;
45
+ #options = {open: false};
46
+
47
+ constructor(object, property, options = {}) {
48
+ super(object, property, 'muigui-pop-down-controller');
49
+ /*
50
+ [ValueView
51
+ [[B][values]] upper row
52
+ [[ visual ]] lower row
53
+ ]
54
+ */
55
+ this.#top = this.add(new ElementView('div', 'muigui-pop-down-top'));
56
+ // this.#top.add(new CheckboxView(makeSetter(this.#options, 'open')));
57
+ const checkboxElem = this.#top.addElem(createElem('input', {
58
+ type: 'checkbox',
59
+ onChange: () => {
60
+ this.#options.open = checkboxElem.checked;
61
+ },
62
+ }));
63
+ this.#valuesView = this.#top.add(new ElementView('div', 'muigui-pop-down-values'));
64
+ this.#bottom = this.add(new ElementView('div', 'muigui-pop-down-bottom'));
65
+ this.setOptions(options);
66
+ }
67
+ updateDisplay() {
68
+ super.updateDisplay();
69
+ const {open} = this.#options;
70
+ this.domElement.children[1].classList.toggle('muigui-open', open);
71
+ this.domElement.children[1].classList.toggle('muigui-closed', !open);
72
+ }
73
+ setOptions(options) {
74
+ copyExistingProperties(this.#options, options);
75
+ super.setOptions(options);
76
+ this.updateDisplay();
77
+ }
78
+ addTop(view) {
79
+ return this.#valuesView.add(view);
80
+ }
81
+ addBottom(view) {
82
+ return this.#bottom.add(view);
83
+ }
84
+ }
@@ -0,0 +1,17 @@
1
+ import RadioGridView from '../views/RadioGridView.js';
2
+ import ValueController from './ValueController.js';
3
+ import { convertToKeyValues } from '../libs/key-values.js';
4
+
5
+ export default class RadioGrid extends ValueController {
6
+ constructor(object, property, options) {
7
+ super(object, property, 'muigui-radio-grid');
8
+ const valueIsNumber = typeof this.getValue() === 'number';
9
+ const {
10
+ keyValues: keyValuesInput,
11
+ cols = 3,
12
+ } = options;
13
+ const keyValues = convertToKeyValues(keyValuesInput, valueIsNumber);
14
+ this.add(new RadioGridView(this, keyValues, cols));
15
+ this.updateDisplay();
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ import ValueController from './ValueController.js';
2
+ import NumberView from '../views/NumberView.js';
3
+ import RangeView from '../views/RangeView.js';
4
+
5
+ export default class Range extends ValueController {
6
+ constructor(object, property, options) {
7
+ super(object, property, 'muigui-range');
8
+ this.add(new RangeView(this, options));
9
+ this.add(new NumberView(this, options));
10
+ }
11
+ }