Skip to content
This repository was archived by the owner on Jun 3, 2022. It is now read-only.

Commit 5dbbc93

Browse files
authored
Initial commit of component render classes. (#8)
* Initial commit of component render classes. * First pass of updates per feedback. * Another pass of updates per feedback. * Refactors components to controls using Composition rather than Inheritance. * Finalizes refactor of components to controls using Composition rather than Inheritance. * Updates constants formatting. * Fixes styles.less spacing/tabs. * Adds class commenting. Adds missing TextFieldControl. Removes SliderComponent. * Cleans up a few comment and strings. * Updates control interfaces. * Refactors variable controls to call a prop callback method when updated. * Work-in-progress. * Now clones variables during update, allowing each control to handle its own `shouldComponentUpdate` method to determine if it should be re-rendered. * Resets package.json. * Adds a render.tsx with logic that handles redrawing when variables update. * Fixes adding callbacks to internal _callbacks * Minor code cleanup.
1 parent 4318947 commit 5dbbc93

14 files changed

+954
-4
lines changed

src/core/variables/Variable.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export interface VariableListParams extends VariableParams {
4545
* @extends Function
4646
*/
4747
export interface VariableCallback extends Function {
48-
variable: Variable;
48+
variable?: Variable;
4949
}
5050

5151
/**
@@ -78,7 +78,7 @@ export class Variable implements VariableParams {
7878
this.defaultValue = defaultValue;
7979
this._selectedValue = defaultValue;
8080
if (callback) {
81-
this.callbacks.push(callback);
81+
this._callbacks.push(callback);
8282
}
8383
this._initialized = true;
8484
}
@@ -156,6 +156,14 @@ export class Variable implements VariableParams {
156156
return this._callbacks;
157157
}
158158

159+
/**
160+
* Adds a callback to array of callbacks.
161+
* @param {VariableCallback} callback The callback to add.
162+
*/
163+
addCallback(callback: VariableCallback): any {
164+
this._callbacks.push(callback);
165+
}
166+
159167
/**
160168
* Invokes each of the callback methods.
161169
*/
@@ -170,7 +178,7 @@ export class Variable implements VariableParams {
170178
* @param {VariableCallback} callback The callback to add and execute.
171179
*/
172180
addAndExecuteCallback(callback: VariableCallback): void {
173-
this.callbacks.push(callback);
181+
this._callbacks.push(callback);
174182
callback(this);
175183
}
176184

src/ui/DOMController.tsx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/** @license
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy
6+
* of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
import * as React from "react";
18+
import { KeyCode, KeyEvent, CSS } from "../lib/Constants";
19+
import { Messaging } from "../lib/Messaging";
20+
import { Overlay } from "./overlay/Overlay";
21+
import { Variable } from "../core/variables/Variable";
22+
23+
/**
24+
* Interface for the properties assigned to the DOMController component.
25+
* @interface
26+
*/
27+
interface ControllerProps {
28+
wrapperElement: HTMLElement;
29+
variables: Array<Variable>;
30+
updateVariable(variable: Variable, selectedValue: any): void;
31+
}
32+
33+
/**
34+
* Renders an MDL card-styled overlay containing a child control for each
35+
* variable.
36+
* @class
37+
* @extends React.Component
38+
*/
39+
export class DOMController extends React.Component<ControllerProps, void> {
40+
41+
/** @override */
42+
componentDidMount() {
43+
// Register for messaging and key events.
44+
Messaging.register(this.onMessageReceived.bind(this));
45+
this.addKeyListener();
46+
}
47+
48+
/** @override */
49+
componentWillUnmount() {
50+
// Unregister for messaging and key events.
51+
Messaging.unregister();
52+
this.removeKeyListener();
53+
}
54+
55+
/**
56+
* Handles receiving of window message.
57+
* @param {MessageEvent} event The received message event.
58+
*/
59+
onMessageReceived(event: MessageEvent): void {
60+
if (event.data === Messaging.type.ToggleVisibility) {
61+
this.toggleVisibility();
62+
}
63+
}
64+
65+
/** Adds a key listener. */
66+
addKeyListener(): void {
67+
document.addEventListener(KeyEvent.DOWN, (e: KeyboardEvent) => {
68+
if (e.keyCode === KeyCode.ESC) {
69+
this.toggleVisibility();
70+
}
71+
});
72+
}
73+
74+
/** Removes a key listener. */
75+
removeKeyListener(): void {
76+
document.removeEventListener(KeyEvent.DOWN);
77+
}
78+
79+
/** Toggles the Remixer overlay visibility. */
80+
toggleVisibility() {
81+
this.props.wrapperElement.classList.toggle(CSS.RMX_VISIBLE);
82+
}
83+
84+
/** @override */
85+
render() {
86+
return (
87+
<div className="mdl-card mdl-shadow--6dp">
88+
<div className="mdl-card__title" ref="myInput">
89+
<h2 className="mdl-card__title-text">Remixer</h2>
90+
</div>
91+
<div className="mdl-card__supporting-text mdl-card__actions mdl-card--border">
92+
<Overlay
93+
variables={this.props.variables}
94+
updateVariable={this.props.updateVariable}
95+
/>
96+
</div>
97+
</div>
98+
);
99+
}
100+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/** @license
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy
6+
* of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
import * as React from "react";
18+
import { ColorControlProps } from "./controlProps";
19+
import { CSS, VariableType } from "../../lib/Constants";
20+
21+
/**
22+
* A color swatch picker control consisting of a single color swatch for each
23+
* possible value.
24+
* @class
25+
* @extends React.Component
26+
*/
27+
export class ColorSwatchControl extends React.Component<ColorControlProps, void> {
28+
29+
/** Handles the update event for this control. */
30+
onClick = (event: React.FormEvent<HTMLElement>): void => {
31+
this.props.updateVariable(
32+
this.props.variable,
33+
(event.target as HTMLElement).dataset["value"]
34+
);
35+
}
36+
37+
/** @override */
38+
shouldComponentUpdate(nextProps: ColorControlProps) {
39+
return nextProps.variable !== this.props.variable;
40+
}
41+
42+
/** @override */
43+
render() {
44+
const {
45+
title,
46+
possibleValues,
47+
selectedValue
48+
} = this.props.variable;
49+
50+
return (
51+
<div className={`${CSS.RMX_COLOR_SWATCH} ${CSS.MDL_LIST_ITEM} ${CSS.MDL_TWO_LINE}`}>
52+
<span className={CSS.MDL_PRIMARY}>
53+
<span>{title}
54+
<span className={CSS.RMX_SELECTED_VALUE}>{selectedValue}</span>
55+
</span>
56+
<span className={CSS.MDL_SECONDARY}>
57+
{possibleValues.map((value: string) => (
58+
<ColorSwatch color={value} key={value}
59+
isSelected={selectedValue === value}
60+
onClick={this.onClick}
61+
/>
62+
))}
63+
</span>
64+
</span>
65+
</div>
66+
);
67+
}
68+
}
69+
70+
/**
71+
* Interface containing properties for a single color swatch.
72+
* @interface
73+
*/
74+
interface ColorSwatchProps {
75+
color: string;
76+
isSelected: boolean;
77+
onClick: any;
78+
}
79+
80+
/**
81+
* Returns a single color swatch displayed within the `ColorSwatchControl`.
82+
* @param {ColorSwatchProps} props The color swatch properties.
83+
*/
84+
function ColorSwatch(props: ColorSwatchProps) {
85+
const {
86+
color,
87+
isSelected,
88+
onClick,
89+
} = props;
90+
return (
91+
<div
92+
className={CSS.RMX_COLOR_SWATCH_ITEM}
93+
style={{backgroundColor: color}}
94+
data-value={color}
95+
onClick={onClick}
96+
>
97+
{isSelected ? <i className="material-icons">check</i> : ""}
98+
</div>
99+
);
100+
}

src/ui/controls/DropdownControl.tsx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/** @license
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy
6+
* of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
import * as React from "react";
18+
import { CSS } from "../../lib/Constants";
19+
import { StringControlProps } from "./controlProps";
20+
21+
/**
22+
* A dropdown control.
23+
* @class
24+
* @extends React.Component
25+
*/
26+
export class DropdownControl extends React.Component<StringControlProps, void> {
27+
28+
/** Handles the update event for this control. */
29+
onClick = (event: React.FormEvent<HTMLElement>): void => {
30+
this.props.updateVariable(
31+
this.props.variable,
32+
(event.target as HTMLElement).dataset["value"]
33+
);
34+
}
35+
36+
/** @override */
37+
shouldComponentUpdate(nextProps: StringControlProps) {
38+
return nextProps.variable !== this.props.variable;
39+
}
40+
41+
/** @override */
42+
render() {
43+
const {
44+
title,
45+
key,
46+
possibleValues,
47+
selectedValue
48+
} = this.props.variable;
49+
const id = `${CSS.RMX_DROPDOWN}-${key}`;
50+
51+
return (
52+
<div className={`${CSS.RMX_DROPDOWN} ${CSS.MDL_LIST_ITEM}`}>
53+
<span className={CSS.MDL_PRIMARY}>{title}</span>
54+
<span className={CSS.MDL_SECONDARY}>
55+
<button id={id} className="mdl-button mdl-js-button">
56+
<span>
57+
{selectedValue}<i className="material-icons">arrow_drop_down</i>
58+
</span>
59+
</button>
60+
<ul
61+
className="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect"
62+
htmlFor={id}
63+
>
64+
{possibleValues.map((value: string) => (
65+
<li className="mdl-menu__item" key={value}
66+
onClick={this.onClick}
67+
data-value={value}>{value}
68+
</li>
69+
))}
70+
</ul>
71+
</span>
72+
</div>
73+
);
74+
}
75+
}

src/ui/controls/RadioListControl.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/** @license
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy
6+
* of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
import * as React from "react";
18+
import { CSS, VariableType } from "../../lib/Constants";
19+
import { StringControlProps } from "./controlProps";
20+
21+
/**
22+
* A radio list control.
23+
* @class
24+
* @extends React.Component
25+
*/
26+
export class RadioListControl extends React.Component<StringControlProps, void> {
27+
28+
/** Handles the update event for this control. */
29+
onChange = (event: React.FormEvent<HTMLInputElement>): void => {
30+
this.props.updateVariable(
31+
this.props.variable,
32+
(event.target as HTMLInputElement).value
33+
);
34+
}
35+
36+
/** @override */
37+
shouldComponentUpdate(nextProps: StringControlProps) {
38+
return nextProps.variable !== this.props.variable;
39+
}
40+
41+
/** @override */
42+
render() {
43+
const {
44+
title,
45+
key,
46+
possibleValues,
47+
selectedValue
48+
} = this.props.variable;
49+
const id = `${CSS.RMX_RADIO_LIST_ITEM}-${key}`;
50+
51+
return (
52+
<div className={`${CSS.RMX_RADIO_LIST} ${CSS.MDL_LIST_ITEM}`}>
53+
<span className={CSS.MDL_PRIMARY}>{title}</span>
54+
<span className={CSS.MDL_SECONDARY}>
55+
{possibleValues.map((value: string, i: number) => (
56+
<label className={`${CSS.RMX_RADIO_LIST_ITEM} mdl-radio mdl-js-radio mdl-js-ripple-effect`}
57+
htmlFor={`${id}-${i}`} key={value}
58+
>
59+
<input type="radio" id={`${id}-${i}`}
60+
className="mdl-radio__button"
61+
name="options" value={value}
62+
checked={selectedValue === value}
63+
onChange={this.onChange}
64+
/>
65+
<span className="mdl-radio__label">{value}</span>
66+
</label>
67+
))}
68+
</span>
69+
</div>
70+
);
71+
}
72+
}

0 commit comments

Comments
 (0)