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

Add the render event dispatched on roots #15

Merged
merged 1 commit into from
Sep 12, 2017
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## Unreleased

- …
- Dispatch the render event on roots.

The render event provides a hook to add custom logic after the render is
complete. It allows to restore focus, selection and caret positions after
render.

## 0.1.0 (September 8, 2017)

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,12 @@ I know, I know. But it works! Check out the examples:

- [example01][] - an obligatory Todo App.
- [example02][] by @flynnham.
- [example03][] illustrates limitations of _innerself_ when dealing with text
inputs and how to work around them.

[example01]: https://stasm.github.io/innerself/example01/
[example02]: https://stasm.github.io/innerself/example02/
[example03]: https://stasm.github.io/innerself/example03/


## How It Works
Expand Down
12 changes: 12 additions & 0 deletions example03/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import html from "../index";
import { connect } from "./store";

import TextInput from "./TextInput";
import CharCounter from "./CharCounter";

export default function App(idx) {
return html`
${TextInput(idx)}
${CharCounter()}
`;
}
10 changes: 10 additions & 0 deletions example03/CharCounter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import html from "../index";
import { connect } from "./store";

function CharCounter({value}) {
return html`
<div>Characters typed: ${value.length}</div>
`;
}

export default connect(CharCounter);
11 changes: 11 additions & 0 deletions example03/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# innerself example 03

An example illustrating how much hand-holding innerself needs to handle
form-based elements. Because the assignment to innerHTML completely re-creates
the entire DOM tree under the root, all local state of the descendant elements
is lost upop re-render. Focus and selection need to be restored manually.

To install the dependencies and serve the example locally run:

$ npm install
$ npm start
12 changes: 12 additions & 0 deletions example03/TextInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import html from "../index";
import { connect } from "./store";

function TextInput({value}, idx) {
return html`
<textarea id="text-input-${idx}"
placeholder="Type here…"
onkeyup="dispatch('CHANGE_VALUE', this)">${value}</textarea>
`;
}

export default connect(TextInput);
14 changes: 14 additions & 0 deletions example03/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<meta charset="utf8">
<title>innerself example 03</title>
<script defer src="dist.js"></script>

<h1>innerself example 03</h1>
<h2>Focus is lost after re-render by default</h2>
<div id="root1"></div>
<h2>Use the render event to restore focus</h2>
<div id="root2"></div>
<h2>Use the render event to restore focus and caret position</h2>
<div id="root3"></div>


29 changes: 29 additions & 0 deletions example03/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { attach } from "./store";
import App from "./App";

const root1 = document.querySelector("#root1");
const root2 = document.querySelector("#root2");
const root3 = document.querySelector("#root3");

attach(() => App(1), root1);
attach(() => App(2), root2);
attach(() => App(3), root3);

root2.addEventListener("render", function(event) {
// event.detail is the state that was rendered.
const { id, selectionStart, selectionEnd } = event.detail;
if (id) {
const textarea = root2.querySelector("#" + id);
textarea.focus();
}
});

root3.addEventListener("render", function(event) {
// event.detail is the state that was rendered.
const { id, selectionStart, selectionEnd } = event.detail;
if (id) {
const textarea = root3.querySelector("#" + id);
textarea.focus();
textarea.setSelectionRange(selectionStart, selectionEnd);
}
});
Loading