(define-macro (mithril:init) "(mithril:init) Loads Mithril into the document head and sets the pragma->sxml function." `(begin (get-resource "https://cdnjs.cloudflare.com/ajax/libs/mithril/2.2.2/mithril.min.js") (pragma->sxml m))) (mithril:init) (define-macro (mithril:comp view . args) "(mithril:comp view . args) Creates a Mithril component object, where VIEW is a function body used to display the component, and ARGS is a list of keyword-value pairs that specify additional values on the component object. For example, the following code creates a stateful heading component: ``` (define Heading (component (sxml (h1 ~vnode.state.title)) :title \"Title Text\")) ```" (when (and (not (null? args)) (= (remainder (length args) 2) 1)) (error (format "mithril:comp-> Component macro expects even length args list. Call: (mithril:comp ~s ~s)" view args))) `(object :view (lambda (vnode) (,@view)) ,@args)) (define (mithril:repl prompt) "(mithril:repl prompt preamble) Returns a REPL Mithril component that allows evaluating custom LIPS code. The environment used by this REPL is the same as the application execution environment, meaning that the DOM and running scripts can be modified. PROMPT specifies the user prompt." (let* ((add-line (lambda (state text prompt?) (map (lambda (l) (set! state.lines (cons `&(:text ,l :prompt ,prompt?) state.lines))) (string-split "\n" text)))) (evaluate (lambda (state cmd) (add-line state (format "~a~a" prompt cmd) #t) (let ((res (eval (with-input-from-string cmd read)))) (when res (add-line state res #f))))) (handle-key-down (lambda (state e) (cond ((equal? e.key "Enter") (e.preventDefault) (let ((cmd state.input)) (set! state.input "") (evaluate state cmd))))))) (mithril:comp (let ((state vnode.state)) (sxml (div.repl (div.repl-output ~(list->array (map (lambda (line) (m ".line" line.text)) (reverse state.lines)))) (div.repl-input (span.prompt ~prompt) (input (@ (type "text") (value state.input) (oninput (lambda (e) (set! state.input e.target.value))) (onkeydown (lambda (e) (handle-key-down state e))) (oncreate (lambda (vnode) (set! state.inputRef vnode.dome) (vnode.dom.focus))) (onfocus (lambda () (object))) (autofocus #t))))))) :oninit (lambda (vnode) (set! vnode.state.lines '()) (set! vnode.state.input "")))))