etaf/etaf-playground.el
Kinneyzhang 43b17192d9 feat: implement unified etaf architecture
Deliver the unified View and Component model with retained Runtime, reactive scopes, Context, Behaviors, events, Actions, styles, Resources, Data, official UI Components, and Playground examples.\n\nVerification: make check and make load pass in the independent repository; sibling Ebox core tests pass 544/544.
2026-08-05 02:56:13 +08:00

115 lines
3.6 KiB
EmacsLisp

;;; etaf-playground.el --- Small ETAF application examples -*- lexical-binding: t; -*-
;; SPDX-License-Identifier: GPL-3.0-or-later
;;; Commentary:
;; The ETAF playground is an optional application example. It exercises only
;; public ETAF APIs; the Ebox playground remains a separate sibling package.
;;; Code:
(require 'cl-lib)
(require 'etaf)
(defconst etaf-playground-buffer-name "*ETAF Playground*"
"Default buffer name used by `etaf-playground-open'.")
;;;###autoload
(etaf-define-component etaf-playground-counter (&key title)
"Render a small stateful counter titled TITLE.
The counter demonstrates a retained `:setup' Scope, reactive state, semantic
Host references, and ordinary `:on-press' callbacks without introducing a
special counter node or a second event model."
:setup
(let ((count (etaf-ref 0 :name 'playground-count)))
(lambda ()
(etaf-view
(column
:class "etaf-playground-counter"
(text :face 'bold (expr :value title))
(text
(expr :value (format "Count: %d" (etaf-value count))))
(row
(text
:ref 'decrement
:role 'button
:tab-index 0
:on-press (lambda () (cl-decf (etaf-value count)))
" - ")
(text
:ref 'increment
:role 'button
:tab-index 0
:on-press (lambda () (cl-incf (etaf-value count)))
" + ")))))))
;;;###autoload
(defun etaf-playground-view ()
"Return the core ETAF playground View.
The returned View has no buffer or global state side effect until it is passed
to `etaf-mount'."
(etaf-view
(column
:class "etaf-playground-root"
(text :face 'bold "ETAF Playground")
(text :color "#687386"
"One grammar: Hosts, Components, props, children, and expr.")
(etaf-playground-counter :title "Reactive counter")
(text :color "#687386"
"Press + or - with `etaf-dispatch-event' or the normal event bridge."))))
;;;###autoload
(defun etaf-playground-ui-view ()
"Return a playground View that also demonstrates the official UI catalog.
Loading this function requires `etaf-ui'; the core playground itself does not
depend on that optional Component catalog."
(require 'etaf-ui)
(etaf-view
(column
(etaf-panel :title "Official Components"
(etaf-button
:label "A public Component"
:on-press (lambda () (message "ETAF UI button pressed")))
(etaf-checkbox
:checked nil
:label "Controlled checkbox"
:on-change (lambda (value)
(message "Checkbox value: %s" value))))
(etaf-playground-counter :title "Core counter"))))
;;;###autoload
(defun etaf-playground-open (&optional buffer-name)
"Mount the core ETAF playground in BUFFER-NAME and return its buffer."
(interactive)
(etaf-mount (or buffer-name etaf-playground-buffer-name)
(etaf-playground-view)))
;;;###autoload
(defun etaf-playground-open-ui (&optional buffer-name)
"Mount the ETAF playground with official UI Components in BUFFER-NAME."
(interactive)
(etaf-mount (or buffer-name etaf-playground-buffer-name)
(etaf-playground-ui-view)))
;;;###autoload
(defun etaf-playground-close (&optional buffer-name)
"Unmount and kill the playground BUFFER-NAME, returning its buffer.
When BUFFER-NAME is nil, use `etaf-playground-buffer-name'."
(interactive)
(let* ((name (or buffer-name etaf-playground-buffer-name))
(buffer (get-buffer name)))
(when-let ((runtime (and buffer (etaf-runtime-for-buffer buffer))))
(etaf-unmount runtime))
(when buffer
(kill-buffer buffer))
buffer))
(provide 'etaf-playground)
;;; etaf-playground.el ends here