Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made single node selection more obvious #121

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- [#130](https://github.com/equinor/webviz-core-components/pull/130) - Added feedback button to `WebvizPluginPlaceholder`. Added `href` and `target` properties to `WebvizToolbarButton`.

### Changed
- [#121](https://github.com/equinor/webviz-core-components/pull/121) - Changed rendering of `SmartNodeSelector` component when only one node can be selected.

### Fixed
- [#124](https://github.com/equinor/webviz-core-components/pull/124) - `SmartNodeSelector` now returns all selected tags (also invalid and duplicate ones) to parent.
- [#123](https://github.com/equinor/webviz-core-components/pull/123) - Removed unused variables and added types to `SmartNodeSelector` and its tests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
min-width: 200px;
}

.SmartNodeSelector--frameless {
border: 0;
padding: 0;
padding-right: 40px;
}

.SmartNodeSelector--Invalid {
border: 1px #eb0000 solid !IMPORTANT;
}
Expand Down Expand Up @@ -164,6 +170,7 @@

.SmartNodeSelector__InnerTag {
display: flex;
flex: 1;
border-radius: 4px;
background-color: #fefefe;
white-space: nowrap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,15 +606,17 @@ export default class SmartNodeSelectorComponent extends Component<SmartNodeSelec
}

markTagsAsSelected(startIndex: number, endIndex: number): void {
this.state.nodeSelections.map((nodeSelection, index) => {
if (index >= startIndex && index <= endIndex) {
nodeSelection.setSelected(true);
}
else {
nodeSelection.setSelected(false);
}
});
this.updateState({ forceUpdate: true });
if (this.props.maxNumSelectedNodes !== 1) {
this.state.nodeSelections.map((nodeSelection, index) => {
if (index >= startIndex && index <= endIndex) {
nodeSelection.setSelected(true);
}
else {
nodeSelection.setSelected(false);
}
});
this.updateState({ forceUpdate: true });
}
}

unselectAllTags({
Expand Down Expand Up @@ -1023,23 +1025,31 @@ export default class SmartNodeSelectorComponent extends Component<SmartNodeSelec
)
}

const frameless = maxNumSelectedNodes === 1;

return (
<div id={id} ref={this.ref}>
{label && <label>{label}</label>}
<div className={classNames({
"SmartNodeSelector": true,
"SmartNodeSelector--frameless": frameless,
"SmartNodeSelector--SuggestionsActive": suggestionsVisible,
"SmartNodeSelector--Invalid":
(maxNumSelectedNodes > 0 && this.countValidSelections() > maxNumSelectedNodes)
})}
onClick={(e) => this.selectLastInput(e)}
onMouseDown={(e) => this.handleMouseDown(e)}
>
<ul className="SmartNodeSelector__Tags" ref={this.tagFieldRef}>
<ul
className="SmartNodeSelector__Tags"
ref={this.tagFieldRef}
style={frameless ? { width: "100%" } : {}}
>
{nodeSelections.map((selection, index) => (
<Tag
key={`${index}`}
index={index}
frameless={frameless}
placeholder={placeholder ? placeholder : "Add new tag"}
treeNodeSelection={selection}
countTags={this.countTags()}
Expand Down Expand Up @@ -1075,7 +1085,7 @@ export default class SmartNodeSelectorComponent extends Component<SmartNodeSelec
/>
}
</div>
{maxNumSelectedNodes > 0 && <div className={classNames({
{maxNumSelectedNodes > 1 && <div className={classNames({
"SmartNodeSelector__NumberOfTags": true,
"SmartNodeSelector__Error": this.countValidSelections() > maxNumSelectedNodes
})} ref={this.refNumberOfTags}>Selected {this.countValidSelections()} of {maxNumSelectedNodes}</div>}
Expand Down
85 changes: 53 additions & 32 deletions src/lib/components/SmartNodeSelector/components/Tag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type TagProps = {
treeNodeSelection: TreeNodeSelection;
countTags: number;
currentTag: boolean;
frameless: boolean;
checkIfDuplicate: (nodeSelection: TreeNodeSelection, index: number) => boolean;
inputKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
inputKeyUp: (e: React.KeyboardEvent<HTMLInputElement>) => void;
Expand All @@ -44,18 +45,6 @@ export default class Tag extends Component<TagProps> {
this.state = { hovered: false };
}

componentDidMount(): void {
const {treeNodeSelection} = this.props;
const input = (
treeNodeSelection.getRef() as React.RefObject<HTMLInputElement>
).current as HTMLInputElement;
if (input) {
const value = input.value === "" ? input.placeholder : input.value;
const width = this.calculateTextWidth(value);
input.style.width = width + "px";
}
}

private addAdditionalClasses(invalid: boolean): boolean {
const { currentTag, treeNodeSelection } = this.props;
return (
Expand Down Expand Up @@ -85,10 +74,10 @@ export default class Tag extends Component<TagProps> {
return classNames(ret);
}

private outerTagClasses(invalid: boolean, duplicate: boolean): string {
private outerTagClasses(invalid: boolean, duplicate: boolean, frameless: boolean): string {
return classNames({
"SmartNodeSelector__Tag": true,
"SmartNodeSelector__Border": this.displayAsTag(),
"SmartNodeSelector__Border": this.displayAsTag() || frameless,
[
!(this.addAdditionalClasses(invalid)) ? ""
: invalid ? "SmartNodeSelector__Invalid"
Expand Down Expand Up @@ -290,12 +279,51 @@ export default class Tag extends Component<TagProps> {
}
}

private calculateInputWidth(): string {
const {
treeNodeSelection,
} = this.props;
const displayText = treeNodeSelection.displayText();

if (treeNodeSelection.getFocussedNodeName() === ""
&& treeNodeSelection.getFocussedLevel() == 0) {
return "100px";
}
else {
return this.calculateTextWidth(displayText) + "px";
}
}

private makeStyle(): { [key: string]: string | number } {
const {
treeNodeSelection,
frameless,
} = this.props;

const colors = treeNodeSelection.colors();
const style = {};

if (colors.length >= 2) {
style["background"] = `linear-gradient(to left, ${colors.join(", ")}) border-box`;
style["border"] = "1px solid transparent";
}
else {
style["borderColor"] = colors[0];
}

if (frameless) {
style["flex"] = "1";
}

return style;
}

render(): React.ReactNode {
const {
index,
treeNodeSelection,
currentTag,
placeholder,
frameless,
checkIfDuplicate,
inputKeyDown,
inputKeyUp,
Expand All @@ -309,26 +337,17 @@ export default class Tag extends Component<TagProps> {
const valid = treeNodeSelection.isValid();
const duplicate = checkIfDuplicate(treeNodeSelection, index);

const colors = treeNodeSelection.colors();
const style = colors.length >= 2 ? {
background: `linear-gradient(to left, ${colors.join(", ")}) border-box`,
border: "1px solid transparent"
}
: colors.length == 1 ? {
borderColor: `${colors[0]}`
} : {};

return (
<li
key={"Tag_" + index}
title={this.tagTitle(treeNodeSelection, index)}
className={this.outerTagClasses((!valid && !currentTag), duplicate)}
style={style}
className={this.outerTagClasses((!valid && !currentTag), duplicate, frameless)}
style={this.makeStyle()}
onMouseEnter={(): void => this.setState({ hovered: true })}
onMouseLeave={(): void => this.setState({ hovered: false })}
>
{
this.displayAsTag() &&
this.displayAsTag() && !frameless &&
<button
type="button"
key={"TagRemoveButton_" + index}
Expand Down Expand Up @@ -356,15 +375,12 @@ export default class Tag extends Component<TagProps> {
(
treeNodeSelection.getFocussedNodeName() === ""
&& treeNodeSelection.getFocussedLevel() == 0
? placeholder : ""
? "Add new tag..." : ""
)
}
value={displayText}
style={{
width: (treeNodeSelection.getFocussedNodeName() === ""
&& treeNodeSelection.getFocussedLevel() == 0 ? 100
: this.calculateTextWidth(displayText)
) + "px"
width: this.calculateInputWidth()
}}
ref={treeNodeSelection.getRef()}
onInput={(e): void => this.handleInput(e)}
Expand Down Expand Up @@ -410,6 +426,11 @@ Tag.propTypes = {
* Boolean stating if this is the currently active tag.
*/
currentTag: PropTypes.bool.isRequired,
/**
* Flag stating if the tag should be displayed frameless
* (no border, no remove button).
*/
frameless: PropTypes.bool.isRequired,
/**
* Function to check if this tag is a duplicate.
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/js/__snapshots__/SmartNodeSelector.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ exports[`SmartNodeSelector Renders correctly (compare to snapshot in ./__snapsho
<input
placeholder="Add new tag..."
spellcheck="false"
style="width: 50px;"
style="width: 100px;"
type="text"
value=""
/>
Expand Down