Initial rendering of a Todos-MVC app. (events are called but don't trigger a re-rendering yet, renderin-function does not yet support updating DOM yet)

This commit is contained in:
2019-10-23 01:13:27 +02:00
parent 31cfda50f5
commit 5169c5018d
13 changed files with 361 additions and 47 deletions

View File

@@ -1,4 +1,4 @@
import {defineElement, render, CustomElement} from "../../packages/csx-custom-elements/lib";
import {defineElement, render, CustomElement} from "../../packages/csx-custom-elements";
@defineElement('example-page')
export class ExamplePage extends CustomElement{

View File

@@ -0,0 +1,50 @@
import {defineElement, render, CustomElement, Host} from "../../../packages/csx-custom-elements";
import style from './my-todo.scss';
import {TodoInput} from './todo-input';
import {TodoItem} from './todo-item';
@defineElement('my-todo')
export class MyTodo extends CustomElement{
uid = 1;
todos = [
{id: this.uid++, text: "my initial todo", checked: false },
{id: this.uid++, text: "Learn about Web Components", checked: false },
];
render(){
return (
<Host>
<style>{ style }</style>
<h1>CSX Todo</h1>
<section>
<todo-input onSubmit={this.handleSubmit}/>
<ul id="list-container"
onCheck={this.handleCheck}
onRemove={this.handleRemove}
>
{this.todos.map(item =>
<todo-item
model={ item.id }
checked={( item.checked )}
>{ item.text }</todo-item>
)}
</ul>
</section>
</Host>
);
}
handleSubmit = ({ detail: text }) => {
this.todos = [...this.todos, { id: this.uid++, text, checked: false }];
};
handleCheck = ({detail: checked}, id) => {
let indexOf = this.todos.findIndex(t=>t.id===id);
let updated = {...this.todos[indexOf], checked};
this.todos = [...this.todos.slice(0,indexOf), updated, ...this.todos.slice(indexOf+1)];
};
handleRemove = (e,id)=>{
let indexOf = this.todos.findIndex(t=>t.id===id);
this.todos = [...this.todos.slice(0,indexOf), ...this.todos.slice(indexOf+1)];
}
}

View File

@@ -0,0 +1,24 @@
:host {
display: block;
}
h1 {
font-size: 60px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.15);
}
section {
background: #fff;
margin: 30px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#list-container {
margin: 0;
padding: 0;
list-style: none;
border-top: 1px solid #e6e6e6;
}

View File

@@ -0,0 +1,35 @@
import {defineElement, render, CustomElement, Host} from "../../../packages/csx-custom-elements";
import style from './todo-input.scss';
@defineElement('todo-input')
export class TodoInput extends CustomElement{
value = "";
render(){
return (
<Host>
<style>{ style }</style>
<form onSubmit={ this.handleSubmit }>
<input
value={this.value}
type="text"
placeholder="What needs to be done?"
onInput={this.handleInput}
/>
</form>
</Host>
)
}
handleSubmit = (e)=>{
e.preventDefault();
if (!this.value) return;
this.dispatchEvent(new CustomEvent('submit', {
detail: this.value
}));
this.state = "";
};
handleInput = ({target: {value}})=>{
this.value = value;
};
}

View File

@@ -0,0 +1,29 @@
:host {
display: block;
}
form {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
input {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #CCC;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
}

View File

@@ -0,0 +1,37 @@
import {defineElement, render, CustomElement, Host, ShadowDOM} from "../../../packages/csx-custom-elements";
import style from './todo-item.scss';
@defineElement('todo-item')
export class TodoItem extends CustomElement{
checked = false;// TODO annotate as prop (attribute)
render(){
return (
<Host>
<ShadowDOM>
<style>{ style }</style>
<li class={( this.checked ? 'completed' : '' )}>
<input
type="checkbox" checked={ this.checked }
onChange={this.handleChange}
/>
<label>
<slot />
</label>
<button onClick={this.handleClick}>x</button>
</li>
</ShadowDOM>
</Host>
);
}
handleChange = ()=>{
this.dispatchEvent(new CustomEvent('check', {
detail: (this.checked=!this.checked)
}));
};
handleClick = ()=>{
this.dispatchEvent(new CustomEvent('remove', {
}));
};
}

View File

@@ -0,0 +1,88 @@
:host {
display: block;
}
li {
font-size: 24px;
display: block;
position: relative;
border-bottom: 1px solid #ededed;
}
li input {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 9px;
bottom: 0;
margin: auto 0;
border: none;
/* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
li input:after {
content: url('data:image/svg+xml;utf8,<svg%20xmlns%3D"http%3A//www.w3.org/2000/svg"%20width%3D"40"%20height%3D"40"%20viewBox%3D"-10%20-18%20100%20135"><circle%20cx%3D"50"%20cy%3D"50"%20r%3D"50"%20fill%3D"none"%20stroke%3D"%23ededed"%20stroke-width%3D"3"/></svg>');
}
li input:checked:after {
content: url('data:image/svg+xml;utf8,<svg%20xmlns%3D"http%3A//www.w3.org/2000/svg"%20width%3D"40"%20height%3D"40"%20viewBox%3D"-10%20-18%20100%20135"><circle%20cx%3D"50"%20cy%3D"50"%20r%3D"50"%20fill%3D"none"%20stroke%3D"%23bddad5"%20stroke-width%3D"3"/><path%20fill%3D"%235dc2af"%20d%3D"M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z"/></svg>');
}
li label {
white-space: pre;
word-break: break-word;
padding: 15px 60px 15px 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
li button,
li input[type="checkbox"] {
outline: none;
}
li button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
}
li button {
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
li button:hover {
color: #af5b5e;
}

View File

@@ -1,9 +1,10 @@
import {render} from "../../packages/csx-custom-elements";
import style from "./index.scss";
import {MyTodo} from "./components/my-todo";
// Replace this with an example implementation of the Todos-MVC app
// look for inspiration here: https://github.com/shprink/web-components-todo
document.body.appendChild(render(<style>{style}</style>));
document.body.appendChild(render(<div class="center-me">
<h1>Todos MVC</h1>
<MyTodo />
</div>));