Skip to content

Instantly share code, notes, and snippets.

@mpacer
Created September 20, 2017 03:06
Show Gist options
  • Save mpacer/d622f3ea35dcd4f18ecde86c2a401701 to your computer and use it in GitHub Desktop.
Save mpacer/d622f3ea35dcd4f18ecde86c2a401701 to your computer and use it in GitHub Desktop.
Nicer tags
// pages/tags.js
// At 127.0.0.1:3000/tags on a next dev run
import React from "react";
const ButtonStyle = {
border: "none",
backgroundColor: "#c3e2e9",
display: "inline-block",
textDecoration: "none",
padding: ".25em 0.5em",
margin: "0em 0em 0em .2em",
borderRadius: "5px 5px 5px 5px",
font: "Monospace",
fontFamily: "Monospace",
verticalAlign:"middle",
fontSize: ".75em"
}
const textStyle ={
fontFamily: "Monospace",
font: "Monospace",
}
const spanStyle ={
verticalAlign:"middle",
listStyleType:"none",
backgroundColor: "#93b7bf",
border: "none",
padding: ".25em 0.2em",
borderRadius: "3px 3px 3px 3px",
margin: "0.5em 0.5em 0.5em 0.5em",
textOverflow:"ellipsis",
maxWidth:"50px",
overflow:"hidden"
}
function dropTag(tags, dropTag) {
return tags.filter((tag) => tag !== dropTag);
}
function appendTag(tags, newTag) {
// Since arrays are mutable, we use `concat` to return a copy of the original
// array with our new tag
// Question: is the reason to not just change it mutably that that isn't clean
// and against the ethos of React?
// NOTE: We're now using Set to guarantee uniqueness
// Question: why do we need to transform it back into an array for this to work?
var newtags = [].concat(tags, newTag);
var uniqtags = new Set(newtags);
// I'm assuming we can do something more interesting than alphabetical sort later on
return [...uniqtags].sort()
}
// Heavily based on the template provided in
// https://facebook.github.io/react/docs/forms.html#controlled-components
class TagForm extends React.Component{
constructor(props){
super(props);
this.state = {value: ""};
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event){
this.setState({value: event.target.value});
}
handleSubmit(event){
event.preventDefault();
this.props.onChange(appendTag(this.props.tags, this.state.value ));
this.state.value = "";
}
render() {
return (
// Q: if you uncomment line 42, this will work; why doesn't line 43?
// <form onSubmit={(e) => {this.handleSubmit(e); e.preventDefault();}}>
<form onSubmit={this.handleSubmit}>
<label>
Tag:
<input type="text" value={this.state.value} onChange={this.handleChange}/>
</label>
</form>
);
}
}
// Filled this in with my real implementation (mostly above in TagForm)
const Tags = props => (
<div>
{/*
Question: I need to pass this down to TagForm in order for it to bubble up
correctly. Is there a more idiomatic way to approach this? */}
<TagForm tags={props.tags} onChange={props.onChange}/>
<p>
{props.tags.map(
tag =>
<span
style={
{...spanStyle,
...textStyle}
}
key={tag}
>
{tag}
<Remover
tags={props.tags}
tag={tag}
onChange={props.onChange}
/>
</span>)
}
</p>
</div>
);
const Remover = props => (
<button style={ButtonStyle} onClick={
() => props.onChange(dropTag(props.tags, props.tag))}
>
×
</button>
);
export default class TagPage extends React.Component {
tagUpdate = tags => this.setState({ tags });
constructor(props) {
super(props);
this.state = {
tags: ["test"]
};
}
render() {
return <Tags tags={this.state.tags} onChange={this.tagUpdate} />;
}
}
@mpacer
Copy link
Author

mpacer commented Sep 20, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment