mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-08-16 23:10:29 +00:00
Type definitions for Mithril 1.1
This commit is contained in:
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { Hyperscript } from "mithril";
|
||||
declare const h: Hyperscript;
|
||||
export = h;
|
||||
Vendored
+238
-821
File diff suppressed because it is too large
Load Diff
@@ -1,55 +0,0 @@
|
||||
|
||||
// This is the todolist example from http://lhorie.github.io/mithril/getting-started.html
|
||||
|
||||
var todo = {
|
||||
|
||||
//the Todo class has two properties
|
||||
Todo: function(data: any) {
|
||||
this.description = m.prop(data.description);
|
||||
this.done = m.prop(false);
|
||||
},
|
||||
|
||||
//the TodoList class is a list of Todo's
|
||||
TodoList: Array,
|
||||
|
||||
//the controller uses three model-level entities, of which one is a custom defined class:
|
||||
//`Todo` is the central class in this application
|
||||
//`list` is merely a generic array, with standard array methods
|
||||
//`description` is a temporary storage box that holds a string
|
||||
//
|
||||
//the `add` method simply adds a new todo to the list
|
||||
controller: function() {
|
||||
this.list = new todo.TodoList();
|
||||
this.description = m.prop("");
|
||||
|
||||
this.add = function() {
|
||||
if (this.description()) {
|
||||
this.list.push(new (<any>todo.Todo)({description: this.description()}));
|
||||
this.description("");
|
||||
}
|
||||
}.bind(this);
|
||||
},
|
||||
|
||||
//here's the view
|
||||
view: function(ctrl: any) {
|
||||
return m("html", [
|
||||
m("body", [
|
||||
m("input", {onchange: m.withAttr("value", ctrl.description), value: ctrl.description()} as any /* TODO remove `as any` */),
|
||||
m("button", {onclick: ctrl.add} as any /* TODO remove `as any` */, "Add"),
|
||||
m("table", [
|
||||
ctrl.list.map(function(task: any) {
|
||||
return m("tr", [
|
||||
m("td", [
|
||||
m("input[type=checkbox]", {onclick: m.withAttr("checked", task.done), checked: task.done()} as any /* TODO remove `as any` */)
|
||||
]),
|
||||
m("td", {style: {textDecoration: task.done() ? "line-through" : "none"}} as any /* TODO remove `as any` */, task.description()),
|
||||
])
|
||||
})
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
//initialize the application
|
||||
m.mount(document, todo);
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { Mount } from "mithril";
|
||||
declare const mount: Mount;
|
||||
export = mount;
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { Redraw } from "mithril";
|
||||
declare const redraw: Redraw;
|
||||
export = redraw;
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { Render } from "mithril";
|
||||
declare const render: Render;
|
||||
export = render;
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { Request } from "mithril";
|
||||
declare const request: Request;
|
||||
export = request;
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { Route } from "mithril";
|
||||
declare const route: Route;
|
||||
export = route;
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
declare namespace Stream {
|
||||
export type Combiner<T> = (...streams: any[]) => T;
|
||||
|
||||
export interface Stream<T> {
|
||||
/** Returns the value of the stream. */
|
||||
(): T;
|
||||
/** Sets the value of the stream. */
|
||||
(value: T): this;
|
||||
/** Creates a dependent stream whose value is set to the result of the callback function. */
|
||||
map(f: (current: T) => Stream<T> | T | void): Stream<T>;
|
||||
/** Creates a dependent stream whose value is set to the result of the callback function. */
|
||||
map<U>(f: (current: T) => Stream<U> | U): Stream<U>;
|
||||
/** This method is functionally identical to stream. It exists to conform to Fantasy Land's Applicative specification. */
|
||||
of(val?: T): Stream<T>;
|
||||
/** Apply. */
|
||||
ap<U>(f: Stream<(value: T) => U>): Stream<U>;
|
||||
/** A co-dependent stream that unregisters dependent streams when set to true. */
|
||||
end: Stream<boolean>;
|
||||
/** When a stream is passed as the argument to JSON.stringify(), the value of the stream is serialized.*/
|
||||
toJSON(): string;
|
||||
/** Returns the value of the stream. */
|
||||
valueOf(): T;
|
||||
}
|
||||
|
||||
export interface Static {
|
||||
/** Creates a stream. */
|
||||
<T>(value?: T): Stream<T>;
|
||||
/** Creates a computed stream that reactively updates if any of its upstreams are updated. */
|
||||
combine<T>(combiner: Combiner<T>, streams: Stream<any>[]): Stream<T>;
|
||||
/** Creates a stream whose value is the array of values from an array of streams. */
|
||||
merge(streams: Stream<any>[]): Stream<any[]>;
|
||||
/** Creates a new stream with the results of calling the function on every incoming stream with and accumulator and the incoming value. */
|
||||
scan<T, U>(fn: (acc: U, value: T) => U, acc: U, stream: Stream<T>): Stream<U>;
|
||||
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
|
||||
scanMerge<T,U>(pairs: [Stream<T>, (acc: U, value: T) => U][], acc: U): Stream<U>;
|
||||
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
|
||||
scanMerge<U>(pairs: [Stream<any>, (acc: U, value: any) => U][], acc: U): Stream<U>;
|
||||
/** A special value that can be returned to stream callbacks to halt execution of downstreams. */
|
||||
readonly HALT: any;
|
||||
}
|
||||
}
|
||||
|
||||
declare const Stream: Stream.Static;
|
||||
export = Stream;
|
||||
@@ -0,0 +1,738 @@
|
||||
// Typescript adaptation of mithril's test suite.
|
||||
// Not intended to be run; only to compile & check types.
|
||||
|
||||
import * as m from 'mithril'
|
||||
import * as stream from 'mithril/stream'
|
||||
|
||||
const FRAME_BUDGET = 100
|
||||
|
||||
{
|
||||
let vnode = m("div")
|
||||
console.assert(vnode.tag === "div")
|
||||
console.assert(typeof m.version === "string")
|
||||
console.assert(m.version.indexOf(".") > -1)
|
||||
}
|
||||
|
||||
{
|
||||
const vnode = m.trust("<br>")
|
||||
}
|
||||
|
||||
{
|
||||
const vnode = m.fragment({key: 123}, [m("div")])
|
||||
console.assert((vnode.children as m.Vnode<any,any>[]).length === 1)
|
||||
console.assert(vnode.children![0].tag === 'div')
|
||||
}
|
||||
|
||||
{
|
||||
const handler = m.withAttr("value", (value) => {})
|
||||
handler({currentTarget: {value: 10}})
|
||||
}
|
||||
|
||||
{
|
||||
const params = m.parseQueryString("?a=1&b=2")
|
||||
const query = m.buildQueryString({a: 1, b: 2})
|
||||
}
|
||||
|
||||
{
|
||||
const root = window.document.createElement("div")
|
||||
m.render(root, m("div"))
|
||||
console.assert(root.childNodes.length === 1)
|
||||
}
|
||||
|
||||
{
|
||||
const root = window.document.createElement("div")
|
||||
m.mount(root, {view: function() {return m("div")}})
|
||||
console.assert(root.childNodes.length === 1)
|
||||
console.assert(root.firstChild!.nodeName === "DIV")
|
||||
}
|
||||
|
||||
{
|
||||
const root = window.document.createElement("div")
|
||||
m.route(root, "/a", {
|
||||
"/a": {view: function() {return m("div")}}
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
console.assert(root.childNodes.length === 1)
|
||||
console.assert(root.firstChild!.nodeName === "DIV")
|
||||
}, FRAME_BUDGET)
|
||||
}
|
||||
|
||||
{
|
||||
const root = window.document.createElement("div")
|
||||
m.route.prefix("#")
|
||||
m.route(root, "/a", {
|
||||
"/a": {view: function() {return m("div")}}
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
console.assert(root.childNodes.length === 1)
|
||||
console.assert(root.firstChild!.nodeName === "DIV")
|
||||
}, FRAME_BUDGET)
|
||||
}
|
||||
|
||||
{
|
||||
const root = window.document.createElement("div")
|
||||
m.route(root, "/a", {
|
||||
"/a": {view: function() {return m("div")}}
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
console.assert(m.route.get() === "/a")
|
||||
}, FRAME_BUDGET)
|
||||
}
|
||||
|
||||
{
|
||||
const root = window.document.createElement("div")
|
||||
m.route(root, "/a", {
|
||||
"/:id": {view: function() {return m("div")}}
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
m.route.set("/b")
|
||||
setTimeout(function() {
|
||||
console.assert(m.route.get() === "/b")
|
||||
}, FRAME_BUDGET)
|
||||
}, FRAME_BUDGET)
|
||||
}
|
||||
|
||||
{
|
||||
let count = 0
|
||||
const root = window.document.createElement("div")
|
||||
m.mount(root, {view: function() {count++}})
|
||||
setTimeout(function() {
|
||||
m.redraw()
|
||||
console.assert(count === 2)
|
||||
}, FRAME_BUDGET)
|
||||
}
|
||||
|
||||
//
|
||||
// Additional tests by andraaspar
|
||||
//
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/hyperscript.html#components
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
|
||||
// define a component
|
||||
let Greeter: m.Comp<{}, {}> = {
|
||||
view: function(vnode) {
|
||||
return m("div", vnode.attrs, ["Hello ", vnode.children])
|
||||
}
|
||||
}
|
||||
|
||||
// consume it
|
||||
m(Greeter, { style: "color:red;" }, "world")
|
||||
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/hyperscript.html#keys
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
|
||||
let users = [
|
||||
{ id: 1, name: "John" },
|
||||
{ id: 2, name: "Mary" },
|
||||
]
|
||||
|
||||
function userInputs(users: { id: number, name: string }[]) {
|
||||
return users.map(function(u) {
|
||||
return m("input", { key: u.id }, u.name)
|
||||
})
|
||||
}
|
||||
|
||||
m.render(document.body, userInputs(users))
|
||||
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/components.html#state
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let ComponentWithInitialState: m.Comp<{}, {data: string}> = {
|
||||
data: "Initial content",
|
||||
view: function(vnode) {
|
||||
return m("div", vnode.state.data)
|
||||
}
|
||||
}
|
||||
|
||||
m(ComponentWithInitialState)
|
||||
})
|
||||
|
||||
;(function() {
|
||||
let ComponentWithDynamicState: m.Comp<{text: string}, {data?: string}> = {
|
||||
oninit: function(vnode) {
|
||||
vnode.state.data = vnode.attrs.text
|
||||
},
|
||||
view: function(vnode) {
|
||||
return m("div", vnode.state.data)
|
||||
}
|
||||
}
|
||||
|
||||
m(ComponentWithDynamicState, { text: "Hello" })
|
||||
})
|
||||
|
||||
;(function() {
|
||||
let ComponentUsingThis: m.Comp<{text: string}, {data?: string}> = {
|
||||
oninit: function(vnode) {
|
||||
this.data = vnode.attrs.text
|
||||
},
|
||||
view: function(vnode) {
|
||||
return m("div", this.data)
|
||||
}
|
||||
}
|
||||
|
||||
m(ComponentUsingThis, { text: "Hello" })
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/lifecycle-methods.html
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let Fader: m.Comp<{}, {}> = {
|
||||
onbeforeremove: function(vnode) {
|
||||
vnode.dom.classList.add("fade-out")
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, 1000)
|
||||
})
|
||||
},
|
||||
view: function() {
|
||||
return m("div", "Bye")
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/route.html#wrapping-a-layout-component
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
|
||||
let Home = {
|
||||
view: function() {
|
||||
return "Welcome"
|
||||
}
|
||||
}
|
||||
|
||||
let state = {
|
||||
term: "",
|
||||
search: function() {
|
||||
// save the state for this route
|
||||
// this is equivalent to `history.replaceState({term: state.term}, null, location.href)`
|
||||
m.route.set(m.route.get(), null, { replace: true, state: { term: state.term } })
|
||||
|
||||
// navigate away
|
||||
location.href = "https://google.com/?q=" + state.term
|
||||
}
|
||||
}
|
||||
|
||||
let Form: m.Comp<{term: string}, {}> = {
|
||||
oninit: function(vnode) {
|
||||
state.term = vnode.attrs.term || "" // populated from the `history.state` property if the user presses the back button
|
||||
},
|
||||
view: function() {
|
||||
return m("form", [
|
||||
m("input[placeholder='Search']", { oninput: m.withAttr("value", function(v) { state.term = v }), value: state.term }),
|
||||
m("button", { onclick: state.search }, "Search")
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
let Layout: m.Comp<{}, {}> = {
|
||||
view: function(vnode) {
|
||||
return m(".layout", vnode.children)
|
||||
}
|
||||
}
|
||||
|
||||
// example 1
|
||||
m.route(document.body, "/", {
|
||||
"/": {
|
||||
view: function() {
|
||||
return m(Layout, m(Home))
|
||||
},
|
||||
},
|
||||
"/form": {
|
||||
view: function() {
|
||||
return m(Layout, m(Form))
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// example 2
|
||||
m.route(document.body, "/", {
|
||||
"/": {
|
||||
render: function() {
|
||||
return m(Layout, m(Home))
|
||||
},
|
||||
},
|
||||
"/form": {
|
||||
render: function() {
|
||||
return m(Layout, m(Form))
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// functionally equivalent to example 1
|
||||
let Anon1 = {
|
||||
view: function() {
|
||||
return m(Layout, m(Home))
|
||||
},
|
||||
}
|
||||
let Anon2 = {
|
||||
view: function() {
|
||||
return m(Layout, m(Form))
|
||||
},
|
||||
}
|
||||
|
||||
m.route(document.body, "/", {
|
||||
"/": {
|
||||
render: function() {
|
||||
return m(Anon1)
|
||||
}
|
||||
},
|
||||
"/form": {
|
||||
render: function() {
|
||||
return m(Anon2)
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/route.html#preloading-data
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let state = {
|
||||
users: <any[]>[],
|
||||
loadUsers: function() {
|
||||
return m.request<any>("/api/v1/users").then(function(users) {
|
||||
state.users = users
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
m.route(document.body, "/user/list", {
|
||||
"/user/list": {
|
||||
onmatch: state.loadUsers,
|
||||
render: function() {
|
||||
return state.users.map(function(user) {
|
||||
return m("div", user.id)
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/request.html#monitoring-progress
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let progress = 0
|
||||
|
||||
m.mount(document.body, {
|
||||
view: function() {
|
||||
return [
|
||||
m("input[type=file]", { onchange: upload }),
|
||||
progress + "% completed"
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
function upload(e: Event) {
|
||||
let file = (<FileList>(<HTMLInputElement>e.target).files)[0]
|
||||
|
||||
let data = new FormData()
|
||||
data.append("myfile", file)
|
||||
|
||||
m.request({
|
||||
method: "POST",
|
||||
url: "/api/v1/upload",
|
||||
data: data,
|
||||
config: function(xhr) {
|
||||
xhr.addEventListener("progress", function(e) {
|
||||
progress = e.loaded / e.total
|
||||
|
||||
m.redraw() // tell Mithril that data changed and a re-render is needed
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/request.html#casting-response-to-a-type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
|
||||
// Start rewrite to TypeScript
|
||||
class User {
|
||||
name: string;
|
||||
constructor(data: any) {
|
||||
this.name = data.firstName + " " + data.lastName
|
||||
}
|
||||
}
|
||||
// End rewrite to TypeScript
|
||||
|
||||
// function User(data) {
|
||||
// this.name = data.firstName + " " + data.lastName
|
||||
// }
|
||||
|
||||
m.request<User[]>({
|
||||
method: "GET",
|
||||
url: "/api/v1/users",
|
||||
type: User
|
||||
})
|
||||
.then(function(users) {
|
||||
console.log(users[0].name) // logs a name
|
||||
})
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/request.html#non-json-responses
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
m.request<string>({
|
||||
method: "GET",
|
||||
url: "/files/icon.svg",
|
||||
deserialize: function(value) { return value }
|
||||
})
|
||||
.then(function(svg) {
|
||||
m.render(document.body, m.trust(svg))
|
||||
})
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/jsonp.html
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
m.jsonp({
|
||||
url: "/api/v1/users/:id",
|
||||
data: { id: 1 },
|
||||
callbackKey: "callback",
|
||||
})
|
||||
.then(function(result) {
|
||||
console.log(result)
|
||||
})
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/fragment.html
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let groupVisible = true
|
||||
let log = function() {
|
||||
console.log("group is now visible")
|
||||
}
|
||||
|
||||
m("ul", [
|
||||
m("li", "child 1"),
|
||||
m("li", "child 2"),
|
||||
groupVisible ? m.fragment({ oninit: log }, [
|
||||
// a fragment containing two elements
|
||||
m("li", "child 3"),
|
||||
m("li", "child 4"),
|
||||
]) : null
|
||||
])
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/stream.html#computed-properties
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let firstName = stream("John")
|
||||
let lastName = stream("Doe")
|
||||
let fullName = stream.merge([firstName, lastName]).map(function(values) {
|
||||
return values.join(" ")
|
||||
})
|
||||
|
||||
console.log(fullName()) // logs "John Doe"
|
||||
|
||||
firstName("Mary")
|
||||
|
||||
console.log(fullName()) // logs "Mary Doe"
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/stream.html#chaining-streams
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let halted = stream(1).map(function(value) {
|
||||
return stream.HALT
|
||||
})
|
||||
|
||||
halted.map(function() {
|
||||
// never runs
|
||||
})
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/stream.html#combining-streams
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let a = stream(5)
|
||||
let b = stream(7)
|
||||
|
||||
let added = stream.combine(function(a: stream.Stream<number>, b: stream.Stream<number>) {
|
||||
return a() + b()
|
||||
}, [a, b])
|
||||
|
||||
console.log(added()) // logs 12
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://mithril.js.org/stream.html#ended-state
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
let value = stream<number>()
|
||||
let doubled = value.map(function(value) { return value * 2 })
|
||||
|
||||
value.end(true) // set to ended state
|
||||
|
||||
value(5)
|
||||
|
||||
console.log(doubled())
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// https://github.com/lhorie/mithril.js/blob/master/examples/animation/mosaic.html
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Excerpt
|
||||
|
||||
;(function() {
|
||||
|
||||
let root = (<Element>document.getElementById("root"))
|
||||
|
||||
let empty: any[] = []
|
||||
let full: any[] = []
|
||||
for (let i = 0; i < 100; i++) full.push(i)
|
||||
|
||||
let cells: any[]
|
||||
|
||||
function view() {
|
||||
return m(".container", cells.map(function(i) {
|
||||
return m(".slice", {
|
||||
style: {backgroundPosition: (i % 10 * 11) + "% " + (Math.floor(i / 10) * 11) + "%"},
|
||||
onbeforeremove: exit
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
function exit(vnode: m.VnodeDOM<any, any>) {
|
||||
vnode.dom.classList.add("exit")
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
function run() {
|
||||
cells = cells === full ? empty : full
|
||||
|
||||
m.render(root, [view()])
|
||||
|
||||
setTimeout(run, 2000)
|
||||
}
|
||||
|
||||
run()
|
||||
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// https://github.com/lhorie/mithril.js/blob/master/examples/editor/index.html
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Excerpt
|
||||
|
||||
;(function() {
|
||||
|
||||
// Start extra declarations
|
||||
let marked = (v: string) => v
|
||||
// End extra declarations
|
||||
|
||||
//model
|
||||
let state = {
|
||||
text: "# Markdown Editor\n\nType on the left panel and see the result on the right panel",
|
||||
update: function(value: string) {
|
||||
state.text = value
|
||||
}
|
||||
}
|
||||
|
||||
//view
|
||||
let Editor = {
|
||||
view: function() {
|
||||
return [
|
||||
m("textarea.input", {
|
||||
oninput: m.withAttr("value", state.update),
|
||||
value: state.text
|
||||
}),
|
||||
m(".preview", m.trust(marked(state.text))),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(<Element>document.getElementById("editor"), Editor)
|
||||
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// https://github.com/lhorie/mithril.js/blob/master/examples/todomvc/todomvc.js
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
;(function() {
|
||||
|
||||
//model
|
||||
let state = {
|
||||
dispatch: function(action: string, args?: any) {
|
||||
(<any>state)[action].apply(state, args || [])
|
||||
requestAnimationFrame(function() {
|
||||
localStorage["todos-mithril"] = JSON.stringify(state.todos)
|
||||
})
|
||||
},
|
||||
|
||||
todos: JSON.parse(localStorage["todos-mithril"] || "[]"),
|
||||
editing: <any>null,
|
||||
filter: "",
|
||||
remaining: 0,
|
||||
todosByStatus: <any>[],
|
||||
showing: <string><any>undefined,
|
||||
|
||||
createTodo: function(title: string) {
|
||||
state.todos.push({title: title.trim(), completed: false})
|
||||
},
|
||||
setStatuses: function(completed: boolean) {
|
||||
for (let i = 0; i < state.todos.length; i++) state.todos[i].completed = completed
|
||||
},
|
||||
setStatus: function(todo: any, completed: boolean) {
|
||||
todo.completed = completed
|
||||
},
|
||||
destroy: function(todo: any) {
|
||||
let index = state.todos.indexOf(todo)
|
||||
if (index > -1) state.todos.splice(index, 1)
|
||||
},
|
||||
clear: function() {
|
||||
for (let i = 0; i < state.todos.length; i++) {
|
||||
if (state.todos[i].completed) state.destroy(state.todos[i--])
|
||||
}
|
||||
},
|
||||
|
||||
edit: function(todo: any) {
|
||||
state.editing = todo
|
||||
},
|
||||
update: function(title: string) {
|
||||
if (state.editing != null) {
|
||||
state.editing.title = title.trim()
|
||||
if (state.editing.title === "") state.destroy(state.editing)
|
||||
state.editing = null
|
||||
}
|
||||
},
|
||||
reset: function() {
|
||||
state.editing = null
|
||||
},
|
||||
|
||||
computed: function(vnode: m.Vnode<any, any>) {
|
||||
state.showing = vnode.attrs.status || ""
|
||||
state.remaining = state.todos.filter(function(todo: any) {return !todo.completed}).length
|
||||
state.todosByStatus = state.todos.filter(function(todo: any) {
|
||||
switch (state.showing) {
|
||||
case "": return true
|
||||
case "active": return !todo.completed
|
||||
case "completed": return todo.completed
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//view
|
||||
let Todos: m.Comp<{}, {
|
||||
add(e: Event): void
|
||||
toggleAll(): void
|
||||
toggle(todo: any): void
|
||||
focus(vnode: m.VnodeDOM<any, any>, todo: any): void
|
||||
save(e: KeyboardEvent): void
|
||||
}> = {
|
||||
add: function(e: KeyboardEvent) {
|
||||
if (e.keyCode === 13) {
|
||||
state.dispatch("createTodo", [(<HTMLInputElement>e.target).value]);
|
||||
(<HTMLInputElement>e.target).value = ""
|
||||
}
|
||||
},
|
||||
toggleAll: function() {
|
||||
state.dispatch("setStatuses", [(<HTMLInputElement>document.getElementById("toggle-all")).checked])
|
||||
},
|
||||
toggle: function(todo: any) {
|
||||
state.dispatch("setStatus", [todo, !todo.completed])
|
||||
},
|
||||
focus: function(vnode: m.VnodeDOM<any, any>, todo: any) {
|
||||
if (todo === state.editing && vnode.dom !== document.activeElement) {
|
||||
(<HTMLInputElement>vnode.dom).value = todo.title
|
||||
(<HTMLInputElement>vnode.dom).focus()
|
||||
(<HTMLInputElement>vnode.dom).selectionStart = (<HTMLInputElement>vnode.dom).selectionEnd = todo.title.length
|
||||
}
|
||||
},
|
||||
save: function(e: KeyboardEvent) {
|
||||
if (e.keyCode === 13 || e.type === "blur") state.dispatch("update", [(<HTMLInputElement>e.target).value])
|
||||
else if (e.keyCode === 27) state.dispatch("reset")
|
||||
},
|
||||
oninit: state.computed,
|
||||
onbeforeupdate: state.computed,
|
||||
view: function(vnode) {
|
||||
let ui = vnode.state
|
||||
return [
|
||||
m("header.header", [
|
||||
m("h1", "todos"),
|
||||
m("input#new-todo[placeholder='What needs to be done?'][autofocus]", {onkeypress: ui.add}),
|
||||
]),
|
||||
m("section#main", {style: {display: state.todos.length > 0 ? "" : "none"}}, [
|
||||
m("input#toggle-all[type='checkbox']", {checked: state.remaining === 0, onclick: ui.toggleAll}),
|
||||
m("label[for='toggle-all']", {onclick: ui.toggleAll}, "Mark all as complete"),
|
||||
m("ul#todo-list", [
|
||||
state.todosByStatus.map(function(todo: any) {
|
||||
return m("li", {class: (todo.completed ? "completed" : "") + " " + (todo === state.editing ? "editing" : "")}, [
|
||||
m(".view", [
|
||||
m("input.toggle[type='checkbox']", {checked: todo.completed, onclick: function() {ui.toggle(todo)}}),
|
||||
m("label", {ondblclick: function() {state.dispatch("edit", [todo])}}, todo.title),
|
||||
m("button.destroy", {onclick: function() {state.dispatch("destroy", [todo])}}),
|
||||
]),
|
||||
m("input.edit", {onupdate: function(vnode: m.VnodeDOM<any, any>) {ui.focus(vnode, todo)}, onkeypress: ui.save, onblur: ui.save})
|
||||
])
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
state.todos.length ? m("footer#footer", [
|
||||
m("span#todo-count", [
|
||||
m("strong", state.remaining),
|
||||
state.remaining === 1 ? " item left" : " items left",
|
||||
]),
|
||||
m("ul#filters", [
|
||||
m("li", m("a[href='/']", {oncreate: m.route.link, class: state.showing === "" ? "selected" : ""}, "All")),
|
||||
m("li", m("a[href='/active']", {oncreate: m.route.link, class: state.showing === "active" ? "selected" : ""}, "Active")),
|
||||
m("li", m("a[href='/completed']", {oncreate: m.route.link, class: state.showing === "completed" ? "selected" : ""}, "Completed")),
|
||||
]),
|
||||
m("button#clear-completed", {onclick: function() {state.dispatch("clear")}}, "Clear completed"),
|
||||
]) : null,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
m.route(document.getElementById("todoapp")!, "/", {
|
||||
"/": Todos,
|
||||
"/:status": Todos,
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,135 @@
|
||||
import * as m from 'mithril'
|
||||
import {ClassComponent, CVnode, CVnodeDOM} from 'mithril'
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 0.
|
||||
// Simplest component example - no attrs or state.
|
||||
//
|
||||
class Comp0 implements ClassComponent<{}> {
|
||||
constructor (vnode: CVnode<{}>) {
|
||||
}
|
||||
view() {
|
||||
return m('span', "Test")
|
||||
}
|
||||
}
|
||||
|
||||
// Mount the component
|
||||
m.mount(document.getElementById('comp0')!, Comp0)
|
||||
|
||||
// Unmount the component
|
||||
m.mount(document.getElementById('comp0')!, null)
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 1.
|
||||
// Simple example with lifecycle methods.
|
||||
//
|
||||
class Comp1 implements ClassComponent<{}> {
|
||||
oninit (vnode: CVnode<{}>) {
|
||||
}
|
||||
oncreate ({dom}: CVnodeDOM<{}>) {
|
||||
}
|
||||
view (vnode: CVnode<{}>) {
|
||||
return m('span', "Test")
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 2.
|
||||
// Component with attrs type
|
||||
//
|
||||
interface Comp2Attrs {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
class Comp2 implements ClassComponent<Comp2Attrs> {
|
||||
view ({attrs: {title, description}}: CVnode<Comp2Attrs>) {
|
||||
return [m('h2', title), m('p', description)]
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 3.
|
||||
// Declares attrs type inline.
|
||||
// Uses comp2 with typed attrs and makes use of `onremove`
|
||||
// lifecycle method.
|
||||
//
|
||||
class Comp3 implements ClassComponent<{pageHead: string}> {
|
||||
oncreate ({dom}: CVnodeDOM<{pageHead: string}>) {
|
||||
// Can do stuff with dom
|
||||
}
|
||||
view ({attrs}: CVnode<{pageHead: string}>) {
|
||||
return m('.page',
|
||||
m('h1', attrs.pageHead),
|
||||
m(Comp2,
|
||||
{
|
||||
// attrs is type checked - nice!
|
||||
title: "A Title",
|
||||
description: "Some descriptive text.",
|
||||
onremove: (vnode) => {
|
||||
// Vnode type is inferred
|
||||
console.log("comp2 was removed")
|
||||
},
|
||||
}
|
||||
),
|
||||
// Test other hyperscript parameter variations
|
||||
m(Comp1, m(Comp1)),
|
||||
m('br')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 4.
|
||||
// Typed attrs, component with state, methods
|
||||
//
|
||||
interface Comp4Attrs {
|
||||
name: string
|
||||
}
|
||||
|
||||
class Comp4 implements ClassComponent<Comp4Attrs> {
|
||||
count: number
|
||||
constructor (vnode: CVnode<Comp4Attrs>) {
|
||||
this.count = 0
|
||||
}
|
||||
add (num: number) {
|
||||
this.count += num
|
||||
}
|
||||
view ({attrs}: CVnode<Comp4Attrs>) {
|
||||
return [
|
||||
m('h1', `This ${attrs.name} has been clicked ${this.count} times`),
|
||||
m('button',
|
||||
{
|
||||
onclick: () => this.add(1)
|
||||
},
|
||||
"Click me")
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Test that all are mountable components
|
||||
//
|
||||
m.route(document.body, '/', {
|
||||
'/comp0': Comp0,
|
||||
'/comp1': Comp1,
|
||||
'/comp2': Comp2,
|
||||
'/comp3': Comp3,
|
||||
'/comp4': Comp4
|
||||
})
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Concise module example with default export
|
||||
//
|
||||
export interface Attrs {
|
||||
name: string
|
||||
}
|
||||
|
||||
export default class MyComponent implements ClassComponent<Attrs> {
|
||||
count = 0
|
||||
view ({attrs}: CVnode<Attrs>) {
|
||||
return m('span', `name: ${attrs.name}, count: ${this.count}`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
import * as m from 'mithril'
|
||||
import {Component, Comp} from 'mithril'
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 0.
|
||||
// Simplest component example - no attrs or state.
|
||||
//
|
||||
const comp0 = {
|
||||
view() {
|
||||
return m('span', "Test")
|
||||
}
|
||||
}
|
||||
|
||||
// Mount the component
|
||||
m.mount(document.getElementById('comp0')!, comp0)
|
||||
|
||||
// Unmount the component
|
||||
m.mount(document.getElementById('comp0')!, null)
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 1.
|
||||
// Simple example. Vnode type for component methods is inferred.
|
||||
//
|
||||
const comp1: Component<{},{}> = {
|
||||
oncreate ({dom}) {
|
||||
// vnode.dom type inferred
|
||||
},
|
||||
view (vnode) {
|
||||
return m('span', "Test")
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 2.
|
||||
// Component with attrs
|
||||
//
|
||||
interface Comp2Attrs {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const comp2: Component<Comp2Attrs,{}> = {
|
||||
view ({attrs: {title, description}}) { // Comp2Attrs type is inferred
|
||||
return [m('h2', title), m('p', description)]
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 3.
|
||||
// Declares attrs type inline.
|
||||
// Uses comp2 with typed attrs and makes use of `onremove`
|
||||
// lifecycle method.
|
||||
//
|
||||
const comp3: Component<{pageHead: string},{}> = {
|
||||
oncreate ({dom}) {
|
||||
// Can do stuff with dom
|
||||
},
|
||||
view ({attrs}) {
|
||||
return m('.page',
|
||||
m('h1', attrs.pageHead),
|
||||
m(comp2,
|
||||
{
|
||||
// attrs is type checked - nice!
|
||||
title: "A Title",
|
||||
description: "Some descriptive text.",
|
||||
onremove: (vnode) => {
|
||||
console.log("comp2 was removed")
|
||||
},
|
||||
}
|
||||
),
|
||||
// Test other hyperscript parameter variations
|
||||
m(comp1, m(comp1)),
|
||||
m('br')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 4.
|
||||
// Typed attrs and state, and `this` type is inferred.
|
||||
//
|
||||
interface Comp4Attrs {
|
||||
name: string
|
||||
}
|
||||
|
||||
interface Comp4State {
|
||||
count: number
|
||||
add: (this: Comp4State, num: number) => void
|
||||
}
|
||||
|
||||
// Either of these two Comp4 defs will work:
|
||||
type Comp4 = Component<Comp4Attrs,Comp4State> & Comp4State
|
||||
//interface Comp4 extends Component<Comp4Attrs,Comp4State>, Comp4State {}
|
||||
|
||||
const comp4: Comp4 = {
|
||||
count: 0, // <- Must be declared to satisfy Comp4 type which includes Comp4State type
|
||||
add (num) {
|
||||
// num and this types inferred
|
||||
this.count += num
|
||||
},
|
||||
oninit() {
|
||||
this.count = 0
|
||||
},
|
||||
view ({attrs}) {
|
||||
return [
|
||||
m('h1', `This ${attrs.name} has been clicked ${this.count} times`),
|
||||
m('button',
|
||||
{
|
||||
// 'this' is typed!
|
||||
onclick: () => this.add(1)
|
||||
},
|
||||
"Click me")
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 5.
|
||||
// Stateful component (Equivalent to Comp4 example.)
|
||||
// Avoids the use of `this` completely; state manipulated
|
||||
// through vnode.state.
|
||||
//
|
||||
const comp5: Component<Comp4Attrs,Comp4State> = {
|
||||
oninit ({state}) {
|
||||
state.count = 0
|
||||
state.add = num => {state.count += num}
|
||||
},
|
||||
view ({attrs, state}) {
|
||||
return [
|
||||
m('h1', `This ${attrs.name} has been clicked ${state.count} times`),
|
||||
m('button',
|
||||
{
|
||||
onclick: () => {state.add(1)}
|
||||
},
|
||||
"Click me"
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Concise module example with default export
|
||||
//
|
||||
interface Attrs {
|
||||
name: string
|
||||
}
|
||||
|
||||
interface State {
|
||||
count: number
|
||||
}
|
||||
|
||||
export default {
|
||||
count: 0,
|
||||
view ({attrs}) {
|
||||
return m('span', `name: ${attrs.name}, count: ${this.count}`)
|
||||
}
|
||||
} as Comp<Attrs,State>
|
||||
// Using the Comp type will apply the State intersection type for us.
|
||||
@@ -0,0 +1,179 @@
|
||||
import * as m from 'mithril'
|
||||
import {Component, FactoryComponent, Vnode} from 'mithril'
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 0.
|
||||
// Simplest component example - no attrs or state.
|
||||
//
|
||||
function comp0() {
|
||||
return {
|
||||
view() {
|
||||
return m('span', "Test")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mount the component
|
||||
m.mount(document.getElementById('comp0')!, comp0)
|
||||
|
||||
// Unmount the component
|
||||
m.mount(document.getElementById('comp0')!, null)
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 1.
|
||||
// Simple example. Vnode type for component methods is inferred.
|
||||
//
|
||||
function comp1() {
|
||||
return {
|
||||
oncreate ({dom}) {
|
||||
// vnode.dom type inferred
|
||||
},
|
||||
view (vnode) {
|
||||
return m('span', "Test")
|
||||
}
|
||||
} as Component<{},{}>
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 2.
|
||||
// Component with attrs type. Different type annotation
|
||||
// style to infer factory vnode type.
|
||||
//
|
||||
interface Comp2Attrs {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const comp2 = function (vnode) { // vnode is inferred
|
||||
return {
|
||||
view ({attrs: {title, description}}) { // Comp2Attrs type is inferred
|
||||
return [m('h2', title), m('p', description)]
|
||||
}
|
||||
}
|
||||
} as FactoryComponent<Comp2Attrs>
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 3.
|
||||
// Declares attrs type inline.
|
||||
// Uses comp2 with typed attrs and makes use of `onremove`
|
||||
// lifecycle method.
|
||||
//
|
||||
const comp3 = function() {
|
||||
return {
|
||||
oncreate ({dom}) {
|
||||
// Can do stuff with dom
|
||||
},
|
||||
view ({attrs}) {
|
||||
return m('.page',
|
||||
m('h1', attrs.pageHead),
|
||||
m(comp2,
|
||||
{
|
||||
// attrs is type checked - nice!
|
||||
title: "A Title",
|
||||
description: "Some descriptive text.",
|
||||
onremove: (vnode) => {
|
||||
console.log("comp2 was removed")
|
||||
},
|
||||
}
|
||||
),
|
||||
// Test other hyperscript parameter variations
|
||||
m(comp1, m(comp1)),
|
||||
m('br')
|
||||
)
|
||||
}
|
||||
}
|
||||
} as FactoryComponent<{pageHead: string}>
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 4.
|
||||
// Stateful component using closure method & var
|
||||
// to hold state.
|
||||
//
|
||||
interface Comp4Attrs {
|
||||
name: string
|
||||
}
|
||||
|
||||
function comp4(): Component<Comp4Attrs,{}> {
|
||||
let count = 0
|
||||
|
||||
function add (num: number) {
|
||||
count += num
|
||||
}
|
||||
|
||||
return {
|
||||
oninit() {
|
||||
count = 0
|
||||
},
|
||||
view ({attrs}) {
|
||||
return [
|
||||
m('h1', `This ${attrs.name} has been clicked ${count} times`),
|
||||
m('button',
|
||||
{
|
||||
onclick: () => add(1)
|
||||
},
|
||||
"Click me"
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// 5.
|
||||
// Stateful component (Equivalent to Comp4 example.)
|
||||
// Uses vnode.state instead of closure.
|
||||
//
|
||||
interface Comp5State {
|
||||
count: number
|
||||
add (num: number): void
|
||||
}
|
||||
|
||||
function comp5(): Component<Comp4Attrs,Comp5State> {
|
||||
return {
|
||||
oninit ({state}) {
|
||||
state.count = 0
|
||||
state.add = num => {state.count += num}
|
||||
},
|
||||
view ({attrs, state}) {
|
||||
return [
|
||||
m('h1', `This ${attrs.name} has been clicked ${state.count} times`),
|
||||
m('button',
|
||||
{
|
||||
onclick: () => {state.add(1)}
|
||||
},
|
||||
"Click me"
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Test that all are mountable components
|
||||
//
|
||||
m.route(document.body, '/', {
|
||||
'/comp0': comp0,
|
||||
'/comp1': comp1,
|
||||
'/comp2': comp2,
|
||||
'/comp3': comp3,
|
||||
'/comp4': comp4,
|
||||
'/comp5': comp5
|
||||
})
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Concise module example with default export
|
||||
//
|
||||
interface Attrs {
|
||||
name: string
|
||||
}
|
||||
|
||||
export default (): Component<Attrs,{}> => {
|
||||
let count = 0
|
||||
return {
|
||||
view ({attrs}) {
|
||||
return m('span', `name: ${attrs.name}, count: ${count}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import * as m from 'mithril'
|
||||
import {Vnode} from 'mithril/'
|
||||
import * as h from 'mithril/hyperscript'
|
||||
|
||||
const vnode = m.fragment({id: 'abc'}, ['test'])
|
||||
|
||||
m.fragment({}, ['Test', 123])
|
||||
|
||||
m.fragment(
|
||||
{
|
||||
id: 'abc',
|
||||
oninit: (vnode: Vnode<any,any>) => {
|
||||
console.log('oninit')
|
||||
}
|
||||
},
|
||||
[h('p', 'test1'), [123, h('p', 'abc'), ['abc']], 'Abc', h('p', 'test2')]
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
import * as m from 'mithril'
|
||||
|
||||
interface Result {
|
||||
id: number
|
||||
}
|
||||
|
||||
m.jsonp<Result>('/item').then(data => {
|
||||
console.log(data.id)
|
||||
})
|
||||
|
||||
class User {
|
||||
id: number
|
||||
constructor (result: Result) {
|
||||
this.id = result.id
|
||||
}
|
||||
}
|
||||
|
||||
m.jsonp<User>({
|
||||
url: '/user',
|
||||
data: {test: 'abc'},
|
||||
type: User,
|
||||
callbackName: 'getuser',
|
||||
callbackKey: 'key',
|
||||
background: true
|
||||
}).then(user => {
|
||||
console.log(user.id)
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import * as m from 'mithril'
|
||||
|
||||
const vnode = m.trust('Some <strong>bold</strong> text.')
|
||||
|
||||
const params = m.parseQueryString('?id=123')
|
||||
|
||||
const qstr = m.buildQueryString({id: 123})
|
||||
|
||||
m.render(document.body, 'Hello')
|
||||
m.render(document.body, m('h1', 'Test'))
|
||||
m.render(document.body, [
|
||||
m('h1', 'Test'), "abc", null, 123, false, m('p', 'Vnode array'),
|
||||
['a', 123, undefined, m('div', 'Nested')]
|
||||
])
|
||||
|
||||
m.redraw()
|
||||
@@ -0,0 +1,73 @@
|
||||
import * as request from 'mithril/request'
|
||||
|
||||
interface Result {
|
||||
id: number
|
||||
}
|
||||
|
||||
request<Result>({method: "GET", url: "/item"}).then(result => {
|
||||
console.log(result.id)
|
||||
})
|
||||
|
||||
request<{a: string}>("/item", {method: "POST"}).then(result => {
|
||||
console.log(result.a)
|
||||
})
|
||||
|
||||
request<any>({
|
||||
method: "GET",
|
||||
url: "/item",
|
||||
data: {x: "y"}
|
||||
}).then(result => {
|
||||
console.log(result)
|
||||
})
|
||||
|
||||
request<Result>({
|
||||
method: "GET",
|
||||
url: "/item",
|
||||
data: 5,
|
||||
serialize: (data: number) => "id=" + data.toString()
|
||||
}).then(result => {
|
||||
console.log(result)
|
||||
})
|
||||
|
||||
request<Result>('/item', {
|
||||
method: "GET",
|
||||
deserialize: str => JSON.parse(str) as Result
|
||||
}).then(result => {
|
||||
console.log(result.id)
|
||||
})
|
||||
|
||||
request<Result>('/id', {
|
||||
method: "GET",
|
||||
extract: xhr => ({id: Number(xhr.responseText)})
|
||||
}).then(result => {
|
||||
console.log(result.id)
|
||||
})
|
||||
|
||||
request<Result>('/item', {
|
||||
config: xhr => {
|
||||
xhr.setRequestHeader('accept', '*')
|
||||
},
|
||||
headers: {"Content-Type": "application/json"},
|
||||
background: true,
|
||||
}).then(result => {
|
||||
console.log(result.id)
|
||||
})
|
||||
|
||||
class Item {
|
||||
identifier: number
|
||||
constructor(result: Result) {
|
||||
this.identifier = result.id
|
||||
}
|
||||
}
|
||||
|
||||
request<Item>('/item', {
|
||||
method: 'GET',
|
||||
async: true,
|
||||
user: "Me",
|
||||
password: "qwerty",
|
||||
withCredentials: true,
|
||||
type: Item,
|
||||
useBody: false
|
||||
}).then(item => {
|
||||
console.log(item.identifier)
|
||||
})
|
||||
@@ -0,0 +1,60 @@
|
||||
import {Component} from 'mithril'
|
||||
import * as h from 'mithril/hyperscript'
|
||||
import * as route from 'mithril/route'
|
||||
|
||||
const component1 = {
|
||||
view() {
|
||||
return h('h1', 'Test')
|
||||
}
|
||||
}
|
||||
|
||||
const component2 = {
|
||||
view ({attrs: {title}}) {
|
||||
return h('h1', title)
|
||||
}
|
||||
} as Component<{title: string},{}>
|
||||
|
||||
route(document.body, '/', {
|
||||
'/': component1,
|
||||
'/test1': {
|
||||
onmatch (args, path) {
|
||||
return component1
|
||||
}
|
||||
},
|
||||
'/test2': {
|
||||
render(vnode) {
|
||||
return h(component1)
|
||||
}
|
||||
},
|
||||
'test3': {
|
||||
onmatch (args, path) {
|
||||
return component2
|
||||
},
|
||||
render (vnode) {
|
||||
return ['abc', 123, null, h(component2), ['nested', h('p', 123)]]
|
||||
}
|
||||
},
|
||||
'test4': {
|
||||
onmatch (args, path) {
|
||||
// Must provide a Promise type if we want type checking
|
||||
return new Promise<Component<{title: string},{}>>((resolve, reject) => {
|
||||
resolve(component2)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
route.prefix('/app')
|
||||
route.set('/test1')
|
||||
|
||||
route.set('/test/:id', {id: 1})
|
||||
|
||||
route.set('/test2', undefined, {
|
||||
replace: true,
|
||||
state: {abc: 123},
|
||||
title: "Title"
|
||||
})
|
||||
|
||||
const path: string = route.get()
|
||||
|
||||
const fn = route.link(h('div', 'test'))
|
||||
@@ -0,0 +1,391 @@
|
||||
import * as stream from 'mithril/stream'
|
||||
import {Stream} from 'mithril/stream'
|
||||
|
||||
{
|
||||
const s = stream(1)
|
||||
const initialValue = s()
|
||||
s(2)
|
||||
const newValue = s()
|
||||
console.assert(initialValue === 1)
|
||||
console.assert(newValue === 2)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream()
|
||||
console.assert(s() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
const s: Stream<number | undefined> = stream(1)
|
||||
s(undefined)
|
||||
console.assert(s() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(stream(1))
|
||||
console.assert(s()() === 1)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream()
|
||||
const doubled = stream.combine(function(s) {return s() * 2}, [s])
|
||||
s(2)
|
||||
console.assert(doubled() === 4)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(2)
|
||||
const doubled = stream.combine(function(s) {return s() * 2}, [s])
|
||||
console.assert(doubled() === 4)
|
||||
}
|
||||
|
||||
{
|
||||
const s1 = stream()
|
||||
const s2 = stream()
|
||||
const added = stream.combine(function(s1, s2) {return s1() + s2()}, [s1, s2])
|
||||
s1(2)
|
||||
s2(3)
|
||||
console.assert(added() === 5)
|
||||
}
|
||||
|
||||
{
|
||||
const s1 = stream(2)
|
||||
const s2 = stream(3)
|
||||
const added = stream.combine(function(s1, s2) {return s1() + s2()}, [s1, s2])
|
||||
console.assert(added() === 5)
|
||||
}
|
||||
|
||||
{
|
||||
const s1 = stream(2)
|
||||
const s2 = stream()
|
||||
const added = stream.combine(function(s1, s2) {return s1() + s2()}, [s1, s2])
|
||||
s2(3)
|
||||
console.assert(added() === 5)
|
||||
}
|
||||
|
||||
{
|
||||
let count = 0
|
||||
const a = stream()
|
||||
const b = stream.combine(function(a) {return a() * 2}, [a])
|
||||
const c = stream.combine(function(a) {return a() * a()}, [a])
|
||||
const d = stream.combine(function(b, c) {
|
||||
count++
|
||||
return b() + c()
|
||||
}, [b, c])
|
||||
a(3)
|
||||
console.assert(d() === 15)
|
||||
console.assert(count === 1)
|
||||
}
|
||||
|
||||
{
|
||||
let count = 0
|
||||
const a = stream(3)
|
||||
const b = stream.combine(function(a) {return a() * 2}, [a])
|
||||
const c = stream.combine(function(a) {return a() * a()}, [a])
|
||||
const d = stream.combine(function(b, c) {
|
||||
count++
|
||||
return b() + c()
|
||||
}, [b, c])
|
||||
console.assert(d() === 15)
|
||||
console.assert(count === 1)
|
||||
}
|
||||
|
||||
{
|
||||
let streams: Stream<any>[] = []
|
||||
const a = stream()
|
||||
const b = stream()
|
||||
const c = stream.combine(function(a, b, changed) {
|
||||
streams = changed
|
||||
}, [a, b])
|
||||
a(3)
|
||||
b(5)
|
||||
console.assert(streams.length === 1)
|
||||
console.assert(streams[0] === b)
|
||||
}
|
||||
|
||||
{
|
||||
let streams: Stream<number>[] = []
|
||||
const a = stream(3)
|
||||
const b = stream(5)
|
||||
const c = stream.combine(function(a, b, changed) {
|
||||
streams = changed
|
||||
}, [a, b])
|
||||
a(7)
|
||||
console.assert(streams.length === 1)
|
||||
console.assert(streams[0] === a)
|
||||
}
|
||||
|
||||
{
|
||||
const a = stream(1)
|
||||
const b = stream.combine(function(a) {
|
||||
return undefined
|
||||
}, [a])
|
||||
|
||||
console.assert(b() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
const a = stream(1)
|
||||
const b = stream.combine(function(a) {
|
||||
return stream(2)
|
||||
}, [a])
|
||||
console.assert(b()() === 2)
|
||||
}
|
||||
|
||||
{
|
||||
const a = stream(1)
|
||||
const b = stream.combine(function(a) {
|
||||
return stream()
|
||||
}, [a])
|
||||
console.assert(b()() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
let count = 0
|
||||
const a = stream(1)
|
||||
const b = stream.combine(function(a) {
|
||||
return stream.HALT
|
||||
}, [a])
|
||||
["fantasy-land/map"](function() {
|
||||
count++
|
||||
return 1
|
||||
})
|
||||
console.assert(b() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
const all = stream.merge([
|
||||
stream(10),
|
||||
stream("20"),
|
||||
stream({value: 30}),
|
||||
])
|
||||
}
|
||||
|
||||
{
|
||||
const straggler = stream()
|
||||
const all = stream.merge([
|
||||
stream(10),
|
||||
stream("20"),
|
||||
straggler,
|
||||
])
|
||||
console.assert(all() === undefined)
|
||||
straggler(30)
|
||||
}
|
||||
|
||||
{
|
||||
let value = 0
|
||||
const id = function(value: number) {return value}
|
||||
const a = stream<number>()
|
||||
const b = stream<number>()
|
||||
|
||||
const all = stream.merge([a.map(id), b.map(id)]).map(function(data) {
|
||||
value = data[0] + data[1]
|
||||
})
|
||||
|
||||
a(1)
|
||||
b(2)
|
||||
console.assert(value === 3)
|
||||
|
||||
a(3)
|
||||
b(4)
|
||||
console.assert(value === 7)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream()
|
||||
const doubled = stream.combine(function(stream) {return stream() * 2}, [s])
|
||||
s.end(true)
|
||||
s(3)
|
||||
console.assert(doubled() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(2)
|
||||
const doubled = stream.combine(function(stream) {return stream() * 2}, [s])
|
||||
s.end(true)
|
||||
s(3)
|
||||
console.assert(doubled() === 4)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(2)
|
||||
s.end(true)
|
||||
const doubled = stream.combine(function(stream) {return stream() * 2}, [s])
|
||||
s(3)
|
||||
console.assert(doubled() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(2)
|
||||
const doubled = stream.combine(function(stream) {return stream() * 2}, [s])
|
||||
doubled.end(true)
|
||||
s(4)
|
||||
console.assert(doubled() === 4)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream<number>()
|
||||
const doubled = s["fantasy-land/map"](function(value: number) {return value * 2})
|
||||
s(3)
|
||||
console.assert(doubled() === 6)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(3)
|
||||
const doubled = s["fantasy-land/map"](function(value: number) {return value * 2})
|
||||
console.assert(doubled() === 6)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream<undefined>()
|
||||
const mapped = s["fantasy-land/map"](function(value: undefined) {return String(value)})
|
||||
s(undefined)
|
||||
console.assert(mapped() === "undefined")
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(undefined)
|
||||
const mapped = s["fantasy-land/map"](function(value: undefined) {return String(value)})
|
||||
console.assert(mapped() === "undefined")
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(undefined)
|
||||
const mapped = s["fantasy-land/map"](function(value: undefined) {return stream()})
|
||||
console.assert(mapped()() === undefined)
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(undefined)
|
||||
console.assert(s["fantasy-land/map"] === s.map)
|
||||
}
|
||||
|
||||
{
|
||||
const apply = stream(function(value: number) {return value * 2})
|
||||
const s = stream(3)
|
||||
const applied = s["fantasy-land/ap"](apply)
|
||||
console.assert(applied() === 6)
|
||||
apply(function(value) {return value / 3})
|
||||
console.assert(applied() === 1)
|
||||
s(9)
|
||||
console.assert(applied() === 3)
|
||||
}
|
||||
|
||||
{
|
||||
const apply = stream(function(value: undefined) {return String(value)})
|
||||
const s = stream(undefined)
|
||||
const applied = s["fantasy-land/ap"](apply)
|
||||
console.assert(applied() === "undefined")
|
||||
apply(function(value) {return String(value) + "a"})
|
||||
console.assert(applied() === "undefineda")
|
||||
}
|
||||
|
||||
{
|
||||
const s = stream(3)
|
||||
const mapped = s["fantasy-land/map"](function(value: number) {return value})
|
||||
console.assert(s() === mapped())
|
||||
}
|
||||
|
||||
{
|
||||
const f = function f(x: number) {return x * 2}
|
||||
const g = function g(x: number) {return x * x}
|
||||
const s = stream(3)
|
||||
const mapped = s["fantasy-land/map"](function(value: any) {return f(g(value))})
|
||||
const composed = s["fantasy-land/map"](g)["fantasy-land/map"](f)
|
||||
console.assert(mapped() === 18)
|
||||
console.assert(mapped() === composed())
|
||||
}
|
||||
|
||||
{
|
||||
const a = stream(function(value: number) {return value * 2})
|
||||
const u = stream(function(value: number) {return value * 3})
|
||||
const v = stream(5)
|
||||
const mapped = v["fantasy-land/ap"](u["fantasy-land/ap"](a["fantasy-land/map"](function(f: any) {
|
||||
return function(g: any) {
|
||||
return function(x: any) {
|
||||
return f(g(x))
|
||||
}
|
||||
}
|
||||
})))
|
||||
const composed = v["fantasy-land/ap"](u)["fantasy-land/ap"](a)
|
||||
console.assert(mapped() === 30)
|
||||
console.assert(mapped() === composed())
|
||||
}
|
||||
|
||||
{
|
||||
const a = stream()["fantasy-land/of"](function(value: number) {return value})
|
||||
const v = stream(5)
|
||||
console.assert(v["fantasy-land/ap"](a)() === 5)
|
||||
console.assert(v["fantasy-land/ap"](a)() === v())
|
||||
}
|
||||
|
||||
{
|
||||
const a = stream(0)
|
||||
const f = function(value: number) {return value * 2}
|
||||
const x = 3
|
||||
console.assert(a["fantasy-land/of"](x)["fantasy-land/ap"](a["fantasy-land/of"](f))() === 6)
|
||||
console.assert(a["fantasy-land/of"](x)["fantasy-land/ap"](a["fantasy-land/of"](f))() === a["fantasy-land/of"](f(x))())
|
||||
}
|
||||
|
||||
{
|
||||
const u = stream(function(value: number) {return value * 2})
|
||||
const a = stream()
|
||||
const y = 3
|
||||
console.assert(a["fantasy-land/of"](y)["fantasy-land/ap"](u)() === 6)
|
||||
console.assert(a["fantasy-land/of"](y)["fantasy-land/ap"](u)() === u["fantasy-land/ap"](a["fantasy-land/of"](function(f: any) {return f(y)}))())
|
||||
}
|
||||
|
||||
// scan
|
||||
|
||||
{
|
||||
const parent = stream<number>()
|
||||
const child = stream.scan((out, p) => out - p, 123, parent)
|
||||
}
|
||||
|
||||
{
|
||||
const parent = stream<number>()
|
||||
const child = stream.scan((arr, p) => arr.concat(p), [] as number[], parent)
|
||||
parent(7)
|
||||
}
|
||||
|
||||
// scanMerge
|
||||
|
||||
{
|
||||
const parent1 = stream<number>()
|
||||
const parent2 = stream<number>()
|
||||
|
||||
const child = stream.scanMerge([
|
||||
[parent1, (out, p1) => out + p1],
|
||||
[parent2, (out, p2) => out + p2]
|
||||
], -10)
|
||||
}
|
||||
|
||||
{
|
||||
const parent1 = stream<string>()
|
||||
const parent2 = stream<string>()
|
||||
|
||||
const child = stream.scanMerge([
|
||||
[parent1, (out, p1) => out + p1],
|
||||
[parent2, (out, p2) => out + p2 + p2]
|
||||
], "a")
|
||||
|
||||
parent1("b")
|
||||
parent2("c")
|
||||
parent1("b")
|
||||
|
||||
console.assert(child() === 'abccb')
|
||||
}
|
||||
|
||||
{
|
||||
const parent1 = stream<string>()
|
||||
const parent2 = stream<number>()
|
||||
const child = stream.scanMerge([
|
||||
[parent1, (out, p1) => out + p1],
|
||||
[parent2, (out, p2) => out + p2 + p2]
|
||||
], "a")
|
||||
|
||||
parent1("a")
|
||||
parent2(1)
|
||||
|
||||
console.assert(child() === 'aa11')
|
||||
}
|
||||
+38
-22
@@ -1,23 +1,39 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": false,
|
||||
"strictNullChecks": false,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": [
|
||||
"../"
|
||||
],
|
||||
"types": [],
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"index.d.ts",
|
||||
"mithril-tests.ts"
|
||||
]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": ["es2015", "dom"],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noEmit": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": "../",
|
||||
"typeRoots": ["../"],
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"test/test-api.ts",
|
||||
"test/test-class-component.ts",
|
||||
"test/test-component.ts",
|
||||
"test/test-factory-component.ts",
|
||||
"test/test-fragment.ts",
|
||||
"test/test-jsonp.ts",
|
||||
"test/test-misc.ts",
|
||||
"test/test-request.ts",
|
||||
"test/test-route.ts",
|
||||
"test/test-stream.ts",
|
||||
"index.d.ts",
|
||||
"hyperscript.d.ts",
|
||||
"mount.d.ts",
|
||||
"redraw.d.ts",
|
||||
"render.d.ts",
|
||||
"request.d.ts",
|
||||
"route.d.ts",
|
||||
"withAttr.d.ts",
|
||||
"stream/index.d.ts"
|
||||
],
|
||||
"atom": {
|
||||
"rewriteTsconfig": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"rules": {
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
false,
|
||||
"check-space"
|
||||
],
|
||||
"indent": [
|
||||
true,
|
||||
"tabs"
|
||||
],
|
||||
"no-duplicate-variable": true,
|
||||
"no-eval": true,
|
||||
"no-internal-module": false,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-var-keyword": true,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [
|
||||
false,
|
||||
"double"
|
||||
],
|
||||
"semicolon": [false, "always"],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
false,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"variable-name": [
|
||||
true,
|
||||
"ban-keywords"
|
||||
],
|
||||
"whitespace": [
|
||||
false,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { WithAttr } from "mithril";
|
||||
declare const withAttr: WithAttr;
|
||||
export = withAttr;
|
||||
Reference in New Issue
Block a user